Commit | Line | Data |
---|---|---|
40cb7613 IT |
1 | /* |
2 | * Freescale MMA9553L Intelligent Pedometer 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/gpio/consumer.h> | |
21 | #include <linux/iio/iio.h> | |
22 | #include <linux/iio/sysfs.h> | |
23 | #include <linux/iio/events.h> | |
24 | #include <linux/pm_runtime.h> | |
25 | #include "mma9551_core.h" | |
26 | ||
27 | #define MMA9553_DRV_NAME "mma9553" | |
28 | #define MMA9553_IRQ_NAME "mma9553_event" | |
29 | #define MMA9553_GPIO_NAME "mma9553_int" | |
30 | ||
31 | /* Pedometer configuration registers (R/W) */ | |
32 | #define MMA9553_REG_CONF_SLEEPMIN 0x00 | |
33 | #define MMA9553_REG_CONF_SLEEPMAX 0x02 | |
34 | #define MMA9553_REG_CONF_SLEEPTHD 0x04 | |
35 | #define MMA9553_MASK_CONF_WORD GENMASK(15, 0) | |
36 | ||
37 | #define MMA9553_REG_CONF_CONF_STEPLEN 0x06 | |
38 | #define MMA9553_MASK_CONF_CONFIG BIT(15) | |
39 | #define MMA9553_MASK_CONF_ACT_DBCNTM BIT(14) | |
40 | #define MMA9553_MASK_CONF_SLP_DBCNTM BIT(13) | |
41 | #define MMA9553_MASK_CONF_STEPLEN GENMASK(7, 0) | |
42 | ||
43 | #define MMA9553_REG_CONF_HEIGHT_WEIGHT 0x08 | |
44 | #define MMA9553_MASK_CONF_HEIGHT GENMASK(15, 8) | |
45 | #define MMA9553_MASK_CONF_WEIGHT GENMASK(7, 0) | |
46 | ||
47 | #define MMA9553_REG_CONF_FILTER 0x0A | |
48 | #define MMA9553_MASK_CONF_FILTSTEP GENMASK(15, 8) | |
49 | #define MMA9553_MASK_CONF_MALE BIT(7) | |
50 | #define MMA9553_MASK_CONF_FILTTIME GENMASK(6, 0) | |
51 | ||
52 | #define MMA9553_REG_CONF_SPEED_STEP 0x0C | |
53 | #define MMA9553_MASK_CONF_SPDPRD GENMASK(15, 8) | |
54 | #define MMA9553_MASK_CONF_STEPCOALESCE GENMASK(7, 0) | |
55 | ||
56 | #define MMA9553_REG_CONF_ACTTHD 0x0E | |
57 | ||
58 | /* Pedometer status registers (R-only) */ | |
59 | #define MMA9553_REG_STATUS 0x00 | |
60 | #define MMA9553_MASK_STATUS_MRGFL BIT(15) | |
61 | #define MMA9553_MASK_STATUS_SUSPCHG BIT(14) | |
62 | #define MMA9553_MASK_STATUS_STEPCHG BIT(13) | |
63 | #define MMA9553_MASK_STATUS_ACTCHG BIT(12) | |
64 | #define MMA9553_MASK_STATUS_SUSP BIT(11) | |
65 | #define MMA9553_MASK_STATUS_ACTIVITY (BIT(10) | BIT(9) | BIT(8)) | |
66 | #define MMA9553_MASK_STATUS_VERSION 0x00FF | |
67 | ||
68 | #define MMA9553_REG_STEPCNT 0x02 | |
69 | #define MMA9553_REG_DISTANCE 0x04 | |
70 | #define MMA9553_REG_SPEED 0x06 | |
71 | #define MMA9553_REG_CALORIES 0x08 | |
72 | #define MMA9553_REG_SLEEPCNT 0x0A | |
73 | ||
74 | /* Pedometer events are always mapped to this pin. */ | |
75 | #define MMA9553_DEFAULT_GPIO_PIN mma9551_gpio6 | |
76 | #define MMA9553_DEFAULT_GPIO_POLARITY 0 | |
77 | ||
78 | /* Bitnum used for gpio configuration = bit number in high status byte */ | |
79 | #define STATUS_TO_BITNUM(bit) (ffs(bit) - 9) | |
80 | ||
81 | #define MMA9553_DEFAULT_SAMPLE_RATE 30 /* Hz */ | |
82 | ||
83 | /* | |
84 | * The internal activity level must be stable for ACTTHD samples before | |
85 | * ACTIVITY is updated.The ACTIVITY variable contains the current activity | |
86 | * level and is updated every time a step is detected or once a second | |
87 | * if there are no steps. | |
88 | */ | |
89 | #define MMA9553_ACTIVITY_THD_TO_SEC(thd) ((thd) / MMA9553_DEFAULT_SAMPLE_RATE) | |
90 | #define MMA9553_ACTIVITY_SEC_TO_THD(sec) ((sec) * MMA9553_DEFAULT_SAMPLE_RATE) | |
91 | ||
92 | /* | |
93 | * Autonomously suspend pedometer if acceleration vector magnitude | |
94 | * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds. | |
95 | */ | |
96 | #define MMA9553_DEFAULT_SLEEPMIN 3688 /* 0,9 g */ | |
97 | #define MMA9553_DEFAULT_SLEEPMAX 4508 /* 1,1 g */ | |
98 | #define MMA9553_DEFAULT_SLEEPTHD (MMA9553_DEFAULT_SAMPLE_RATE * 30) | |
99 | ||
100 | #define MMA9553_CONFIG_RETRIES 2 | |
101 | ||
102 | /* Status register - activity field */ | |
103 | enum activity_level { | |
104 | ACTIVITY_UNKNOWN, | |
105 | ACTIVITY_REST, | |
106 | ACTIVITY_WALKING, | |
107 | ACTIVITY_JOGGING, | |
108 | ACTIVITY_RUNNING, | |
109 | }; | |
110 | ||
111 | static struct mma9553_event_info { | |
112 | enum iio_chan_type type; | |
113 | enum iio_modifier mod; | |
114 | enum iio_event_direction dir; | |
115 | } mma9553_events_info[] = { | |
116 | { | |
117 | .type = IIO_STEPS, | |
118 | .mod = IIO_NO_MOD, | |
119 | .dir = IIO_EV_DIR_NONE, | |
120 | }, | |
121 | { | |
122 | .type = IIO_ACTIVITY, | |
123 | .mod = IIO_MOD_STILL, | |
124 | .dir = IIO_EV_DIR_RISING, | |
125 | }, | |
126 | { | |
127 | .type = IIO_ACTIVITY, | |
128 | .mod = IIO_MOD_STILL, | |
129 | .dir = IIO_EV_DIR_FALLING, | |
130 | }, | |
131 | { | |
132 | .type = IIO_ACTIVITY, | |
133 | .mod = IIO_MOD_WALKING, | |
134 | .dir = IIO_EV_DIR_RISING, | |
135 | }, | |
136 | { | |
137 | .type = IIO_ACTIVITY, | |
138 | .mod = IIO_MOD_WALKING, | |
139 | .dir = IIO_EV_DIR_FALLING, | |
140 | }, | |
141 | { | |
142 | .type = IIO_ACTIVITY, | |
143 | .mod = IIO_MOD_JOGGING, | |
144 | .dir = IIO_EV_DIR_RISING, | |
145 | }, | |
146 | { | |
147 | .type = IIO_ACTIVITY, | |
148 | .mod = IIO_MOD_JOGGING, | |
149 | .dir = IIO_EV_DIR_FALLING, | |
150 | }, | |
151 | { | |
152 | .type = IIO_ACTIVITY, | |
153 | .mod = IIO_MOD_RUNNING, | |
154 | .dir = IIO_EV_DIR_RISING, | |
155 | }, | |
156 | { | |
157 | .type = IIO_ACTIVITY, | |
158 | .mod = IIO_MOD_RUNNING, | |
159 | .dir = IIO_EV_DIR_FALLING, | |
160 | }, | |
161 | }; | |
162 | ||
163 | #define MMA9553_EVENTS_INFO_SIZE ARRAY_SIZE(mma9553_events_info) | |
164 | ||
165 | struct mma9553_event { | |
166 | struct mma9553_event_info *info; | |
167 | bool enabled; | |
168 | }; | |
169 | ||
170 | struct mma9553_conf_regs { | |
171 | u16 sleepmin; | |
172 | u16 sleepmax; | |
173 | u16 sleepthd; | |
174 | u16 config; | |
175 | u16 height_weight; | |
176 | u16 filter; | |
177 | u16 speed_step; | |
178 | u16 actthd; | |
179 | } __packed; | |
180 | ||
181 | struct mma9553_data { | |
182 | struct i2c_client *client; | |
183 | struct mutex mutex; | |
184 | struct mma9553_conf_regs conf; | |
185 | struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE]; | |
186 | int num_events; | |
187 | u8 gpio_bitnum; | |
188 | /* | |
189 | * This is used for all features that depend on step count: | |
190 | * step count, distance, speed, calories. | |
191 | */ | |
192 | bool stepcnt_enabled; | |
193 | u16 stepcnt; | |
194 | u8 activity; | |
195 | s64 timestamp; | |
196 | }; | |
197 | ||
198 | static u8 mma9553_get_bits(u16 val, u16 mask) | |
199 | { | |
200 | return (val & mask) >> (ffs(mask) - 1); | |
201 | } | |
202 | ||
203 | static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask) | |
204 | { | |
205 | return (current_val & ~mask) | (val << (ffs(mask) - 1)); | |
206 | } | |
207 | ||
208 | static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity) | |
209 | { | |
210 | switch (activity) { | |
211 | case ACTIVITY_RUNNING: | |
212 | return IIO_MOD_RUNNING; | |
213 | case ACTIVITY_JOGGING: | |
214 | return IIO_MOD_JOGGING; | |
215 | case ACTIVITY_WALKING: | |
216 | return IIO_MOD_WALKING; | |
217 | case ACTIVITY_REST: | |
218 | return IIO_MOD_STILL; | |
219 | case ACTIVITY_UNKNOWN: | |
220 | default: | |
221 | return IIO_NO_MOD; | |
222 | } | |
223 | } | |
224 | ||
225 | static void mma9553_init_events(struct mma9553_data *data) | |
226 | { | |
227 | int i; | |
228 | ||
229 | data->num_events = MMA9553_EVENTS_INFO_SIZE; | |
230 | for (i = 0; i < data->num_events; i++) { | |
231 | data->events[i].info = &mma9553_events_info[i]; | |
232 | data->events[i].enabled = false; | |
233 | } | |
234 | } | |
235 | ||
236 | static struct mma9553_event *mma9553_get_event(struct mma9553_data *data, | |
237 | enum iio_chan_type type, | |
238 | enum iio_modifier mod, | |
239 | enum iio_event_direction dir) | |
240 | { | |
241 | int i; | |
242 | ||
243 | for (i = 0; i < data->num_events; i++) | |
244 | if (data->events[i].info->type == type && | |
245 | data->events[i].info->mod == mod && | |
246 | data->events[i].info->dir == dir) | |
247 | return &data->events[i]; | |
248 | ||
249 | return NULL; | |
250 | } | |
251 | ||
252 | static bool mma9553_is_any_event_enabled(struct mma9553_data *data, | |
253 | bool check_type, | |
254 | enum iio_chan_type type) | |
255 | { | |
256 | int i; | |
257 | ||
258 | for (i = 0; i < data->num_events; i++) | |
259 | if ((check_type && data->events[i].info->type == type && | |
260 | data->events[i].enabled) || | |
261 | (!check_type && data->events[i].enabled)) | |
262 | return true; | |
263 | ||
264 | return false; | |
265 | } | |
266 | ||
267 | static int mma9553_set_config(struct mma9553_data *data, u16 reg, | |
268 | u16 *p_reg_val, u16 val, u16 mask) | |
269 | { | |
270 | int ret, retries; | |
271 | u16 reg_val, config; | |
272 | ||
273 | reg_val = *p_reg_val; | |
274 | if (val == mma9553_get_bits(reg_val, mask)) | |
275 | return 0; | |
276 | ||
277 | reg_val = mma9553_set_bits(reg_val, val, mask); | |
278 | ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER, | |
279 | reg, reg_val); | |
280 | if (ret < 0) { | |
281 | dev_err(&data->client->dev, | |
282 | "error writing config register 0x%x\n", reg); | |
283 | return ret; | |
284 | } | |
285 | ||
286 | *p_reg_val = reg_val; | |
287 | ||
288 | /* Reinitializes the pedometer with current configuration values */ | |
289 | config = mma9553_set_bits(data->conf.config, 1, | |
290 | MMA9553_MASK_CONF_CONFIG); | |
291 | ||
292 | ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER, | |
293 | MMA9553_REG_CONF_CONF_STEPLEN, config); | |
294 | if (ret < 0) { | |
295 | dev_err(&data->client->dev, | |
296 | "error writing config register 0x%x\n", | |
297 | MMA9553_REG_CONF_CONF_STEPLEN); | |
298 | return ret; | |
299 | } | |
300 | ||
301 | retries = MMA9553_CONFIG_RETRIES; | |
302 | do { | |
303 | mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE); | |
304 | ret = mma9551_read_config_word(data->client, | |
305 | MMA9551_APPID_PEDOMETER, | |
306 | MMA9553_REG_CONF_CONF_STEPLEN, | |
307 | &config); | |
308 | if (ret < 0) | |
309 | return ret; | |
310 | } while (mma9553_get_bits(config, MMA9553_MASK_CONF_CONFIG) && | |
311 | --retries > 0); | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
316 | static int mma9553_read_activity_stepcnt(struct mma9553_data *data, | |
317 | u8 *activity, u16 *stepcnt) | |
318 | { | |
319 | u32 status_stepcnt; | |
320 | u16 status; | |
321 | int ret; | |
322 | ||
323 | ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER, | |
324 | MMA9553_REG_STATUS, sizeof(u32), | |
325 | (u16 *) &status_stepcnt); | |
326 | if (ret < 0) { | |
327 | dev_err(&data->client->dev, | |
328 | "error reading status and stepcnt\n"); | |
329 | return ret; | |
330 | } | |
331 | ||
332 | status = status_stepcnt & MMA9553_MASK_CONF_WORD; | |
333 | *activity = mma9553_get_bits(status, MMA9553_MASK_STATUS_ACTIVITY); | |
334 | *stepcnt = status_stepcnt >> 16; | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
339 | static int mma9553_conf_gpio(struct mma9553_data *data) | |
340 | { | |
341 | u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER; | |
342 | int ret; | |
343 | struct mma9553_event *ev_step_detect; | |
344 | bool activity_enabled; | |
345 | ||
346 | activity_enabled = | |
347 | mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY); | |
348 | ev_step_detect = | |
349 | mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE); | |
350 | ||
351 | /* | |
352 | * If both step detector and activity are enabled, use the MRGFL bit. | |
353 | * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags. | |
354 | */ | |
355 | if (activity_enabled && ev_step_detect->enabled) | |
356 | bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_MRGFL); | |
357 | else if (ev_step_detect->enabled) | |
358 | bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_STEPCHG); | |
359 | else if (activity_enabled) | |
360 | bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_ACTCHG); | |
361 | else /* Reset */ | |
362 | appid = MMA9551_APPID_NONE; | |
363 | ||
364 | if (data->gpio_bitnum == bitnum) | |
365 | return 0; | |
366 | ||
367 | /* Save initial values for activity and stepcnt */ | |
368 | if (activity_enabled || ev_step_detect->enabled) | |
369 | mma9553_read_activity_stepcnt(data, &data->activity, | |
370 | &data->stepcnt); | |
371 | ||
372 | ret = mma9551_gpio_config(data->client, | |
373 | MMA9553_DEFAULT_GPIO_PIN, | |
374 | appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY); | |
375 | if (ret < 0) | |
376 | return ret; | |
377 | data->gpio_bitnum = bitnum; | |
378 | ||
379 | return 0; | |
380 | } | |
381 | ||
382 | static int mma9553_init(struct mma9553_data *data) | |
383 | { | |
384 | int ret; | |
385 | ||
386 | ret = mma9551_read_version(data->client); | |
387 | if (ret) | |
388 | return ret; | |
389 | ||
390 | /* | |
391 | * Read all the pedometer configuration registers. This is used as | |
392 | * a device identification command to differentiate the MMA9553L | |
393 | * from the MMA9550L. | |
394 | */ | |
395 | ret = | |
396 | mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER, | |
397 | MMA9553_REG_CONF_SLEEPMIN, | |
398 | sizeof(data->conf), (u16 *) &data->conf); | |
399 | if (ret < 0) { | |
400 | dev_err(&data->client->dev, | |
401 | "device is not MMA9553L: failed to read cfg regs\n"); | |
402 | return ret; | |
403 | } | |
404 | ||
405 | ||
406 | /* Reset gpio */ | |
407 | data->gpio_bitnum = -1; | |
408 | ret = mma9553_conf_gpio(data); | |
409 | if (ret < 0) | |
410 | return ret; | |
411 | ||
412 | ret = mma9551_app_reset(data->client, MMA9551_RSC_PED); | |
413 | if (ret < 0) | |
414 | return ret; | |
415 | ||
416 | /* Init config registers */ | |
417 | data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN; | |
418 | data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX; | |
419 | data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD; | |
420 | data->conf.config = | |
421 | mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG); | |
422 | /* | |
423 | * Clear the activity debounce counter when the activity level changes, | |
424 | * so that the confidence level applies for any activity level. | |
425 | */ | |
426 | data->conf.config = mma9553_set_bits(data->conf.config, 1, | |
427 | MMA9553_MASK_CONF_ACT_DBCNTM); | |
428 | ret = | |
429 | mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER, | |
430 | MMA9553_REG_CONF_SLEEPMIN, | |
431 | sizeof(data->conf), (u16 *) &data->conf); | |
432 | if (ret < 0) { | |
433 | dev_err(&data->client->dev, | |
434 | "failed to write configuration registers\n"); | |
435 | return ret; | |
436 | } | |
437 | ||
438 | return mma9551_set_device_state(data->client, true); | |
439 | } | |
440 | ||
441 | static int mma9553_read_raw(struct iio_dev *indio_dev, | |
442 | struct iio_chan_spec const *chan, | |
443 | int *val, int *val2, long mask) | |
444 | { | |
445 | struct mma9553_data *data = iio_priv(indio_dev); | |
446 | int ret; | |
447 | u16 tmp; | |
448 | u8 activity; | |
449 | bool powered_on; | |
450 | ||
451 | switch (mask) { | |
452 | case IIO_CHAN_INFO_PROCESSED: | |
453 | switch (chan->type) { | |
454 | case IIO_STEPS: | |
455 | /* | |
456 | * The HW only counts steps and other dependent | |
457 | * parameters (speed, distance, calories, activity) | |
458 | * if power is on (from enabling an event or the | |
459 | * step counter */ | |
460 | powered_on = | |
461 | mma9553_is_any_event_enabled(data, false, 0) || | |
462 | data->stepcnt_enabled; | |
463 | if (!powered_on) { | |
464 | dev_err(&data->client->dev, | |
465 | "No channels enabled\n"); | |
466 | return -EINVAL; | |
467 | } | |
468 | mutex_lock(&data->mutex); | |
469 | ret = mma9551_read_status_word(data->client, | |
470 | MMA9551_APPID_PEDOMETER, | |
471 | MMA9553_REG_STEPCNT, | |
472 | &tmp); | |
473 | mutex_unlock(&data->mutex); | |
474 | if (ret < 0) | |
475 | return ret; | |
476 | *val = tmp; | |
477 | return IIO_VAL_INT; | |
478 | case IIO_DISTANCE: | |
479 | powered_on = | |
480 | mma9553_is_any_event_enabled(data, false, 0) || | |
481 | data->stepcnt_enabled; | |
482 | if (!powered_on) { | |
483 | dev_err(&data->client->dev, | |
484 | "No channels enabled\n"); | |
485 | return -EINVAL; | |
486 | } | |
487 | mutex_lock(&data->mutex); | |
488 | ret = mma9551_read_status_word(data->client, | |
489 | MMA9551_APPID_PEDOMETER, | |
490 | MMA9553_REG_DISTANCE, | |
491 | &tmp); | |
492 | mutex_unlock(&data->mutex); | |
493 | if (ret < 0) | |
494 | return ret; | |
495 | *val = tmp; | |
496 | return IIO_VAL_INT; | |
497 | case IIO_ACTIVITY: | |
498 | powered_on = | |
499 | mma9553_is_any_event_enabled(data, false, 0) || | |
500 | data->stepcnt_enabled; | |
501 | if (!powered_on) { | |
502 | dev_err(&data->client->dev, | |
503 | "No channels enabled\n"); | |
504 | return -EINVAL; | |
505 | } | |
506 | mutex_lock(&data->mutex); | |
507 | ret = mma9551_read_status_word(data->client, | |
508 | MMA9551_APPID_PEDOMETER, | |
509 | MMA9553_REG_STATUS, | |
510 | &tmp); | |
511 | mutex_unlock(&data->mutex); | |
512 | if (ret < 0) | |
513 | return ret; | |
514 | ||
515 | activity = | |
516 | mma9553_get_bits(tmp, MMA9553_MASK_STATUS_ACTIVITY); | |
517 | ||
518 | /* | |
519 | * The device does not support confidence value levels, | |
520 | * so we will always have 100% for current activity and | |
521 | * 0% for the others. | |
522 | */ | |
523 | if (chan->channel2 == mma9553_activity_to_mod(activity)) | |
524 | *val = 100; | |
525 | else | |
526 | *val = 0; | |
527 | return IIO_VAL_INT; | |
528 | default: | |
529 | return -EINVAL; | |
530 | } | |
531 | case IIO_CHAN_INFO_RAW: | |
532 | switch (chan->type) { | |
533 | case IIO_VELOCITY: /* m/h */ | |
534 | if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z) | |
535 | return -EINVAL; | |
536 | powered_on = | |
537 | mma9553_is_any_event_enabled(data, false, 0) || | |
538 | data->stepcnt_enabled; | |
539 | if (!powered_on) { | |
540 | dev_err(&data->client->dev, | |
541 | "No channels enabled\n"); | |
542 | return -EINVAL; | |
543 | } | |
544 | mutex_lock(&data->mutex); | |
545 | ret = mma9551_read_status_word(data->client, | |
546 | MMA9551_APPID_PEDOMETER, | |
547 | MMA9553_REG_SPEED, &tmp); | |
548 | mutex_unlock(&data->mutex); | |
549 | if (ret < 0) | |
550 | return ret; | |
551 | *val = tmp; | |
552 | return IIO_VAL_INT; | |
553 | case IIO_ENERGY: /* Cal or kcal */ | |
554 | powered_on = | |
555 | mma9553_is_any_event_enabled(data, false, 0) || | |
556 | data->stepcnt_enabled; | |
557 | if (!powered_on) { | |
558 | dev_err(&data->client->dev, | |
559 | "No channels enabled\n"); | |
560 | return -EINVAL; | |
561 | } | |
562 | mutex_lock(&data->mutex); | |
563 | ret = mma9551_read_status_word(data->client, | |
564 | MMA9551_APPID_PEDOMETER, | |
565 | MMA9553_REG_CALORIES, | |
566 | &tmp); | |
567 | mutex_unlock(&data->mutex); | |
568 | if (ret < 0) | |
569 | return ret; | |
570 | *val = tmp; | |
571 | return IIO_VAL_INT; | |
572 | case IIO_ACCEL: | |
573 | mutex_lock(&data->mutex); | |
574 | ret = mma9551_read_accel_chan(data->client, | |
575 | chan, val, val2); | |
576 | mutex_unlock(&data->mutex); | |
577 | return ret; | |
578 | default: | |
579 | return -EINVAL; | |
580 | } | |
581 | case IIO_CHAN_INFO_SCALE: | |
582 | switch (chan->type) { | |
583 | case IIO_VELOCITY: /* m/h to m/s */ | |
584 | if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z) | |
585 | return -EINVAL; | |
586 | *val = 0; | |
587 | *val2 = 277; /* 0.000277 */ | |
588 | return IIO_VAL_INT_PLUS_MICRO; | |
589 | case IIO_ENERGY: /* Cal or kcal to J */ | |
590 | *val = 4184; | |
591 | return IIO_VAL_INT; | |
592 | case IIO_ACCEL: | |
593 | return mma9551_read_accel_scale(val, val2); | |
594 | default: | |
595 | return -EINVAL; | |
596 | } | |
597 | case IIO_CHAN_INFO_ENABLE: | |
598 | *val = data->stepcnt_enabled; | |
599 | return IIO_VAL_INT; | |
600 | case IIO_CHAN_INFO_CALIBHEIGHT: | |
601 | tmp = mma9553_get_bits(data->conf.height_weight, | |
602 | MMA9553_MASK_CONF_HEIGHT); | |
603 | *val = tmp / 100; /* cm to m */ | |
604 | *val2 = (tmp % 100) * 10000; | |
605 | return IIO_VAL_INT_PLUS_MICRO; | |
606 | case IIO_CHAN_INFO_CALIBWEIGHT: | |
607 | *val = mma9553_get_bits(data->conf.height_weight, | |
608 | MMA9553_MASK_CONF_WEIGHT); | |
609 | return IIO_VAL_INT; | |
610 | case IIO_CHAN_INFO_DEBOUNCE_COUNT: | |
611 | switch (chan->type) { | |
612 | case IIO_STEPS: | |
613 | *val = mma9553_get_bits(data->conf.filter, | |
614 | MMA9553_MASK_CONF_FILTSTEP); | |
615 | return IIO_VAL_INT; | |
616 | default: | |
617 | return -EINVAL; | |
618 | } | |
619 | case IIO_CHAN_INFO_DEBOUNCE_TIME: | |
620 | switch (chan->type) { | |
621 | case IIO_STEPS: | |
622 | *val = mma9553_get_bits(data->conf.filter, | |
623 | MMA9553_MASK_CONF_FILTTIME); | |
624 | return IIO_VAL_INT; | |
625 | default: | |
626 | return -EINVAL; | |
627 | } | |
628 | case IIO_CHAN_INFO_INT_TIME: | |
629 | switch (chan->type) { | |
630 | case IIO_VELOCITY: | |
631 | if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z) | |
632 | return -EINVAL; | |
633 | *val = mma9553_get_bits(data->conf.speed_step, | |
634 | MMA9553_MASK_CONF_SPDPRD); | |
635 | return IIO_VAL_INT; | |
636 | default: | |
637 | return -EINVAL; | |
638 | } | |
639 | default: | |
640 | return -EINVAL; | |
641 | } | |
642 | } | |
643 | ||
644 | static int mma9553_write_raw(struct iio_dev *indio_dev, | |
645 | struct iio_chan_spec const *chan, | |
646 | int val, int val2, long mask) | |
647 | { | |
648 | struct mma9553_data *data = iio_priv(indio_dev); | |
649 | int ret, tmp; | |
650 | ||
651 | switch (mask) { | |
652 | case IIO_CHAN_INFO_ENABLE: | |
653 | if (data->stepcnt_enabled == !!val) | |
654 | return 0; | |
655 | mutex_lock(&data->mutex); | |
656 | ret = mma9551_set_power_state(data->client, val); | |
657 | if (ret < 0) { | |
658 | mutex_unlock(&data->mutex); | |
659 | return ret; | |
660 | } | |
661 | data->stepcnt_enabled = val; | |
662 | mutex_unlock(&data->mutex); | |
663 | return 0; | |
664 | case IIO_CHAN_INFO_CALIBHEIGHT: | |
665 | /* m to cm */ | |
666 | tmp = val * 100 + val2 / 10000; | |
667 | if (tmp < 0 || tmp > 255) | |
668 | return -EINVAL; | |
669 | mutex_lock(&data->mutex); | |
670 | ret = mma9553_set_config(data, | |
671 | MMA9553_REG_CONF_HEIGHT_WEIGHT, | |
672 | &data->conf.height_weight, | |
673 | tmp, MMA9553_MASK_CONF_HEIGHT); | |
674 | mutex_unlock(&data->mutex); | |
675 | return ret; | |
676 | case IIO_CHAN_INFO_CALIBWEIGHT: | |
677 | if (val < 0 || val > 255) | |
678 | return -EINVAL; | |
679 | mutex_lock(&data->mutex); | |
680 | ret = mma9553_set_config(data, | |
681 | MMA9553_REG_CONF_HEIGHT_WEIGHT, | |
682 | &data->conf.height_weight, | |
683 | val, MMA9553_MASK_CONF_WEIGHT); | |
684 | mutex_unlock(&data->mutex); | |
685 | return ret; | |
686 | case IIO_CHAN_INFO_DEBOUNCE_COUNT: | |
687 | switch (chan->type) { | |
688 | case IIO_STEPS: | |
689 | /* | |
690 | * Set to 0 to disable step filtering. If the value | |
691 | * specified is greater than 6, then 6 will be used. | |
692 | */ | |
693 | if (val < 0) | |
694 | return -EINVAL; | |
695 | if (val > 6) | |
696 | val = 6; | |
697 | mutex_lock(&data->mutex); | |
698 | ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER, | |
699 | &data->conf.filter, val, | |
700 | MMA9553_MASK_CONF_FILTSTEP); | |
701 | mutex_unlock(&data->mutex); | |
702 | return ret; | |
703 | default: | |
704 | return -EINVAL; | |
705 | } | |
706 | case IIO_CHAN_INFO_DEBOUNCE_TIME: | |
707 | switch (chan->type) { | |
708 | case IIO_STEPS: | |
709 | if (val < 0 || val > 127) | |
710 | return -EINVAL; | |
711 | mutex_lock(&data->mutex); | |
712 | ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER, | |
713 | &data->conf.filter, val, | |
714 | MMA9553_MASK_CONF_FILTTIME); | |
715 | mutex_unlock(&data->mutex); | |
716 | return ret; | |
717 | default: | |
718 | return -EINVAL; | |
719 | } | |
720 | case IIO_CHAN_INFO_INT_TIME: | |
721 | switch (chan->type) { | |
722 | case IIO_VELOCITY: | |
723 | if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z) | |
724 | return -EINVAL; | |
725 | /* | |
726 | * If set to a value greater than 5, then 5 will be | |
727 | * used. Warning: Do not set SPDPRD to 0 or 1 as | |
728 | * this may cause undesirable behavior. | |
729 | */ | |
730 | if (val < 2) | |
731 | return -EINVAL; | |
732 | if (val > 5) | |
733 | val = 5; | |
734 | mutex_lock(&data->mutex); | |
735 | ret = mma9553_set_config(data, | |
736 | MMA9553_REG_CONF_SPEED_STEP, | |
737 | &data->conf.speed_step, val, | |
738 | MMA9553_MASK_CONF_SPDPRD); | |
739 | mutex_unlock(&data->mutex); | |
740 | return ret; | |
741 | default: | |
742 | return -EINVAL; | |
743 | } | |
744 | default: | |
745 | return -EINVAL; | |
746 | } | |
747 | } | |
748 | ||
749 | static int mma9553_read_event_config(struct iio_dev *indio_dev, | |
750 | const struct iio_chan_spec *chan, | |
751 | enum iio_event_type type, | |
752 | enum iio_event_direction dir) | |
753 | { | |
754 | ||
755 | struct mma9553_data *data = iio_priv(indio_dev); | |
756 | struct mma9553_event *event; | |
757 | ||
758 | event = mma9553_get_event(data, chan->type, chan->channel2, dir); | |
759 | if (!event) | |
760 | return -EINVAL; | |
761 | ||
762 | return event->enabled; | |
763 | } | |
764 | ||
765 | static int mma9553_write_event_config(struct iio_dev *indio_dev, | |
766 | const struct iio_chan_spec *chan, | |
767 | enum iio_event_type type, | |
768 | enum iio_event_direction dir, int state) | |
769 | { | |
770 | struct mma9553_data *data = iio_priv(indio_dev); | |
771 | struct mma9553_event *event; | |
772 | int ret; | |
773 | ||
774 | event = mma9553_get_event(data, chan->type, chan->channel2, dir); | |
775 | if (!event) | |
776 | return -EINVAL; | |
777 | ||
778 | if (event->enabled == state) | |
779 | return 0; | |
780 | ||
781 | mutex_lock(&data->mutex); | |
782 | ||
783 | ret = mma9551_set_power_state(data->client, state); | |
784 | if (ret < 0) | |
785 | goto err_out; | |
786 | event->enabled = state; | |
787 | ||
788 | ret = mma9553_conf_gpio(data); | |
789 | if (ret < 0) | |
790 | goto err_conf_gpio; | |
791 | ||
792 | mutex_unlock(&data->mutex); | |
793 | ||
794 | return ret; | |
795 | ||
796 | err_conf_gpio: | |
797 | if (state) { | |
798 | event->enabled = false; | |
799 | mma9551_set_power_state(data->client, false); | |
800 | } | |
801 | err_out: | |
802 | mutex_unlock(&data->mutex); | |
803 | return ret; | |
804 | } | |
805 | ||
806 | static int mma9553_read_event_value(struct iio_dev *indio_dev, | |
807 | const struct iio_chan_spec *chan, | |
808 | enum iio_event_type type, | |
809 | enum iio_event_direction dir, | |
810 | enum iio_event_info info, | |
811 | int *val, int *val2) | |
812 | { | |
813 | struct mma9553_data *data = iio_priv(indio_dev); | |
814 | ||
815 | *val2 = 0; | |
816 | switch (info) { | |
817 | case IIO_EV_INFO_VALUE: | |
818 | switch (chan->type) { | |
819 | case IIO_STEPS: | |
820 | *val = mma9553_get_bits(data->conf.speed_step, | |
821 | MMA9553_MASK_CONF_STEPCOALESCE); | |
822 | return IIO_VAL_INT; | |
823 | case IIO_ACTIVITY: | |
824 | /* | |
825 | * The device does not support confidence value levels. | |
826 | * We set an average of 50%. | |
827 | */ | |
828 | *val = 50; | |
829 | return IIO_VAL_INT; | |
830 | default: | |
831 | return -EINVAL; | |
832 | } | |
833 | case IIO_EV_INFO_PERIOD: | |
834 | switch (chan->type) { | |
835 | case IIO_ACTIVITY: | |
836 | *val = MMA9553_ACTIVITY_THD_TO_SEC(data->conf.actthd); | |
837 | return IIO_VAL_INT; | |
838 | default: | |
839 | return -EINVAL; | |
840 | } | |
841 | default: | |
842 | return -EINVAL; | |
843 | } | |
844 | } | |
845 | ||
846 | static int mma9553_write_event_value(struct iio_dev *indio_dev, | |
847 | const struct iio_chan_spec *chan, | |
848 | enum iio_event_type type, | |
849 | enum iio_event_direction dir, | |
850 | enum iio_event_info info, | |
851 | int val, int val2) | |
852 | { | |
853 | struct mma9553_data *data = iio_priv(indio_dev); | |
854 | int ret; | |
855 | ||
856 | switch (info) { | |
857 | case IIO_EV_INFO_VALUE: | |
858 | switch (chan->type) { | |
859 | case IIO_STEPS: | |
860 | if (val < 0 || val > 255) | |
861 | return -EINVAL; | |
862 | mutex_lock(&data->mutex); | |
863 | ret = mma9553_set_config(data, | |
864 | MMA9553_REG_CONF_SPEED_STEP, | |
865 | &data->conf.speed_step, val, | |
866 | MMA9553_MASK_CONF_STEPCOALESCE); | |
867 | mutex_unlock(&data->mutex); | |
868 | return ret; | |
869 | default: | |
870 | return -EINVAL; | |
871 | } | |
872 | case IIO_EV_INFO_PERIOD: | |
873 | switch (chan->type) { | |
874 | case IIO_ACTIVITY: | |
875 | mutex_lock(&data->mutex); | |
876 | ret = mma9553_set_config(data, MMA9553_REG_CONF_ACTTHD, | |
877 | &data->conf.actthd, | |
878 | MMA9553_ACTIVITY_SEC_TO_THD | |
879 | (val), MMA9553_MASK_CONF_WORD); | |
880 | mutex_unlock(&data->mutex); | |
881 | return ret; | |
882 | default: | |
883 | return -EINVAL; | |
884 | } | |
885 | default: | |
886 | return -EINVAL; | |
887 | } | |
888 | } | |
889 | ||
890 | static int mma9553_get_calibgender_mode(struct iio_dev *indio_dev, | |
891 | const struct iio_chan_spec *chan) | |
892 | { | |
893 | struct mma9553_data *data = iio_priv(indio_dev); | |
894 | u8 gender; | |
895 | ||
896 | gender = mma9553_get_bits(data->conf.filter, MMA9553_MASK_CONF_MALE); | |
897 | /* | |
898 | * HW expects 0 for female and 1 for male, | |
899 | * while iio index is 0 for male and 1 for female | |
900 | */ | |
901 | return !gender; | |
902 | } | |
903 | ||
904 | static int mma9553_set_calibgender_mode(struct iio_dev *indio_dev, | |
905 | const struct iio_chan_spec *chan, | |
906 | unsigned int mode) | |
907 | { | |
908 | struct mma9553_data *data = iio_priv(indio_dev); | |
909 | u8 gender = !mode; | |
910 | int ret; | |
911 | ||
912 | if ((mode != 0) && (mode != 1)) | |
913 | return -EINVAL; | |
914 | mutex_lock(&data->mutex); | |
915 | ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER, | |
916 | &data->conf.filter, gender, | |
917 | MMA9553_MASK_CONF_MALE); | |
918 | mutex_unlock(&data->mutex); | |
919 | ||
920 | return ret; | |
921 | } | |
922 | ||
923 | static const struct iio_event_spec mma9553_step_event = { | |
924 | .type = IIO_EV_TYPE_CHANGE, | |
925 | .dir = IIO_EV_DIR_NONE, | |
926 | .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE), | |
927 | }; | |
928 | ||
929 | static const struct iio_event_spec mma9553_activity_events[] = { | |
930 | { | |
931 | .type = IIO_EV_TYPE_THRESH, | |
932 | .dir = IIO_EV_DIR_RISING, | |
933 | .mask_separate = BIT(IIO_EV_INFO_ENABLE) | | |
934 | BIT(IIO_EV_INFO_VALUE) | | |
935 | BIT(IIO_EV_INFO_PERIOD), | |
936 | }, | |
937 | { | |
938 | .type = IIO_EV_TYPE_THRESH, | |
939 | .dir = IIO_EV_DIR_FALLING, | |
940 | .mask_separate = BIT(IIO_EV_INFO_ENABLE) | | |
941 | BIT(IIO_EV_INFO_VALUE) | | |
942 | BIT(IIO_EV_INFO_PERIOD), | |
943 | }, | |
944 | }; | |
945 | ||
946 | static const char * const calibgender_modes[] = { "male", "female" }; | |
947 | ||
948 | static const struct iio_enum mma9553_calibgender_enum = { | |
949 | .items = calibgender_modes, | |
950 | .num_items = ARRAY_SIZE(calibgender_modes), | |
951 | .get = mma9553_get_calibgender_mode, | |
952 | .set = mma9553_set_calibgender_mode, | |
953 | }; | |
954 | ||
955 | static const struct iio_chan_spec_ext_info mma9553_ext_info[] = { | |
956 | IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum), | |
957 | IIO_ENUM_AVAILABLE("calibgender", &mma9553_calibgender_enum), | |
958 | {}, | |
959 | }; | |
960 | ||
961 | #define MMA9553_PEDOMETER_CHANNEL(_type, _mask) { \ | |
962 | .type = _type, \ | |
963 | .info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE) | \ | |
964 | BIT(IIO_CHAN_INFO_CALIBHEIGHT) | \ | |
965 | _mask, \ | |
966 | .ext_info = mma9553_ext_info, \ | |
967 | } | |
968 | ||
969 | #define MMA9553_ACTIVITY_CHANNEL(_chan2) { \ | |
970 | .type = IIO_ACTIVITY, \ | |
971 | .modified = 1, \ | |
972 | .channel2 = _chan2, \ | |
973 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \ | |
974 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT), \ | |
975 | .event_spec = mma9553_activity_events, \ | |
976 | .num_event_specs = ARRAY_SIZE(mma9553_activity_events), \ | |
977 | .ext_info = mma9553_ext_info, \ | |
978 | } | |
979 | ||
980 | static const struct iio_chan_spec mma9553_channels[] = { | |
981 | MMA9551_ACCEL_CHANNEL(IIO_MOD_X), | |
982 | MMA9551_ACCEL_CHANNEL(IIO_MOD_Y), | |
983 | MMA9551_ACCEL_CHANNEL(IIO_MOD_Z), | |
984 | ||
985 | { | |
986 | .type = IIO_STEPS, | |
987 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | | |
988 | BIT(IIO_CHAN_INFO_ENABLE) | | |
989 | BIT(IIO_CHAN_INFO_DEBOUNCE_COUNT) | | |
990 | BIT(IIO_CHAN_INFO_DEBOUNCE_TIME), | |
991 | .event_spec = &mma9553_step_event, | |
992 | .num_event_specs = 1, | |
993 | }, | |
994 | ||
995 | MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)), | |
996 | { | |
997 | .type = IIO_VELOCITY, | |
998 | .modified = 1, | |
999 | .channel2 = IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z, | |
1000 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
1001 | BIT(IIO_CHAN_INFO_SCALE) | | |
1002 | BIT(IIO_CHAN_INFO_INT_TIME) | | |
1003 | BIT(IIO_CHAN_INFO_ENABLE), | |
1004 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT), | |
1005 | .ext_info = mma9553_ext_info, | |
1006 | }, | |
1007 | MMA9553_PEDOMETER_CHANNEL(IIO_ENERGY, BIT(IIO_CHAN_INFO_RAW) | | |
1008 | BIT(IIO_CHAN_INFO_SCALE) | | |
1009 | BIT(IIO_CHAN_INFO_CALIBWEIGHT)), | |
1010 | ||
1011 | MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING), | |
1012 | MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING), | |
1013 | MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING), | |
1014 | MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL), | |
1015 | }; | |
1016 | ||
1017 | static const struct iio_info mma9553_info = { | |
1018 | .driver_module = THIS_MODULE, | |
1019 | .read_raw = mma9553_read_raw, | |
1020 | .write_raw = mma9553_write_raw, | |
1021 | .read_event_config = mma9553_read_event_config, | |
1022 | .write_event_config = mma9553_write_event_config, | |
1023 | .read_event_value = mma9553_read_event_value, | |
1024 | .write_event_value = mma9553_write_event_value, | |
1025 | }; | |
1026 | ||
1027 | static irqreturn_t mma9553_irq_handler(int irq, void *private) | |
1028 | { | |
1029 | struct iio_dev *indio_dev = private; | |
1030 | struct mma9553_data *data = iio_priv(indio_dev); | |
1031 | ||
1032 | data->timestamp = iio_get_time_ns(); | |
1033 | /* | |
1034 | * Since we only configure the interrupt pin when an | |
1035 | * event is enabled, we are sure we have at least | |
1036 | * one event enabled at this point. | |
1037 | */ | |
1038 | return IRQ_WAKE_THREAD; | |
1039 | } | |
1040 | ||
1041 | static irqreturn_t mma9553_event_handler(int irq, void *private) | |
1042 | { | |
1043 | struct iio_dev *indio_dev = private; | |
1044 | struct mma9553_data *data = iio_priv(indio_dev); | |
1045 | u16 stepcnt; | |
1046 | u8 activity; | |
1047 | struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect; | |
1048 | int ret; | |
1049 | ||
1050 | mutex_lock(&data->mutex); | |
1051 | ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt); | |
1052 | if (ret < 0) { | |
1053 | mutex_unlock(&data->mutex); | |
1054 | return IRQ_HANDLED; | |
1055 | } | |
1056 | ||
1057 | ev_prev_activity = | |
1058 | mma9553_get_event(data, IIO_ACTIVITY, | |
1059 | mma9553_activity_to_mod(data->activity), | |
1060 | IIO_EV_DIR_FALLING); | |
1061 | ev_activity = | |
1062 | mma9553_get_event(data, IIO_ACTIVITY, | |
1063 | mma9553_activity_to_mod(activity), | |
1064 | IIO_EV_DIR_RISING); | |
1065 | ev_step_detect = | |
1066 | mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE); | |
1067 | ||
1068 | if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) { | |
1069 | data->stepcnt = stepcnt; | |
1070 | iio_push_event(indio_dev, | |
1071 | IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD, | |
1072 | IIO_EV_DIR_NONE, IIO_EV_TYPE_CHANGE, 0, 0, 0), | |
1073 | data->timestamp); | |
1074 | } | |
1075 | ||
1076 | if (activity != data->activity) { | |
1077 | data->activity = activity; | |
1078 | /* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */ | |
1079 | if (ev_prev_activity && ev_prev_activity->enabled) | |
1080 | iio_push_event(indio_dev, | |
1081 | IIO_EVENT_CODE(IIO_ACTIVITY, 0, | |
1082 | ev_prev_activity->info->mod, | |
1083 | IIO_EV_DIR_FALLING, | |
1084 | IIO_EV_TYPE_THRESH, 0, 0, 0), | |
1085 | data->timestamp); | |
1086 | ||
1087 | if (ev_activity && ev_activity->enabled) | |
1088 | iio_push_event(indio_dev, | |
1089 | IIO_EVENT_CODE(IIO_ACTIVITY, 0, | |
1090 | ev_activity->info->mod, | |
1091 | IIO_EV_DIR_RISING, | |
1092 | IIO_EV_TYPE_THRESH, 0, 0, 0), | |
1093 | data->timestamp); | |
1094 | } | |
1095 | mutex_unlock(&data->mutex); | |
1096 | ||
1097 | return IRQ_HANDLED; | |
1098 | } | |
1099 | ||
1100 | static int mma9553_gpio_probe(struct i2c_client *client) | |
1101 | { | |
1102 | struct device *dev; | |
1103 | struct gpio_desc *gpio; | |
1104 | int ret; | |
1105 | ||
1106 | if (!client) | |
1107 | return -EINVAL; | |
1108 | ||
1109 | dev = &client->dev; | |
1110 | ||
1111 | /* data ready gpio interrupt pin */ | |
b457f53a | 1112 | gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0, GPIOD_IN); |
40cb7613 IT |
1113 | if (IS_ERR(gpio)) { |
1114 | dev_err(dev, "acpi gpio get index failed\n"); | |
1115 | return PTR_ERR(gpio); | |
1116 | } | |
1117 | ||
40cb7613 IT |
1118 | ret = gpiod_to_irq(gpio); |
1119 | ||
1120 | dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
1121 | ||
1122 | return ret; | |
1123 | } | |
1124 | ||
1125 | static const char *mma9553_match_acpi_device(struct device *dev) | |
1126 | { | |
1127 | const struct acpi_device_id *id; | |
1128 | ||
1129 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | |
1130 | if (!id) | |
1131 | return NULL; | |
1132 | ||
1133 | return dev_name(dev); | |
1134 | } | |
1135 | ||
1136 | static int mma9553_probe(struct i2c_client *client, | |
1137 | const struct i2c_device_id *id) | |
1138 | { | |
1139 | struct mma9553_data *data; | |
1140 | struct iio_dev *indio_dev; | |
1141 | const char *name = NULL; | |
1142 | int ret; | |
1143 | ||
1144 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
1145 | if (!indio_dev) | |
1146 | return -ENOMEM; | |
1147 | ||
1148 | data = iio_priv(indio_dev); | |
1149 | i2c_set_clientdata(client, indio_dev); | |
1150 | data->client = client; | |
1151 | ||
1152 | if (id) | |
1153 | name = id->name; | |
1154 | else if (ACPI_HANDLE(&client->dev)) | |
1155 | name = mma9553_match_acpi_device(&client->dev); | |
1156 | else | |
1157 | return -ENOSYS; | |
1158 | ||
1159 | mutex_init(&data->mutex); | |
1160 | mma9553_init_events(data); | |
1161 | ||
1162 | ret = mma9553_init(data); | |
1163 | if (ret < 0) | |
1164 | return ret; | |
1165 | ||
1166 | indio_dev->dev.parent = &client->dev; | |
1167 | indio_dev->channels = mma9553_channels; | |
1168 | indio_dev->num_channels = ARRAY_SIZE(mma9553_channels); | |
1169 | indio_dev->name = name; | |
1170 | indio_dev->modes = INDIO_DIRECT_MODE; | |
1171 | indio_dev->info = &mma9553_info; | |
1172 | ||
1173 | if (client->irq < 0) | |
1174 | client->irq = mma9553_gpio_probe(client); | |
1175 | ||
1176 | if (client->irq >= 0) { | |
1177 | ret = devm_request_threaded_irq(&client->dev, client->irq, | |
1178 | mma9553_irq_handler, | |
1179 | mma9553_event_handler, | |
1180 | IRQF_TRIGGER_RISING, | |
1181 | MMA9553_IRQ_NAME, indio_dev); | |
1182 | if (ret < 0) { | |
1183 | dev_err(&client->dev, "request irq %d failed\n", | |
1184 | client->irq); | |
1185 | goto out_poweroff; | |
1186 | } | |
1187 | ||
1188 | } | |
1189 | ||
1190 | ret = iio_device_register(indio_dev); | |
1191 | if (ret < 0) { | |
1192 | dev_err(&client->dev, "unable to register iio device\n"); | |
1193 | goto out_poweroff; | |
1194 | } | |
1195 | ||
1196 | ret = pm_runtime_set_active(&client->dev); | |
1197 | if (ret < 0) | |
1198 | goto out_iio_unregister; | |
1199 | ||
1200 | pm_runtime_enable(&client->dev); | |
1201 | pm_runtime_set_autosuspend_delay(&client->dev, | |
1202 | MMA9551_AUTO_SUSPEND_DELAY_MS); | |
1203 | pm_runtime_use_autosuspend(&client->dev); | |
1204 | ||
1205 | dev_dbg(&indio_dev->dev, "Registered device %s\n", name); | |
1206 | ||
1207 | return 0; | |
1208 | ||
1209 | out_iio_unregister: | |
1210 | iio_device_unregister(indio_dev); | |
1211 | out_poweroff: | |
1212 | mma9551_set_device_state(client, false); | |
1213 | return ret; | |
1214 | } | |
1215 | ||
1216 | static int mma9553_remove(struct i2c_client *client) | |
1217 | { | |
1218 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
1219 | struct mma9553_data *data = iio_priv(indio_dev); | |
1220 | ||
1221 | pm_runtime_disable(&client->dev); | |
1222 | pm_runtime_set_suspended(&client->dev); | |
1223 | pm_runtime_put_noidle(&client->dev); | |
1224 | ||
1225 | iio_device_unregister(indio_dev); | |
1226 | mutex_lock(&data->mutex); | |
1227 | mma9551_set_device_state(data->client, false); | |
1228 | mutex_unlock(&data->mutex); | |
1229 | ||
1230 | return 0; | |
1231 | } | |
1232 | ||
1233 | #ifdef CONFIG_PM | |
1234 | static int mma9553_runtime_suspend(struct device *dev) | |
1235 | { | |
1236 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
1237 | struct mma9553_data *data = iio_priv(indio_dev); | |
1238 | int ret; | |
1239 | ||
1240 | mutex_lock(&data->mutex); | |
1241 | ret = mma9551_set_device_state(data->client, false); | |
1242 | mutex_unlock(&data->mutex); | |
1243 | if (ret < 0) { | |
1244 | dev_err(&data->client->dev, "powering off device failed\n"); | |
1245 | return -EAGAIN; | |
1246 | } | |
1247 | ||
1248 | return 0; | |
1249 | } | |
1250 | ||
1251 | static int mma9553_runtime_resume(struct device *dev) | |
1252 | { | |
1253 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
1254 | struct mma9553_data *data = iio_priv(indio_dev); | |
1255 | int ret; | |
1256 | ||
1257 | ret = mma9551_set_device_state(data->client, true); | |
1258 | if (ret < 0) | |
1259 | return ret; | |
1260 | ||
1261 | mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE); | |
1262 | ||
1263 | return 0; | |
1264 | } | |
1265 | #endif | |
1266 | ||
1267 | #ifdef CONFIG_PM_SLEEP | |
1268 | static int mma9553_suspend(struct device *dev) | |
1269 | { | |
1270 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
1271 | struct mma9553_data *data = iio_priv(indio_dev); | |
1272 | int ret; | |
1273 | ||
1274 | mutex_lock(&data->mutex); | |
1275 | ret = mma9551_set_device_state(data->client, false); | |
1276 | mutex_unlock(&data->mutex); | |
1277 | ||
1278 | return ret; | |
1279 | } | |
1280 | ||
1281 | static int mma9553_resume(struct device *dev) | |
1282 | { | |
1283 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | |
1284 | struct mma9553_data *data = iio_priv(indio_dev); | |
1285 | int ret; | |
1286 | ||
1287 | mutex_lock(&data->mutex); | |
1288 | ret = mma9551_set_device_state(data->client, true); | |
1289 | mutex_unlock(&data->mutex); | |
1290 | ||
1291 | return ret; | |
1292 | } | |
1293 | #endif | |
1294 | ||
1295 | static const struct dev_pm_ops mma9553_pm_ops = { | |
1296 | SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume) | |
1297 | SET_RUNTIME_PM_OPS(mma9553_runtime_suspend, | |
1298 | mma9553_runtime_resume, NULL) | |
1299 | }; | |
1300 | ||
1301 | static const struct acpi_device_id mma9553_acpi_match[] = { | |
1302 | {"MMA9553", 0}, | |
1303 | {}, | |
1304 | }; | |
1305 | ||
1306 | MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match); | |
1307 | ||
1308 | static const struct i2c_device_id mma9553_id[] = { | |
1309 | {"mma9553", 0}, | |
1310 | {}, | |
1311 | }; | |
1312 | ||
1313 | MODULE_DEVICE_TABLE(i2c, mma9553_id); | |
1314 | ||
1315 | static struct i2c_driver mma9553_driver = { | |
1316 | .driver = { | |
1317 | .name = MMA9553_DRV_NAME, | |
1318 | .acpi_match_table = ACPI_PTR(mma9553_acpi_match), | |
1319 | .pm = &mma9553_pm_ops, | |
1320 | }, | |
1321 | .probe = mma9553_probe, | |
1322 | .remove = mma9553_remove, | |
1323 | .id_table = mma9553_id, | |
1324 | }; | |
1325 | ||
1326 | module_i2c_driver(mma9553_driver); | |
1327 | ||
1328 | MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>"); | |
1329 | MODULE_LICENSE("GPL v2"); | |
1330 | MODULE_DESCRIPTION("MMA9553L pedometer platform driver"); |