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