⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsc2003andcs7103.c

📁 TI四线式电阻触摸芯片TSC2003LINUX驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/i2c/chips/tsc2003.c * *  Copyright (C) 2005 Bill Gatliff <bgat at billgatliff.com> *  Changes for 2.6.20 kernel by Nicholas Chen <nchen at cs.umd.edu> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 as *  published by the Free Software Foundation. * *  Driver for TI's TSC2003 I2C Touch Screen Controller *///#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/string.h>#include <linux/bcd.h>#include <linux/list.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/input.h>#include <linux/delay.h>#include <asm-arm/arch-pxa/irqs.h>static unsigned short normal_i2c[]= {0x48, I2C_CLIENT_END };I2C_CLIENT_INSMOD_1(tsc2003);#define DRIVER_NAME "tsc2003"enum tsc2003_pd {  PD_POWERDOWN = 0, /* penirq */  PD_IREFOFF_ADCON = 1, /* no penirq */  PD_IREFON_ADCOFF = 2, /* penirq */  PD_IREFON_ADCON = 3, /* no penirq */  PD_PENIRQ_ARM = PD_IREFON_ADCOFF,  PD_PENIRQ_DISARM = PD_IREFON_ADCON,};enum tsc2003_m {  M_12BIT = 0,  M_8BIT = 1};enum tsc2003_cmd {  MEAS_TEMP0 = 0,  MEAS_VBAT1 = 1,  MEAS_IN1 = 2,  MEAS_TEMP1 = 4,  MEAS_VBAT2 = 5,  MEAS_IN2 = 6,  ACTIVATE_NX_DRIVERS = 8,  ACTIVATE_NY_DRIVERS = 9,  ACTIVATE_YNX_DRIVERS = 10,  MEAS_XPOS = 12,  MEAS_YPOS = 13,  MEAS_Z1POS = 14,  MEAS_Z2POS = 15};#define TSC2003_CMD(cn,pdn,m) (((cn) << 4) | ((pdn) << 2) | ((m) << 1))#define ADC_MAX ((1 << 12) - 1)struct tsc2003_data {  struct i2c_client client;  struct device_driver driver;  struct input_dev *idev;  struct timer_list penirq_timer;  struct semaphore sem;  struct task_struct *tstask;  struct completion tstask_completion;  struct completion penirq_completion;  enum tsc2003_pd pd;  enum tsc2003_m m;  int penirq;  int vbat1;  int vbat2;  int temp0;  int temp1;  int in1;  int in2;};static int tsc2003_i2c_detect (struct i2c_adapter *adapter, int address, int kind);static inline int tsc2003_command (struct tsc2003_data *data,                                   enum tsc2003_cmd cmd,                                   enum tsc2003_pd pd){  char c;  int ret;  down(&data->sem);  c = TSC2003_CMD(cmd, pd, data->m);  ret = i2c_master_send(&data->client, &c, 1);  up(&data->sem);  return ret;}static int tsc2003_read (struct tsc2003_data *data,                         enum tsc2003_cmd cmd,                         enum tsc2003_pd pd,                         int *val){  char c;  char d[2];  int ret;  c = TSC2003_CMD(cmd, pd, data->m);  ret = i2c_master_send(&data->client, &c, 1);  if (ret <= 0) goto err;  udelay(20);  ret = i2c_master_recv(&data->client, d, data->m == M_12BIT ? 2 : 1);  if (ret <= 0) goto err;  if (val)    {      *val = d[0];      *val <<= 4;      if (data->m == M_12BIT)        *val += (d[1] >> 4);    }#if defined(CONFIG_I2C_DEBUG_CHIP)  printk(KERN_ERR "%s: val[%x] = %d\n",         __FUNCTION__, cmd, (((int)d[0]) << 8) + d[1]);#endif  return 0; err:  if (!ret) ret = -ENODEV;  return ret;}static inline int tsc2003_read_temp0 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_TEMP0, pd, t);}static inline int tsc2003_read_temp1 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_TEMP1, pd, t);}static inline int tsc2003_read_xpos (struct tsc2003_data *d, enum tsc2003_pd pd, int *x){  return tsc2003_read(d, MEAS_XPOS, pd, x);}static inline int tsc2003_read_ypos (struct tsc2003_data *d, enum tsc2003_pd pd, int *y){  return tsc2003_read(d, MEAS_YPOS, pd, y);}static inline int tsc2003_read_pressure (struct tsc2003_data *d, enum tsc2003_pd pd, int *p){  return tsc2003_read(d, MEAS_Z1POS, pd, p);}static inline int tsc2003_read_in1 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_IN1, pd, t);}static inline int tsc2003_read_in2 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_IN2, pd, t);}static inline int tsc2003_read_vbat1 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_VBAT1, pd, t);}static inline int tsc2003_read_vbat2 (struct tsc2003_data *d, enum tsc2003_pd pd, int *t){  return tsc2003_read(d, MEAS_VBAT2, pd, t);}static inline int tsc2003_powerdown (struct tsc2003_data *d){  /* we don't have a distinct powerdown command,     so do a benign read with the PD bits cleared */  return tsc2003_read(d, MEAS_IN1, PD_POWERDOWN, 0);}void tsc2003_init_client (struct i2c_client *client){  struct tsc2003_data *data = i2c_get_clientdata(client);  data->pd = PD_PENIRQ_DISARM;  data->m = M_8BIT;  return;}#define PENUP_TIMEOUT 50 /* msec */static irqreturn_t tsc2003_penirq (int irq, void *v){  struct tsc2003_data *d = v;  complete(&d->penirq_completion);  return IRQ_HANDLED;}/*static int tsc2003_remove (struct device *dev){  struct tsc2003_data *d = container_of(dev->driver, struct tsc2003_data, driver);  free_irq(d->penirq,d);  input_unregister_device(d->idev);  return 0;}*/static void tsc2003_pen_up (unsigned long v){  struct tsc2003_data *d = (struct tsc2003_data *)v;  input_report_abs(d->idev, ABS_PRESSURE, 0);  input_sync(d->idev);  return;}static inline void tsc2003_restart_pen_up_timer (struct tsc2003_data *d){  mod_timer(&d->penirq_timer, jiffies + (PENUP_TIMEOUT * HZ) / 1000);}static int tsc2003ts_thread (void *v){  struct tsc2003_data *d = v;  struct task_struct *tsk = current;  int ret;    d->tstask = tsk;  daemonize(DRIVER_NAME "tsd");  allow_signal(SIGKILL);  complete(&d->tstask_completion);#if defined(CONFIG_I2C_DEBUG_CHIP)  printk(KERN_INFO "%s: address 0x%x\n",         __FUNCTION__, d->client.addr);#endif  while (!signal_pending(tsk))    {      unsigned int x, y, p;           if (!down_interruptible(&d->sem))        {          d->pd = PD_PENIRQ_DISARM;          disable_irq(d->penirq);          tsc2003_read_xpos(d, PD_PENIRQ_DISARM, &x);          tsc2003_read_ypos(d, PD_PENIRQ_DISARM, &y);          tsc2003_read_pressure(d, PD_PENIRQ_DISARM, &p);                   /* non-X-Y driver read to avoid glitch in penirq (errata?) */          tsc2003_read_vbat1(d, PD_PENIRQ_DISARM, 0);          enable_irq(d->penirq);         	            input_report_abs(d->idev, ABS_X, 4096 - x);          input_report_abs(d->idev, ABS_Y, 4096 - y);          input_report_abs(d->idev, ABS_PRESSURE, p);         input_sync(d->idev);                     do            {              ret = wait_for_completion_interruptible_timeout(&d->penirq_completion, HZ / 100);              if (ret)                {                  if (d->pd == PD_PENIRQ_DISARM)                    {                      /* fake penirq, avoid glitch and then start watching for real now */                      d->pd = PD_PENIRQ_ARM;                      tsc2003_read_vbat1(d, PD_PENIRQ_ARM, 0);                      up(&d->sem);                    }                  else                    {                      /* pen down event, (re)start the pen up timer */                      tsc2003_restart_pen_up_timer(d);                    }                }              else                {                  if (d->pd != PD_PENIRQ_ARM)                    {                      /* fake penirq never arrived, which would be the case                         for a level-triggered irq line */                      tsc2003_read_vbat1(d, PD_PENIRQ_ARM, 0);                      d->pd = PD_PENIRQ_ARM;                      up(&d->sem);                    }                  if (timer_pending(&d->penirq_timer))                    {                      /* pen is down, time to send (another) sample */                      break;                    }                  else                    {                      /* pen is up, nothing to do but wait for it to 			come down */						wait_for_completion_interruptible(&d->penirq_completion);                      /* pen is down, (re)start the pen up timer */                      tsc2003_restart_pen_up_timer(d);                      break;                    }                }            }          while (!signal_pending(tsk));        }    }       d->tstask = NULL;  complete_and_exit(&d->tstask_completion, 0);}static int tsc2003_idev_open (struct input_dev *idev){  struct tsc2003_data *d = idev->private;  int ret = 0;  if (down_interruptible(&d->sem))    return -EINTR;  if (d->tstask)    panic(DRIVER_NAME "tsd already running (!). abort.");    d->penirq_timer.data = (unsigned long)d;  d->penirq_timer.function = tsc2003_pen_up;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -