1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 230ba3eadSSriramakrishnan Govindarajan /* 330ba3eadSSriramakrishnan Govindarajan * Driver for keys on TCA6416 I2C IO expander 430ba3eadSSriramakrishnan Govindarajan * 530ba3eadSSriramakrishnan Govindarajan * Copyright (C) 2010 Texas Instruments 630ba3eadSSriramakrishnan Govindarajan * 730ba3eadSSriramakrishnan Govindarajan * Author : Sriramakrishnan.A.G. <srk@ti.com> 830ba3eadSSriramakrishnan Govindarajan */ 930ba3eadSSriramakrishnan Govindarajan 1030ba3eadSSriramakrishnan Govindarajan #include <linux/types.h> 1130ba3eadSSriramakrishnan Govindarajan #include <linux/module.h> 1230ba3eadSSriramakrishnan Govindarajan #include <linux/init.h> 1330ba3eadSSriramakrishnan Govindarajan #include <linux/delay.h> 1430ba3eadSSriramakrishnan Govindarajan #include <linux/slab.h> 1530ba3eadSSriramakrishnan Govindarajan #include <linux/interrupt.h> 1630ba3eadSSriramakrishnan Govindarajan #include <linux/workqueue.h> 1730ba3eadSSriramakrishnan Govindarajan #include <linux/gpio.h> 1830ba3eadSSriramakrishnan Govindarajan #include <linux/i2c.h> 1930ba3eadSSriramakrishnan Govindarajan #include <linux/input.h> 2030ba3eadSSriramakrishnan Govindarajan #include <linux/tca6416_keypad.h> 2130ba3eadSSriramakrishnan Govindarajan 2230ba3eadSSriramakrishnan Govindarajan #define TCA6416_INPUT 0 2330ba3eadSSriramakrishnan Govindarajan #define TCA6416_OUTPUT 1 2430ba3eadSSriramakrishnan Govindarajan #define TCA6416_INVERT 2 2530ba3eadSSriramakrishnan Govindarajan #define TCA6416_DIRECTION 3 2630ba3eadSSriramakrishnan Govindarajan 2730ba3eadSSriramakrishnan Govindarajan static const struct i2c_device_id tca6416_id[] = { 2830ba3eadSSriramakrishnan Govindarajan { "tca6416-keys", 16, }, 29b8a3d6bcSTony SIM { "tca6408-keys", 8, }, 3030ba3eadSSriramakrishnan Govindarajan { } 3130ba3eadSSriramakrishnan Govindarajan }; 3230ba3eadSSriramakrishnan Govindarajan MODULE_DEVICE_TABLE(i2c, tca6416_id); 3330ba3eadSSriramakrishnan Govindarajan 3430ba3eadSSriramakrishnan Govindarajan struct tca6416_drv_data { 3530ba3eadSSriramakrishnan Govindarajan struct input_dev *input; 3630ba3eadSSriramakrishnan Govindarajan struct tca6416_button data[0]; 3730ba3eadSSriramakrishnan Govindarajan }; 3830ba3eadSSriramakrishnan Govindarajan 3930ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip { 4030ba3eadSSriramakrishnan Govindarajan uint16_t reg_output; 4130ba3eadSSriramakrishnan Govindarajan uint16_t reg_direction; 4230ba3eadSSriramakrishnan Govindarajan uint16_t reg_input; 4330ba3eadSSriramakrishnan Govindarajan 4430ba3eadSSriramakrishnan Govindarajan struct i2c_client *client; 4530ba3eadSSriramakrishnan Govindarajan struct input_dev *input; 4630ba3eadSSriramakrishnan Govindarajan struct delayed_work dwork; 47b8a3d6bcSTony SIM int io_size; 4830ba3eadSSriramakrishnan Govindarajan int irqnum; 49b8a3d6bcSTony SIM u16 pinmask; 5030ba3eadSSriramakrishnan Govindarajan bool use_polling; 5130ba3eadSSriramakrishnan Govindarajan struct tca6416_button buttons[0]; 5230ba3eadSSriramakrishnan Govindarajan }; 5330ba3eadSSriramakrishnan Govindarajan 5430ba3eadSSriramakrishnan Govindarajan static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val) 5530ba3eadSSriramakrishnan Govindarajan { 5630ba3eadSSriramakrishnan Govindarajan int error; 5730ba3eadSSriramakrishnan Govindarajan 58b8a3d6bcSTony SIM error = chip->io_size > 8 ? 59b8a3d6bcSTony SIM i2c_smbus_write_word_data(chip->client, reg << 1, val) : 60b8a3d6bcSTony SIM i2c_smbus_write_byte_data(chip->client, reg, val); 6130ba3eadSSriramakrishnan Govindarajan if (error < 0) { 6230ba3eadSSriramakrishnan Govindarajan dev_err(&chip->client->dev, 6330ba3eadSSriramakrishnan Govindarajan "%s failed, reg: %d, val: %d, error: %d\n", 6430ba3eadSSriramakrishnan Govindarajan __func__, reg, val, error); 6530ba3eadSSriramakrishnan Govindarajan return error; 6630ba3eadSSriramakrishnan Govindarajan } 6730ba3eadSSriramakrishnan Govindarajan 6830ba3eadSSriramakrishnan Govindarajan return 0; 6930ba3eadSSriramakrishnan Govindarajan } 7030ba3eadSSriramakrishnan Govindarajan 7130ba3eadSSriramakrishnan Govindarajan static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val) 7230ba3eadSSriramakrishnan Govindarajan { 7330ba3eadSSriramakrishnan Govindarajan int retval; 7430ba3eadSSriramakrishnan Govindarajan 75b8a3d6bcSTony SIM retval = chip->io_size > 8 ? 76b8a3d6bcSTony SIM i2c_smbus_read_word_data(chip->client, reg << 1) : 77b8a3d6bcSTony SIM i2c_smbus_read_byte_data(chip->client, reg); 7830ba3eadSSriramakrishnan Govindarajan if (retval < 0) { 7930ba3eadSSriramakrishnan Govindarajan dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n", 8030ba3eadSSriramakrishnan Govindarajan __func__, reg, retval); 8130ba3eadSSriramakrishnan Govindarajan return retval; 8230ba3eadSSriramakrishnan Govindarajan } 8330ba3eadSSriramakrishnan Govindarajan 8430ba3eadSSriramakrishnan Govindarajan *val = (u16)retval; 8530ba3eadSSriramakrishnan Govindarajan return 0; 8630ba3eadSSriramakrishnan Govindarajan } 8730ba3eadSSriramakrishnan Govindarajan 8830ba3eadSSriramakrishnan Govindarajan static void tca6416_keys_scan(struct tca6416_keypad_chip *chip) 8930ba3eadSSriramakrishnan Govindarajan { 9030ba3eadSSriramakrishnan Govindarajan struct input_dev *input = chip->input; 9130ba3eadSSriramakrishnan Govindarajan u16 reg_val, val; 9230ba3eadSSriramakrishnan Govindarajan int error, i, pin_index; 9330ba3eadSSriramakrishnan Govindarajan 9430ba3eadSSriramakrishnan Govindarajan error = tca6416_read_reg(chip, TCA6416_INPUT, ®_val); 9530ba3eadSSriramakrishnan Govindarajan if (error) 9630ba3eadSSriramakrishnan Govindarajan return; 9730ba3eadSSriramakrishnan Govindarajan 9830ba3eadSSriramakrishnan Govindarajan reg_val &= chip->pinmask; 9930ba3eadSSriramakrishnan Govindarajan 10030ba3eadSSriramakrishnan Govindarajan /* Figure out which lines have changed */ 10130ba3eadSSriramakrishnan Govindarajan val = reg_val ^ chip->reg_input; 10230ba3eadSSriramakrishnan Govindarajan chip->reg_input = reg_val; 10330ba3eadSSriramakrishnan Govindarajan 10430ba3eadSSriramakrishnan Govindarajan for (i = 0, pin_index = 0; i < 16; i++) { 10530ba3eadSSriramakrishnan Govindarajan if (val & (1 << i)) { 10630ba3eadSSriramakrishnan Govindarajan struct tca6416_button *button = &chip->buttons[pin_index]; 10730ba3eadSSriramakrishnan Govindarajan unsigned int type = button->type ?: EV_KEY; 10830ba3eadSSriramakrishnan Govindarajan int state = ((reg_val & (1 << i)) ? 1 : 0) 10930ba3eadSSriramakrishnan Govindarajan ^ button->active_low; 11030ba3eadSSriramakrishnan Govindarajan 11130ba3eadSSriramakrishnan Govindarajan input_event(input, type, button->code, !!state); 11230ba3eadSSriramakrishnan Govindarajan input_sync(input); 11330ba3eadSSriramakrishnan Govindarajan } 11430ba3eadSSriramakrishnan Govindarajan 11530ba3eadSSriramakrishnan Govindarajan if (chip->pinmask & (1 << i)) 11630ba3eadSSriramakrishnan Govindarajan pin_index++; 11730ba3eadSSriramakrishnan Govindarajan } 11830ba3eadSSriramakrishnan Govindarajan } 11930ba3eadSSriramakrishnan Govindarajan 12030ba3eadSSriramakrishnan Govindarajan /* 12130ba3eadSSriramakrishnan Govindarajan * This is threaded IRQ handler and this can (and will) sleep. 12230ba3eadSSriramakrishnan Govindarajan */ 12330ba3eadSSriramakrishnan Govindarajan static irqreturn_t tca6416_keys_isr(int irq, void *dev_id) 12430ba3eadSSriramakrishnan Govindarajan { 12530ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip = dev_id; 12630ba3eadSSriramakrishnan Govindarajan 12730ba3eadSSriramakrishnan Govindarajan tca6416_keys_scan(chip); 12830ba3eadSSriramakrishnan Govindarajan 12930ba3eadSSriramakrishnan Govindarajan return IRQ_HANDLED; 13030ba3eadSSriramakrishnan Govindarajan } 13130ba3eadSSriramakrishnan Govindarajan 13230ba3eadSSriramakrishnan Govindarajan static void tca6416_keys_work_func(struct work_struct *work) 13330ba3eadSSriramakrishnan Govindarajan { 13430ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip = 13530ba3eadSSriramakrishnan Govindarajan container_of(work, struct tca6416_keypad_chip, dwork.work); 13630ba3eadSSriramakrishnan Govindarajan 13730ba3eadSSriramakrishnan Govindarajan tca6416_keys_scan(chip); 13830ba3eadSSriramakrishnan Govindarajan schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); 13930ba3eadSSriramakrishnan Govindarajan } 14030ba3eadSSriramakrishnan Govindarajan 14130ba3eadSSriramakrishnan Govindarajan static int tca6416_keys_open(struct input_dev *dev) 14230ba3eadSSriramakrishnan Govindarajan { 14330ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip = input_get_drvdata(dev); 14430ba3eadSSriramakrishnan Govindarajan 14530ba3eadSSriramakrishnan Govindarajan /* Get initial device state in case it has switches */ 14630ba3eadSSriramakrishnan Govindarajan tca6416_keys_scan(chip); 14730ba3eadSSriramakrishnan Govindarajan 14830ba3eadSSriramakrishnan Govindarajan if (chip->use_polling) 14930ba3eadSSriramakrishnan Govindarajan schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100)); 15030ba3eadSSriramakrishnan Govindarajan else 15130ba3eadSSriramakrishnan Govindarajan enable_irq(chip->irqnum); 15230ba3eadSSriramakrishnan Govindarajan 15330ba3eadSSriramakrishnan Govindarajan return 0; 15430ba3eadSSriramakrishnan Govindarajan } 15530ba3eadSSriramakrishnan Govindarajan 15630ba3eadSSriramakrishnan Govindarajan static void tca6416_keys_close(struct input_dev *dev) 15730ba3eadSSriramakrishnan Govindarajan { 15830ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip = input_get_drvdata(dev); 15930ba3eadSSriramakrishnan Govindarajan 16030ba3eadSSriramakrishnan Govindarajan if (chip->use_polling) 16130ba3eadSSriramakrishnan Govindarajan cancel_delayed_work_sync(&chip->dwork); 16230ba3eadSSriramakrishnan Govindarajan else 16330ba3eadSSriramakrishnan Govindarajan disable_irq(chip->irqnum); 16430ba3eadSSriramakrishnan Govindarajan } 16530ba3eadSSriramakrishnan Govindarajan 1665298cc4cSBill Pemberton static int tca6416_setup_registers(struct tca6416_keypad_chip *chip) 16730ba3eadSSriramakrishnan Govindarajan { 16830ba3eadSSriramakrishnan Govindarajan int error; 16930ba3eadSSriramakrishnan Govindarajan 17030ba3eadSSriramakrishnan Govindarajan error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output); 17130ba3eadSSriramakrishnan Govindarajan if (error) 17230ba3eadSSriramakrishnan Govindarajan return error; 17330ba3eadSSriramakrishnan Govindarajan 17430ba3eadSSriramakrishnan Govindarajan error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); 17530ba3eadSSriramakrishnan Govindarajan if (error) 17630ba3eadSSriramakrishnan Govindarajan return error; 17730ba3eadSSriramakrishnan Govindarajan 17830ba3eadSSriramakrishnan Govindarajan /* ensure that keypad pins are set to input */ 17930ba3eadSSriramakrishnan Govindarajan error = tca6416_write_reg(chip, TCA6416_DIRECTION, 18030ba3eadSSriramakrishnan Govindarajan chip->reg_direction | chip->pinmask); 18130ba3eadSSriramakrishnan Govindarajan if (error) 18230ba3eadSSriramakrishnan Govindarajan return error; 18330ba3eadSSriramakrishnan Govindarajan 18430ba3eadSSriramakrishnan Govindarajan error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction); 18530ba3eadSSriramakrishnan Govindarajan if (error) 18630ba3eadSSriramakrishnan Govindarajan return error; 18730ba3eadSSriramakrishnan Govindarajan 18830ba3eadSSriramakrishnan Govindarajan error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input); 18930ba3eadSSriramakrishnan Govindarajan if (error) 19030ba3eadSSriramakrishnan Govindarajan return error; 19130ba3eadSSriramakrishnan Govindarajan 19230ba3eadSSriramakrishnan Govindarajan chip->reg_input &= chip->pinmask; 19330ba3eadSSriramakrishnan Govindarajan 19430ba3eadSSriramakrishnan Govindarajan return 0; 19530ba3eadSSriramakrishnan Govindarajan } 19630ba3eadSSriramakrishnan Govindarajan 1975298cc4cSBill Pemberton static int tca6416_keypad_probe(struct i2c_client *client, 19830ba3eadSSriramakrishnan Govindarajan const struct i2c_device_id *id) 19930ba3eadSSriramakrishnan Govindarajan { 20030ba3eadSSriramakrishnan Govindarajan struct tca6416_keys_platform_data *pdata; 20130ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip; 20230ba3eadSSriramakrishnan Govindarajan struct input_dev *input; 20330ba3eadSSriramakrishnan Govindarajan int error; 20430ba3eadSSriramakrishnan Govindarajan int i; 20530ba3eadSSriramakrishnan Govindarajan 20630ba3eadSSriramakrishnan Govindarajan /* Check functionality */ 20730ba3eadSSriramakrishnan Govindarajan if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { 20830ba3eadSSriramakrishnan Govindarajan dev_err(&client->dev, "%s adapter not supported\n", 20930ba3eadSSriramakrishnan Govindarajan dev_driver_string(&client->adapter->dev)); 21030ba3eadSSriramakrishnan Govindarajan return -ENODEV; 21130ba3eadSSriramakrishnan Govindarajan } 21230ba3eadSSriramakrishnan Govindarajan 213c838cb3dSJingoo Han pdata = dev_get_platdata(&client->dev); 21430ba3eadSSriramakrishnan Govindarajan if (!pdata) { 21530ba3eadSSriramakrishnan Govindarajan dev_dbg(&client->dev, "no platform data\n"); 21630ba3eadSSriramakrishnan Govindarajan return -EINVAL; 21730ba3eadSSriramakrishnan Govindarajan } 21830ba3eadSSriramakrishnan Govindarajan 219fb5fc09cSGustavo A. R. Silva chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL); 22030ba3eadSSriramakrishnan Govindarajan input = input_allocate_device(); 22130ba3eadSSriramakrishnan Govindarajan if (!chip || !input) { 22230ba3eadSSriramakrishnan Govindarajan error = -ENOMEM; 22330ba3eadSSriramakrishnan Govindarajan goto fail1; 22430ba3eadSSriramakrishnan Govindarajan } 22530ba3eadSSriramakrishnan Govindarajan 22630ba3eadSSriramakrishnan Govindarajan chip->client = client; 22730ba3eadSSriramakrishnan Govindarajan chip->input = input; 228b8a3d6bcSTony SIM chip->io_size = id->driver_data; 22930ba3eadSSriramakrishnan Govindarajan chip->pinmask = pdata->pinmask; 23030ba3eadSSriramakrishnan Govindarajan chip->use_polling = pdata->use_polling; 23130ba3eadSSriramakrishnan Govindarajan 23230ba3eadSSriramakrishnan Govindarajan INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func); 23330ba3eadSSriramakrishnan Govindarajan 23430ba3eadSSriramakrishnan Govindarajan input->phys = "tca6416-keys/input0"; 23530ba3eadSSriramakrishnan Govindarajan input->name = client->name; 23630ba3eadSSriramakrishnan Govindarajan input->dev.parent = &client->dev; 23730ba3eadSSriramakrishnan Govindarajan 23830ba3eadSSriramakrishnan Govindarajan input->open = tca6416_keys_open; 23930ba3eadSSriramakrishnan Govindarajan input->close = tca6416_keys_close; 24030ba3eadSSriramakrishnan Govindarajan 24130ba3eadSSriramakrishnan Govindarajan input->id.bustype = BUS_HOST; 24230ba3eadSSriramakrishnan Govindarajan input->id.vendor = 0x0001; 24330ba3eadSSriramakrishnan Govindarajan input->id.product = 0x0001; 24430ba3eadSSriramakrishnan Govindarajan input->id.version = 0x0100; 24530ba3eadSSriramakrishnan Govindarajan 24630ba3eadSSriramakrishnan Govindarajan /* Enable auto repeat feature of Linux input subsystem */ 24730ba3eadSSriramakrishnan Govindarajan if (pdata->rep) 24830ba3eadSSriramakrishnan Govindarajan __set_bit(EV_REP, input->evbit); 24930ba3eadSSriramakrishnan Govindarajan 25030ba3eadSSriramakrishnan Govindarajan for (i = 0; i < pdata->nbuttons; i++) { 25130ba3eadSSriramakrishnan Govindarajan unsigned int type; 25230ba3eadSSriramakrishnan Govindarajan 25330ba3eadSSriramakrishnan Govindarajan chip->buttons[i] = pdata->buttons[i]; 25430ba3eadSSriramakrishnan Govindarajan type = (pdata->buttons[i].type) ?: EV_KEY; 25530ba3eadSSriramakrishnan Govindarajan input_set_capability(input, type, pdata->buttons[i].code); 25630ba3eadSSriramakrishnan Govindarajan } 25730ba3eadSSriramakrishnan Govindarajan 25830ba3eadSSriramakrishnan Govindarajan input_set_drvdata(input, chip); 25930ba3eadSSriramakrishnan Govindarajan 26030ba3eadSSriramakrishnan Govindarajan /* 26130ba3eadSSriramakrishnan Govindarajan * Initialize cached registers from their original values. 26230ba3eadSSriramakrishnan Govindarajan * we can't share this chip with another i2c master. 26330ba3eadSSriramakrishnan Govindarajan */ 26430ba3eadSSriramakrishnan Govindarajan error = tca6416_setup_registers(chip); 26530ba3eadSSriramakrishnan Govindarajan if (error) 26630ba3eadSSriramakrishnan Govindarajan goto fail1; 26730ba3eadSSriramakrishnan Govindarajan 26830ba3eadSSriramakrishnan Govindarajan if (!chip->use_polling) { 26930ba3eadSSriramakrishnan Govindarajan if (pdata->irq_is_gpio) 27030ba3eadSSriramakrishnan Govindarajan chip->irqnum = gpio_to_irq(client->irq); 27130ba3eadSSriramakrishnan Govindarajan else 27230ba3eadSSriramakrishnan Govindarajan chip->irqnum = client->irq; 27330ba3eadSSriramakrishnan Govindarajan 27430ba3eadSSriramakrishnan Govindarajan error = request_threaded_irq(chip->irqnum, NULL, 27530ba3eadSSriramakrishnan Govindarajan tca6416_keys_isr, 2769b7e31bbSLars-Peter Clausen IRQF_TRIGGER_FALLING | 2779b7e31bbSLars-Peter Clausen IRQF_ONESHOT, 27830ba3eadSSriramakrishnan Govindarajan "tca6416-keypad", chip); 27930ba3eadSSriramakrishnan Govindarajan if (error) { 28030ba3eadSSriramakrishnan Govindarajan dev_dbg(&client->dev, 28130ba3eadSSriramakrishnan Govindarajan "Unable to claim irq %d; error %d\n", 28230ba3eadSSriramakrishnan Govindarajan chip->irqnum, error); 28330ba3eadSSriramakrishnan Govindarajan goto fail1; 28430ba3eadSSriramakrishnan Govindarajan } 28530ba3eadSSriramakrishnan Govindarajan disable_irq(chip->irqnum); 28630ba3eadSSriramakrishnan Govindarajan } 28730ba3eadSSriramakrishnan Govindarajan 28830ba3eadSSriramakrishnan Govindarajan error = input_register_device(input); 28930ba3eadSSriramakrishnan Govindarajan if (error) { 29030ba3eadSSriramakrishnan Govindarajan dev_dbg(&client->dev, 29130ba3eadSSriramakrishnan Govindarajan "Unable to register input device, error: %d\n", error); 29230ba3eadSSriramakrishnan Govindarajan goto fail2; 29330ba3eadSSriramakrishnan Govindarajan } 29430ba3eadSSriramakrishnan Govindarajan 29530ba3eadSSriramakrishnan Govindarajan i2c_set_clientdata(client, chip); 29664dcddd8SMagnus Damm device_init_wakeup(&client->dev, 1); 29730ba3eadSSriramakrishnan Govindarajan 29830ba3eadSSriramakrishnan Govindarajan return 0; 29930ba3eadSSriramakrishnan Govindarajan 30030ba3eadSSriramakrishnan Govindarajan fail2: 30130ba3eadSSriramakrishnan Govindarajan if (!chip->use_polling) { 30230ba3eadSSriramakrishnan Govindarajan free_irq(chip->irqnum, chip); 30330ba3eadSSriramakrishnan Govindarajan enable_irq(chip->irqnum); 30430ba3eadSSriramakrishnan Govindarajan } 30530ba3eadSSriramakrishnan Govindarajan fail1: 30630ba3eadSSriramakrishnan Govindarajan input_free_device(input); 30730ba3eadSSriramakrishnan Govindarajan kfree(chip); 30830ba3eadSSriramakrishnan Govindarajan return error; 30930ba3eadSSriramakrishnan Govindarajan } 31030ba3eadSSriramakrishnan Govindarajan 311e2619cf7SBill Pemberton static int tca6416_keypad_remove(struct i2c_client *client) 31230ba3eadSSriramakrishnan Govindarajan { 31330ba3eadSSriramakrishnan Govindarajan struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); 31430ba3eadSSriramakrishnan Govindarajan 31530ba3eadSSriramakrishnan Govindarajan if (!chip->use_polling) { 31630ba3eadSSriramakrishnan Govindarajan free_irq(chip->irqnum, chip); 31730ba3eadSSriramakrishnan Govindarajan enable_irq(chip->irqnum); 31830ba3eadSSriramakrishnan Govindarajan } 31930ba3eadSSriramakrishnan Govindarajan 32030ba3eadSSriramakrishnan Govindarajan input_unregister_device(chip->input); 32130ba3eadSSriramakrishnan Govindarajan kfree(chip); 32230ba3eadSSriramakrishnan Govindarajan 32330ba3eadSSriramakrishnan Govindarajan return 0; 32430ba3eadSSriramakrishnan Govindarajan } 32530ba3eadSSriramakrishnan Govindarajan 32664dcddd8SMagnus Damm #ifdef CONFIG_PM_SLEEP 32764dcddd8SMagnus Damm static int tca6416_keypad_suspend(struct device *dev) 32864dcddd8SMagnus Damm { 32964dcddd8SMagnus Damm struct i2c_client *client = to_i2c_client(dev); 33064dcddd8SMagnus Damm struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); 33164dcddd8SMagnus Damm 33264dcddd8SMagnus Damm if (device_may_wakeup(dev)) 33364dcddd8SMagnus Damm enable_irq_wake(chip->irqnum); 33464dcddd8SMagnus Damm 33564dcddd8SMagnus Damm return 0; 33664dcddd8SMagnus Damm } 33764dcddd8SMagnus Damm 33864dcddd8SMagnus Damm static int tca6416_keypad_resume(struct device *dev) 33964dcddd8SMagnus Damm { 34064dcddd8SMagnus Damm struct i2c_client *client = to_i2c_client(dev); 34164dcddd8SMagnus Damm struct tca6416_keypad_chip *chip = i2c_get_clientdata(client); 34264dcddd8SMagnus Damm 34364dcddd8SMagnus Damm if (device_may_wakeup(dev)) 34464dcddd8SMagnus Damm disable_irq_wake(chip->irqnum); 34564dcddd8SMagnus Damm 34664dcddd8SMagnus Damm return 0; 34764dcddd8SMagnus Damm } 34864dcddd8SMagnus Damm #endif 34964dcddd8SMagnus Damm 35064dcddd8SMagnus Damm static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops, 35164dcddd8SMagnus Damm tca6416_keypad_suspend, tca6416_keypad_resume); 35230ba3eadSSriramakrishnan Govindarajan 35330ba3eadSSriramakrishnan Govindarajan static struct i2c_driver tca6416_keypad_driver = { 35430ba3eadSSriramakrishnan Govindarajan .driver = { 35530ba3eadSSriramakrishnan Govindarajan .name = "tca6416-keypad", 35664dcddd8SMagnus Damm .pm = &tca6416_keypad_dev_pm_ops, 35730ba3eadSSriramakrishnan Govindarajan }, 35830ba3eadSSriramakrishnan Govindarajan .probe = tca6416_keypad_probe, 3591cb0aa88SBill Pemberton .remove = tca6416_keypad_remove, 36030ba3eadSSriramakrishnan Govindarajan .id_table = tca6416_id, 36130ba3eadSSriramakrishnan Govindarajan }; 36230ba3eadSSriramakrishnan Govindarajan 36330ba3eadSSriramakrishnan Govindarajan static int __init tca6416_keypad_init(void) 36430ba3eadSSriramakrishnan Govindarajan { 36530ba3eadSSriramakrishnan Govindarajan return i2c_add_driver(&tca6416_keypad_driver); 36630ba3eadSSriramakrishnan Govindarajan } 36730ba3eadSSriramakrishnan Govindarajan 36830ba3eadSSriramakrishnan Govindarajan subsys_initcall(tca6416_keypad_init); 36930ba3eadSSriramakrishnan Govindarajan 37030ba3eadSSriramakrishnan Govindarajan static void __exit tca6416_keypad_exit(void) 37130ba3eadSSriramakrishnan Govindarajan { 37230ba3eadSSriramakrishnan Govindarajan i2c_del_driver(&tca6416_keypad_driver); 37330ba3eadSSriramakrishnan Govindarajan } 37430ba3eadSSriramakrishnan Govindarajan module_exit(tca6416_keypad_exit); 37530ba3eadSSriramakrishnan Govindarajan 37630ba3eadSSriramakrishnan Govindarajan MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>"); 37730ba3eadSSriramakrishnan Govindarajan MODULE_DESCRIPTION("Keypad driver over tca6146 IO expander"); 37830ba3eadSSriramakrishnan Govindarajan MODULE_LICENSE("GPL"); 379