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

qt1070.c (6397B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Atmel AT42QT1070 QTouch Sensor Controller
      4 *
      5 *  Copyright (C) 2011 Atmel
      6 *
      7 *  Authors: Bo Shen <voice.shen@atmel.com>
      8 *
      9 *  Base on AT42QT2160 driver by:
     10 *  Raphael Derosso Pereira <raphaelpereira@gmail.com>
     11 *  Copyright (C) 2009
     12 */
     13#include <linux/kernel.h>
     14#include <linux/module.h>
     15#include <linux/i2c.h>
     16#include <linux/input.h>
     17#include <linux/slab.h>
     18#include <linux/irq.h>
     19#include <linux/interrupt.h>
     20#include <linux/jiffies.h>
     21#include <linux/delay.h>
     22
     23/* Address for each register */
     24#define CHIP_ID            0x00
     25#define QT1070_CHIP_ID     0x2E
     26
     27#define FW_VERSION         0x01
     28#define QT1070_FW_VERSION  0x15
     29
     30#define DET_STATUS         0x02
     31
     32#define KEY_STATUS         0x03
     33
     34/* Calibrate */
     35#define CALIBRATE_CMD      0x38
     36#define QT1070_CAL_TIME    200
     37
     38/* Reset */
     39#define RESET              0x39
     40#define QT1070_RESET_TIME  255
     41
     42/* AT42QT1070 support up to 7 keys */
     43static const unsigned short qt1070_key2code[] = {
     44	KEY_0, KEY_1, KEY_2, KEY_3,
     45	KEY_4, KEY_5, KEY_6,
     46};
     47
     48struct qt1070_data {
     49	struct i2c_client *client;
     50	struct input_dev *input;
     51	unsigned int irq;
     52	unsigned short keycodes[ARRAY_SIZE(qt1070_key2code)];
     53	u8 last_keys;
     54};
     55
     56static int qt1070_read(struct i2c_client *client, u8 reg)
     57{
     58	int ret;
     59
     60	ret = i2c_smbus_read_byte_data(client, reg);
     61	if (ret < 0)
     62		dev_err(&client->dev,
     63			"can not read register, returned %d\n", ret);
     64
     65	return ret;
     66}
     67
     68static int qt1070_write(struct i2c_client *client, u8 reg, u8 data)
     69{
     70	int ret;
     71
     72	ret = i2c_smbus_write_byte_data(client, reg, data);
     73	if (ret < 0)
     74		dev_err(&client->dev,
     75			"can not write register, returned %d\n", ret);
     76
     77	return ret;
     78}
     79
     80static bool qt1070_identify(struct i2c_client *client)
     81{
     82	int id, ver;
     83
     84	/* Read Chip ID */
     85	id = qt1070_read(client, CHIP_ID);
     86	if (id != QT1070_CHIP_ID) {
     87		dev_err(&client->dev, "ID %d not supported\n", id);
     88		return false;
     89	}
     90
     91	/* Read firmware version */
     92	ver = qt1070_read(client, FW_VERSION);
     93	if (ver < 0) {
     94		dev_err(&client->dev, "could not read the firmware version\n");
     95		return false;
     96	}
     97
     98	dev_info(&client->dev, "AT42QT1070 firmware version %x\n", ver);
     99
    100	return true;
    101}
    102
    103static irqreturn_t qt1070_interrupt(int irq, void *dev_id)
    104{
    105	struct qt1070_data *data = dev_id;
    106	struct i2c_client *client = data->client;
    107	struct input_dev *input = data->input;
    108	int i;
    109	u8 new_keys, keyval, mask = 0x01;
    110
    111	/* Read the detected status register, thus clearing interrupt */
    112	qt1070_read(client, DET_STATUS);
    113
    114	/* Read which key changed */
    115	new_keys = qt1070_read(client, KEY_STATUS);
    116
    117	for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
    118		keyval = new_keys & mask;
    119		if ((data->last_keys & mask) != keyval)
    120			input_report_key(input, data->keycodes[i], keyval);
    121		mask <<= 1;
    122	}
    123	input_sync(input);
    124
    125	data->last_keys = new_keys;
    126	return IRQ_HANDLED;
    127}
    128
    129static int qt1070_probe(struct i2c_client *client,
    130				const struct i2c_device_id *id)
    131{
    132	struct qt1070_data *data;
    133	struct input_dev *input;
    134	int i;
    135	int err;
    136
    137	err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
    138	if (!err) {
    139		dev_err(&client->dev, "%s adapter not supported\n",
    140			dev_driver_string(&client->adapter->dev));
    141		return -ENODEV;
    142	}
    143
    144	if (!client->irq) {
    145		dev_err(&client->dev, "please assign the irq to this device\n");
    146		return -EINVAL;
    147	}
    148
    149	/* Identify the qt1070 chip */
    150	if (!qt1070_identify(client))
    151		return -ENODEV;
    152
    153	data = kzalloc(sizeof(struct qt1070_data), GFP_KERNEL);
    154	input = input_allocate_device();
    155	if (!data || !input) {
    156		dev_err(&client->dev, "insufficient memory\n");
    157		err = -ENOMEM;
    158		goto err_free_mem;
    159	}
    160
    161	data->client = client;
    162	data->input = input;
    163	data->irq = client->irq;
    164
    165	input->name = "AT42QT1070 QTouch Sensor";
    166	input->dev.parent = &client->dev;
    167	input->id.bustype = BUS_I2C;
    168
    169	/* Add the keycode */
    170	input->keycode = data->keycodes;
    171	input->keycodesize = sizeof(data->keycodes[0]);
    172	input->keycodemax = ARRAY_SIZE(qt1070_key2code);
    173
    174	__set_bit(EV_KEY, input->evbit);
    175
    176	for (i = 0; i < ARRAY_SIZE(qt1070_key2code); i++) {
    177		data->keycodes[i] = qt1070_key2code[i];
    178		__set_bit(qt1070_key2code[i], input->keybit);
    179	}
    180
    181	/* Calibrate device */
    182	qt1070_write(client, CALIBRATE_CMD, 1);
    183	msleep(QT1070_CAL_TIME);
    184
    185	/* Soft reset */
    186	qt1070_write(client, RESET, 1);
    187	msleep(QT1070_RESET_TIME);
    188
    189	err = request_threaded_irq(client->irq, NULL, qt1070_interrupt,
    190				   IRQF_TRIGGER_NONE | IRQF_ONESHOT,
    191				   client->dev.driver->name, data);
    192	if (err) {
    193		dev_err(&client->dev, "fail to request irq\n");
    194		goto err_free_mem;
    195	}
    196
    197	/* Register the input device */
    198	err = input_register_device(data->input);
    199	if (err) {
    200		dev_err(&client->dev, "Failed to register input device\n");
    201		goto err_free_irq;
    202	}
    203
    204	i2c_set_clientdata(client, data);
    205
    206	/* Read to clear the chang line */
    207	qt1070_read(client, DET_STATUS);
    208
    209	return 0;
    210
    211err_free_irq:
    212	free_irq(client->irq, data);
    213err_free_mem:
    214	input_free_device(input);
    215	kfree(data);
    216	return err;
    217}
    218
    219static int qt1070_remove(struct i2c_client *client)
    220{
    221	struct qt1070_data *data = i2c_get_clientdata(client);
    222
    223	/* Release IRQ */
    224	free_irq(client->irq, data);
    225
    226	input_unregister_device(data->input);
    227	kfree(data);
    228
    229	return 0;
    230}
    231
    232#ifdef CONFIG_PM_SLEEP
    233static int qt1070_suspend(struct device *dev)
    234{
    235	struct i2c_client *client = to_i2c_client(dev);
    236	struct qt1070_data *data = i2c_get_clientdata(client);
    237
    238	if (device_may_wakeup(dev))
    239		enable_irq_wake(data->irq);
    240
    241	return 0;
    242}
    243
    244static int qt1070_resume(struct device *dev)
    245{
    246	struct i2c_client *client = to_i2c_client(dev);
    247	struct qt1070_data *data = i2c_get_clientdata(client);
    248
    249	if (device_may_wakeup(dev))
    250		disable_irq_wake(data->irq);
    251
    252	return 0;
    253}
    254#endif
    255
    256static SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume);
    257
    258static const struct i2c_device_id qt1070_id[] = {
    259	{ "qt1070", 0 },
    260	{ },
    261};
    262MODULE_DEVICE_TABLE(i2c, qt1070_id);
    263
    264#ifdef CONFIG_OF
    265static const struct of_device_id qt1070_of_match[] = {
    266	{ .compatible = "qt1070", },
    267	{ },
    268};
    269MODULE_DEVICE_TABLE(of, qt1070_of_match);
    270#endif
    271
    272static struct i2c_driver qt1070_driver = {
    273	.driver	= {
    274		.name	= "qt1070",
    275		.of_match_table = of_match_ptr(qt1070_of_match),
    276		.pm	= &qt1070_pm_ops,
    277	},
    278	.id_table	= qt1070_id,
    279	.probe		= qt1070_probe,
    280	.remove		= qt1070_remove,
    281};
    282
    283module_i2c_driver(qt1070_driver);
    284
    285MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
    286MODULE_DESCRIPTION("Driver for AT42QT1070 QTouch sensor");
    287MODULE_LICENSE("GPL");