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