linux触摸屏驱动分析,touchscreen, struct input_dev,基于TSC2007

代码从2.6.32拷贝:

[cpp:nogutter]  view plain copy
  1. /* 
  2.  * drivers/input/touchscreen/tsc2007.c 
  3.  * 
  4.  * Copyright (c) 2008 MtekVision Co., Ltd. 
  5.  *  Kwangwoo Lee <[email protected]> 
  6.  * 
  7.  * Using code from: 
  8.  *  - ads7846.c 
  9.  *  Copyright (c) 2005 David Brownell 
  10.  *  Copyright (c) 2006 Nokia Corporation 
  11.  *  - corgi_ts.c 
  12.  *  Copyright (C) 2004-2005 Richard Purdie 
  13.  *  - omap_ts.[hc], ads7846.h, ts_osk.c 
  14.  *  Copyright (C) 2002 MontaVista Software 
  15.  *  Copyright (C) 2004 Texas Instruments 
  16.  *  Copyright (C) 2005 Dirk Behme 
  17.  * 
  18.  *  This program is free software; you can redistribute it and/or modify 
  19.  *  it under the terms of the GNU General Public License version 2 as 
  20.  *  published by the Free Software Foundation. 
  21.  */  
  22. #include <linux/module.h>  
  23. #include <linux/slab.h>  
  24. #include <linux/input.h>  
  25. #include <linux/interrupt.h>  
  26. #include <linux/i2c.h>  
  27. #include <linux/i2c/tsc2007.h>  
  28. #define TS_POLL_DELAY           1 /* ms delay between samples */  
  29. #define TS_POLL_PERIOD          1 /* ms delay between samples */  
  30. #define TSC2007_MEASURE_TEMP0       (0x0 << 4)  
  31. #define TSC2007_MEASURE_AUX     (0x2 << 4)  
  32. #define TSC2007_MEASURE_TEMP1       (0x4 << 4)  
  33. #define TSC2007_ACTIVATE_XN     (0x8 << 4)  
  34. #define TSC2007_ACTIVATE_YN     (0x9 << 4)  
  35. #define TSC2007_ACTIVATE_YP_XN      (0xa << 4)  
  36. #define TSC2007_SETUP           (0xb << 4)  
  37. #define TSC2007_MEASURE_X       (0xc << 4)  
  38. #define TSC2007_MEASURE_Y       (0xd << 4)  
  39. #define TSC2007_MEASURE_Z1      (0xe << 4)  
  40. #define TSC2007_MEASURE_Z2      (0xf << 4)  
  41. #define TSC2007_POWER_OFF_IRQ_EN    (0x0 << 2)  
  42. #define TSC2007_ADC_ON_IRQ_DIS0     (0x1 << 2)  
  43. #define TSC2007_ADC_OFF_IRQ_EN      (0x2 << 2)  
  44. #define TSC2007_ADC_ON_IRQ_DIS1     (0x3 << 2)  
  45. #define TSC2007_12BIT           (0x0 << 1)  
  46. #define TSC2007_8BIT            (0x1 << 1)  
  47. #define MAX_12BIT           ((1 << 12) - 1)  
  48. #define ADC_ON_12BIT    (TSC2007_12BIT | TSC2007_ADC_ON_IRQ_DIS0)  
  49. #define READ_Y      (ADC_ON_12BIT | TSC2007_MEASURE_Y)  
  50. #define READ_Z1     (ADC_ON_12BIT | TSC2007_MEASURE_Z1)  
  51. #define READ_Z2     (ADC_ON_12BIT | TSC2007_MEASURE_Z2)  
  52. #define READ_X      (ADC_ON_12BIT | TSC2007_MEASURE_X)  
  53. #define PWRDOWN     (TSC2007_12BIT | TSC2007_POWER_OFF_IRQ_EN)  
  54. struct ts_event {  
  55.     u16 x;  
  56.     u16 y;  
  57.     u16 z1, z2;  
  58. };  
  59. struct tsc2007 {  
  60.     struct input_dev    *input;  
  61.     char            phys[32];  
  62.     struct delayed_work work;  
  63.     struct i2c_client   *client;  
  64.     u16         model;  
  65.     u16         x_plate_ohms;  
  66.     bool            pendown;  
  67.     int         irq;  
  68.     int         (*get_pendown_state)(void);  
  69.     void            (*clear_penirq)(void);  
  70. };  
  71. static inline int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)  
  72. {  
  73.     s32 data;  
  74.     u16 val;  
  75.     data = i2c_smbus_read_word_data(tsc->client, cmd);  
  76.     if (data < 0) {  
  77.         dev_err(&tsc->client->dev, "i2c io error: %d/n", data);  
  78.         return data;  
  79.     }  
  80.     /* The protocol and raw data format from i2c interface: 
  81.      * S Addr Wr [A] Comm [A] S Addr Rd [A] [DataLow] A [DataHigh] NA P 
  82.      * Where DataLow has [D11-D4], DataHigh has [D3-D0 << 4 | Dummy 4bit]. 
  83.      */  
  84.     val = swab16(data) >> 4;  
  85.     dev_dbg(&tsc->client->dev, "data: 0x%x, val: 0x%x/n", data, val);  
  86.     return val;  
  87. }  
  88. static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)  
  89. {  
  90.     /* y- still on; turn on only y+ (and ADC) */  
  91.     tc->y = tsc2007_xfer(tsc, READ_Y);  
  92.     /* turn y- off, x+ on, then leave in lowpower */  
  93.     tc->x = tsc2007_xfer(tsc, READ_X);  
  94.     /* turn y+ off, x- on; we'll use formula #1 */  
  95.     tc->z1 = tsc2007_xfer(tsc, READ_Z1);  
  96.     tc->z2 = tsc2007_xfer(tsc, READ_Z2);  
  97.     /* Prepare for next touch reading - power down ADC, enable PENIRQ */  
  98.     tsc2007_xfer(tsc, PWRDOWN);  
  99. }  
  100. static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc)  
  101. {  
  102.     u32 rt = 0;  
  103.     /* range filtering */  
  104.     if (tc->x == MAX_12BIT)  
  105.         tc->x = 0;  
  106.     if (likely(tc->x && tc->z1)) {  
  107.         /* compute touch pressure resistance using equation #1 */  
  108.         rt = tc->z2 - tc->z1;  
  109.         rt *= tc->x;  
  110.         rt *= tsc->x_plate_ohms;  
  111.         rt /= tc->z1;  
  112.         rt = (rt + 2047) >> 12;  
  113.     }  
  114.     return rt;  
  115. }  
  116. static void tsc2007_send_up_event(struct tsc2007 *tsc)  
  117. {  
  118.     struct input_dev *input = tsc->input;  
  119.     dev_dbg(&tsc->client->dev, "UP/n");  
  120.     input_report_key(input, BTN_TOUCH, 0);  
  121.     input_report_abs(input, ABS_PRESSURE, 0);  
  122.     input_sync(input);  
  123. }  
  124. //中断后跑到这里来  
  125. static void tsc2007_work(struct work_struct *work)  
  126. {  
  127.     struct tsc2007 *ts =  
  128.         container_of(to_delayed_work(work), struct tsc2007, work);  
  129.     struct ts_event tc;  
  130.     u32 rt;  
  131.     /* 
  132.      * NOTE: We can't rely on the pressure to determine the pen down 
  133.      * state, even though this controller has a pressure sensor. 
  134.      * The pressure value can fluctuate for quite a while after 
  135.      * lifting the pen and in some cases may not even settle at the 
  136.      * expected value. 
  137.      * 
  138.      * The only safe way to check for the pen up condition is in the 
  139.      * work function by reading the pen signal state (it's a GPIO 
  140.      * and IRQ). Unfortunately such callback is not always available, 
  141.      * in that case we have rely on the pressure anyway. 
  142.      */  
  143.     if (ts->get_pendown_state) {  
  144.         if (unlikely(!ts->get_pendown_state())) {  
  145.             tsc2007_send_up_event(ts);  
  146.             ts->pendown = false;  
  147.             goto out;  
  148.         }  
  149.         dev_dbg(&ts->client->dev, "pen is still down/n");  
  150.     }  
  151.     tsc2007_read_values(ts, &tc);  
  152.     rt = tsc2007_calculate_pressure(ts, &tc); //计算压力  
  153.     if (rt > MAX_12BIT) {  
  154.         /* 
  155.          * Sample found inconsistent by debouncing or pressure is 
  156.          * beyond the maximum. Don't report it to user space, 
  157.          * repeat at least once more the measurement. 
  158.          */  
  159.         dev_dbg(&ts->client->dev, "ignored pressure %d/n", rt);  
  160.         goto out;  
  161.     }  
  162.     if (rt) {  
  163.         struct input_dev *input = ts->input;  
  164.         if (!ts->pendown) {  
  165.             dev_dbg(&ts->client->dev, "DOWN/n");  
  166.             input_report_key(input, BTN_TOUCH, 1);  
  167.             ts->pendown = true;  
  168.         }  
  169.         input_report_abs(input, ABS_X, tc.x);  
  170.         input_report_abs(input, ABS_Y, tc.y);  
  171.         input_report_abs(input, ABS_PRESSURE, rt);  
  172.         input_sync(input);  
  173.         dev_dbg(&ts->client->dev, "point(%4d,%4d), pressure (%4u)/n",  
  174.             tc.x, tc.y, rt);  
  175.     } else if (!ts->get_pendown_state && ts->pendown) {  
  176.         /* 
  177.          * We don't have callback to check pendown state, so we 
  178.          * have to assume that since pressure reported is 0 the 
  179.          * pen was lifted up. 
  180.          */  
  181.         tsc2007_send_up_event(ts);  
  182.         ts->pendown = false;  
  183.     }  
  184.  out:  
  185.     if (ts->pendown)  
  186.         schedule_delayed_work(&ts->work,  
  187.                       msecs_to_jiffies(TS_POLL_PERIOD));  
  188.     else  
  189.         enable_irq(ts->irq);  
  190. }  
  191. static irqreturn_t tsc2007_irq(int irq, void *handle)  
  192. {  
  193.     struct tsc2007 *ts = handle;  
  194.     if (!ts->get_pendown_state || likely(ts->get_pendown_state())) {  
  195.         disable_irq_nosync(ts->irq);  
  196.         schedule_delayed_work(&ts->work,  
  197.                       msecs_to_jiffies(TS_POLL_DELAY));  
  198.     }  
  199.     if (ts->clear_penirq)  
  200.         ts->clear_penirq();  
  201.     return IRQ_HANDLED;  
  202. }  
  203. static void tsc2007_free_irq(struct tsc2007 *ts)  
  204. {  
  205.     free_irq(ts->irq, ts);  
  206.     if (cancel_delayed_work_sync(&ts->work)) {  
  207.         /* 
  208.          * Work was pending, therefore we need to enable 
  209.          * IRQ here to balance the disable_irq() done in the 
  210.          * interrupt handler. 
  211.          */  
  212.         enable_irq(ts->irq);  
  213.     }  
  214. }  
  215. static int __devinit tsc2007_probe(struct i2c_client *client,  
  216.                    const struct i2c_device_id *id)  
  217. {  
  218.     struct tsc2007 *ts;  
  219.     struct tsc2007_platform_data *pdata = pdata = client->dev.platform_data;  
  220.     struct input_dev *input_dev;  
  221.     int err;  
  222.     if (!pdata) {  
  223.         dev_err(&client->dev, "platform data is required!/n");  
  224.         return -EINVAL;  
  225.     }  
  226.     if (!i2c_check_functionality(client->adapter,  
  227.                      I2C_FUNC_SMBUS_READ_WORD_DATA))  
  228.         return -EIO;  
  229.     ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL);  
  230.     input_dev = input_allocate_device();  
  231.     if (!ts || !input_dev) {  
  232.         err = -ENOMEM;  
  233.         goto err_free_mem;  
  234.     }  
  235.     ts->client = client;  
  236.     ts->irq = client->irq;  
  237.     ts->input = input_dev;  
  238.     INIT_DELAYED_WORK(&ts->work, tsc2007_work);  
  239.     ts->model             = pdata->model;  
  240.     ts->x_plate_ohms      = pdata->x_plate_ohms;  
  241.     ts->get_pendown_state = pdata->get_pendown_state;  
  242.     ts->clear_penirq      = pdata->clear_penirq;  
  243.     snprintf(ts->phys, sizeof(ts->phys),  
  244.          "%s/input0", dev_name(&client->dev));  
  245.     input_dev->name = "TSC2007 Touchscreen";  
  246.     input_dev->phys = ts->phys;  
  247.     input_dev->id.bustype = BUS_I2C;  
  248.     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);  
  249.     input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);  
  250.     input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, 0, 0);  
  251.     input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0);  
  252.     input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, 0, 0);  
  253.     if (pdata->init_platform_hw)  
  254.         pdata->init_platform_hw();  
  255.     err = request_irq(ts->irq, tsc2007_irq, 0,  
  256.             client->dev.driver->name, ts);  
  257.     if (err < 0) {  
  258.         dev_err(&client->dev, "irq %d busy?/n", ts->irq);  
  259.         goto err_free_mem;  
  260.     }  
  261.     /* Prepare for touch readings - power down ADC and enable PENIRQ */  
  262.     err = tsc2007_xfer(ts, PWRDOWN);  
  263.     if (err < 0)  
  264.         goto err_free_irq;  
  265.     err = input_register_device(input_dev);  
  266.     if (err)  
  267.         goto err_free_irq;  
  268.     i2c_set_clientdata(client, ts);  
  269.     return 0;  
  270.  err_free_irq:  
  271.     tsc2007_free_irq(ts);  
  272.     if (pdata->exit_platform_hw)  
  273.         pdata->exit_platform_hw();  
  274.  err_free_mem:  
  275.     input_free_device(input_dev);  
  276.     kfree(ts);  
  277.     return err;  
  278. }  
  279. static int __devexit tsc2007_remove(struct i2c_client *client)  
  280. {  
  281.     struct tsc2007  *ts = i2c_get_clientdata(client);  
  282.     struct tsc2007_platform_data *pdata = client->dev.platform_data;  
  283.     tsc2007_free_irq(ts);  
  284.     if (pdata->exit_platform_hw)  
  285.         pdata->exit_platform_hw();  
  286.     input_unregister_device(ts->input);  
  287.     kfree(ts);  
  288.     return 0;  
  289. }  
  290. static struct i2c_device_id tsc2007_idtable[] = {  
  291.     { "tsc2007", 0 },  
  292.     { }  
  293. };  
  294. MODULE_DEVICE_TABLE(i2c, tsc2007_idtable);  
  295. static struct i2c_driver tsc2007_driver = {  
  296.     .driver = {  
  297.         .owner  = THIS_MODULE,  
  298.         .name   = "tsc2007"  
  299.     },  
  300.     .id_table   = tsc2007_idtable,  
  301.     .probe      = tsc2007_probe,  
  302.     .remove     = __devexit_p(tsc2007_remove),  
  303. };  
  304. static int __init tsc2007_init(void)  
  305. {  
  306.     return i2c_add_driver(&tsc2007_driver);  
  307. }  
  308. static void __exit tsc2007_exit(void)  
  309. {  
  310.     i2c_del_driver(&tsc2007_driver);  
  311. }  
  312. module_init(tsc2007_init);  
  313. module_exit(tsc2007_exit);  
  314. MODULE_AUTHOR("Kwangwoo Lee <[email protected]>");  
  315. MODULE_DESCRIPTION("TSC2007 TouchScreen Driver");  
  316. MODULE_LICENSE("GPL");  
 

看一遍后就大概知道流程了。

当按下触摸板后产生中断,中断里面调用延时函数进入底半部程序。

在调度函数里面,先读取坐标,计算压力,然后根据压力大小上报坐标。

若触摸板一直按下,那么就重新调用,并通过压力值来看触摸板是否释放。

你可能感兴趣的:(c,linux,struct,report,Module,input)