1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2010, 2011 Fabien Marteau <fabien.marteau@armadeus.com>
4*4882a593Smuzhiyun * Sponsored by ARMadeus Systems
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Driver for Austria Microsystems joysticks AS5011
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * TODO:
9*4882a593Smuzhiyun * - Power on the chip when open() and power down when close()
10*4882a593Smuzhiyun * - Manage power mode
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/i2c.h>
14*4882a593Smuzhiyun #include <linux/interrupt.h>
15*4882a593Smuzhiyun #include <linux/input.h>
16*4882a593Smuzhiyun #include <linux/gpio.h>
17*4882a593Smuzhiyun #include <linux/delay.h>
18*4882a593Smuzhiyun #include <linux/input/as5011.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/module.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define DRIVER_DESC "Driver for Austria Microsystems AS5011 joystick"
23*4882a593Smuzhiyun #define MODULE_DEVICE_ALIAS "as5011"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun MODULE_AUTHOR("Fabien Marteau <fabien.marteau@armadeus.com>");
26*4882a593Smuzhiyun MODULE_DESCRIPTION(DRIVER_DESC);
27*4882a593Smuzhiyun MODULE_LICENSE("GPL");
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* registers */
30*4882a593Smuzhiyun #define AS5011_CTRL1 0x76
31*4882a593Smuzhiyun #define AS5011_CTRL2 0x75
32*4882a593Smuzhiyun #define AS5011_XP 0x43
33*4882a593Smuzhiyun #define AS5011_XN 0x44
34*4882a593Smuzhiyun #define AS5011_YP 0x53
35*4882a593Smuzhiyun #define AS5011_YN 0x54
36*4882a593Smuzhiyun #define AS5011_X_REG 0x41
37*4882a593Smuzhiyun #define AS5011_Y_REG 0x42
38*4882a593Smuzhiyun #define AS5011_X_RES_INT 0x51
39*4882a593Smuzhiyun #define AS5011_Y_RES_INT 0x52
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* CTRL1 bits */
42*4882a593Smuzhiyun #define AS5011_CTRL1_LP_PULSED 0x80
43*4882a593Smuzhiyun #define AS5011_CTRL1_LP_ACTIVE 0x40
44*4882a593Smuzhiyun #define AS5011_CTRL1_LP_CONTINUE 0x20
45*4882a593Smuzhiyun #define AS5011_CTRL1_INT_WUP_EN 0x10
46*4882a593Smuzhiyun #define AS5011_CTRL1_INT_ACT_EN 0x08
47*4882a593Smuzhiyun #define AS5011_CTRL1_EXT_CLK_EN 0x04
48*4882a593Smuzhiyun #define AS5011_CTRL1_SOFT_RST 0x02
49*4882a593Smuzhiyun #define AS5011_CTRL1_DATA_VALID 0x01
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun /* CTRL2 bits */
52*4882a593Smuzhiyun #define AS5011_CTRL2_EXT_SAMPLE_EN 0x08
53*4882a593Smuzhiyun #define AS5011_CTRL2_RC_BIAS_ON 0x04
54*4882a593Smuzhiyun #define AS5011_CTRL2_INV_SPINNING 0x02
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define AS5011_MAX_AXIS 80
57*4882a593Smuzhiyun #define AS5011_MIN_AXIS (-80)
58*4882a593Smuzhiyun #define AS5011_FUZZ 8
59*4882a593Smuzhiyun #define AS5011_FLAT 40
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun struct as5011_device {
62*4882a593Smuzhiyun struct input_dev *input_dev;
63*4882a593Smuzhiyun struct i2c_client *i2c_client;
64*4882a593Smuzhiyun unsigned int button_gpio;
65*4882a593Smuzhiyun unsigned int button_irq;
66*4882a593Smuzhiyun unsigned int axis_irq;
67*4882a593Smuzhiyun };
68*4882a593Smuzhiyun
as5011_i2c_write(struct i2c_client * client,uint8_t aregaddr,uint8_t avalue)69*4882a593Smuzhiyun static int as5011_i2c_write(struct i2c_client *client,
70*4882a593Smuzhiyun uint8_t aregaddr,
71*4882a593Smuzhiyun uint8_t avalue)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun uint8_t data[2] = { aregaddr, avalue };
74*4882a593Smuzhiyun struct i2c_msg msg = {
75*4882a593Smuzhiyun .addr = client->addr,
76*4882a593Smuzhiyun .flags = I2C_M_IGNORE_NAK,
77*4882a593Smuzhiyun .len = 2,
78*4882a593Smuzhiyun .buf = (uint8_t *)data
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun int error;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun error = i2c_transfer(client->adapter, &msg, 1);
83*4882a593Smuzhiyun return error < 0 ? error : 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
as5011_i2c_read(struct i2c_client * client,uint8_t aregaddr,signed char * value)86*4882a593Smuzhiyun static int as5011_i2c_read(struct i2c_client *client,
87*4882a593Smuzhiyun uint8_t aregaddr, signed char *value)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun uint8_t data[2] = { aregaddr };
90*4882a593Smuzhiyun struct i2c_msg msg_set[2] = {
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun .addr = client->addr,
93*4882a593Smuzhiyun .flags = I2C_M_REV_DIR_ADDR,
94*4882a593Smuzhiyun .len = 1,
95*4882a593Smuzhiyun .buf = (uint8_t *)data
96*4882a593Smuzhiyun },
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun .addr = client->addr,
99*4882a593Smuzhiyun .flags = I2C_M_RD | I2C_M_NOSTART,
100*4882a593Smuzhiyun .len = 1,
101*4882a593Smuzhiyun .buf = (uint8_t *)data
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun };
104*4882a593Smuzhiyun int error;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun error = i2c_transfer(client->adapter, msg_set, 2);
107*4882a593Smuzhiyun if (error < 0)
108*4882a593Smuzhiyun return error;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun *value = data[0] & 0x80 ? -1 * (1 + ~data[0]) : data[0];
111*4882a593Smuzhiyun return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun
as5011_button_interrupt(int irq,void * dev_id)114*4882a593Smuzhiyun static irqreturn_t as5011_button_interrupt(int irq, void *dev_id)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun struct as5011_device *as5011 = dev_id;
117*4882a593Smuzhiyun int val = gpio_get_value_cansleep(as5011->button_gpio);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun input_report_key(as5011->input_dev, BTN_JOYSTICK, !val);
120*4882a593Smuzhiyun input_sync(as5011->input_dev);
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun return IRQ_HANDLED;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
as5011_axis_interrupt(int irq,void * dev_id)125*4882a593Smuzhiyun static irqreturn_t as5011_axis_interrupt(int irq, void *dev_id)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun struct as5011_device *as5011 = dev_id;
128*4882a593Smuzhiyun int error;
129*4882a593Smuzhiyun signed char x, y;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun error = as5011_i2c_read(as5011->i2c_client, AS5011_X_RES_INT, &x);
132*4882a593Smuzhiyun if (error < 0)
133*4882a593Smuzhiyun goto out;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun error = as5011_i2c_read(as5011->i2c_client, AS5011_Y_RES_INT, &y);
136*4882a593Smuzhiyun if (error < 0)
137*4882a593Smuzhiyun goto out;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun input_report_abs(as5011->input_dev, ABS_X, x);
140*4882a593Smuzhiyun input_report_abs(as5011->input_dev, ABS_Y, y);
141*4882a593Smuzhiyun input_sync(as5011->input_dev);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun out:
144*4882a593Smuzhiyun return IRQ_HANDLED;
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
as5011_configure_chip(struct as5011_device * as5011,const struct as5011_platform_data * plat_dat)147*4882a593Smuzhiyun static int as5011_configure_chip(struct as5011_device *as5011,
148*4882a593Smuzhiyun const struct as5011_platform_data *plat_dat)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct i2c_client *client = as5011->i2c_client;
151*4882a593Smuzhiyun int error;
152*4882a593Smuzhiyun signed char value;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* chip soft reset */
155*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_CTRL1,
156*4882a593Smuzhiyun AS5011_CTRL1_SOFT_RST);
157*4882a593Smuzhiyun if (error < 0) {
158*4882a593Smuzhiyun dev_err(&client->dev, "Soft reset failed\n");
159*4882a593Smuzhiyun return error;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun mdelay(10);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_CTRL1,
165*4882a593Smuzhiyun AS5011_CTRL1_LP_PULSED |
166*4882a593Smuzhiyun AS5011_CTRL1_LP_ACTIVE |
167*4882a593Smuzhiyun AS5011_CTRL1_INT_ACT_EN);
168*4882a593Smuzhiyun if (error < 0) {
169*4882a593Smuzhiyun dev_err(&client->dev, "Power config failed\n");
170*4882a593Smuzhiyun return error;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_CTRL2,
174*4882a593Smuzhiyun AS5011_CTRL2_INV_SPINNING);
175*4882a593Smuzhiyun if (error < 0) {
176*4882a593Smuzhiyun dev_err(&client->dev, "Can't invert spinning\n");
177*4882a593Smuzhiyun return error;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun /* write threshold */
181*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_XP, plat_dat->xp);
182*4882a593Smuzhiyun if (error < 0) {
183*4882a593Smuzhiyun dev_err(&client->dev, "Can't write threshold\n");
184*4882a593Smuzhiyun return error;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_XN, plat_dat->xn);
188*4882a593Smuzhiyun if (error < 0) {
189*4882a593Smuzhiyun dev_err(&client->dev, "Can't write threshold\n");
190*4882a593Smuzhiyun return error;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_YP, plat_dat->yp);
194*4882a593Smuzhiyun if (error < 0) {
195*4882a593Smuzhiyun dev_err(&client->dev, "Can't write threshold\n");
196*4882a593Smuzhiyun return error;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun error = as5011_i2c_write(client, AS5011_YN, plat_dat->yn);
200*4882a593Smuzhiyun if (error < 0) {
201*4882a593Smuzhiyun dev_err(&client->dev, "Can't write threshold\n");
202*4882a593Smuzhiyun return error;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /* to free irq gpio in chip */
206*4882a593Smuzhiyun error = as5011_i2c_read(client, AS5011_X_RES_INT, &value);
207*4882a593Smuzhiyun if (error < 0) {
208*4882a593Smuzhiyun dev_err(&client->dev, "Can't read i2c X resolution value\n");
209*4882a593Smuzhiyun return error;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun return 0;
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
as5011_probe(struct i2c_client * client,const struct i2c_device_id * id)215*4882a593Smuzhiyun static int as5011_probe(struct i2c_client *client,
216*4882a593Smuzhiyun const struct i2c_device_id *id)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun const struct as5011_platform_data *plat_data;
219*4882a593Smuzhiyun struct as5011_device *as5011;
220*4882a593Smuzhiyun struct input_dev *input_dev;
221*4882a593Smuzhiyun int irq;
222*4882a593Smuzhiyun int error;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun plat_data = dev_get_platdata(&client->dev);
225*4882a593Smuzhiyun if (!plat_data)
226*4882a593Smuzhiyun return -EINVAL;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (!plat_data->axis_irq) {
229*4882a593Smuzhiyun dev_err(&client->dev, "No axis IRQ?\n");
230*4882a593Smuzhiyun return -EINVAL;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun if (!i2c_check_functionality(client->adapter,
234*4882a593Smuzhiyun I2C_FUNC_NOSTART |
235*4882a593Smuzhiyun I2C_FUNC_PROTOCOL_MANGLING)) {
236*4882a593Smuzhiyun dev_err(&client->dev,
237*4882a593Smuzhiyun "need i2c bus that supports protocol mangling\n");
238*4882a593Smuzhiyun return -ENODEV;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
242*4882a593Smuzhiyun input_dev = input_allocate_device();
243*4882a593Smuzhiyun if (!as5011 || !input_dev) {
244*4882a593Smuzhiyun dev_err(&client->dev,
245*4882a593Smuzhiyun "Can't allocate memory for device structure\n");
246*4882a593Smuzhiyun error = -ENOMEM;
247*4882a593Smuzhiyun goto err_free_mem;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun as5011->i2c_client = client;
251*4882a593Smuzhiyun as5011->input_dev = input_dev;
252*4882a593Smuzhiyun as5011->button_gpio = plat_data->button_gpio;
253*4882a593Smuzhiyun as5011->axis_irq = plat_data->axis_irq;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun input_dev->name = "Austria Microsystem as5011 joystick";
256*4882a593Smuzhiyun input_dev->id.bustype = BUS_I2C;
257*4882a593Smuzhiyun input_dev->dev.parent = &client->dev;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun input_set_capability(input_dev, EV_KEY, BTN_JOYSTICK);
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun input_set_abs_params(input_dev, ABS_X,
262*4882a593Smuzhiyun AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
263*4882a593Smuzhiyun input_set_abs_params(as5011->input_dev, ABS_Y,
264*4882a593Smuzhiyun AS5011_MIN_AXIS, AS5011_MAX_AXIS, AS5011_FUZZ, AS5011_FLAT);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun error = gpio_request(as5011->button_gpio, "AS5011 button");
267*4882a593Smuzhiyun if (error < 0) {
268*4882a593Smuzhiyun dev_err(&client->dev, "Failed to request button gpio\n");
269*4882a593Smuzhiyun goto err_free_mem;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun irq = gpio_to_irq(as5011->button_gpio);
273*4882a593Smuzhiyun if (irq < 0) {
274*4882a593Smuzhiyun dev_err(&client->dev,
275*4882a593Smuzhiyun "Failed to get irq number for button gpio\n");
276*4882a593Smuzhiyun error = irq;
277*4882a593Smuzhiyun goto err_free_button_gpio;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
280*4882a593Smuzhiyun as5011->button_irq = irq;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun error = request_threaded_irq(as5011->button_irq,
283*4882a593Smuzhiyun NULL, as5011_button_interrupt,
284*4882a593Smuzhiyun IRQF_TRIGGER_RISING |
285*4882a593Smuzhiyun IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
286*4882a593Smuzhiyun "as5011_button", as5011);
287*4882a593Smuzhiyun if (error < 0) {
288*4882a593Smuzhiyun dev_err(&client->dev,
289*4882a593Smuzhiyun "Can't allocate button irq %d\n", as5011->button_irq);
290*4882a593Smuzhiyun goto err_free_button_gpio;
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun error = as5011_configure_chip(as5011, plat_data);
294*4882a593Smuzhiyun if (error)
295*4882a593Smuzhiyun goto err_free_button_irq;
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun error = request_threaded_irq(as5011->axis_irq, NULL,
298*4882a593Smuzhiyun as5011_axis_interrupt,
299*4882a593Smuzhiyun plat_data->axis_irqflags | IRQF_ONESHOT,
300*4882a593Smuzhiyun "as5011_joystick", as5011);
301*4882a593Smuzhiyun if (error) {
302*4882a593Smuzhiyun dev_err(&client->dev,
303*4882a593Smuzhiyun "Can't allocate axis irq %d\n", plat_data->axis_irq);
304*4882a593Smuzhiyun goto err_free_button_irq;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun error = input_register_device(as5011->input_dev);
308*4882a593Smuzhiyun if (error) {
309*4882a593Smuzhiyun dev_err(&client->dev, "Failed to register input device\n");
310*4882a593Smuzhiyun goto err_free_axis_irq;
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun i2c_set_clientdata(client, as5011);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun return 0;
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun err_free_axis_irq:
318*4882a593Smuzhiyun free_irq(as5011->axis_irq, as5011);
319*4882a593Smuzhiyun err_free_button_irq:
320*4882a593Smuzhiyun free_irq(as5011->button_irq, as5011);
321*4882a593Smuzhiyun err_free_button_gpio:
322*4882a593Smuzhiyun gpio_free(as5011->button_gpio);
323*4882a593Smuzhiyun err_free_mem:
324*4882a593Smuzhiyun input_free_device(input_dev);
325*4882a593Smuzhiyun kfree(as5011);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun return error;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
as5011_remove(struct i2c_client * client)330*4882a593Smuzhiyun static int as5011_remove(struct i2c_client *client)
331*4882a593Smuzhiyun {
332*4882a593Smuzhiyun struct as5011_device *as5011 = i2c_get_clientdata(client);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun free_irq(as5011->axis_irq, as5011);
335*4882a593Smuzhiyun free_irq(as5011->button_irq, as5011);
336*4882a593Smuzhiyun gpio_free(as5011->button_gpio);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun input_unregister_device(as5011->input_dev);
339*4882a593Smuzhiyun kfree(as5011);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return 0;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun static const struct i2c_device_id as5011_id[] = {
345*4882a593Smuzhiyun { MODULE_DEVICE_ALIAS, 0 },
346*4882a593Smuzhiyun { }
347*4882a593Smuzhiyun };
348*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, as5011_id);
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun static struct i2c_driver as5011_driver = {
351*4882a593Smuzhiyun .driver = {
352*4882a593Smuzhiyun .name = "as5011",
353*4882a593Smuzhiyun },
354*4882a593Smuzhiyun .probe = as5011_probe,
355*4882a593Smuzhiyun .remove = as5011_remove,
356*4882a593Smuzhiyun .id_table = as5011_id,
357*4882a593Smuzhiyun };
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun module_i2c_driver(as5011_driver);
360