Advertisement
ruberval

cypress-touchkey.c

May 16th, 2013
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 17.92 KB | None | 0 0
  1. /*
  2.  * Copyright 2006-2010, Cypress Semiconductor Corporation.
  3.  * Copyright (C) 2010, Samsung Electronics Co. Ltd. All Rights Reserved.
  4.  * Copyright (C) 2011 <kang@insecure.ws>
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version 2
  9.  * of the License, or (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 51 Franklin Street, Fifth Floor
  19.  * Boston, MA  02110-1301, USA.
  20.  *
  21.  */
  22. #include <linux/module.h>
  23. #include <linux/kernel.h>
  24. #include <linux/timer.h>
  25. #include <linux/init.h>
  26. #include <linux/i2c.h>
  27. #include <linux/slab.h>
  28. #include <linux/interrupt.h>
  29. #include <linux/delay.h>
  30. #include <linux/input.h>
  31. #include <linux/earlysuspend.h>
  32. #include <linux/miscdevice.h>
  33. #include <linux/input/cypress-touchkey.h>
  34.  
  35. #ifdef CONFIG_GENERIC_BLN
  36. #include <linux/bln.h>
  37. #endif
  38.  
  39. #define SCANCODE_MASK       0x07
  40. #define UPDOWN_EVENT_MASK   0x08
  41. #define ESD_STATE_MASK      0x10
  42.  
  43. #define BACKLIGHT_ON        0x10
  44. #define BACKLIGHT_OFF       0x20
  45.  
  46. #define OLD_BACKLIGHT_ON    0x1
  47. #define OLD_BACKLIGHT_OFF   0x2
  48.  
  49. #define DEVICE_NAME "cypress-touchkey"
  50.  
  51. int bl_on = 0;
  52. static DEFINE_SEMAPHORE(enable_sem);
  53. static DEFINE_SEMAPHORE(i2c_sem);
  54.  
  55. struct cypress_touchkey_devdata *bl_devdata;
  56.  
  57. static int bl_timeout = 1600; // This gets overridden by userspace AriesParts
  58. static struct timer_list bl_timer;
  59. static void bl_off(struct work_struct *bl_off_work);
  60. static DECLARE_WORK(bl_off_work, bl_off);
  61.  
  62. extern bool bln_enabled;
  63.  
  64. struct cypress_touchkey_devdata {
  65.     struct i2c_client *client;
  66.     struct input_dev *input_dev;
  67.     struct touchkey_platform_data *pdata;
  68.     struct early_suspend early_suspend;
  69.     u8 backlight_on;
  70.     u8 backlight_off;
  71.     bool is_dead;
  72.     bool is_powering_on;
  73.     bool has_legacy_keycode;
  74.     bool is_sleeping;
  75. };
  76.  
  77. #ifdef CONFIG_GENERIC_BLN
  78. static struct cypress_touchkey_devdata *blndevdata;
  79. #endif
  80.  
  81. static int i2c_touchkey_read_byte(struct cypress_touchkey_devdata *devdata,
  82.                     u8 *val)
  83. {
  84.     int ret;
  85.     int retry = 2;
  86.  
  87.     down(&i2c_sem);
  88.  
  89.     while (true) {
  90.         ret = i2c_smbus_read_byte(devdata->client);
  91.         if (ret >= 0) {
  92.             *val = ret;
  93.             ret = 0;
  94.             break;
  95.         }
  96.  
  97.         if (!retry--) {
  98.             dev_err(&devdata->client->dev, "i2c read error\n");
  99.             break;
  100.         }
  101.         msleep(10);
  102.     }
  103.  
  104.     up(&i2c_sem);
  105.  
  106.     return ret;
  107. }
  108.  
  109. static int i2c_touchkey_write_byte(struct cypress_touchkey_devdata *devdata,
  110.                     u8 val)
  111. {
  112.     int ret;
  113.     int retry = 2;
  114.  
  115.     down(&i2c_sem);
  116.  
  117.     while (true) {
  118.         ret = i2c_smbus_write_byte(devdata->client, val);
  119.         if (!ret) {
  120.             ret = 0;
  121.             break;
  122.         }
  123.  
  124.         if (!retry--) {
  125.             dev_err(&devdata->client->dev, "i2c write error\n");
  126.             break;
  127.         }
  128.         msleep(10);
  129.     }
  130.  
  131.     up(&i2c_sem);
  132.  
  133.     return ret;
  134. }
  135.  
  136. static void all_keys_up(struct cypress_touchkey_devdata *devdata)
  137. {
  138.     int i;
  139.  
  140.     for (i = 0; i < devdata->pdata->keycode_cnt; i++)
  141.         input_report_key(devdata->input_dev,
  142.                         devdata->pdata->keycode[i], 0);
  143.  
  144.     input_sync(devdata->input_dev);
  145. }
  146.  
  147. static void bl_off(struct work_struct *bl_off_work)
  148. {
  149.     if (bl_devdata == NULL || unlikely(bl_devdata->is_dead) ||
  150.         bl_devdata->is_powering_on || bl_on || bl_devdata->is_sleeping)
  151.         return;
  152.  
  153.     i2c_touchkey_write_byte(bl_devdata, bl_devdata->backlight_off);
  154. }
  155.  
  156. void bl_timer_callback(unsigned long data)
  157. {
  158.     schedule_work(&bl_off_work);
  159. }
  160.  
  161. static void bl_set_timeout() {
  162.     if (bl_timeout > 0) {
  163.         mod_timer(&bl_timer, jiffies + msecs_to_jiffies(bl_timeout));
  164.     }
  165. }
  166.  
  167. static int recovery_routine(struct cypress_touchkey_devdata *devdata)
  168. {
  169.     int ret = -1;
  170.     int retry = 10;
  171.     u8 data;
  172.     int irq_eint;
  173.  
  174.     if (unlikely(devdata->is_dead)) {
  175.         dev_err(&devdata->client->dev, "%s: Device is already dead, "
  176.                 "skipping recovery\n", __func__);
  177.         return -ENODEV;
  178.     }
  179.  
  180.     irq_eint = devdata->client->irq;
  181.  
  182.     down(&enable_sem);
  183.  
  184.     all_keys_up(devdata);
  185.  
  186.     disable_irq_nosync(irq_eint);
  187.     while (retry--) {
  188.         devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  189.         devdata->pdata->touchkey_onoff(TOUCHKEY_ON);
  190.         ret = i2c_touchkey_read_byte(devdata, &data);
  191.         if (!ret) {
  192.             if (!devdata->is_sleeping)
  193.                 enable_irq(irq_eint);
  194.             goto out;
  195.         }
  196.         dev_err(&devdata->client->dev, "%s: i2c transfer error retry = "
  197.                 "%d\n", __func__, retry);
  198.     }
  199.     devdata->is_dead = true;
  200.     devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  201.     dev_err(&devdata->client->dev, "%s: touchkey died\n", __func__);
  202. out:
  203.     dev_err(&devdata->client->dev, "%s: recovery_routine\n", __func__);
  204.     up(&enable_sem);
  205.     return ret;
  206. }
  207.  
  208. // Accidental touch key prevention (see mxt224.c)
  209. extern unsigned int touch_state_val;
  210.  
  211. static irqreturn_t touchkey_interrupt_thread(int irq, void *touchkey_devdata)
  212. {
  213.     u8 data;
  214.     int i;
  215.     int ret;
  216.     int scancode;
  217.     struct cypress_touchkey_devdata *devdata = touchkey_devdata;
  218.  
  219.     ret = i2c_touchkey_read_byte(devdata, &data);
  220.     if (ret || (data & ESD_STATE_MASK)) {
  221.         ret = recovery_routine(devdata);
  222.         if (ret) {
  223.             dev_err(&devdata->client->dev, "%s: touchkey recovery "
  224.                     "failed!\n", __func__);
  225.             goto err;
  226.         }
  227.     }
  228.  
  229.     if (devdata->has_legacy_keycode) {
  230.         scancode = (data & SCANCODE_MASK) - 1;
  231.         if (scancode < 0 || scancode >= devdata->pdata->keycode_cnt) {
  232.             dev_err(&devdata->client->dev, "%s: scancode is out of "
  233.                 "range\n", __func__);
  234.             goto err;
  235.         }
  236.  
  237.         /* Don't send down event while the touch screen is being pressed
  238.          * to prevent accidental touch key hit.
  239.          */
  240.         if ((data & UPDOWN_EVENT_MASK) || !touch_state_val) {
  241.             input_report_key(devdata->input_dev,
  242.                 devdata->pdata->keycode[scancode],
  243.                 !(data & UPDOWN_EVENT_MASK));
  244.         }
  245.     } else {
  246.         for (i = 0; i < devdata->pdata->keycode_cnt; i++)
  247.             input_report_key(devdata->input_dev,
  248.                 devdata->pdata->keycode[i],
  249.                 !!(data & (1U << i)));
  250.     }
  251.  
  252.     input_sync(devdata->input_dev);
  253.     bl_set_timeout();
  254. err:
  255.     return IRQ_HANDLED;
  256. }
  257.  
  258. static irqreturn_t touchkey_interrupt_handler(int irq, void *touchkey_devdata)
  259. {
  260.     struct cypress_touchkey_devdata *devdata = touchkey_devdata;
  261.  
  262.     if (devdata->is_powering_on) {
  263.         dev_dbg(&devdata->client->dev, "%s: ignoring spurious boot "
  264.                     "interrupt\n", __func__);
  265.         return IRQ_HANDLED;
  266.     }
  267.  
  268.     return IRQ_WAKE_THREAD;
  269. }
  270.  
  271. static void notify_led_on(void) {
  272.     down(&enable_sem);
  273.  
  274.     if (unlikely(bl_devdata->is_dead) || bl_on)
  275.         goto out;
  276.  
  277.     if (bl_devdata->is_sleeping) {
  278.         bl_devdata->pdata->touchkey_sleep_onoff(TOUCHKEY_ON);
  279.         bl_devdata->pdata->touchkey_onoff(TOUCHKEY_ON);
  280.     }
  281.     i2c_touchkey_write_byte(bl_devdata, bl_devdata->backlight_on);
  282.     bl_on = 1;
  283.  
  284.     printk(KERN_DEBUG "%s: notification led enabled\n", __FUNCTION__);
  285.  
  286. out:
  287.     up(&enable_sem);
  288. }
  289.  
  290. static void notify_led_off(void) {
  291.     // Avoid race condition with touch key resume
  292.     down(&enable_sem);
  293.  
  294.     if (unlikely(bl_devdata->is_dead) || !bl_on)
  295.         goto out;
  296.  
  297.     if (bl_on && bl_timer.expires < jiffies) // Don't disable if there's a timer scheduled
  298.         i2c_touchkey_write_byte(bl_devdata, bl_devdata->backlight_off);
  299.  
  300.     bl_devdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF);
  301.     if (bl_devdata->is_sleeping)
  302.         bl_devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  303.  
  304.     bl_on = 0;
  305.  
  306.     printk(KERN_DEBUG "%s: notification led disabled\n", __FUNCTION__);
  307.  
  308. out:
  309.     up(&enable_sem);
  310. }
  311.  
  312. #ifdef CONFIG_HAS_EARLYSUSPEND
  313. static void cypress_touchkey_early_suspend(struct early_suspend *h)
  314. {
  315.     struct cypress_touchkey_devdata *devdata =
  316.         container_of(h, struct cypress_touchkey_devdata, early_suspend);
  317.  
  318.     down(&enable_sem);
  319.  
  320.     devdata->is_powering_on = true;
  321.  
  322.     if (unlikely(devdata->is_dead)) {
  323.         goto out;
  324.     }
  325.  
  326.     disable_irq(devdata->client->irq);
  327.  
  328. <<<<<<< HEAD
  329. #ifdef CONFIG_GENERIC_BLN
  330. =======
  331. if (bln_enabled) {
  332. >>>>>>> e109dc475850e7ba66112cace6cc235ed7bcbd38
  333.   /*
  334.    * Disallow powering off the touchkey controller
  335.    * while a led notification is ongoing
  336.    */
  337.   if(!bln_is_ongoing()) {
  338.     devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  339.     devdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF);
  340.   }
  341. <<<<<<< HEAD
  342. #else
  343.     if (!bl_on)
  344.         devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  345. #endif
  346. =======
  347. } else {
  348.     if (!bl_on)
  349.         devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  350. }
  351. >>>>>>> e109dc475850e7ba66112cace6cc235ed7bcbd38
  352.     all_keys_up(devdata);
  353.     devdata->is_sleeping = true;
  354.  
  355. out:
  356.     up(&enable_sem);
  357. }
  358.  
  359. static void cypress_touchkey_early_resume(struct early_suspend *h)
  360. {
  361.     struct cypress_touchkey_devdata *devdata =
  362.         container_of(h, struct cypress_touchkey_devdata, early_suspend);
  363.  
  364.     // Avoid race condition with LED notification disable
  365.     down(&enable_sem);
  366.  
  367.     devdata->pdata->touchkey_onoff(TOUCHKEY_ON);
  368.  
  369.     if (i2c_touchkey_write_byte(devdata, devdata->backlight_on)) {
  370.         devdata->is_dead = true;
  371.         devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  372.         dev_err(&devdata->client->dev, "%s: touch keypad not responding"
  373.                 " to commands, disabling\n", __func__);
  374.         up(&enable_sem);
  375.         return;
  376.     }
  377.     devdata->is_dead = false;
  378.     enable_irq(devdata->client->irq);
  379.     devdata->is_powering_on = false;
  380.     devdata->is_sleeping = false;
  381.  
  382.     up(&enable_sem);
  383.  
  384.     bl_set_timeout();
  385. }
  386. #endif
  387.  
  388. static ssize_t led_status_read(struct device *dev, struct device_attribute *attr, char *buf) {
  389.     return sprintf(buf,"%u\n", bl_on);
  390. }
  391.  
  392. static ssize_t led_status_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
  393. {
  394.     unsigned int data;
  395.  
  396.     if (sscanf(buf, "%u\n", &data)) {
  397.         if (data == 1)
  398.             notify_led_on();
  399.         else
  400.             notify_led_off();
  401.     }
  402.     return size;
  403. }
  404.  
  405. static ssize_t bl_timeout_read(struct device *dev, struct device_attribute *attr, char *buf) {
  406.     return sprintf(buf,"%d\n", bl_timeout);
  407. }
  408.  
  409. static ssize_t bl_timeout_write(struct device *dev, struct device_attribute *attr, const char *buf, size_t size)
  410. {
  411.     sscanf(buf, "%d\n", &bl_timeout);
  412.     return size;
  413. }
  414.  
  415. static DEVICE_ATTR(led, S_IRUGO | S_IWUGO , led_status_read, led_status_write);
  416. static DEVICE_ATTR(bl_timeout, S_IRUGO | S_IWUGO, bl_timeout_read, bl_timeout_write);
  417.  
  418. static struct attribute *bl_led_attributes[] = {
  419.         &dev_attr_led.attr,
  420.         &dev_attr_bl_timeout.attr, // Not the best place, but creating a new device is more trouble that it's worth
  421.         NULL
  422. };
  423.  
  424. static struct attribute_group bl_led_group = {
  425.         .attrs  = bl_led_attributes,
  426. };
  427.  
  428. static struct miscdevice bl_led_device = {
  429.         .minor = MISC_DYNAMIC_MINOR,
  430.         .name = "notification",
  431. };
  432.  
  433. #ifdef CONFIG_GENERIC_BLN
  434. static void enable_touchkey_backlights(void){
  435.        i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_on);
  436. }
  437.  
  438. static void disable_touchkey_backlights(void){
  439.        i2c_touchkey_write_byte(blndevdata, blndevdata->backlight_off);
  440. }
  441.  
  442. static void cypress_touchkey_enable_led_notification(void){
  443.   /* is_powering_on signals whether touchkey lights are used for touchmode */
  444.   if (blndevdata->is_powering_on){
  445.     /* reconfigure gpio for sleep mode */
  446.     blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_ON);
  447.  
  448.     /*
  449.      * power on the touchkey controller
  450.      * This is actually not needed, but it is intentionally
  451.      * left for the case that the early_resume() function
  452.      * did not power on the touchkey controller for some reasons
  453.      */
  454.     blndevdata->pdata->touchkey_onoff(TOUCHKEY_ON);
  455.  
  456.     /* write to i2cbus, enable backlights */
  457.     enable_touchkey_backlights();
  458.   }
  459.   else
  460. #ifdef CONFIG_TOUCH_WAKE
  461.       {
  462.     enable_touchkey_backlights();
  463.       }
  464. #else
  465.       pr_info("%s: cannot set notification led, touchkeys are enabled\n",__FUNCTION__);
  466. #endif
  467. }
  468.  
  469. static void cypress_touchkey_disable_led_notification(void){
  470.   /*
  471.    * reconfigure gpio for sleep mode, this has to be done
  472.    * independently from the power status
  473.    */
  474.   blndevdata->pdata->touchkey_sleep_onoff(TOUCHKEY_OFF);
  475.  
  476.   /* if touchkeys lights are not used for touchmode */
  477.   if (blndevdata->is_powering_on){
  478.     disable_touchkey_backlights();
  479.  
  480.     #if 0
  481.     /*
  482.      * power off the touchkey controller
  483.      * This is actually not needed, the early_suspend function
  484.      * should take care of powering off the touchkey controller
  485.      */
  486.     blndevdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  487.     #endif
  488.   }
  489. #ifdef CONFIG_TOUCH_WAKE
  490.   else
  491.       {
  492.     disable_touchkey_backlights();
  493.       }
  494. #endif  
  495. }
  496.  
  497. static struct bln_implementation cypress_touchkey_bln = {
  498.   .enable = cypress_touchkey_enable_led_notification,
  499.   .disable = cypress_touchkey_disable_led_notification,
  500. };
  501. #endif
  502.  
  503.  
  504. static int cypress_touchkey_probe(struct i2c_client *client,
  505.         const struct i2c_device_id *id)
  506. {
  507.     struct device *dev = &client->dev;
  508.     struct input_dev *input_dev;
  509.     struct cypress_touchkey_devdata *devdata;
  510.     u8 data[3];
  511.     int err;
  512.     int cnt;
  513.  
  514.     if (!dev->platform_data) {
  515.         dev_err(dev, "%s: Platform data is NULL\n", __func__);
  516.         return -EINVAL;
  517.     }
  518.  
  519.     devdata = kzalloc(sizeof(*devdata), GFP_KERNEL);
  520.     if (devdata == NULL) {
  521.         dev_err(dev, "%s: failed to create our state\n", __func__);
  522.         return -ENODEV;
  523.     }
  524.  
  525.     devdata->client = client;
  526.     i2c_set_clientdata(client, devdata);
  527.  
  528.     devdata->pdata = client->dev.platform_data;
  529.     if (!devdata->pdata->keycode) {
  530.         dev_err(dev, "%s: Invalid platform data\n", __func__);
  531.         err = -EINVAL;
  532.         goto err_null_keycodes;
  533.     }
  534.  
  535.     strlcpy(devdata->client->name, DEVICE_NAME, I2C_NAME_SIZE);
  536.  
  537.     input_dev = input_allocate_device();
  538.     if (!input_dev) {
  539.         err = -ENOMEM;
  540.         goto err_input_alloc_dev;
  541.     }
  542.  
  543.     devdata->input_dev = input_dev;
  544.     dev_set_drvdata(&input_dev->dev, devdata);
  545.     input_dev->name = DEVICE_NAME;
  546.     input_dev->id.bustype = BUS_HOST;
  547.  
  548.     for (cnt = 0; cnt < devdata->pdata->keycode_cnt; cnt++)
  549.         input_set_capability(input_dev, EV_KEY,
  550.                     devdata->pdata->keycode[cnt]);
  551.  
  552.     err = input_register_device(input_dev);
  553.     if (err)
  554.         goto err_input_reg_dev;
  555.  
  556.     devdata->is_powering_on = true;
  557.     devdata->is_sleeping = false;
  558.  
  559.     devdata->pdata->touchkey_onoff(TOUCHKEY_ON);
  560.  
  561.     err = i2c_master_recv(client, data, sizeof(data));
  562.  
  563.     if (err < sizeof(data)) {
  564.         if (err >= 0)
  565.             err = -EIO;
  566.         dev_err(dev, "%s: error reading hardware version\n", __func__);
  567.         goto err_read;
  568.     }
  569.  
  570.     dev_info(dev, "%s: hardware rev1 = %#02x, rev2 = %#02x\n", __func__,
  571.                 data[1], data[2]);
  572.  
  573. #ifdef CONFIG_KEYPAD_CYPRESS_TOUCH_HAS_LEGACY_KEYCODE
  574.     devdata->has_legacy_keycode = true;
  575. #else
  576.     devdata->has_legacy_keycode = data[1] >= 0xc4 || data[1] < 0x9 ||
  577.                     (data[1] == 0x9 && data[2] < 0x9);
  578. #endif
  579.  
  580.     if (data[1] < 0xc4 && (data[1] >= 0x8 ||
  581.                 (data[1] == 0x8 && data[2] >= 0x9)) &&
  582.                 devdata->has_legacy_keycode == false) {
  583.         devdata->backlight_on = BACKLIGHT_ON;
  584.         devdata->backlight_off = BACKLIGHT_OFF;
  585.     } else {
  586.         devdata->backlight_on = OLD_BACKLIGHT_ON;
  587.         devdata->backlight_off = OLD_BACKLIGHT_OFF;
  588.     }
  589.  
  590.     err = i2c_touchkey_write_byte(devdata, devdata->backlight_off);
  591.     if (err) {
  592.         dev_err(dev, "%s: touch keypad backlight on failed\n",
  593.                 __func__);
  594.         /* The device may not be responding because of bad firmware
  595.          */
  596.         goto err_backlight_off;
  597.     }
  598.  
  599.     err = request_threaded_irq(client->irq, touchkey_interrupt_handler,
  600.                 touchkey_interrupt_thread, IRQF_TRIGGER_FALLING,
  601.                 DEVICE_NAME, devdata);
  602.     if (err) {
  603.         dev_err(dev, "%s: Can't allocate irq.\n", __func__);
  604.         goto err_req_irq;
  605.     }
  606.  
  607. #ifdef CONFIG_HAS_EARLYSUSPEND
  608.     devdata->early_suspend.suspend = cypress_touchkey_early_suspend;
  609.     devdata->early_suspend.resume = cypress_touchkey_early_resume;
  610. #endif
  611.     register_early_suspend(&devdata->early_suspend);
  612.  
  613.     devdata->is_powering_on = false;
  614.  
  615. #ifdef CONFIG_GENERIC_BLN
  616.   blndevdata = devdata;
  617.   register_bln_implementation(&cypress_touchkey_bln);
  618. #endif
  619.  
  620.     if (misc_register(&bl_led_device))
  621.         printk("%s misc_register(%s) failed\n", __FUNCTION__, bl_led_device.name);
  622.     else {
  623.         if (sysfs_create_group(&bl_led_device.this_device->kobj, &bl_led_group) < 0)
  624.             pr_err("failed to create sysfs group for device %s\n", bl_led_device.name);
  625.     }
  626.  
  627.     bl_devdata = devdata;
  628.     setup_timer(&bl_timer, bl_timer_callback, 0);
  629.  
  630.     return 0;
  631.  
  632. err_req_irq:
  633. err_backlight_off:
  634.     input_unregister_device(input_dev);
  635.     goto touchkey_off;
  636. err_input_reg_dev:
  637. err_read:
  638.     input_free_device(input_dev);
  639. touchkey_off:
  640.     devdata->is_powering_on = false;
  641.     devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  642. err_input_alloc_dev:
  643. err_null_keycodes:
  644.     kfree(devdata);
  645.     return err;
  646. }
  647.  
  648. static int __devexit i2c_touchkey_remove(struct i2c_client *client)
  649. {
  650.     struct cypress_touchkey_devdata *devdata = i2c_get_clientdata(client);
  651.  
  652.     dev_err(&client->dev, "%s: i2c_touchkey_remove\n", __func__);
  653.  
  654.     misc_deregister(&bl_led_device);
  655.  
  656.     unregister_early_suspend(&devdata->early_suspend);
  657.     /* If the device is dead IRQs are disabled, we need to rebalance them */
  658.     if (unlikely(devdata->is_dead))
  659.         enable_irq(client->irq);
  660.     else {
  661.         devdata->pdata->touchkey_onoff(TOUCHKEY_OFF);
  662.         devdata->is_powering_on = false;
  663.     }
  664.     free_irq(client->irq, devdata);
  665.     all_keys_up(devdata);
  666.     input_unregister_device(devdata->input_dev);
  667.     del_timer(&bl_timer);
  668.     kfree(devdata);
  669.     return 0;
  670. }
  671.  
  672. static const struct i2c_device_id cypress_touchkey_id[] = {
  673.     { CYPRESS_TOUCHKEY_DEV_NAME, 0 },
  674. };
  675.  
  676. MODULE_DEVICE_TABLE(i2c, cypress_touchkey_id);
  677.  
  678. struct i2c_driver touchkey_i2c_driver = {
  679.     .driver = {
  680.         .name = "cypress_touchkey_driver",
  681.     },
  682.     .id_table = cypress_touchkey_id,
  683.     .probe = cypress_touchkey_probe,
  684.     .remove = __devexit_p(i2c_touchkey_remove),
  685. };
  686.  
  687. static int __init touchkey_init(void)
  688. {
  689.     int ret = 0;
  690.  
  691.     ret = i2c_add_driver(&touchkey_i2c_driver);
  692.     if (ret)
  693.         pr_err("%s: cypress touch keypad registration failed. (%d)\n",
  694.                 __func__, ret);
  695.  
  696.     return ret;
  697. }
  698.  
  699. static void __exit touchkey_exit(void)
  700. {
  701.     i2c_del_driver(&touchkey_i2c_driver);
  702. }
  703.  
  704. late_initcall(touchkey_init);
  705. module_exit(touchkey_exit);
  706.  
  707. MODULE_LICENSE("GPL");
  708. MODULE_AUTHOR("@@@");
  709. MODULE_DESCRIPTION("cypress touch keypad");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement