xref: /linux/drivers/input/touchscreen/sx8654.c (revision 4d6ca227c768b50b05cf183974b40abe444e9d0c)
1 /*
2  * Driver for Semtech SX8654 I2C touchscreen controller.
3  *
4  * Copyright (c) 2015 Armadeus Systems
5  *	Sébastien Szymanski <sebastien.szymanski@armadeus.com>
6  *
7  * Using code from:
8  *  - sx865x.c
9  *	Copyright (c) 2013 U-MoBo Srl
10  *	Pierluigi Passaro <p.passaro@u-mobo.com>
11  *  - sx8650.c
12  *      Copyright (c) 2009 Wayne Roberts
13  *  - tsc2007.c
14  *      Copyright (c) 2008 Kwangwoo Lee
15  *  - ads7846.c
16  *      Copyright (c) 2005 David Brownell
17  *      Copyright (c) 2006 Nokia Corporation
18  *  - corgi_ts.c
19  *      Copyright (C) 2004-2005 Richard Purdie
20  *  - omap_ts.[hc], ads7846.h, ts_osk.c
21  *      Copyright (C) 2002 MontaVista Software
22  *      Copyright (C) 2004 Texas Instruments
23  *      Copyright (C) 2005 Dirk Behme
24  *
25  *  This program is free software; you can redistribute it and/or modify
26  *  it under the terms of the GNU General Public License version 2 as
27  *  published by the Free Software Foundation.
28  */
29 
30 #include <linux/input.h>
31 #include <linux/module.h>
32 #include <linux/of.h>
33 #include <linux/i2c.h>
34 #include <linux/interrupt.h>
35 #include <linux/irq.h>
36 
37 /* register addresses */
38 #define I2C_REG_TOUCH0			0x00
39 #define I2C_REG_TOUCH1			0x01
40 #define I2C_REG_CHANMASK		0x04
41 #define I2C_REG_IRQMASK			0x22
42 #define I2C_REG_IRQSRC			0x23
43 #define I2C_REG_SOFTRESET		0x3f
44 
45 /* commands */
46 #define CMD_READ_REGISTER		0x40
47 #define CMD_MANUAL			0xc0
48 #define CMD_PENTRG			0xe0
49 
50 /* value for I2C_REG_SOFTRESET */
51 #define SOFTRESET_VALUE			0xde
52 
53 /* bits for I2C_REG_IRQSRC */
54 #define IRQ_PENTOUCH_TOUCHCONVDONE	0x08
55 #define IRQ_PENRELEASE			0x04
56 
57 /* bits for RegTouch1 */
58 #define CONDIRQ				0x20
59 #define FILT_7SA			0x03
60 
61 /* bits for I2C_REG_CHANMASK */
62 #define CONV_X				0x80
63 #define CONV_Y				0x40
64 
65 /* coordinates rate: higher nibble of CTRL0 register */
66 #define RATE_MANUAL			0x00
67 #define RATE_5000CPS			0xf0
68 
69 /* power delay: lower nibble of CTRL0 register */
70 #define POWDLY_1_1MS			0x0b
71 
72 #define MAX_12BIT			((1 << 12) - 1)
73 
74 struct sx8654 {
75 	struct input_dev *input;
76 	struct i2c_client *client;
77 };
78 
79 static irqreturn_t sx8654_irq(int irq, void *handle)
80 {
81 	struct sx8654 *sx8654 = handle;
82 	int irqsrc;
83 	u8 data[4];
84 	unsigned int x, y;
85 	int retval;
86 
87 	irqsrc = i2c_smbus_read_byte_data(sx8654->client,
88 					  CMD_READ_REGISTER | I2C_REG_IRQSRC);
89 	dev_dbg(&sx8654->client->dev, "irqsrc = 0x%x", irqsrc);
90 
91 	if (irqsrc < 0)
92 		goto out;
93 
94 	if (irqsrc & IRQ_PENRELEASE) {
95 		dev_dbg(&sx8654->client->dev, "pen release interrupt");
96 
97 		input_report_key(sx8654->input, BTN_TOUCH, 0);
98 		input_sync(sx8654->input);
99 	}
100 
101 	if (irqsrc & IRQ_PENTOUCH_TOUCHCONVDONE) {
102 		dev_dbg(&sx8654->client->dev, "pen touch interrupt");
103 
104 		retval = i2c_master_recv(sx8654->client, data, sizeof(data));
105 		if (retval != sizeof(data))
106 			goto out;
107 
108 		/* invalid data */
109 		if (unlikely(data[0] & 0x80 || data[2] & 0x80))
110 			goto out;
111 
112 		x = ((data[0] & 0xf) << 8) | (data[1]);
113 		y = ((data[2] & 0xf) << 8) | (data[3]);
114 
115 		input_report_abs(sx8654->input, ABS_X, x);
116 		input_report_abs(sx8654->input, ABS_Y, y);
117 		input_report_key(sx8654->input, BTN_TOUCH, 1);
118 		input_sync(sx8654->input);
119 
120 		dev_dbg(&sx8654->client->dev, "point(%4d,%4d)\n", x, y);
121 	}
122 
123 out:
124 	return IRQ_HANDLED;
125 }
126 
127 static int sx8654_open(struct input_dev *dev)
128 {
129 	struct sx8654 *sx8654 = input_get_drvdata(dev);
130 	struct i2c_client *client = sx8654->client;
131 	int error;
132 
133 	/* enable pen trigger mode */
134 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0,
135 					  RATE_5000CPS | POWDLY_1_1MS);
136 	if (error) {
137 		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
138 		return error;
139 	}
140 
141 	error = i2c_smbus_write_byte(client, CMD_PENTRG);
142 	if (error) {
143 		dev_err(&client->dev, "writing command CMD_PENTRG failed");
144 		return error;
145 	}
146 
147 	enable_irq(client->irq);
148 
149 	return 0;
150 }
151 
152 static void sx8654_close(struct input_dev *dev)
153 {
154 	struct sx8654 *sx8654 = input_get_drvdata(dev);
155 	struct i2c_client *client = sx8654->client;
156 	int error;
157 
158 	disable_irq(client->irq);
159 
160 	/* enable manual mode mode */
161 	error = i2c_smbus_write_byte(client, CMD_MANUAL);
162 	if (error) {
163 		dev_err(&client->dev, "writing command CMD_MANUAL failed");
164 		return;
165 	}
166 
167 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH0, 0);
168 	if (error) {
169 		dev_err(&client->dev, "writing to I2C_REG_TOUCH0 failed");
170 		return;
171 	}
172 }
173 
174 static int sx8654_probe(struct i2c_client *client,
175 			const struct i2c_device_id *id)
176 {
177 	struct sx8654 *sx8654;
178 	struct input_dev *input;
179 	int error;
180 
181 	if (!i2c_check_functionality(client->adapter,
182 				     I2C_FUNC_SMBUS_READ_WORD_DATA))
183 		return -ENXIO;
184 
185 	sx8654 = devm_kzalloc(&client->dev, sizeof(*sx8654), GFP_KERNEL);
186 	if (!sx8654)
187 		return -ENOMEM;
188 
189 	input = devm_input_allocate_device(&client->dev);
190 	if (!input)
191 		return -ENOMEM;
192 
193 	input->name = "SX8654 I2C Touchscreen";
194 	input->id.bustype = BUS_I2C;
195 	input->dev.parent = &client->dev;
196 	input->open = sx8654_open;
197 	input->close = sx8654_close;
198 
199 	__set_bit(INPUT_PROP_DIRECT, input->propbit);
200 	input_set_capability(input, EV_KEY, BTN_TOUCH);
201 	input_set_abs_params(input, ABS_X, 0, MAX_12BIT, 0, 0);
202 	input_set_abs_params(input, ABS_Y, 0, MAX_12BIT, 0, 0);
203 
204 	sx8654->client = client;
205 	sx8654->input = input;
206 
207 	input_set_drvdata(sx8654->input, sx8654);
208 
209 	error = i2c_smbus_write_byte_data(client, I2C_REG_SOFTRESET,
210 					  SOFTRESET_VALUE);
211 	if (error) {
212 		dev_err(&client->dev, "writing softreset value failed");
213 		return error;
214 	}
215 
216 	error = i2c_smbus_write_byte_data(client, I2C_REG_CHANMASK,
217 					  CONV_X | CONV_Y);
218 	if (error) {
219 		dev_err(&client->dev, "writing to I2C_REG_CHANMASK failed");
220 		return error;
221 	}
222 
223 	error = i2c_smbus_write_byte_data(client, I2C_REG_IRQMASK,
224 					  IRQ_PENTOUCH_TOUCHCONVDONE |
225 						IRQ_PENRELEASE);
226 	if (error) {
227 		dev_err(&client->dev, "writing to I2C_REG_IRQMASK failed");
228 		return error;
229 	}
230 
231 	error = i2c_smbus_write_byte_data(client, I2C_REG_TOUCH1,
232 					  CONDIRQ | FILT_7SA);
233 	if (error) {
234 		dev_err(&client->dev, "writing to I2C_REG_TOUCH1 failed");
235 		return error;
236 	}
237 
238 	error = devm_request_threaded_irq(&client->dev, client->irq,
239 					  NULL, sx8654_irq,
240 					  IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
241 					  client->name, sx8654);
242 	if (error) {
243 		dev_err(&client->dev,
244 			"Failed to enable IRQ %d, error: %d\n",
245 			client->irq, error);
246 		return error;
247 	}
248 
249 	/* Disable the IRQ, we'll enable it in sx8654_open() */
250 	disable_irq(client->irq);
251 
252 	error = input_register_device(sx8654->input);
253 	if (error)
254 		return error;
255 
256 	return 0;
257 }
258 
259 #ifdef CONFIG_OF
260 static const struct of_device_id sx8654_of_match[] = {
261 	{ .compatible = "semtech,sx8654", },
262 	{ },
263 };
264 MODULE_DEVICE_TABLE(of, sx8654_of_match);
265 #endif
266 
267 static const struct i2c_device_id sx8654_id_table[] = {
268 	{ "semtech_sx8654", 0 },
269 	{ },
270 };
271 MODULE_DEVICE_TABLE(i2c, sx8654_id_table);
272 
273 static struct i2c_driver sx8654_driver = {
274 	.driver = {
275 		.name = "sx8654",
276 		.of_match_table = of_match_ptr(sx8654_of_match),
277 	},
278 	.id_table = sx8654_id_table,
279 	.probe = sx8654_probe,
280 };
281 module_i2c_driver(sx8654_driver);
282 
283 MODULE_AUTHOR("Sébastien Szymanski <sebastien.szymanski@armadeus.com>");
284 MODULE_DESCRIPTION("Semtech SX8654 I2C Touchscreen Driver");
285 MODULE_LICENSE("GPL");
286