xref: /linux/drivers/input/keyboard/qt2160.c (revision 0e47e3dccfcfaa262d3162ab353474d91d792000)
1fde11323SRaphael Derosso Pereira /*
2fde11323SRaphael Derosso Pereira  *  qt2160.c - Atmel AT42QT2160 Touch Sense Controller
3fde11323SRaphael Derosso Pereira  *
4fde11323SRaphael Derosso Pereira  *  Copyright (C) 2009 Raphael Derosso Pereira <raphaelpereira@gmail.com>
5fde11323SRaphael Derosso Pereira  *
6fde11323SRaphael Derosso Pereira  *  This program is free software; you can redistribute it and/or modify
7fde11323SRaphael Derosso Pereira  *  it under the terms of the GNU General Public License as published by
8fde11323SRaphael Derosso Pereira  *  the Free Software Foundation; either version 2 of the License, or
9fde11323SRaphael Derosso Pereira  *  (at your option) any later version.
10fde11323SRaphael Derosso Pereira  *
11fde11323SRaphael Derosso Pereira  *  This program is distributed in the hope that it will be useful,
12fde11323SRaphael Derosso Pereira  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13fde11323SRaphael Derosso Pereira  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14fde11323SRaphael Derosso Pereira  *  GNU General Public License for more details.
15fde11323SRaphael Derosso Pereira  *
16fde11323SRaphael Derosso Pereira  *  You should have received a copy of the GNU General Public License
17fde11323SRaphael Derosso Pereira  *  along with this program; if not, write to the Free Software
18fde11323SRaphael Derosso Pereira  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19fde11323SRaphael Derosso Pereira  */
20fde11323SRaphael Derosso Pereira 
21fde11323SRaphael Derosso Pereira #include <linux/kernel.h>
22fde11323SRaphael Derosso Pereira #include <linux/init.h>
23*0e47e3dcSJavier Martin #include <linux/leds.h>
24fde11323SRaphael Derosso Pereira #include <linux/module.h>
25fde11323SRaphael Derosso Pereira #include <linux/slab.h>
26fde11323SRaphael Derosso Pereira #include <linux/jiffies.h>
27fde11323SRaphael Derosso Pereira #include <linux/i2c.h>
28fde11323SRaphael Derosso Pereira #include <linux/irq.h>
29fde11323SRaphael Derosso Pereira #include <linux/interrupt.h>
30fde11323SRaphael Derosso Pereira #include <linux/input.h>
31fde11323SRaphael Derosso Pereira 
32fde11323SRaphael Derosso Pereira #define QT2160_VALID_CHIPID  0x11
33fde11323SRaphael Derosso Pereira 
34fde11323SRaphael Derosso Pereira #define QT2160_CMD_CHIPID     0
35fde11323SRaphael Derosso Pereira #define QT2160_CMD_CODEVER    1
36fde11323SRaphael Derosso Pereira #define QT2160_CMD_GSTAT      2
37fde11323SRaphael Derosso Pereira #define QT2160_CMD_KEYS3      3
38fde11323SRaphael Derosso Pereira #define QT2160_CMD_KEYS4      4
39fde11323SRaphael Derosso Pereira #define QT2160_CMD_SLIDE      5
40fde11323SRaphael Derosso Pereira #define QT2160_CMD_GPIOS      6
41fde11323SRaphael Derosso Pereira #define QT2160_CMD_SUBVER     7
42fde11323SRaphael Derosso Pereira #define QT2160_CMD_CALIBRATE  10
43*0e47e3dcSJavier Martin #define QT2160_CMD_DRIVE_X    70
44*0e47e3dcSJavier Martin #define QT2160_CMD_PWMEN_X    74
45*0e47e3dcSJavier Martin #define QT2160_CMD_PWM_DUTY   76
46*0e47e3dcSJavier Martin 
47*0e47e3dcSJavier Martin #define QT2160_NUM_LEDS_X	8
48fde11323SRaphael Derosso Pereira 
49fde11323SRaphael Derosso Pereira #define QT2160_CYCLE_INTERVAL	(2*HZ)
50fde11323SRaphael Derosso Pereira 
51fde11323SRaphael Derosso Pereira static unsigned char qt2160_key2code[] = {
52fde11323SRaphael Derosso Pereira 	KEY_0, KEY_1, KEY_2, KEY_3,
53fde11323SRaphael Derosso Pereira 	KEY_4, KEY_5, KEY_6, KEY_7,
54fde11323SRaphael Derosso Pereira 	KEY_8, KEY_9, KEY_A, KEY_B,
55fde11323SRaphael Derosso Pereira 	KEY_C, KEY_D, KEY_E, KEY_F,
56fde11323SRaphael Derosso Pereira };
57fde11323SRaphael Derosso Pereira 
58*0e47e3dcSJavier Martin #ifdef CONFIG_LEDS_CLASS
59*0e47e3dcSJavier Martin struct qt2160_led {
60*0e47e3dcSJavier Martin 	struct qt2160_data *qt2160;
61*0e47e3dcSJavier Martin 	struct led_classdev cdev;
62*0e47e3dcSJavier Martin 	struct work_struct work;
63*0e47e3dcSJavier Martin 	char name[32];
64*0e47e3dcSJavier Martin 	int id;
65*0e47e3dcSJavier Martin 	enum led_brightness new_brightness;
66*0e47e3dcSJavier Martin };
67*0e47e3dcSJavier Martin #endif
68*0e47e3dcSJavier Martin 
69fde11323SRaphael Derosso Pereira struct qt2160_data {
70fde11323SRaphael Derosso Pereira 	struct i2c_client *client;
71fde11323SRaphael Derosso Pereira 	struct input_dev *input;
72fde11323SRaphael Derosso Pereira 	struct delayed_work dwork;
73fde11323SRaphael Derosso Pereira 	spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
74fde11323SRaphael Derosso Pereira 	unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
75fde11323SRaphael Derosso Pereira 	u16 key_matrix;
76*0e47e3dcSJavier Martin #ifdef CONFIG_LEDS_CLASS
77*0e47e3dcSJavier Martin 	struct qt2160_led leds[QT2160_NUM_LEDS_X];
78*0e47e3dcSJavier Martin 	struct mutex led_lock;
79*0e47e3dcSJavier Martin #endif
80fde11323SRaphael Derosso Pereira };
81fde11323SRaphael Derosso Pereira 
82*0e47e3dcSJavier Martin static int qt2160_read(struct i2c_client *client, u8 reg);
83*0e47e3dcSJavier Martin static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
84*0e47e3dcSJavier Martin 
85*0e47e3dcSJavier Martin #ifdef CONFIG_LEDS_CLASS
86*0e47e3dcSJavier Martin 
87*0e47e3dcSJavier Martin static void qt2160_led_work(struct work_struct *work)
88*0e47e3dcSJavier Martin {
89*0e47e3dcSJavier Martin 	struct qt2160_led *led = container_of(work, struct qt2160_led, work);
90*0e47e3dcSJavier Martin 	struct qt2160_data *qt2160 = led->qt2160;
91*0e47e3dcSJavier Martin 	struct i2c_client *client = qt2160->client;
92*0e47e3dcSJavier Martin 	int value = led->new_brightness;
93*0e47e3dcSJavier Martin 	u32 drive, pwmen;
94*0e47e3dcSJavier Martin 
95*0e47e3dcSJavier Martin 	mutex_lock(&qt2160->led_lock);
96*0e47e3dcSJavier Martin 
97*0e47e3dcSJavier Martin 	drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
98*0e47e3dcSJavier Martin 	pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
99*0e47e3dcSJavier Martin 	if (value != LED_OFF) {
100*0e47e3dcSJavier Martin 		drive |= (1 << led->id);
101*0e47e3dcSJavier Martin 		pwmen |= (1 << led->id);
102*0e47e3dcSJavier Martin 
103*0e47e3dcSJavier Martin 	} else {
104*0e47e3dcSJavier Martin 		drive &= ~(1 << led->id);
105*0e47e3dcSJavier Martin 		pwmen &= ~(1 << led->id);
106*0e47e3dcSJavier Martin 	}
107*0e47e3dcSJavier Martin 	qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
108*0e47e3dcSJavier Martin 	qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
109*0e47e3dcSJavier Martin 
110*0e47e3dcSJavier Martin 	/*
111*0e47e3dcSJavier Martin 	 * Changing this register will change the brightness
112*0e47e3dcSJavier Martin 	 * of every LED in the qt2160. It's a HW limitation.
113*0e47e3dcSJavier Martin 	 */
114*0e47e3dcSJavier Martin 	if (value != LED_OFF)
115*0e47e3dcSJavier Martin 		qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
116*0e47e3dcSJavier Martin 
117*0e47e3dcSJavier Martin 	mutex_unlock(&qt2160->led_lock);
118*0e47e3dcSJavier Martin }
119*0e47e3dcSJavier Martin 
120*0e47e3dcSJavier Martin static void qt2160_led_set(struct led_classdev *cdev,
121*0e47e3dcSJavier Martin 			   enum led_brightness value)
122*0e47e3dcSJavier Martin {
123*0e47e3dcSJavier Martin 	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
124*0e47e3dcSJavier Martin 
125*0e47e3dcSJavier Martin 	led->new_brightness = value;
126*0e47e3dcSJavier Martin 	schedule_work(&led->work);
127*0e47e3dcSJavier Martin }
128*0e47e3dcSJavier Martin 
129*0e47e3dcSJavier Martin #endif /* CONFIG_LEDS_CLASS */
130*0e47e3dcSJavier Martin 
131fde11323SRaphael Derosso Pereira static int qt2160_read_block(struct i2c_client *client,
132fde11323SRaphael Derosso Pereira 			     u8 inireg, u8 *buffer, unsigned int count)
133fde11323SRaphael Derosso Pereira {
134fde11323SRaphael Derosso Pereira 	int error, idx = 0;
135fde11323SRaphael Derosso Pereira 
136fde11323SRaphael Derosso Pereira 	/*
137fde11323SRaphael Derosso Pereira 	 * Can't use SMBus block data read. Check for I2C functionality to speed
138fde11323SRaphael Derosso Pereira 	 * things up whenever possible. Otherwise we will be forced to read
139fde11323SRaphael Derosso Pereira 	 * sequentially.
140fde11323SRaphael Derosso Pereira 	 */
141fde11323SRaphael Derosso Pereira 	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))	{
142fde11323SRaphael Derosso Pereira 
143fde11323SRaphael Derosso Pereira 		error = i2c_smbus_write_byte(client, inireg + idx);
144fde11323SRaphael Derosso Pereira 		if (error) {
145fde11323SRaphael Derosso Pereira 			dev_err(&client->dev,
146fde11323SRaphael Derosso Pereira 				"couldn't send request. Returned %d\n", error);
147fde11323SRaphael Derosso Pereira 			return error;
148fde11323SRaphael Derosso Pereira 		}
149fde11323SRaphael Derosso Pereira 
150fde11323SRaphael Derosso Pereira 		error = i2c_master_recv(client, buffer, count);
151fde11323SRaphael Derosso Pereira 		if (error != count) {
152fde11323SRaphael Derosso Pereira 			dev_err(&client->dev,
153fde11323SRaphael Derosso Pereira 				"couldn't read registers. Returned %d bytes\n", error);
154fde11323SRaphael Derosso Pereira 			return error;
155fde11323SRaphael Derosso Pereira 		}
156fde11323SRaphael Derosso Pereira 	} else {
157fde11323SRaphael Derosso Pereira 
158fde11323SRaphael Derosso Pereira 		while (count--) {
159fde11323SRaphael Derosso Pereira 			int data;
160fde11323SRaphael Derosso Pereira 
161fde11323SRaphael Derosso Pereira 			error = i2c_smbus_write_byte(client, inireg + idx);
162fde11323SRaphael Derosso Pereira 			if (error) {
163fde11323SRaphael Derosso Pereira 				dev_err(&client->dev,
164fde11323SRaphael Derosso Pereira 					"couldn't send request. Returned %d\n", error);
165fde11323SRaphael Derosso Pereira 				return error;
166fde11323SRaphael Derosso Pereira 			}
167fde11323SRaphael Derosso Pereira 
168fde11323SRaphael Derosso Pereira 			data = i2c_smbus_read_byte(client);
169fde11323SRaphael Derosso Pereira 			if (data < 0) {
170fde11323SRaphael Derosso Pereira 				dev_err(&client->dev,
171fde11323SRaphael Derosso Pereira 					"couldn't read register. Returned %d\n", data);
172fde11323SRaphael Derosso Pereira 				return data;
173fde11323SRaphael Derosso Pereira 			}
174fde11323SRaphael Derosso Pereira 
175fde11323SRaphael Derosso Pereira 			buffer[idx++] = data;
176fde11323SRaphael Derosso Pereira 		}
177fde11323SRaphael Derosso Pereira 	}
178fde11323SRaphael Derosso Pereira 
179fde11323SRaphael Derosso Pereira 	return 0;
180fde11323SRaphael Derosso Pereira }
181fde11323SRaphael Derosso Pereira 
182fde11323SRaphael Derosso Pereira static int qt2160_get_key_matrix(struct qt2160_data *qt2160)
183fde11323SRaphael Derosso Pereira {
184fde11323SRaphael Derosso Pereira 	struct i2c_client *client = qt2160->client;
185fde11323SRaphael Derosso Pereira 	struct input_dev *input = qt2160->input;
186fde11323SRaphael Derosso Pereira 	u8 regs[6];
187fde11323SRaphael Derosso Pereira 	u16 old_matrix, new_matrix;
188fde11323SRaphael Derosso Pereira 	int ret, i, mask;
189fde11323SRaphael Derosso Pereira 
190fde11323SRaphael Derosso Pereira 	dev_dbg(&client->dev, "requesting keys...\n");
191fde11323SRaphael Derosso Pereira 
192fde11323SRaphael Derosso Pereira 	/*
193fde11323SRaphael Derosso Pereira 	 * Read all registers from General Status Register
194fde11323SRaphael Derosso Pereira 	 * to GPIOs register
195fde11323SRaphael Derosso Pereira 	 */
196fde11323SRaphael Derosso Pereira 	ret = qt2160_read_block(client, QT2160_CMD_GSTAT, regs, 6);
197fde11323SRaphael Derosso Pereira 	if (ret) {
198fde11323SRaphael Derosso Pereira 		dev_err(&client->dev,
199fde11323SRaphael Derosso Pereira 			"could not perform chip read.\n");
200fde11323SRaphael Derosso Pereira 		return ret;
201fde11323SRaphael Derosso Pereira 	}
202fde11323SRaphael Derosso Pereira 
203fde11323SRaphael Derosso Pereira 	old_matrix = qt2160->key_matrix;
204fde11323SRaphael Derosso Pereira 	qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1];
205fde11323SRaphael Derosso Pereira 
206fde11323SRaphael Derosso Pereira 	mask = 0x01;
207fde11323SRaphael Derosso Pereira 	for (i = 0; i < 16; ++i, mask <<= 1) {
208fde11323SRaphael Derosso Pereira 		int keyval = new_matrix & mask;
209fde11323SRaphael Derosso Pereira 
210fde11323SRaphael Derosso Pereira 		if ((old_matrix & mask) != keyval) {
211fde11323SRaphael Derosso Pereira 			input_report_key(input, qt2160->keycodes[i], keyval);
212fde11323SRaphael Derosso Pereira 			dev_dbg(&client->dev, "key %d %s\n",
213fde11323SRaphael Derosso Pereira 				i, keyval ? "pressed" : "released");
214fde11323SRaphael Derosso Pereira 		}
215fde11323SRaphael Derosso Pereira 	}
216fde11323SRaphael Derosso Pereira 
217fde11323SRaphael Derosso Pereira 	input_sync(input);
218fde11323SRaphael Derosso Pereira 
219fde11323SRaphael Derosso Pereira 	return 0;
220fde11323SRaphael Derosso Pereira }
221fde11323SRaphael Derosso Pereira 
222fde11323SRaphael Derosso Pereira static irqreturn_t qt2160_irq(int irq, void *_qt2160)
223fde11323SRaphael Derosso Pereira {
224fde11323SRaphael Derosso Pereira 	struct qt2160_data *qt2160 = _qt2160;
225fde11323SRaphael Derosso Pereira 	unsigned long flags;
226fde11323SRaphael Derosso Pereira 
227fde11323SRaphael Derosso Pereira 	spin_lock_irqsave(&qt2160->lock, flags);
228fde11323SRaphael Derosso Pereira 
229e7c2f967STejun Heo 	mod_delayed_work(system_wq, &qt2160->dwork, 0);
230fde11323SRaphael Derosso Pereira 
231fde11323SRaphael Derosso Pereira 	spin_unlock_irqrestore(&qt2160->lock, flags);
232fde11323SRaphael Derosso Pereira 
233fde11323SRaphael Derosso Pereira 	return IRQ_HANDLED;
234fde11323SRaphael Derosso Pereira }
235fde11323SRaphael Derosso Pereira 
236fde11323SRaphael Derosso Pereira static void qt2160_schedule_read(struct qt2160_data *qt2160)
237fde11323SRaphael Derosso Pereira {
238fde11323SRaphael Derosso Pereira 	spin_lock_irq(&qt2160->lock);
239fde11323SRaphael Derosso Pereira 	schedule_delayed_work(&qt2160->dwork, QT2160_CYCLE_INTERVAL);
240fde11323SRaphael Derosso Pereira 	spin_unlock_irq(&qt2160->lock);
241fde11323SRaphael Derosso Pereira }
242fde11323SRaphael Derosso Pereira 
243fde11323SRaphael Derosso Pereira static void qt2160_worker(struct work_struct *work)
244fde11323SRaphael Derosso Pereira {
245fde11323SRaphael Derosso Pereira 	struct qt2160_data *qt2160 =
246fde11323SRaphael Derosso Pereira 		container_of(work, struct qt2160_data, dwork.work);
247fde11323SRaphael Derosso Pereira 
248fde11323SRaphael Derosso Pereira 	dev_dbg(&qt2160->client->dev, "worker\n");
249fde11323SRaphael Derosso Pereira 
250fde11323SRaphael Derosso Pereira 	qt2160_get_key_matrix(qt2160);
251fde11323SRaphael Derosso Pereira 
252fde11323SRaphael Derosso Pereira 	/* Avoid device lock up by checking every so often */
253fde11323SRaphael Derosso Pereira 	qt2160_schedule_read(qt2160);
254fde11323SRaphael Derosso Pereira }
255fde11323SRaphael Derosso Pereira 
2565298cc4cSBill Pemberton static int qt2160_read(struct i2c_client *client, u8 reg)
257fde11323SRaphael Derosso Pereira {
258fde11323SRaphael Derosso Pereira 	int ret;
259fde11323SRaphael Derosso Pereira 
260fde11323SRaphael Derosso Pereira 	ret = i2c_smbus_write_byte(client, reg);
261fde11323SRaphael Derosso Pereira 	if (ret) {
262fde11323SRaphael Derosso Pereira 		dev_err(&client->dev,
263fde11323SRaphael Derosso Pereira 			"couldn't send request. Returned %d\n", ret);
264fde11323SRaphael Derosso Pereira 		return ret;
265fde11323SRaphael Derosso Pereira 	}
266fde11323SRaphael Derosso Pereira 
267fde11323SRaphael Derosso Pereira 	ret = i2c_smbus_read_byte(client);
268fde11323SRaphael Derosso Pereira 	if (ret < 0) {
269fde11323SRaphael Derosso Pereira 		dev_err(&client->dev,
270fde11323SRaphael Derosso Pereira 			"couldn't read register. Returned %d\n", ret);
271fde11323SRaphael Derosso Pereira 		return ret;
272fde11323SRaphael Derosso Pereira 	}
273fde11323SRaphael Derosso Pereira 
274fde11323SRaphael Derosso Pereira 	return ret;
275fde11323SRaphael Derosso Pereira }
276fde11323SRaphael Derosso Pereira 
2775298cc4cSBill Pemberton static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
278fde11323SRaphael Derosso Pereira {
279a6e8c0a2SJavier Martin 	int ret;
280fde11323SRaphael Derosso Pereira 
281a6e8c0a2SJavier Martin 	ret = i2c_smbus_write_byte_data(client, reg, data);
282a6e8c0a2SJavier Martin 	if (ret < 0)
283fde11323SRaphael Derosso Pereira 		dev_err(&client->dev,
284a6e8c0a2SJavier Martin 			"couldn't write data. Returned %d\n", ret);
285fde11323SRaphael Derosso Pereira 
286a6e8c0a2SJavier Martin 	return ret;
287fde11323SRaphael Derosso Pereira }
288fde11323SRaphael Derosso Pereira 
289*0e47e3dcSJavier Martin #ifdef CONFIG_LEDS_CLASS
290*0e47e3dcSJavier Martin 
291*0e47e3dcSJavier Martin static int qt2160_register_leds(struct qt2160_data *qt2160)
292*0e47e3dcSJavier Martin {
293*0e47e3dcSJavier Martin 	struct i2c_client *client = qt2160->client;
294*0e47e3dcSJavier Martin 	int ret;
295*0e47e3dcSJavier Martin 	int i;
296*0e47e3dcSJavier Martin 
297*0e47e3dcSJavier Martin 	mutex_init(&qt2160->led_lock);
298*0e47e3dcSJavier Martin 
299*0e47e3dcSJavier Martin 	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
300*0e47e3dcSJavier Martin 		struct qt2160_led *led = &qt2160->leds[i];
301*0e47e3dcSJavier Martin 
302*0e47e3dcSJavier Martin 		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
303*0e47e3dcSJavier Martin 		led->cdev.name = led->name;
304*0e47e3dcSJavier Martin 		led->cdev.brightness_set = qt2160_led_set;
305*0e47e3dcSJavier Martin 		led->cdev.brightness = LED_OFF;
306*0e47e3dcSJavier Martin 		led->id = i;
307*0e47e3dcSJavier Martin 		led->qt2160 = qt2160;
308*0e47e3dcSJavier Martin 
309*0e47e3dcSJavier Martin 		INIT_WORK(&led->work, qt2160_led_work);
310*0e47e3dcSJavier Martin 
311*0e47e3dcSJavier Martin 		ret = led_classdev_register(&client->dev, &led->cdev);
312*0e47e3dcSJavier Martin 		if (ret < 0)
313*0e47e3dcSJavier Martin 			return ret;
314*0e47e3dcSJavier Martin 	}
315*0e47e3dcSJavier Martin 
316*0e47e3dcSJavier Martin 	/* Tur off LEDs */
317*0e47e3dcSJavier Martin 	qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
318*0e47e3dcSJavier Martin 	qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
319*0e47e3dcSJavier Martin 	qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
320*0e47e3dcSJavier Martin 
321*0e47e3dcSJavier Martin 	return 0;
322*0e47e3dcSJavier Martin }
323*0e47e3dcSJavier Martin 
324*0e47e3dcSJavier Martin static void qt2160_unregister_leds(struct qt2160_data *qt2160)
325*0e47e3dcSJavier Martin {
326*0e47e3dcSJavier Martin 	int i;
327*0e47e3dcSJavier Martin 
328*0e47e3dcSJavier Martin 	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
329*0e47e3dcSJavier Martin 		led_classdev_unregister(&qt2160->leds[i].cdev);
330*0e47e3dcSJavier Martin 		cancel_work_sync(&qt2160->leds[i].work);
331*0e47e3dcSJavier Martin 	}
332*0e47e3dcSJavier Martin }
333*0e47e3dcSJavier Martin 
334*0e47e3dcSJavier Martin #else
335*0e47e3dcSJavier Martin 
336*0e47e3dcSJavier Martin static inline int qt2160_register_leds(struct qt2160_data *qt2160)
337*0e47e3dcSJavier Martin {
338*0e47e3dcSJavier Martin 	return 0;
339*0e47e3dcSJavier Martin }
340*0e47e3dcSJavier Martin 
341*0e47e3dcSJavier Martin static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
342*0e47e3dcSJavier Martin {
343*0e47e3dcSJavier Martin }
344*0e47e3dcSJavier Martin 
345*0e47e3dcSJavier Martin #endif
346fde11323SRaphael Derosso Pereira 
3475298cc4cSBill Pemberton static bool qt2160_identify(struct i2c_client *client)
348fde11323SRaphael Derosso Pereira {
349fde11323SRaphael Derosso Pereira 	int id, ver, rev;
350fde11323SRaphael Derosso Pereira 
351fde11323SRaphael Derosso Pereira 	/* Read Chid ID to check if chip is valid */
352fde11323SRaphael Derosso Pereira 	id = qt2160_read(client, QT2160_CMD_CHIPID);
353fde11323SRaphael Derosso Pereira 	if (id != QT2160_VALID_CHIPID) {
354fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "ID %d not supported\n", id);
355fde11323SRaphael Derosso Pereira 		return false;
356fde11323SRaphael Derosso Pereira 	}
357fde11323SRaphael Derosso Pereira 
358fde11323SRaphael Derosso Pereira 	/* Read chip firmware version */
359fde11323SRaphael Derosso Pereira 	ver = qt2160_read(client, QT2160_CMD_CODEVER);
360fde11323SRaphael Derosso Pereira 	if (ver < 0) {
361fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "could not get firmware version\n");
362fde11323SRaphael Derosso Pereira 		return false;
363fde11323SRaphael Derosso Pereira 	}
364fde11323SRaphael Derosso Pereira 
365fde11323SRaphael Derosso Pereira 	/* Read chip firmware revision */
366fde11323SRaphael Derosso Pereira 	rev = qt2160_read(client, QT2160_CMD_SUBVER);
367fde11323SRaphael Derosso Pereira 	if (rev < 0) {
368fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "could not get firmware revision\n");
369fde11323SRaphael Derosso Pereira 		return false;
370fde11323SRaphael Derosso Pereira 	}
371fde11323SRaphael Derosso Pereira 
372fde11323SRaphael Derosso Pereira 	dev_info(&client->dev, "AT42QT2160 firmware version %d.%d.%d\n",
373fde11323SRaphael Derosso Pereira 			ver >> 4, ver & 0xf, rev);
374fde11323SRaphael Derosso Pereira 
375fde11323SRaphael Derosso Pereira 	return true;
376fde11323SRaphael Derosso Pereira }
377fde11323SRaphael Derosso Pereira 
3785298cc4cSBill Pemberton static int qt2160_probe(struct i2c_client *client,
379fde11323SRaphael Derosso Pereira 			const struct i2c_device_id *id)
380fde11323SRaphael Derosso Pereira {
381fde11323SRaphael Derosso Pereira 	struct qt2160_data *qt2160;
382fde11323SRaphael Derosso Pereira 	struct input_dev *input;
383fde11323SRaphael Derosso Pereira 	int i;
384fde11323SRaphael Derosso Pereira 	int error;
385fde11323SRaphael Derosso Pereira 
386fde11323SRaphael Derosso Pereira 	/* Check functionality */
387fde11323SRaphael Derosso Pereira 	error = i2c_check_functionality(client->adapter,
388fde11323SRaphael Derosso Pereira 			I2C_FUNC_SMBUS_BYTE);
389fde11323SRaphael Derosso Pereira 	if (!error) {
390fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "%s adapter not supported\n",
391fde11323SRaphael Derosso Pereira 				dev_driver_string(&client->adapter->dev));
392fde11323SRaphael Derosso Pereira 		return -ENODEV;
393fde11323SRaphael Derosso Pereira 	}
394fde11323SRaphael Derosso Pereira 
395fde11323SRaphael Derosso Pereira 	if (!qt2160_identify(client))
396fde11323SRaphael Derosso Pereira 		return -ENODEV;
397fde11323SRaphael Derosso Pereira 
398fde11323SRaphael Derosso Pereira 	/* Chip is valid and active. Allocate structure */
399fde11323SRaphael Derosso Pereira 	qt2160 = kzalloc(sizeof(struct qt2160_data), GFP_KERNEL);
400fde11323SRaphael Derosso Pereira 	input = input_allocate_device();
401fde11323SRaphael Derosso Pereira 	if (!qt2160 || !input) {
402fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "insufficient memory\n");
403fde11323SRaphael Derosso Pereira 		error = -ENOMEM;
404fde11323SRaphael Derosso Pereira 		goto err_free_mem;
405fde11323SRaphael Derosso Pereira 	}
406fde11323SRaphael Derosso Pereira 
407fde11323SRaphael Derosso Pereira 	qt2160->client = client;
408fde11323SRaphael Derosso Pereira 	qt2160->input = input;
409fde11323SRaphael Derosso Pereira 	INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker);
410fde11323SRaphael Derosso Pereira 	spin_lock_init(&qt2160->lock);
411fde11323SRaphael Derosso Pereira 
412fde11323SRaphael Derosso Pereira 	input->name = "AT42QT2160 Touch Sense Keyboard";
413fde11323SRaphael Derosso Pereira 	input->id.bustype = BUS_I2C;
414fde11323SRaphael Derosso Pereira 
415fde11323SRaphael Derosso Pereira 	input->keycode = qt2160->keycodes;
416fde11323SRaphael Derosso Pereira 	input->keycodesize = sizeof(qt2160->keycodes[0]);
417fde11323SRaphael Derosso Pereira 	input->keycodemax = ARRAY_SIZE(qt2160_key2code);
418fde11323SRaphael Derosso Pereira 
419fde11323SRaphael Derosso Pereira 	__set_bit(EV_KEY, input->evbit);
420fde11323SRaphael Derosso Pereira 	__clear_bit(EV_REP, input->evbit);
421fde11323SRaphael Derosso Pereira 	for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) {
422fde11323SRaphael Derosso Pereira 		qt2160->keycodes[i] = qt2160_key2code[i];
423fde11323SRaphael Derosso Pereira 		__set_bit(qt2160_key2code[i], input->keybit);
424fde11323SRaphael Derosso Pereira 	}
425fde11323SRaphael Derosso Pereira 	__clear_bit(KEY_RESERVED, input->keybit);
426fde11323SRaphael Derosso Pereira 
427fde11323SRaphael Derosso Pereira 	/* Calibrate device */
428fde11323SRaphael Derosso Pereira 	error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1);
429fde11323SRaphael Derosso Pereira 	if (error) {
430fde11323SRaphael Derosso Pereira 		dev_err(&client->dev, "failed to calibrate device\n");
431fde11323SRaphael Derosso Pereira 		goto err_free_mem;
432fde11323SRaphael Derosso Pereira 	}
433fde11323SRaphael Derosso Pereira 
434fde11323SRaphael Derosso Pereira 	if (client->irq) {
435fde11323SRaphael Derosso Pereira 		error = request_irq(client->irq, qt2160_irq,
436fde11323SRaphael Derosso Pereira 				    IRQF_TRIGGER_FALLING, "qt2160", qt2160);
437fde11323SRaphael Derosso Pereira 		if (error) {
438fde11323SRaphael Derosso Pereira 			dev_err(&client->dev,
439fde11323SRaphael Derosso Pereira 				"failed to allocate irq %d\n", client->irq);
440fde11323SRaphael Derosso Pereira 			goto err_free_mem;
441fde11323SRaphael Derosso Pereira 		}
442fde11323SRaphael Derosso Pereira 	}
443fde11323SRaphael Derosso Pereira 
444*0e47e3dcSJavier Martin 	error = qt2160_register_leds(qt2160);
445*0e47e3dcSJavier Martin 	if (error) {
446*0e47e3dcSJavier Martin 		dev_err(&client->dev, "Failed to register leds\n");
447*0e47e3dcSJavier Martin 		goto err_free_irq;
448*0e47e3dcSJavier Martin 	}
449*0e47e3dcSJavier Martin 
450fde11323SRaphael Derosso Pereira 	error = input_register_device(qt2160->input);
451fde11323SRaphael Derosso Pereira 	if (error) {
452fde11323SRaphael Derosso Pereira 		dev_err(&client->dev,
453fde11323SRaphael Derosso Pereira 			"Failed to register input device\n");
454*0e47e3dcSJavier Martin 		goto err_unregister_leds;
455fde11323SRaphael Derosso Pereira 	}
456fde11323SRaphael Derosso Pereira 
457fde11323SRaphael Derosso Pereira 	i2c_set_clientdata(client, qt2160);
458fde11323SRaphael Derosso Pereira 	qt2160_schedule_read(qt2160);
459fde11323SRaphael Derosso Pereira 
460fde11323SRaphael Derosso Pereira 	return 0;
461fde11323SRaphael Derosso Pereira 
462*0e47e3dcSJavier Martin err_unregister_leds:
463*0e47e3dcSJavier Martin 	qt2160_unregister_leds(qt2160);
464fde11323SRaphael Derosso Pereira err_free_irq:
465fde11323SRaphael Derosso Pereira 	if (client->irq)
466fde11323SRaphael Derosso Pereira 		free_irq(client->irq, qt2160);
467fde11323SRaphael Derosso Pereira err_free_mem:
468fde11323SRaphael Derosso Pereira 	input_free_device(input);
469fde11323SRaphael Derosso Pereira 	kfree(qt2160);
470fde11323SRaphael Derosso Pereira 	return error;
471fde11323SRaphael Derosso Pereira }
472fde11323SRaphael Derosso Pereira 
473e2619cf7SBill Pemberton static int qt2160_remove(struct i2c_client *client)
474fde11323SRaphael Derosso Pereira {
475fde11323SRaphael Derosso Pereira 	struct qt2160_data *qt2160 = i2c_get_clientdata(client);
476fde11323SRaphael Derosso Pereira 
477*0e47e3dcSJavier Martin 	qt2160_unregister_leds(qt2160);
478*0e47e3dcSJavier Martin 
479fde11323SRaphael Derosso Pereira 	/* Release IRQ so no queue will be scheduled */
480fde11323SRaphael Derosso Pereira 	if (client->irq)
481fde11323SRaphael Derosso Pereira 		free_irq(client->irq, qt2160);
482fde11323SRaphael Derosso Pereira 
483fde11323SRaphael Derosso Pereira 	cancel_delayed_work_sync(&qt2160->dwork);
484fde11323SRaphael Derosso Pereira 
485fde11323SRaphael Derosso Pereira 	input_unregister_device(qt2160->input);
486fde11323SRaphael Derosso Pereira 	kfree(qt2160);
487fde11323SRaphael Derosso Pereira 
488fde11323SRaphael Derosso Pereira 	return 0;
489fde11323SRaphael Derosso Pereira }
490fde11323SRaphael Derosso Pereira 
491ce7b39a1SMárton Németh static const struct i2c_device_id qt2160_idtable[] = {
492fde11323SRaphael Derosso Pereira 	{ "qt2160", 0, },
493fde11323SRaphael Derosso Pereira 	{ }
494fde11323SRaphael Derosso Pereira };
495fde11323SRaphael Derosso Pereira 
496fde11323SRaphael Derosso Pereira MODULE_DEVICE_TABLE(i2c, qt2160_idtable);
497fde11323SRaphael Derosso Pereira 
498fde11323SRaphael Derosso Pereira static struct i2c_driver qt2160_driver = {
499fde11323SRaphael Derosso Pereira 	.driver = {
500fde11323SRaphael Derosso Pereira 		.name	= "qt2160",
501fde11323SRaphael Derosso Pereira 		.owner  = THIS_MODULE,
502fde11323SRaphael Derosso Pereira 	},
503fde11323SRaphael Derosso Pereira 
504fde11323SRaphael Derosso Pereira 	.id_table	= qt2160_idtable,
505fde11323SRaphael Derosso Pereira 	.probe		= qt2160_probe,
5061cb0aa88SBill Pemberton 	.remove		= qt2160_remove,
507fde11323SRaphael Derosso Pereira };
508fde11323SRaphael Derosso Pereira 
5091b92c1cfSAxel Lin module_i2c_driver(qt2160_driver);
510fde11323SRaphael Derosso Pereira 
511fde11323SRaphael Derosso Pereira MODULE_AUTHOR("Raphael Derosso Pereira <raphaelpereira@gmail.com>");
512fde11323SRaphael Derosso Pereira MODULE_DESCRIPTION("Driver for AT42QT2160 Touch Sensor");
513fde11323SRaphael Derosso Pereira MODULE_LICENSE("GPL");
514