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