diff options
-rw-r--r-- | drivers/iio/accel/Kconfig | 10 | ||||
-rw-r--r-- | drivers/iio/accel/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/accel/mma9551.c | 954 |
3 files changed, 965 insertions, 0 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 9b9be8725e9d..d80616d77034 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig | |||
@@ -105,4 +105,14 @@ config KXCJK1013 | |||
105 | To compile this driver as a module, choose M here: the module will | 105 | To compile this driver as a module, choose M here: the module will |
106 | be called kxcjk-1013. | 106 | be called kxcjk-1013. |
107 | 107 | ||
108 | config MMA9551 | ||
109 | tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver" | ||
110 | depends on I2C | ||
111 | help | ||
112 | Say yes here to build support for the Freescale MMA9551L | ||
113 | Intelligent Motion-Sensing Platform Driver. | ||
114 | |||
115 | To compile this driver as a module, choose M here: the module | ||
116 | will be called mma9551. | ||
117 | |||
108 | endmenu | 118 | endmenu |
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile index a593996c6539..de5b9cb9670f 100644 --- a/drivers/iio/accel/Makefile +++ b/drivers/iio/accel/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o | |||
9 | obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o | 9 | obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o |
10 | obj-$(CONFIG_KXSD9) += kxsd9.o | 10 | obj-$(CONFIG_KXSD9) += kxsd9.o |
11 | obj-$(CONFIG_MMA8452) += mma8452.o | 11 | obj-$(CONFIG_MMA8452) += mma8452.o |
12 | obj-$(CONFIG_MMA9551) += mma9551.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o | 14 | obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o |
14 | st_accel-y := st_accel_core.o | 15 | st_accel-y := st_accel_core.o |
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c new file mode 100644 index 000000000000..1be125bb9161 --- /dev/null +++ b/drivers/iio/accel/mma9551.c | |||
@@ -0,0 +1,954 @@ | |||
1 | /* | ||
2 | * Freescale MMA9551L Intelligent Motion-Sensing Platform driver | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/acpi.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/gpio/consumer.h> | ||
22 | #include <linux/iio/iio.h> | ||
23 | #include <linux/iio/sysfs.h> | ||
24 | #include <linux/iio/events.h> | ||
25 | |||
26 | #define MMA9551_DRV_NAME "mma9551" | ||
27 | #define MMA9551_IRQ_NAME "mma9551_event" | ||
28 | #define MMA9551_GPIO_NAME "mma9551_int" | ||
29 | #define MMA9551_GPIO_COUNT 4 | ||
30 | |||
31 | /* Applications IDs */ | ||
32 | #define MMA9551_APPID_VERSION 0x00 | ||
33 | #define MMA9551_APPID_GPIO 0x03 | ||
34 | #define MMA9551_APPID_AFE 0x06 | ||
35 | #define MMA9551_APPID_TILT 0x0B | ||
36 | #define MMA9551_APPID_SLEEP_WAKE 0x12 | ||
37 | #define MMA9551_APPID_RESET 0x17 | ||
38 | #define MMA9551_APPID_NONE 0xff | ||
39 | |||
40 | /* Command masks for mailbox write command */ | ||
41 | #define MMA9551_CMD_READ_VERSION_INFO 0x00 | ||
42 | #define MMA9551_CMD_READ_CONFIG 0x10 | ||
43 | #define MMA9551_CMD_WRITE_CONFIG 0x20 | ||
44 | #define MMA9551_CMD_READ_STATUS 0x30 | ||
45 | |||
46 | enum mma9551_gpio_pin { | ||
47 | mma9551_gpio6 = 0, | ||
48 | mma9551_gpio7, | ||
49 | mma9551_gpio8, | ||
50 | mma9551_gpio9, | ||
51 | mma9551_gpio_max = mma9551_gpio9, | ||
52 | }; | ||
53 | |||
54 | /* Mailbox read command */ | ||
55 | #define MMA9551_RESPONSE_COCO BIT(7) | ||
56 | |||
57 | /* Error-Status codes returned in mailbox read command */ | ||
58 | #define MMA9551_MCI_ERROR_NONE 0x00 | ||
59 | #define MMA9551_MCI_ERROR_PARAM 0x04 | ||
60 | #define MMA9551_MCI_INVALID_COUNT 0x19 | ||
61 | #define MMA9551_MCI_ERROR_COMMAND 0x1C | ||
62 | #define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21 | ||
63 | #define MMA9551_MCI_ERROR_FIFO_BUSY 0x22 | ||
64 | #define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23 | ||
65 | #define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24 | ||
66 | |||
67 | /* GPIO Application */ | ||
68 | #define MMA9551_GPIO_POL_MSB 0x08 | ||
69 | #define MMA9551_GPIO_POL_LSB 0x09 | ||
70 | |||
71 | /* Sleep/Wake application */ | ||
72 | #define MMA9551_SLEEP_CFG 0x06 | ||
73 | #define MMA9551_SLEEP_CFG_SNCEN BIT(0) | ||
74 | #define MMA9551_SLEEP_CFG_SCHEN BIT(2) | ||
75 | |||
76 | /* AFE application */ | ||
77 | #define MMA9551_AFE_X_ACCEL_REG 0x00 | ||
78 | #define MMA9551_AFE_Y_ACCEL_REG 0x02 | ||
79 | #define MMA9551_AFE_Z_ACCEL_REG 0x04 | ||
80 | |||
81 | /* Tilt application (inclination in IIO terms). */ | ||
82 | #define MMA9551_TILT_XZ_ANG_REG 0x00 | ||
83 | #define MMA9551_TILT_YZ_ANG_REG 0x01 | ||
84 | #define MMA9551_TILT_XY_ANG_REG 0x02 | ||
85 | #define MMA9551_TILT_ANGFLG BIT(7) | ||
86 | #define MMA9551_TILT_QUAD_REG 0x03 | ||
87 | #define MMA9551_TILT_XY_QUAD_SHIFT 0 | ||
88 | #define MMA9551_TILT_YZ_QUAD_SHIFT 2 | ||
89 | #define MMA9551_TILT_XZ_QUAD_SHIFT 4 | ||
90 | #define MMA9551_TILT_CFG_REG 0x01 | ||
91 | #define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0) | ||
92 | |||
93 | /* Tilt events are mapped to the first three GPIO pins. */ | ||
94 | enum mma9551_tilt_axis { | ||
95 | mma9551_x = 0, | ||
96 | mma9551_y, | ||
97 | mma9551_z, | ||
98 | }; | ||
99 | |||
100 | /* | ||
101 | * A response is composed of: | ||
102 | * - control registers: MB0-3 | ||
103 | * - data registers: MB4-31 | ||
104 | * | ||
105 | * A request is composed of: | ||
106 | * - mbox to write to (always 0) | ||
107 | * - control registers: MB1-4 | ||
108 | * - data registers: MB5-31 | ||
109 | */ | ||
110 | #define MMA9551_MAILBOX_CTRL_REGS 4 | ||
111 | #define MMA9551_MAX_MAILBOX_DATA_REGS 28 | ||
112 | #define MMA9551_MAILBOX_REGS 32 | ||
113 | |||
114 | #define MMA9551_I2C_READ_RETRIES 5 | ||
115 | #define MMA9551_I2C_READ_DELAY 50 /* us */ | ||
116 | |||
117 | struct mma9551_mbox_request { | ||
118 | u8 start_mbox; /* Always 0. */ | ||
119 | u8 app_id; | ||
120 | /* | ||
121 | * See Section 5.3.1 of the MMA955xL Software Reference Manual. | ||
122 | * | ||
123 | * Bit 7: reserved, always 0 | ||
124 | * Bits 6-4: command | ||
125 | * Bits 3-0: upper bits of register offset | ||
126 | */ | ||
127 | u8 cmd_off; | ||
128 | u8 lower_off; | ||
129 | u8 nbytes; | ||
130 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1]; | ||
131 | } __packed; | ||
132 | |||
133 | struct mma9551_mbox_response { | ||
134 | u8 app_id; | ||
135 | /* | ||
136 | * See Section 5.3.3 of the MMA955xL Software Reference Manual. | ||
137 | * | ||
138 | * Bit 7: COCO | ||
139 | * Bits 6-0: Error code. | ||
140 | */ | ||
141 | u8 coco_err; | ||
142 | u8 nbytes; | ||
143 | u8 req_bytes; | ||
144 | u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS]; | ||
145 | } __packed; | ||
146 | |||
147 | struct mma9551_version_info { | ||
148 | __be32 device_id; | ||
149 | u8 rom_version[2]; | ||
150 | u8 fw_version[2]; | ||
151 | u8 hw_version[2]; | ||
152 | u8 fw_build[2]; | ||
153 | }; | ||
154 | |||
155 | struct mma9551_data { | ||
156 | struct i2c_client *client; | ||
157 | struct mutex mutex; | ||
158 | int event_enabled[3]; | ||
159 | int irqs[MMA9551_GPIO_COUNT]; | ||
160 | }; | ||
161 | |||
162 | static int mma9551_transfer(struct i2c_client *client, | ||
163 | u8 app_id, u8 command, u16 offset, | ||
164 | u8 *inbytes, int num_inbytes, | ||
165 | u8 *outbytes, int num_outbytes) | ||
166 | { | ||
167 | struct mma9551_mbox_request req; | ||
168 | struct mma9551_mbox_response rsp; | ||
169 | struct i2c_msg in, out; | ||
170 | u8 req_len, err_code; | ||
171 | int ret, retries; | ||
172 | |||
173 | if (offset >= 1 << 12) { | ||
174 | dev_err(&client->dev, "register offset too large\n"); | ||
175 | return -EINVAL; | ||
176 | } | ||
177 | |||
178 | req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes; | ||
179 | req.start_mbox = 0; | ||
180 | req.app_id = app_id; | ||
181 | req.cmd_off = command | (offset >> 8); | ||
182 | req.lower_off = offset; | ||
183 | |||
184 | if (command == MMA9551_CMD_WRITE_CONFIG) | ||
185 | req.nbytes = num_inbytes; | ||
186 | else | ||
187 | req.nbytes = num_outbytes; | ||
188 | if (num_inbytes) | ||
189 | memcpy(req.buf, inbytes, num_inbytes); | ||
190 | |||
191 | out.addr = client->addr; | ||
192 | out.flags = 0; | ||
193 | out.len = req_len; | ||
194 | out.buf = (u8 *)&req; | ||
195 | |||
196 | ret = i2c_transfer(client->adapter, &out, 1); | ||
197 | if (ret < 0) { | ||
198 | dev_err(&client->dev, "i2c write failed\n"); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | retries = MMA9551_I2C_READ_RETRIES; | ||
203 | do { | ||
204 | udelay(MMA9551_I2C_READ_DELAY); | ||
205 | |||
206 | in.addr = client->addr; | ||
207 | in.flags = I2C_M_RD; | ||
208 | in.len = sizeof(rsp); | ||
209 | in.buf = (u8 *)&rsp; | ||
210 | |||
211 | ret = i2c_transfer(client->adapter, &in, 1); | ||
212 | if (ret < 0) { | ||
213 | dev_err(&client->dev, "i2c read failed\n"); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | if (rsp.coco_err & MMA9551_RESPONSE_COCO) | ||
218 | break; | ||
219 | } while (--retries > 0); | ||
220 | |||
221 | if (retries == 0) { | ||
222 | dev_err(&client->dev, | ||
223 | "timed out while waiting for command response\n"); | ||
224 | return -ETIMEDOUT; | ||
225 | } | ||
226 | |||
227 | if (rsp.app_id != app_id) { | ||
228 | dev_err(&client->dev, | ||
229 | "app_id mismatch in response got %02x expected %02x\n", | ||
230 | rsp.app_id, app_id); | ||
231 | return -EINVAL; | ||
232 | } | ||
233 | |||
234 | err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO; | ||
235 | if (err_code != MMA9551_MCI_ERROR_NONE) { | ||
236 | dev_err(&client->dev, "read returned error %x\n", err_code); | ||
237 | return -EINVAL; | ||
238 | } | ||
239 | |||
240 | if (rsp.nbytes != rsp.req_bytes) { | ||
241 | dev_err(&client->dev, | ||
242 | "output length mismatch got %d expected %d\n", | ||
243 | rsp.nbytes, rsp.req_bytes); | ||
244 | return -EINVAL; | ||
245 | } | ||
246 | |||
247 | if (num_outbytes) | ||
248 | memcpy(outbytes, rsp.buf, num_outbytes); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int mma9551_read_config_byte(struct i2c_client *client, u8 app_id, | ||
254 | u16 reg, u8 *val) | ||
255 | { | ||
256 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG, | ||
257 | reg, NULL, 0, val, 1); | ||
258 | } | ||
259 | |||
260 | static int mma9551_write_config_byte(struct i2c_client *client, u8 app_id, | ||
261 | u16 reg, u8 val) | ||
262 | { | ||
263 | return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg, | ||
264 | &val, 1, NULL, 0); | ||
265 | } | ||
266 | |||
267 | static int mma9551_read_status_byte(struct i2c_client *client, u8 app_id, | ||
268 | u16 reg, u8 *val) | ||
269 | { | ||
270 | return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
271 | reg, NULL, 0, val, 1); | ||
272 | } | ||
273 | |||
274 | static int mma9551_read_status_word(struct i2c_client *client, u8 app_id, | ||
275 | u16 reg, u16 *val) | ||
276 | { | ||
277 | int ret; | ||
278 | __be16 v; | ||
279 | |||
280 | ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS, | ||
281 | reg, NULL, 0, (u8 *)&v, 2); | ||
282 | *val = be16_to_cpu(v); | ||
283 | |||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | static int mma9551_update_config_bits(struct i2c_client *client, u8 app_id, | ||
288 | u16 reg, u8 mask, u8 val) | ||
289 | { | ||
290 | int ret; | ||
291 | u8 tmp, orig; | ||
292 | |||
293 | ret = mma9551_read_config_byte(client, app_id, reg, &orig); | ||
294 | if (ret < 0) | ||
295 | return ret; | ||
296 | |||
297 | tmp = orig & ~mask; | ||
298 | tmp |= val & mask; | ||
299 | |||
300 | if (tmp == orig) | ||
301 | return 0; | ||
302 | |||
303 | return mma9551_write_config_byte(client, app_id, reg, tmp); | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * The polarity parameter is described in section 6.2.2, page 66, of the | ||
308 | * Software Reference Manual. Basically, polarity=0 means the interrupt | ||
309 | * line has the same value as the selected bit, while polarity=1 means | ||
310 | * the line is inverted. | ||
311 | */ | ||
312 | static int mma9551_gpio_config(struct i2c_client *client, | ||
313 | enum mma9551_gpio_pin pin, | ||
314 | u8 app_id, u8 bitnum, int polarity) | ||
315 | { | ||
316 | u8 reg, pol_mask, pol_val; | ||
317 | int ret; | ||
318 | |||
319 | if (pin > mma9551_gpio_max) { | ||
320 | dev_err(&client->dev, "bad GPIO pin\n"); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | /* | ||
325 | * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and | ||
326 | * 0x03, and so on. | ||
327 | */ | ||
328 | reg = pin * 2; | ||
329 | |||
330 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
331 | reg, app_id); | ||
332 | if (ret < 0) { | ||
333 | dev_err(&client->dev, "error setting GPIO app_id\n"); | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO, | ||
338 | reg + 1, bitnum); | ||
339 | if (ret < 0) { | ||
340 | dev_err(&client->dev, "error setting GPIO bit number\n"); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | switch (pin) { | ||
345 | case mma9551_gpio6: | ||
346 | reg = MMA9551_GPIO_POL_LSB; | ||
347 | pol_mask = 1 << 6; | ||
348 | break; | ||
349 | case mma9551_gpio7: | ||
350 | reg = MMA9551_GPIO_POL_LSB; | ||
351 | pol_mask = 1 << 7; | ||
352 | break; | ||
353 | case mma9551_gpio8: | ||
354 | reg = MMA9551_GPIO_POL_MSB; | ||
355 | pol_mask = 1 << 0; | ||
356 | break; | ||
357 | case mma9551_gpio9: | ||
358 | reg = MMA9551_GPIO_POL_MSB; | ||
359 | pol_mask = 1 << 1; | ||
360 | break; | ||
361 | } | ||
362 | pol_val = polarity ? pol_mask : 0; | ||
363 | |||
364 | ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg, | ||
365 | pol_mask, pol_val); | ||
366 | if (ret < 0) | ||
367 | dev_err(&client->dev, "error setting GPIO polarity\n"); | ||
368 | |||
369 | return ret; | ||
370 | } | ||
371 | |||
372 | static int mma9551_read_version(struct i2c_client *client) | ||
373 | { | ||
374 | struct mma9551_version_info info; | ||
375 | int ret; | ||
376 | |||
377 | ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00, | ||
378 | NULL, 0, (u8 *)&info, sizeof(info)); | ||
379 | if (ret < 0) | ||
380 | return ret; | ||
381 | |||
382 | dev_info(&client->dev, "Device ID 0x%x, firmware version %02x.%02x\n", | ||
383 | be32_to_cpu(info.device_id), info.fw_version[0], | ||
384 | info.fw_version[1]); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * Use 'false' as the second parameter to cause the device to enter | ||
391 | * sleep. | ||
392 | */ | ||
393 | static int mma9551_set_device_state(struct i2c_client *client, | ||
394 | bool enable) | ||
395 | { | ||
396 | return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE, | ||
397 | MMA9551_SLEEP_CFG, | ||
398 | MMA9551_SLEEP_CFG_SNCEN, | ||
399 | enable ? 0 : MMA9551_SLEEP_CFG_SNCEN); | ||
400 | } | ||
401 | |||
402 | static int mma9551_read_incli_chan(struct i2c_client *client, | ||
403 | const struct iio_chan_spec *chan, | ||
404 | int *val) | ||
405 | { | ||
406 | u8 quad_shift, angle, quadrant; | ||
407 | u16 reg_addr; | ||
408 | int ret; | ||
409 | |||
410 | switch (chan->channel2) { | ||
411 | case IIO_MOD_X: | ||
412 | reg_addr = MMA9551_TILT_YZ_ANG_REG; | ||
413 | quad_shift = MMA9551_TILT_YZ_QUAD_SHIFT; | ||
414 | break; | ||
415 | case IIO_MOD_Y: | ||
416 | reg_addr = MMA9551_TILT_XZ_ANG_REG; | ||
417 | quad_shift = MMA9551_TILT_XZ_QUAD_SHIFT; | ||
418 | break; | ||
419 | case IIO_MOD_Z: | ||
420 | reg_addr = MMA9551_TILT_XY_ANG_REG; | ||
421 | quad_shift = MMA9551_TILT_XY_QUAD_SHIFT; | ||
422 | break; | ||
423 | default: | ||
424 | return -EINVAL; | ||
425 | } | ||
426 | |||
427 | ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT, | ||
428 | reg_addr, &angle); | ||
429 | if (ret < 0) | ||
430 | return ret; | ||
431 | |||
432 | ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT, | ||
433 | MMA9551_TILT_QUAD_REG, &quadrant); | ||
434 | if (ret < 0) | ||
435 | return ret; | ||
436 | |||
437 | angle &= ~MMA9551_TILT_ANGFLG; | ||
438 | quadrant = (quadrant >> quad_shift) & 0x03; | ||
439 | |||
440 | if (quadrant == 1 || quadrant == 3) | ||
441 | *val = 90 * (quadrant + 1) - angle; | ||
442 | else | ||
443 | *val = angle + 90 * quadrant; | ||
444 | |||
445 | return IIO_VAL_INT; | ||
446 | } | ||
447 | |||
448 | static int mma9551_read_accel_chan(struct i2c_client *client, | ||
449 | const struct iio_chan_spec *chan, | ||
450 | int *val, int *val2) | ||
451 | { | ||
452 | u16 reg_addr; | ||
453 | s16 raw_accel; | ||
454 | int ret; | ||
455 | |||
456 | switch (chan->channel2) { | ||
457 | case IIO_MOD_X: | ||
458 | reg_addr = MMA9551_AFE_X_ACCEL_REG; | ||
459 | break; | ||
460 | case IIO_MOD_Y: | ||
461 | reg_addr = MMA9551_AFE_Y_ACCEL_REG; | ||
462 | break; | ||
463 | case IIO_MOD_Z: | ||
464 | reg_addr = MMA9551_AFE_Z_ACCEL_REG; | ||
465 | break; | ||
466 | default: | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | ret = mma9551_read_status_word(client, MMA9551_APPID_AFE, | ||
471 | reg_addr, &raw_accel); | ||
472 | if (ret < 0) | ||
473 | return ret; | ||
474 | |||
475 | *val = raw_accel; | ||
476 | |||
477 | return IIO_VAL_INT; | ||
478 | } | ||
479 | |||
480 | static int mma9551_read_raw(struct iio_dev *indio_dev, | ||
481 | struct iio_chan_spec const *chan, | ||
482 | int *val, int *val2, long mask) | ||
483 | { | ||
484 | struct mma9551_data *data = iio_priv(indio_dev); | ||
485 | int ret; | ||
486 | |||
487 | switch (mask) { | ||
488 | case IIO_CHAN_INFO_PROCESSED: | ||
489 | switch (chan->type) { | ||
490 | case IIO_INCLI: | ||
491 | mutex_lock(&data->mutex); | ||
492 | ret = mma9551_read_incli_chan(data->client, chan, val); | ||
493 | mutex_unlock(&data->mutex); | ||
494 | return ret; | ||
495 | default: | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | case IIO_CHAN_INFO_RAW: | ||
499 | switch (chan->type) { | ||
500 | case IIO_ACCEL: | ||
501 | mutex_lock(&data->mutex); | ||
502 | ret = mma9551_read_accel_chan(data->client, | ||
503 | chan, val, val2); | ||
504 | mutex_unlock(&data->mutex); | ||
505 | return ret; | ||
506 | default: | ||
507 | return -EINVAL; | ||
508 | } | ||
509 | case IIO_CHAN_INFO_SCALE: | ||
510 | switch (chan->type) { | ||
511 | case IIO_ACCEL: | ||
512 | *val = 0; | ||
513 | *val2 = 2440; | ||
514 | return IIO_VAL_INT_PLUS_MICRO; | ||
515 | default: | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | default: | ||
519 | return -EINVAL; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static int mma9551_read_event_config(struct iio_dev *indio_dev, | ||
524 | const struct iio_chan_spec *chan, | ||
525 | enum iio_event_type type, | ||
526 | enum iio_event_direction dir) | ||
527 | { | ||
528 | struct mma9551_data *data = iio_priv(indio_dev); | ||
529 | |||
530 | switch (chan->type) { | ||
531 | case IIO_INCLI: | ||
532 | /* IIO counts axes from 1, because IIO_NO_MOD is 0. */ | ||
533 | return data->event_enabled[chan->channel2 - 1]; | ||
534 | default: | ||
535 | return -EINVAL; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | static int mma9551_config_incli_event(struct iio_dev *indio_dev, | ||
540 | enum iio_modifier axis, | ||
541 | int state) | ||
542 | { | ||
543 | struct mma9551_data *data = iio_priv(indio_dev); | ||
544 | enum mma9551_tilt_axis mma_axis; | ||
545 | int ret; | ||
546 | |||
547 | /* IIO counts axes from 1, because IIO_NO_MOD is 0. */ | ||
548 | mma_axis = axis - 1; | ||
549 | |||
550 | if (data->event_enabled[mma_axis] == state) | ||
551 | return 0; | ||
552 | |||
553 | if (state == 0) { | ||
554 | ret = mma9551_gpio_config(data->client, mma_axis, | ||
555 | MMA9551_APPID_NONE, 0, 0); | ||
556 | if (ret < 0) | ||
557 | return ret; | ||
558 | } else { | ||
559 | int bitnum; | ||
560 | |||
561 | /* Bit 7 of each angle register holds the angle flag. */ | ||
562 | switch (axis) { | ||
563 | case IIO_MOD_X: | ||
564 | bitnum = 7 + 8 * MMA9551_TILT_YZ_ANG_REG; | ||
565 | break; | ||
566 | case IIO_MOD_Y: | ||
567 | bitnum = 7 + 8 * MMA9551_TILT_XZ_ANG_REG; | ||
568 | break; | ||
569 | case IIO_MOD_Z: | ||
570 | bitnum = 7 + 8 * MMA9551_TILT_XY_ANG_REG; | ||
571 | break; | ||
572 | default: | ||
573 | return -EINVAL; | ||
574 | } | ||
575 | |||
576 | ret = mma9551_gpio_config(data->client, mma_axis, | ||
577 | MMA9551_APPID_TILT, bitnum, 0); | ||
578 | if (ret < 0) | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | data->event_enabled[mma_axis] = state; | ||
583 | |||
584 | return ret; | ||
585 | } | ||
586 | |||
587 | static int mma9551_write_event_config(struct iio_dev *indio_dev, | ||
588 | const struct iio_chan_spec *chan, | ||
589 | enum iio_event_type type, | ||
590 | enum iio_event_direction dir, | ||
591 | int state) | ||
592 | { | ||
593 | struct mma9551_data *data = iio_priv(indio_dev); | ||
594 | int ret; | ||
595 | |||
596 | switch (chan->type) { | ||
597 | case IIO_INCLI: | ||
598 | mutex_lock(&data->mutex); | ||
599 | ret = mma9551_config_incli_event(indio_dev, | ||
600 | chan->channel2, state); | ||
601 | mutex_unlock(&data->mutex); | ||
602 | return ret; | ||
603 | default: | ||
604 | return -EINVAL; | ||
605 | } | ||
606 | } | ||
607 | |||
608 | static int mma9551_write_event_value(struct iio_dev *indio_dev, | ||
609 | const struct iio_chan_spec *chan, | ||
610 | enum iio_event_type type, | ||
611 | enum iio_event_direction dir, | ||
612 | enum iio_event_info info, | ||
613 | int val, int val2) | ||
614 | { | ||
615 | struct mma9551_data *data = iio_priv(indio_dev); | ||
616 | int ret; | ||
617 | |||
618 | switch (chan->type) { | ||
619 | case IIO_INCLI: | ||
620 | if (val2 != 0 || val < 1 || val > 10) | ||
621 | return -EINVAL; | ||
622 | mutex_lock(&data->mutex); | ||
623 | ret = mma9551_update_config_bits(data->client, | ||
624 | MMA9551_APPID_TILT, | ||
625 | MMA9551_TILT_CFG_REG, | ||
626 | MMA9551_TILT_ANG_THRESH_MASK, | ||
627 | val); | ||
628 | mutex_unlock(&data->mutex); | ||
629 | return ret; | ||
630 | default: | ||
631 | return -EINVAL; | ||
632 | } | ||
633 | } | ||
634 | |||
635 | static int mma9551_read_event_value(struct iio_dev *indio_dev, | ||
636 | const struct iio_chan_spec *chan, | ||
637 | enum iio_event_type type, | ||
638 | enum iio_event_direction dir, | ||
639 | enum iio_event_info info, | ||
640 | int *val, int *val2) | ||
641 | { | ||
642 | struct mma9551_data *data = iio_priv(indio_dev); | ||
643 | int ret; | ||
644 | u8 tmp; | ||
645 | |||
646 | switch (chan->type) { | ||
647 | case IIO_INCLI: | ||
648 | mutex_lock(&data->mutex); | ||
649 | ret = mma9551_read_config_byte(data->client, | ||
650 | MMA9551_APPID_TILT, | ||
651 | MMA9551_TILT_CFG_REG, &tmp); | ||
652 | mutex_unlock(&data->mutex); | ||
653 | if (ret < 0) | ||
654 | return ret; | ||
655 | *val = tmp & MMA9551_TILT_ANG_THRESH_MASK; | ||
656 | *val2 = 0; | ||
657 | return IIO_VAL_INT; | ||
658 | default: | ||
659 | return -EINVAL; | ||
660 | } | ||
661 | } | ||
662 | |||
663 | static const struct iio_event_spec mma9551_incli_event = { | ||
664 | .type = IIO_EV_TYPE_ROC, | ||
665 | .dir = IIO_EV_DIR_RISING, | ||
666 | .mask_separate = BIT(IIO_EV_INFO_ENABLE), | ||
667 | .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE), | ||
668 | }; | ||
669 | |||
670 | #define MMA9551_ACCEL_CHANNEL(axis) { \ | ||
671 | .type = IIO_ACCEL, \ | ||
672 | .modified = 1, \ | ||
673 | .channel2 = axis, \ | ||
674 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
675 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
676 | } | ||
677 | |||
678 | #define MMA9551_INCLI_CHANNEL(axis) { \ | ||
679 | .type = IIO_INCLI, \ | ||
680 | .modified = 1, \ | ||
681 | .channel2 = axis, \ | ||
682 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ | ||
683 | .event_spec = &mma9551_incli_event, \ | ||
684 | .num_event_specs = 1, \ | ||
685 | } | ||
686 | |||
687 | static const struct iio_chan_spec mma9551_channels[] = { | ||
688 | MMA9551_ACCEL_CHANNEL(IIO_MOD_X), | ||
689 | MMA9551_ACCEL_CHANNEL(IIO_MOD_Y), | ||
690 | MMA9551_ACCEL_CHANNEL(IIO_MOD_Z), | ||
691 | |||
692 | MMA9551_INCLI_CHANNEL(IIO_MOD_X), | ||
693 | MMA9551_INCLI_CHANNEL(IIO_MOD_Y), | ||
694 | MMA9551_INCLI_CHANNEL(IIO_MOD_Z), | ||
695 | }; | ||
696 | |||
697 | static const struct iio_info mma9551_info = { | ||
698 | .driver_module = THIS_MODULE, | ||
699 | .read_raw = mma9551_read_raw, | ||
700 | .read_event_config = mma9551_read_event_config, | ||
701 | .write_event_config = mma9551_write_event_config, | ||
702 | .read_event_value = mma9551_read_event_value, | ||
703 | .write_event_value = mma9551_write_event_value, | ||
704 | }; | ||
705 | |||
706 | static irqreturn_t mma9551_event_handler(int irq, void *private) | ||
707 | { | ||
708 | struct iio_dev *indio_dev = private; | ||
709 | struct mma9551_data *data = iio_priv(indio_dev); | ||
710 | int i, ret, mma_axis = -1; | ||
711 | u16 reg; | ||
712 | u8 val; | ||
713 | |||
714 | mutex_lock(&data->mutex); | ||
715 | |||
716 | for (i = 0; i < 3; i++) | ||
717 | if (irq == data->irqs[i]) { | ||
718 | mma_axis = i; | ||
719 | break; | ||
720 | } | ||
721 | |||
722 | if (mma_axis == -1) { | ||
723 | /* IRQ was triggered on 4th line, which we don't use. */ | ||
724 | dev_warn(&data->client->dev, | ||
725 | "irq triggered on unused line %d\n", data->irqs[3]); | ||
726 | goto out; | ||
727 | } | ||
728 | |||
729 | switch (mma_axis) { | ||
730 | case mma9551_x: | ||
731 | reg = MMA9551_TILT_YZ_ANG_REG; | ||
732 | break; | ||
733 | case mma9551_y: | ||
734 | reg = MMA9551_TILT_XZ_ANG_REG; | ||
735 | break; | ||
736 | case mma9551_z: | ||
737 | reg = MMA9551_TILT_XY_ANG_REG; | ||
738 | break; | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * Read the angle even though we don't use it, otherwise we | ||
743 | * won't get any further interrupts. | ||
744 | */ | ||
745 | ret = mma9551_read_status_byte(data->client, MMA9551_APPID_TILT, | ||
746 | reg, &val); | ||
747 | if (ret < 0) { | ||
748 | dev_err(&data->client->dev, | ||
749 | "error %d reading tilt register in IRQ\n", ret); | ||
750 | goto out; | ||
751 | } | ||
752 | |||
753 | iio_push_event(indio_dev, | ||
754 | IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1), | ||
755 | IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING), | ||
756 | iio_get_time_ns()); | ||
757 | |||
758 | out: | ||
759 | mutex_unlock(&data->mutex); | ||
760 | |||
761 | return IRQ_HANDLED; | ||
762 | } | ||
763 | |||
764 | static int mma9551_init(struct mma9551_data *data) | ||
765 | { | ||
766 | int ret; | ||
767 | |||
768 | ret = mma9551_read_version(data->client); | ||
769 | if (ret) | ||
770 | return ret; | ||
771 | |||
772 | /* Power on chip and enable doze mode. */ | ||
773 | return mma9551_update_config_bits(data->client, | ||
774 | MMA9551_APPID_SLEEP_WAKE, | ||
775 | MMA9551_SLEEP_CFG, | ||
776 | MMA9551_SLEEP_CFG_SCHEN | MMA9551_SLEEP_CFG_SNCEN, | ||
777 | MMA9551_SLEEP_CFG_SCHEN); | ||
778 | } | ||
779 | |||
780 | static int mma9551_gpio_probe(struct iio_dev *indio_dev) | ||
781 | { | ||
782 | struct gpio_desc *gpio; | ||
783 | int i, ret; | ||
784 | struct mma9551_data *data = iio_priv(indio_dev); | ||
785 | struct device *dev = &data->client->dev; | ||
786 | |||
787 | for (i = 0; i < MMA9551_GPIO_COUNT; i++) { | ||
788 | gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i); | ||
789 | if (IS_ERR(gpio)) { | ||
790 | dev_err(dev, "acpi gpio get index failed\n"); | ||
791 | return PTR_ERR(gpio); | ||
792 | } | ||
793 | |||
794 | ret = gpiod_direction_input(gpio); | ||
795 | if (ret) | ||
796 | return ret; | ||
797 | |||
798 | data->irqs[i] = gpiod_to_irq(gpio); | ||
799 | ret = devm_request_threaded_irq(dev, data->irqs[i], | ||
800 | NULL, mma9551_event_handler, | ||
801 | IRQF_TRIGGER_RISING | IRQF_ONESHOT, | ||
802 | MMA9551_IRQ_NAME, indio_dev); | ||
803 | if (ret < 0) { | ||
804 | dev_err(dev, "request irq %d failed\n", data->irqs[i]); | ||
805 | return ret; | ||
806 | } | ||
807 | |||
808 | dev_dbg(dev, "gpio resource, no:%d irq:%d\n", | ||
809 | desc_to_gpio(gpio), data->irqs[i]); | ||
810 | } | ||
811 | |||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static const char *mma9551_match_acpi_device(struct device *dev) | ||
816 | { | ||
817 | const struct acpi_device_id *id; | ||
818 | |||
819 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
820 | if (!id) | ||
821 | return NULL; | ||
822 | |||
823 | return dev_name(dev); | ||
824 | } | ||
825 | |||
826 | static int mma9551_probe(struct i2c_client *client, | ||
827 | const struct i2c_device_id *id) | ||
828 | { | ||
829 | struct mma9551_data *data; | ||
830 | struct iio_dev *indio_dev; | ||
831 | const char *name = NULL; | ||
832 | int ret; | ||
833 | |||
834 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | ||
835 | if (!indio_dev) | ||
836 | return -ENOMEM; | ||
837 | |||
838 | data = iio_priv(indio_dev); | ||
839 | i2c_set_clientdata(client, indio_dev); | ||
840 | data->client = client; | ||
841 | |||
842 | if (id) | ||
843 | name = id->name; | ||
844 | else if (ACPI_HANDLE(&client->dev)) | ||
845 | name = mma9551_match_acpi_device(&client->dev); | ||
846 | |||
847 | ret = mma9551_init(data); | ||
848 | if (ret < 0) | ||
849 | return ret; | ||
850 | |||
851 | mutex_init(&data->mutex); | ||
852 | |||
853 | indio_dev->dev.parent = &client->dev; | ||
854 | indio_dev->channels = mma9551_channels; | ||
855 | indio_dev->num_channels = ARRAY_SIZE(mma9551_channels); | ||
856 | indio_dev->name = name; | ||
857 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
858 | indio_dev->info = &mma9551_info; | ||
859 | |||
860 | ret = mma9551_gpio_probe(indio_dev); | ||
861 | if (ret < 0) | ||
862 | goto out_poweroff; | ||
863 | |||
864 | ret = iio_device_register(indio_dev); | ||
865 | if (ret < 0) { | ||
866 | dev_err(&client->dev, "unable to register iio device\n"); | ||
867 | goto out_poweroff; | ||
868 | } | ||
869 | |||
870 | return 0; | ||
871 | |||
872 | out_poweroff: | ||
873 | mma9551_set_device_state(client, false); | ||
874 | |||
875 | return ret; | ||
876 | } | ||
877 | |||
878 | static int mma9551_remove(struct i2c_client *client) | ||
879 | { | ||
880 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
881 | struct mma9551_data *data = iio_priv(indio_dev); | ||
882 | |||
883 | iio_device_unregister(indio_dev); | ||
884 | mutex_lock(&data->mutex); | ||
885 | mma9551_set_device_state(data->client, false); | ||
886 | mutex_unlock(&data->mutex); | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | #ifdef CONFIG_PM_SLEEP | ||
892 | static int mma9551_suspend(struct device *dev) | ||
893 | { | ||
894 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | ||
895 | struct mma9551_data *data = iio_priv(indio_dev); | ||
896 | |||
897 | mutex_lock(&data->mutex); | ||
898 | mma9551_set_device_state(data->client, false); | ||
899 | mutex_unlock(&data->mutex); | ||
900 | |||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | static int mma9551_resume(struct device *dev) | ||
905 | { | ||
906 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | ||
907 | struct mma9551_data *data = iio_priv(indio_dev); | ||
908 | |||
909 | mutex_lock(&data->mutex); | ||
910 | mma9551_set_device_state(data->client, true); | ||
911 | mutex_unlock(&data->mutex); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | #else | ||
916 | #define mma9551_suspend NULL | ||
917 | #define mma9551_resume NULL | ||
918 | #endif | ||
919 | |||
920 | static const struct dev_pm_ops mma9551_pm_ops = { | ||
921 | SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume) | ||
922 | }; | ||
923 | |||
924 | static const struct acpi_device_id mma9551_acpi_match[] = { | ||
925 | {"MMA9551", 0}, | ||
926 | {}, | ||
927 | }; | ||
928 | |||
929 | MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match); | ||
930 | |||
931 | static const struct i2c_device_id mma9551_id[] = { | ||
932 | {"mma9551", 0}, | ||
933 | {} | ||
934 | }; | ||
935 | |||
936 | MODULE_DEVICE_TABLE(i2c, mma9551_id); | ||
937 | |||
938 | static struct i2c_driver mma9551_driver = { | ||
939 | .driver = { | ||
940 | .name = MMA9551_DRV_NAME, | ||
941 | .acpi_match_table = ACPI_PTR(mma9551_acpi_match), | ||
942 | .pm = &mma9551_pm_ops, | ||
943 | }, | ||
944 | .probe = mma9551_probe, | ||
945 | .remove = mma9551_remove, | ||
946 | .id_table = mma9551_id, | ||
947 | }; | ||
948 | |||
949 | module_i2c_driver(mma9551_driver); | ||
950 | |||
951 | MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); | ||
952 | MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); | ||
953 | MODULE_LICENSE("GPL v2"); | ||
954 | MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver"); | ||