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