cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tca6416-keypad.c (8594B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Driver for keys on TCA6416 I2C IO expander
      4 *
      5 * Copyright (C) 2010 Texas Instruments
      6 *
      7 * Author : Sriramakrishnan.A.G. <srk@ti.com>
      8 */
      9
     10#include <linux/types.h>
     11#include <linux/module.h>
     12#include <linux/init.h>
     13#include <linux/delay.h>
     14#include <linux/slab.h>
     15#include <linux/interrupt.h>
     16#include <linux/workqueue.h>
     17#include <linux/gpio.h>
     18#include <linux/i2c.h>
     19#include <linux/input.h>
     20#include <linux/tca6416_keypad.h>
     21
     22#define TCA6416_INPUT          0
     23#define TCA6416_OUTPUT         1
     24#define TCA6416_INVERT         2
     25#define TCA6416_DIRECTION      3
     26
     27static const struct i2c_device_id tca6416_id[] = {
     28	{ "tca6416-keys", 16, },
     29	{ "tca6408-keys", 8, },
     30	{ }
     31};
     32MODULE_DEVICE_TABLE(i2c, tca6416_id);
     33
     34struct tca6416_drv_data {
     35	struct input_dev *input;
     36	struct tca6416_button data[];
     37};
     38
     39struct tca6416_keypad_chip {
     40	uint16_t reg_output;
     41	uint16_t reg_direction;
     42	uint16_t reg_input;
     43
     44	struct i2c_client *client;
     45	struct input_dev *input;
     46	struct delayed_work dwork;
     47	int io_size;
     48	int irqnum;
     49	u16 pinmask;
     50	bool use_polling;
     51	struct tca6416_button buttons[];
     52};
     53
     54static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
     55{
     56	int error;
     57
     58	error = chip->io_size > 8 ?
     59		i2c_smbus_write_word_data(chip->client, reg << 1, val) :
     60		i2c_smbus_write_byte_data(chip->client, reg, val);
     61	if (error < 0) {
     62		dev_err(&chip->client->dev,
     63			"%s failed, reg: %d, val: %d, error: %d\n",
     64			__func__, reg, val, error);
     65		return error;
     66	}
     67
     68	return 0;
     69}
     70
     71static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
     72{
     73	int retval;
     74
     75	retval = chip->io_size > 8 ?
     76		 i2c_smbus_read_word_data(chip->client, reg << 1) :
     77		 i2c_smbus_read_byte_data(chip->client, reg);
     78	if (retval < 0) {
     79		dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
     80			__func__, reg, retval);
     81		return retval;
     82	}
     83
     84	*val = (u16)retval;
     85	return 0;
     86}
     87
     88static void tca6416_keys_scan(struct tca6416_keypad_chip *chip)
     89{
     90	struct input_dev *input = chip->input;
     91	u16 reg_val, val;
     92	int error, i, pin_index;
     93
     94	error = tca6416_read_reg(chip, TCA6416_INPUT, &reg_val);
     95	if (error)
     96		return;
     97
     98	reg_val &= chip->pinmask;
     99
    100	/* Figure out which lines have changed */
    101	val = reg_val ^ chip->reg_input;
    102	chip->reg_input = reg_val;
    103
    104	for (i = 0, pin_index = 0; i < 16; i++) {
    105		if (val & (1 << i)) {
    106			struct tca6416_button *button = &chip->buttons[pin_index];
    107			unsigned int type = button->type ?: EV_KEY;
    108			int state = ((reg_val & (1 << i)) ? 1 : 0)
    109						^ button->active_low;
    110
    111			input_event(input, type, button->code, !!state);
    112			input_sync(input);
    113		}
    114
    115		if (chip->pinmask & (1 << i))
    116			pin_index++;
    117	}
    118}
    119
    120/*
    121 * This is threaded IRQ handler and this can (and will) sleep.
    122 */
    123static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
    124{
    125	struct tca6416_keypad_chip *chip = dev_id;
    126
    127	tca6416_keys_scan(chip);
    128
    129	return IRQ_HANDLED;
    130}
    131
    132static void tca6416_keys_work_func(struct work_struct *work)
    133{
    134	struct tca6416_keypad_chip *chip =
    135		container_of(work, struct tca6416_keypad_chip, dwork.work);
    136
    137	tca6416_keys_scan(chip);
    138	schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
    139}
    140
    141static int tca6416_keys_open(struct input_dev *dev)
    142{
    143	struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
    144
    145	/* Get initial device state in case it has switches */
    146	tca6416_keys_scan(chip);
    147
    148	if (chip->use_polling)
    149		schedule_delayed_work(&chip->dwork, msecs_to_jiffies(100));
    150	else
    151		enable_irq(chip->irqnum);
    152
    153	return 0;
    154}
    155
    156static void tca6416_keys_close(struct input_dev *dev)
    157{
    158	struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
    159
    160	if (chip->use_polling)
    161		cancel_delayed_work_sync(&chip->dwork);
    162	else
    163		disable_irq(chip->irqnum);
    164}
    165
    166static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
    167{
    168	int error;
    169
    170	error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output);
    171	if (error)
    172		return error;
    173
    174	error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
    175	if (error)
    176		return error;
    177
    178	/* ensure that keypad pins are set to input */
    179	error = tca6416_write_reg(chip, TCA6416_DIRECTION,
    180				  chip->reg_direction | chip->pinmask);
    181	if (error)
    182		return error;
    183
    184	error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
    185	if (error)
    186		return error;
    187
    188	error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input);
    189	if (error)
    190		return error;
    191
    192	chip->reg_input &= chip->pinmask;
    193
    194	return 0;
    195}
    196
    197static int tca6416_keypad_probe(struct i2c_client *client,
    198				   const struct i2c_device_id *id)
    199{
    200	struct tca6416_keys_platform_data *pdata;
    201	struct tca6416_keypad_chip *chip;
    202	struct input_dev *input;
    203	int error;
    204	int i;
    205
    206	/* Check functionality */
    207	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
    208		dev_err(&client->dev, "%s adapter not supported\n",
    209			dev_driver_string(&client->adapter->dev));
    210		return -ENODEV;
    211	}
    212
    213	pdata = dev_get_platdata(&client->dev);
    214	if (!pdata) {
    215		dev_dbg(&client->dev, "no platform data\n");
    216		return -EINVAL;
    217	}
    218
    219	chip = kzalloc(struct_size(chip, buttons, pdata->nbuttons), GFP_KERNEL);
    220	input = input_allocate_device();
    221	if (!chip || !input) {
    222		error = -ENOMEM;
    223		goto fail1;
    224	}
    225
    226	chip->client = client;
    227	chip->input = input;
    228	chip->io_size = id->driver_data;
    229	chip->pinmask = pdata->pinmask;
    230	chip->use_polling = pdata->use_polling;
    231
    232	INIT_DELAYED_WORK(&chip->dwork, tca6416_keys_work_func);
    233
    234	input->phys = "tca6416-keys/input0";
    235	input->name = client->name;
    236	input->dev.parent = &client->dev;
    237
    238	input->open = tca6416_keys_open;
    239	input->close = tca6416_keys_close;
    240
    241	input->id.bustype = BUS_HOST;
    242	input->id.vendor = 0x0001;
    243	input->id.product = 0x0001;
    244	input->id.version = 0x0100;
    245
    246	/* Enable auto repeat feature of Linux input subsystem */
    247	if (pdata->rep)
    248		__set_bit(EV_REP, input->evbit);
    249
    250	for (i = 0; i < pdata->nbuttons; i++) {
    251		unsigned int type;
    252
    253		chip->buttons[i] = pdata->buttons[i];
    254		type = (pdata->buttons[i].type) ?: EV_KEY;
    255		input_set_capability(input, type, pdata->buttons[i].code);
    256	}
    257
    258	input_set_drvdata(input, chip);
    259
    260	/*
    261	 * Initialize cached registers from their original values.
    262	 * we can't share this chip with another i2c master.
    263	 */
    264	error = tca6416_setup_registers(chip);
    265	if (error)
    266		goto fail1;
    267
    268	if (!chip->use_polling) {
    269		if (pdata->irq_is_gpio)
    270			chip->irqnum = gpio_to_irq(client->irq);
    271		else
    272			chip->irqnum = client->irq;
    273
    274		error = request_threaded_irq(chip->irqnum, NULL,
    275					     tca6416_keys_isr,
    276					     IRQF_TRIGGER_FALLING |
    277					     IRQF_ONESHOT | IRQF_NO_AUTOEN,
    278					     "tca6416-keypad", chip);
    279		if (error) {
    280			dev_dbg(&client->dev,
    281				"Unable to claim irq %d; error %d\n",
    282				chip->irqnum, error);
    283			goto fail1;
    284		}
    285	}
    286
    287	error = input_register_device(input);
    288	if (error) {
    289		dev_dbg(&client->dev,
    290			"Unable to register input device, error: %d\n", error);
    291		goto fail2;
    292	}
    293
    294	i2c_set_clientdata(client, chip);
    295	device_init_wakeup(&client->dev, 1);
    296
    297	return 0;
    298
    299fail2:
    300	if (!chip->use_polling) {
    301		free_irq(chip->irqnum, chip);
    302		enable_irq(chip->irqnum);
    303	}
    304fail1:
    305	input_free_device(input);
    306	kfree(chip);
    307	return error;
    308}
    309
    310static int tca6416_keypad_remove(struct i2c_client *client)
    311{
    312	struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
    313
    314	if (!chip->use_polling) {
    315		free_irq(chip->irqnum, chip);
    316		enable_irq(chip->irqnum);
    317	}
    318
    319	input_unregister_device(chip->input);
    320	kfree(chip);
    321
    322	return 0;
    323}
    324
    325#ifdef CONFIG_PM_SLEEP
    326static int tca6416_keypad_suspend(struct device *dev)
    327{
    328	struct i2c_client *client = to_i2c_client(dev);
    329	struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
    330
    331	if (device_may_wakeup(dev))
    332		enable_irq_wake(chip->irqnum);
    333
    334	return 0;
    335}
    336
    337static int tca6416_keypad_resume(struct device *dev)
    338{
    339	struct i2c_client *client = to_i2c_client(dev);
    340	struct tca6416_keypad_chip *chip = i2c_get_clientdata(client);
    341
    342	if (device_may_wakeup(dev))
    343		disable_irq_wake(chip->irqnum);
    344
    345	return 0;
    346}
    347#endif
    348
    349static SIMPLE_DEV_PM_OPS(tca6416_keypad_dev_pm_ops,
    350			 tca6416_keypad_suspend, tca6416_keypad_resume);
    351
    352static struct i2c_driver tca6416_keypad_driver = {
    353	.driver = {
    354		.name	= "tca6416-keypad",
    355		.pm	= &tca6416_keypad_dev_pm_ops,
    356	},
    357	.probe		= tca6416_keypad_probe,
    358	.remove		= tca6416_keypad_remove,
    359	.id_table	= tca6416_id,
    360};
    361
    362static int __init tca6416_keypad_init(void)
    363{
    364	return i2c_add_driver(&tca6416_keypad_driver);
    365}
    366
    367subsys_initcall(tca6416_keypad_init);
    368
    369static void __exit tca6416_keypad_exit(void)
    370{
    371	i2c_del_driver(&tca6416_keypad_driver);
    372}
    373module_exit(tca6416_keypad_exit);
    374
    375MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
    376MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
    377MODULE_LICENSE("GPL");