18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  qt2160.c - Atmel AT42QT2160 Touch Sense Controller
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/leds.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/slab.h>
128c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
138c2ecf20Sopenharmony_ci#include <linux/i2c.h>
148c2ecf20Sopenharmony_ci#include <linux/irq.h>
158c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
168c2ecf20Sopenharmony_ci#include <linux/input.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define QT2160_VALID_CHIPID  0x11
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define QT2160_CMD_CHIPID     0
218c2ecf20Sopenharmony_ci#define QT2160_CMD_CODEVER    1
228c2ecf20Sopenharmony_ci#define QT2160_CMD_GSTAT      2
238c2ecf20Sopenharmony_ci#define QT2160_CMD_KEYS3      3
248c2ecf20Sopenharmony_ci#define QT2160_CMD_KEYS4      4
258c2ecf20Sopenharmony_ci#define QT2160_CMD_SLIDE      5
268c2ecf20Sopenharmony_ci#define QT2160_CMD_GPIOS      6
278c2ecf20Sopenharmony_ci#define QT2160_CMD_SUBVER     7
288c2ecf20Sopenharmony_ci#define QT2160_CMD_CALIBRATE  10
298c2ecf20Sopenharmony_ci#define QT2160_CMD_DRIVE_X    70
308c2ecf20Sopenharmony_ci#define QT2160_CMD_PWMEN_X    74
318c2ecf20Sopenharmony_ci#define QT2160_CMD_PWM_DUTY   76
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define QT2160_NUM_LEDS_X	8
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define QT2160_CYCLE_INTERVAL	(2*HZ)
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic unsigned char qt2160_key2code[] = {
388c2ecf20Sopenharmony_ci	KEY_0, KEY_1, KEY_2, KEY_3,
398c2ecf20Sopenharmony_ci	KEY_4, KEY_5, KEY_6, KEY_7,
408c2ecf20Sopenharmony_ci	KEY_8, KEY_9, KEY_A, KEY_B,
418c2ecf20Sopenharmony_ci	KEY_C, KEY_D, KEY_E, KEY_F,
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#ifdef CONFIG_LEDS_CLASS
458c2ecf20Sopenharmony_cistruct qt2160_led {
468c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160;
478c2ecf20Sopenharmony_ci	struct led_classdev cdev;
488c2ecf20Sopenharmony_ci	char name[32];
498c2ecf20Sopenharmony_ci	int id;
508c2ecf20Sopenharmony_ci	enum led_brightness brightness;
518c2ecf20Sopenharmony_ci};
528c2ecf20Sopenharmony_ci#endif
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct qt2160_data {
558c2ecf20Sopenharmony_ci	struct i2c_client *client;
568c2ecf20Sopenharmony_ci	struct input_dev *input;
578c2ecf20Sopenharmony_ci	struct delayed_work dwork;
588c2ecf20Sopenharmony_ci	unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
598c2ecf20Sopenharmony_ci	u16 key_matrix;
608c2ecf20Sopenharmony_ci#ifdef CONFIG_LEDS_CLASS
618c2ecf20Sopenharmony_ci	struct qt2160_led leds[QT2160_NUM_LEDS_X];
628c2ecf20Sopenharmony_ci#endif
638c2ecf20Sopenharmony_ci};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic int qt2160_read(struct i2c_client *client, u8 reg);
668c2ecf20Sopenharmony_cistatic int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#ifdef CONFIG_LEDS_CLASS
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int qt2160_led_set(struct led_classdev *cdev,
718c2ecf20Sopenharmony_ci			  enum led_brightness value)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
748c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160 = led->qt2160;
758c2ecf20Sopenharmony_ci	struct i2c_client *client = qt2160->client;
768c2ecf20Sopenharmony_ci	u32 drive, pwmen;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (value != led->brightness) {
798c2ecf20Sopenharmony_ci		drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
808c2ecf20Sopenharmony_ci		pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
818c2ecf20Sopenharmony_ci		if (value != LED_OFF) {
828c2ecf20Sopenharmony_ci			drive |= BIT(led->id);
838c2ecf20Sopenharmony_ci			pwmen |= BIT(led->id);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci		} else {
868c2ecf20Sopenharmony_ci			drive &= ~BIT(led->id);
878c2ecf20Sopenharmony_ci			pwmen &= ~BIT(led->id);
888c2ecf20Sopenharmony_ci		}
898c2ecf20Sopenharmony_ci		qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
908c2ecf20Sopenharmony_ci		qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci		/*
938c2ecf20Sopenharmony_ci		 * Changing this register will change the brightness
948c2ecf20Sopenharmony_ci		 * of every LED in the qt2160. It's a HW limitation.
958c2ecf20Sopenharmony_ci		 */
968c2ecf20Sopenharmony_ci		if (value != LED_OFF)
978c2ecf20Sopenharmony_ci			qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci		led->brightness = value;
1008c2ecf20Sopenharmony_ci	}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	return 0;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci#endif /* CONFIG_LEDS_CLASS */
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_cistatic int qt2160_read_block(struct i2c_client *client,
1088c2ecf20Sopenharmony_ci			     u8 inireg, u8 *buffer, unsigned int count)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	int error, idx = 0;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/*
1138c2ecf20Sopenharmony_ci	 * Can't use SMBus block data read. Check for I2C functionality to speed
1148c2ecf20Sopenharmony_ci	 * things up whenever possible. Otherwise we will be forced to read
1158c2ecf20Sopenharmony_ci	 * sequentially.
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))	{
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci		error = i2c_smbus_write_byte(client, inireg + idx);
1208c2ecf20Sopenharmony_ci		if (error) {
1218c2ecf20Sopenharmony_ci			dev_err(&client->dev,
1228c2ecf20Sopenharmony_ci				"couldn't send request. Returned %d\n", error);
1238c2ecf20Sopenharmony_ci			return error;
1248c2ecf20Sopenharmony_ci		}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci		error = i2c_master_recv(client, buffer, count);
1278c2ecf20Sopenharmony_ci		if (error != count) {
1288c2ecf20Sopenharmony_ci			dev_err(&client->dev,
1298c2ecf20Sopenharmony_ci				"couldn't read registers. Returned %d bytes\n", error);
1308c2ecf20Sopenharmony_ci			return error;
1318c2ecf20Sopenharmony_ci		}
1328c2ecf20Sopenharmony_ci	} else {
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		while (count--) {
1358c2ecf20Sopenharmony_ci			int data;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci			error = i2c_smbus_write_byte(client, inireg + idx);
1388c2ecf20Sopenharmony_ci			if (error) {
1398c2ecf20Sopenharmony_ci				dev_err(&client->dev,
1408c2ecf20Sopenharmony_ci					"couldn't send request. Returned %d\n", error);
1418c2ecf20Sopenharmony_ci				return error;
1428c2ecf20Sopenharmony_ci			}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci			data = i2c_smbus_read_byte(client);
1458c2ecf20Sopenharmony_ci			if (data < 0) {
1468c2ecf20Sopenharmony_ci				dev_err(&client->dev,
1478c2ecf20Sopenharmony_ci					"couldn't read register. Returned %d\n", data);
1488c2ecf20Sopenharmony_ci				return data;
1498c2ecf20Sopenharmony_ci			}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci			buffer[idx++] = data;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return 0;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic int qt2160_get_key_matrix(struct qt2160_data *qt2160)
1598c2ecf20Sopenharmony_ci{
1608c2ecf20Sopenharmony_ci	struct i2c_client *client = qt2160->client;
1618c2ecf20Sopenharmony_ci	struct input_dev *input = qt2160->input;
1628c2ecf20Sopenharmony_ci	u8 regs[6];
1638c2ecf20Sopenharmony_ci	u16 old_matrix, new_matrix;
1648c2ecf20Sopenharmony_ci	int ret, i, mask;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	dev_dbg(&client->dev, "requesting keys...\n");
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/*
1698c2ecf20Sopenharmony_ci	 * Read all registers from General Status Register
1708c2ecf20Sopenharmony_ci	 * to GPIOs register
1718c2ecf20Sopenharmony_ci	 */
1728c2ecf20Sopenharmony_ci	ret = qt2160_read_block(client, QT2160_CMD_GSTAT, regs, 6);
1738c2ecf20Sopenharmony_ci	if (ret) {
1748c2ecf20Sopenharmony_ci		dev_err(&client->dev,
1758c2ecf20Sopenharmony_ci			"could not perform chip read.\n");
1768c2ecf20Sopenharmony_ci		return ret;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	old_matrix = qt2160->key_matrix;
1808c2ecf20Sopenharmony_ci	qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	mask = 0x01;
1838c2ecf20Sopenharmony_ci	for (i = 0; i < 16; ++i, mask <<= 1) {
1848c2ecf20Sopenharmony_ci		int keyval = new_matrix & mask;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if ((old_matrix & mask) != keyval) {
1878c2ecf20Sopenharmony_ci			input_report_key(input, qt2160->keycodes[i], keyval);
1888c2ecf20Sopenharmony_ci			dev_dbg(&client->dev, "key %d %s\n",
1898c2ecf20Sopenharmony_ci				i, keyval ? "pressed" : "released");
1908c2ecf20Sopenharmony_ci		}
1918c2ecf20Sopenharmony_ci	}
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	input_sync(input);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	return 0;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_cistatic irqreturn_t qt2160_irq(int irq, void *_qt2160)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160 = _qt2160;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	mod_delayed_work(system_wq, &qt2160->dwork, 0);
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic void qt2160_schedule_read(struct qt2160_data *qt2160)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void qt2160_worker(struct work_struct *work)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160 =
2158c2ecf20Sopenharmony_ci		container_of(work, struct qt2160_data, dwork.work);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	dev_dbg(&qt2160->client->dev, "worker\n");
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	qt2160_get_key_matrix(qt2160);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	/* Avoid device lock up by checking every so often */
2228c2ecf20Sopenharmony_ci	qt2160_schedule_read(qt2160);
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_cistatic int qt2160_read(struct i2c_client *client, u8 reg)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte(client, reg);
2308c2ecf20Sopenharmony_ci	if (ret) {
2318c2ecf20Sopenharmony_ci		dev_err(&client->dev,
2328c2ecf20Sopenharmony_ci			"couldn't send request. Returned %d\n", ret);
2338c2ecf20Sopenharmony_ci		return ret;
2348c2ecf20Sopenharmony_ci	}
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	ret = i2c_smbus_read_byte(client);
2378c2ecf20Sopenharmony_ci	if (ret < 0) {
2388c2ecf20Sopenharmony_ci		dev_err(&client->dev,
2398c2ecf20Sopenharmony_ci			"couldn't read register. Returned %d\n", ret);
2408c2ecf20Sopenharmony_ci		return ret;
2418c2ecf20Sopenharmony_ci	}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return ret;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cistatic int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	int ret;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	ret = i2c_smbus_write_byte_data(client, reg, data);
2518c2ecf20Sopenharmony_ci	if (ret < 0)
2528c2ecf20Sopenharmony_ci		dev_err(&client->dev,
2538c2ecf20Sopenharmony_ci			"couldn't write data. Returned %d\n", ret);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return ret;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci#ifdef CONFIG_LEDS_CLASS
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic int qt2160_register_leds(struct qt2160_data *qt2160)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct i2c_client *client = qt2160->client;
2638c2ecf20Sopenharmony_ci	int ret;
2648c2ecf20Sopenharmony_ci	int i;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
2678c2ecf20Sopenharmony_ci		struct qt2160_led *led = &qt2160->leds[i];
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
2708c2ecf20Sopenharmony_ci		led->cdev.name = led->name;
2718c2ecf20Sopenharmony_ci		led->cdev.brightness_set_blocking = qt2160_led_set;
2728c2ecf20Sopenharmony_ci		led->cdev.brightness = LED_OFF;
2738c2ecf20Sopenharmony_ci		led->id = i;
2748c2ecf20Sopenharmony_ci		led->qt2160 = qt2160;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci		ret = led_classdev_register(&client->dev, &led->cdev);
2778c2ecf20Sopenharmony_ci		if (ret < 0)
2788c2ecf20Sopenharmony_ci			return ret;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	/* Tur off LEDs */
2828c2ecf20Sopenharmony_ci	qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
2838c2ecf20Sopenharmony_ci	qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
2848c2ecf20Sopenharmony_ci	qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_cistatic void qt2160_unregister_leds(struct qt2160_data *qt2160)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	int i;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	for (i = 0; i < QT2160_NUM_LEDS_X; i++)
2948c2ecf20Sopenharmony_ci		led_classdev_unregister(&qt2160->leds[i].cdev);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci#else
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic inline int qt2160_register_leds(struct qt2160_data *qt2160)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	return 0;
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cistatic inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci#endif
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic bool qt2160_identify(struct i2c_client *client)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	int id, ver, rev;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* Read Chid ID to check if chip is valid */
3158c2ecf20Sopenharmony_ci	id = qt2160_read(client, QT2160_CMD_CHIPID);
3168c2ecf20Sopenharmony_ci	if (id != QT2160_VALID_CHIPID) {
3178c2ecf20Sopenharmony_ci		dev_err(&client->dev, "ID %d not supported\n", id);
3188c2ecf20Sopenharmony_ci		return false;
3198c2ecf20Sopenharmony_ci	}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	/* Read chip firmware version */
3228c2ecf20Sopenharmony_ci	ver = qt2160_read(client, QT2160_CMD_CODEVER);
3238c2ecf20Sopenharmony_ci	if (ver < 0) {
3248c2ecf20Sopenharmony_ci		dev_err(&client->dev, "could not get firmware version\n");
3258c2ecf20Sopenharmony_ci		return false;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	/* Read chip firmware revision */
3298c2ecf20Sopenharmony_ci	rev = qt2160_read(client, QT2160_CMD_SUBVER);
3308c2ecf20Sopenharmony_ci	if (rev < 0) {
3318c2ecf20Sopenharmony_ci		dev_err(&client->dev, "could not get firmware revision\n");
3328c2ecf20Sopenharmony_ci		return false;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	dev_info(&client->dev, "AT42QT2160 firmware version %d.%d.%d\n",
3368c2ecf20Sopenharmony_ci			ver >> 4, ver & 0xf, rev);
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	return true;
3398c2ecf20Sopenharmony_ci}
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_cistatic int qt2160_probe(struct i2c_client *client,
3428c2ecf20Sopenharmony_ci			const struct i2c_device_id *id)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160;
3458c2ecf20Sopenharmony_ci	struct input_dev *input;
3468c2ecf20Sopenharmony_ci	int i;
3478c2ecf20Sopenharmony_ci	int error;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	/* Check functionality */
3508c2ecf20Sopenharmony_ci	error = i2c_check_functionality(client->adapter,
3518c2ecf20Sopenharmony_ci			I2C_FUNC_SMBUS_BYTE);
3528c2ecf20Sopenharmony_ci	if (!error) {
3538c2ecf20Sopenharmony_ci		dev_err(&client->dev, "%s adapter not supported\n",
3548c2ecf20Sopenharmony_ci				dev_driver_string(&client->adapter->dev));
3558c2ecf20Sopenharmony_ci		return -ENODEV;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (!qt2160_identify(client))
3598c2ecf20Sopenharmony_ci		return -ENODEV;
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	/* Chip is valid and active. Allocate structure */
3628c2ecf20Sopenharmony_ci	qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL);
3638c2ecf20Sopenharmony_ci	input = input_allocate_device();
3648c2ecf20Sopenharmony_ci	if (!qt2160 || !input) {
3658c2ecf20Sopenharmony_ci		dev_err(&client->dev, "insufficient memory\n");
3668c2ecf20Sopenharmony_ci		error = -ENOMEM;
3678c2ecf20Sopenharmony_ci		goto err_free_mem;
3688c2ecf20Sopenharmony_ci	}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	qt2160->client = client;
3718c2ecf20Sopenharmony_ci	qt2160->input = input;
3728c2ecf20Sopenharmony_ci	INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	input->name = "AT42QT2160 Touch Sense Keyboard";
3758c2ecf20Sopenharmony_ci	input->id.bustype = BUS_I2C;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	input->keycode = qt2160->keycodes;
3788c2ecf20Sopenharmony_ci	input->keycodesize = sizeof(qt2160->keycodes[0]);
3798c2ecf20Sopenharmony_ci	input->keycodemax = ARRAY_SIZE(qt2160_key2code);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	__set_bit(EV_KEY, input->evbit);
3828c2ecf20Sopenharmony_ci	__clear_bit(EV_REP, input->evbit);
3838c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) {
3848c2ecf20Sopenharmony_ci		qt2160->keycodes[i] = qt2160_key2code[i];
3858c2ecf20Sopenharmony_ci		__set_bit(qt2160_key2code[i], input->keybit);
3868c2ecf20Sopenharmony_ci	}
3878c2ecf20Sopenharmony_ci	__clear_bit(KEY_RESERVED, input->keybit);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* Calibrate device */
3908c2ecf20Sopenharmony_ci	error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
3918c2ecf20Sopenharmony_ci	if (error) {
3928c2ecf20Sopenharmony_ci		dev_err(&client->dev, "failed to calibrate device\n");
3938c2ecf20Sopenharmony_ci		goto err_free_mem;
3948c2ecf20Sopenharmony_ci	}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	if (client->irq) {
3978c2ecf20Sopenharmony_ci		error = request_irq(client->irq, qt2160_irq,
3988c2ecf20Sopenharmony_ci				    IRQF_TRIGGER_FALLING, "qt2160", qt2160);
3998c2ecf20Sopenharmony_ci		if (error) {
4008c2ecf20Sopenharmony_ci			dev_err(&client->dev,
4018c2ecf20Sopenharmony_ci				"failed to allocate irq %d\n", client->irq);
4028c2ecf20Sopenharmony_ci			goto err_free_mem;
4038c2ecf20Sopenharmony_ci		}
4048c2ecf20Sopenharmony_ci	}
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	error = qt2160_register_leds(qt2160);
4078c2ecf20Sopenharmony_ci	if (error) {
4088c2ecf20Sopenharmony_ci		dev_err(&client->dev, "Failed to register leds\n");
4098c2ecf20Sopenharmony_ci		goto err_free_irq;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	error = input_register_device(qt2160->input);
4138c2ecf20Sopenharmony_ci	if (error) {
4148c2ecf20Sopenharmony_ci		dev_err(&client->dev,
4158c2ecf20Sopenharmony_ci			"Failed to register input device\n");
4168c2ecf20Sopenharmony_ci		goto err_unregister_leds;
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci	i2c_set_clientdata(client, qt2160);
4208c2ecf20Sopenharmony_ci	qt2160_schedule_read(qt2160);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_cierr_unregister_leds:
4258c2ecf20Sopenharmony_ci	qt2160_unregister_leds(qt2160);
4268c2ecf20Sopenharmony_cierr_free_irq:
4278c2ecf20Sopenharmony_ci	if (client->irq)
4288c2ecf20Sopenharmony_ci		free_irq(client->irq, qt2160);
4298c2ecf20Sopenharmony_cierr_free_mem:
4308c2ecf20Sopenharmony_ci	input_free_device(input);
4318c2ecf20Sopenharmony_ci	kfree(qt2160);
4328c2ecf20Sopenharmony_ci	return error;
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic int qt2160_remove(struct i2c_client *client)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct qt2160_data *qt2160 = i2c_get_clientdata(client);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	qt2160_unregister_leds(qt2160);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	/* Release IRQ so no queue will be scheduled */
4428c2ecf20Sopenharmony_ci	if (client->irq)
4438c2ecf20Sopenharmony_ci		free_irq(client->irq, qt2160);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	cancel_delayed_work_sync(&qt2160->dwork);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	input_unregister_device(qt2160->input);
4488c2ecf20Sopenharmony_ci	kfree(qt2160);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	return 0;
4518c2ecf20Sopenharmony_ci}
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic const struct i2c_device_id qt2160_idtable[] = {
4548c2ecf20Sopenharmony_ci	{ "qt2160", 0, },
4558c2ecf20Sopenharmony_ci	{ }
4568c2ecf20Sopenharmony_ci};
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, qt2160_idtable);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic struct i2c_driver qt2160_driver = {
4618c2ecf20Sopenharmony_ci	.driver = {
4628c2ecf20Sopenharmony_ci		.name	= "qt2160",
4638c2ecf20Sopenharmony_ci	},
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	.id_table	= qt2160_idtable,
4668c2ecf20Sopenharmony_ci	.probe		= qt2160_probe,
4678c2ecf20Sopenharmony_ci	.remove		= qt2160_remove,
4688c2ecf20Sopenharmony_ci};
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_cimodule_i2c_driver(qt2160_driver);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ciMODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
4738c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
4748c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
475