Commit | Line | Data |
---|---|---|
77c4ad2d DB |
1 | /* |
2 | * BMI160 - Bosch IMU (accel, gyro plus external magnetometer) | |
3 | * | |
4 | * Copyright (c) 2016, Intel Corporation. | |
5 | * | |
6 | * This file is subject to the terms and conditions of version 2 of | |
7 | * the GNU General Public License. See the file COPYING in the main | |
8 | * directory of this archive for more details. | |
9 | * | |
10 | * IIO core driver for BMI160, with support for I2C/SPI busses | |
11 | * | |
12 | * TODO: magnetometer, interrupts, hardware FIFO | |
13 | */ | |
14 | #include <linux/module.h> | |
15 | #include <linux/regmap.h> | |
16 | #include <linux/acpi.h> | |
17 | #include <linux/delay.h> | |
18 | ||
19 | #include <linux/iio/iio.h> | |
20 | #include <linux/iio/triggered_buffer.h> | |
21 | #include <linux/iio/trigger_consumer.h> | |
22 | #include <linux/iio/buffer.h> | |
23 | ||
24 | #include "bmi160.h" | |
25 | ||
26 | #define BMI160_REG_CHIP_ID 0x00 | |
27 | #define BMI160_CHIP_ID_VAL 0xD1 | |
28 | ||
29 | #define BMI160_REG_PMU_STATUS 0x03 | |
30 | ||
31 | /* X axis data low byte address, the rest can be obtained using axis offset */ | |
32 | #define BMI160_REG_DATA_MAGN_XOUT_L 0x04 | |
33 | #define BMI160_REG_DATA_GYRO_XOUT_L 0x0C | |
34 | #define BMI160_REG_DATA_ACCEL_XOUT_L 0x12 | |
35 | ||
36 | #define BMI160_REG_ACCEL_CONFIG 0x40 | |
37 | #define BMI160_ACCEL_CONFIG_ODR_MASK GENMASK(3, 0) | |
38 | #define BMI160_ACCEL_CONFIG_BWP_MASK GENMASK(6, 4) | |
39 | ||
40 | #define BMI160_REG_ACCEL_RANGE 0x41 | |
41 | #define BMI160_ACCEL_RANGE_2G 0x03 | |
42 | #define BMI160_ACCEL_RANGE_4G 0x05 | |
43 | #define BMI160_ACCEL_RANGE_8G 0x08 | |
44 | #define BMI160_ACCEL_RANGE_16G 0x0C | |
45 | ||
46 | #define BMI160_REG_GYRO_CONFIG 0x42 | |
47 | #define BMI160_GYRO_CONFIG_ODR_MASK GENMASK(3, 0) | |
48 | #define BMI160_GYRO_CONFIG_BWP_MASK GENMASK(5, 4) | |
49 | ||
50 | #define BMI160_REG_GYRO_RANGE 0x43 | |
51 | #define BMI160_GYRO_RANGE_2000DPS 0x00 | |
52 | #define BMI160_GYRO_RANGE_1000DPS 0x01 | |
53 | #define BMI160_GYRO_RANGE_500DPS 0x02 | |
54 | #define BMI160_GYRO_RANGE_250DPS 0x03 | |
55 | #define BMI160_GYRO_RANGE_125DPS 0x04 | |
56 | ||
57 | #define BMI160_REG_CMD 0x7E | |
58 | #define BMI160_CMD_ACCEL_PM_SUSPEND 0x10 | |
59 | #define BMI160_CMD_ACCEL_PM_NORMAL 0x11 | |
60 | #define BMI160_CMD_ACCEL_PM_LOW_POWER 0x12 | |
61 | #define BMI160_CMD_GYRO_PM_SUSPEND 0x14 | |
62 | #define BMI160_CMD_GYRO_PM_NORMAL 0x15 | |
63 | #define BMI160_CMD_GYRO_PM_FAST_STARTUP 0x17 | |
64 | #define BMI160_CMD_SOFTRESET 0xB6 | |
65 | ||
66 | #define BMI160_REG_DUMMY 0x7F | |
67 | ||
68 | #define BMI160_ACCEL_PMU_MIN_USLEEP 3200 | |
69 | #define BMI160_ACCEL_PMU_MAX_USLEEP 3800 | |
70 | #define BMI160_GYRO_PMU_MIN_USLEEP 55000 | |
71 | #define BMI160_GYRO_PMU_MAX_USLEEP 80000 | |
72 | #define BMI160_SOFTRESET_USLEEP 1000 | |
73 | ||
74 | #define BMI160_CHANNEL(_type, _axis, _index) { \ | |
75 | .type = _type, \ | |
76 | .modified = 1, \ | |
77 | .channel2 = IIO_MOD_##_axis, \ | |
78 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
79 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ | |
80 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | |
81 | .scan_index = _index, \ | |
82 | .scan_type = { \ | |
83 | .sign = 's', \ | |
84 | .realbits = 16, \ | |
85 | .storagebits = 16, \ | |
86 | .endianness = IIO_LE, \ | |
87 | }, \ | |
88 | } | |
89 | ||
90 | /* scan indexes follow DATA register order */ | |
91 | enum bmi160_scan_axis { | |
92 | BMI160_SCAN_EXT_MAGN_X = 0, | |
93 | BMI160_SCAN_EXT_MAGN_Y, | |
94 | BMI160_SCAN_EXT_MAGN_Z, | |
95 | BMI160_SCAN_RHALL, | |
96 | BMI160_SCAN_GYRO_X, | |
97 | BMI160_SCAN_GYRO_Y, | |
98 | BMI160_SCAN_GYRO_Z, | |
99 | BMI160_SCAN_ACCEL_X, | |
100 | BMI160_SCAN_ACCEL_Y, | |
101 | BMI160_SCAN_ACCEL_Z, | |
102 | BMI160_SCAN_TIMESTAMP, | |
103 | }; | |
104 | ||
105 | enum bmi160_sensor_type { | |
106 | BMI160_ACCEL = 0, | |
107 | BMI160_GYRO, | |
108 | BMI160_EXT_MAGN, | |
109 | BMI160_NUM_SENSORS /* must be last */ | |
110 | }; | |
111 | ||
112 | struct bmi160_data { | |
113 | struct regmap *regmap; | |
114 | }; | |
115 | ||
116 | const struct regmap_config bmi160_regmap_config = { | |
117 | .reg_bits = 8, | |
118 | .val_bits = 8, | |
119 | }; | |
120 | EXPORT_SYMBOL(bmi160_regmap_config); | |
121 | ||
122 | struct bmi160_regs { | |
123 | u8 data; /* LSB byte register for X-axis */ | |
124 | u8 config; | |
125 | u8 config_odr_mask; | |
126 | u8 config_bwp_mask; | |
127 | u8 range; | |
128 | u8 pmu_cmd_normal; | |
129 | u8 pmu_cmd_suspend; | |
130 | }; | |
131 | ||
132 | static struct bmi160_regs bmi160_regs[] = { | |
133 | [BMI160_ACCEL] = { | |
134 | .data = BMI160_REG_DATA_ACCEL_XOUT_L, | |
135 | .config = BMI160_REG_ACCEL_CONFIG, | |
136 | .config_odr_mask = BMI160_ACCEL_CONFIG_ODR_MASK, | |
137 | .config_bwp_mask = BMI160_ACCEL_CONFIG_BWP_MASK, | |
138 | .range = BMI160_REG_ACCEL_RANGE, | |
139 | .pmu_cmd_normal = BMI160_CMD_ACCEL_PM_NORMAL, | |
140 | .pmu_cmd_suspend = BMI160_CMD_ACCEL_PM_SUSPEND, | |
141 | }, | |
142 | [BMI160_GYRO] = { | |
143 | .data = BMI160_REG_DATA_GYRO_XOUT_L, | |
144 | .config = BMI160_REG_GYRO_CONFIG, | |
145 | .config_odr_mask = BMI160_GYRO_CONFIG_ODR_MASK, | |
146 | .config_bwp_mask = BMI160_GYRO_CONFIG_BWP_MASK, | |
147 | .range = BMI160_REG_GYRO_RANGE, | |
148 | .pmu_cmd_normal = BMI160_CMD_GYRO_PM_NORMAL, | |
149 | .pmu_cmd_suspend = BMI160_CMD_GYRO_PM_SUSPEND, | |
150 | }, | |
151 | }; | |
152 | ||
153 | struct bmi160_pmu_time { | |
154 | unsigned long min; | |
155 | unsigned long max; | |
156 | }; | |
157 | ||
158 | static struct bmi160_pmu_time bmi160_pmu_time[] = { | |
159 | [BMI160_ACCEL] = { | |
160 | .min = BMI160_ACCEL_PMU_MIN_USLEEP, | |
161 | .max = BMI160_ACCEL_PMU_MAX_USLEEP | |
162 | }, | |
163 | [BMI160_GYRO] = { | |
164 | .min = BMI160_GYRO_PMU_MIN_USLEEP, | |
165 | .max = BMI160_GYRO_PMU_MIN_USLEEP, | |
166 | }, | |
167 | }; | |
168 | ||
169 | struct bmi160_scale { | |
170 | u8 bits; | |
171 | int uscale; | |
172 | }; | |
173 | ||
174 | struct bmi160_odr { | |
175 | u8 bits; | |
176 | int odr; | |
177 | int uodr; | |
178 | }; | |
179 | ||
180 | static const struct bmi160_scale bmi160_accel_scale[] = { | |
181 | { BMI160_ACCEL_RANGE_2G, 598}, | |
182 | { BMI160_ACCEL_RANGE_4G, 1197}, | |
183 | { BMI160_ACCEL_RANGE_8G, 2394}, | |
184 | { BMI160_ACCEL_RANGE_16G, 4788}, | |
185 | }; | |
186 | ||
187 | static const struct bmi160_scale bmi160_gyro_scale[] = { | |
188 | { BMI160_GYRO_RANGE_2000DPS, 1065}, | |
189 | { BMI160_GYRO_RANGE_1000DPS, 532}, | |
190 | { BMI160_GYRO_RANGE_500DPS, 266}, | |
191 | { BMI160_GYRO_RANGE_250DPS, 133}, | |
192 | { BMI160_GYRO_RANGE_125DPS, 66}, | |
193 | }; | |
194 | ||
195 | struct bmi160_scale_item { | |
196 | const struct bmi160_scale *tbl; | |
197 | int num; | |
198 | }; | |
199 | ||
200 | static const struct bmi160_scale_item bmi160_scale_table[] = { | |
201 | [BMI160_ACCEL] = { | |
202 | .tbl = bmi160_accel_scale, | |
203 | .num = ARRAY_SIZE(bmi160_accel_scale), | |
204 | }, | |
205 | [BMI160_GYRO] = { | |
206 | .tbl = bmi160_gyro_scale, | |
207 | .num = ARRAY_SIZE(bmi160_gyro_scale), | |
208 | }, | |
209 | }; | |
210 | ||
211 | static const struct bmi160_odr bmi160_accel_odr[] = { | |
212 | {0x01, 0, 78125}, | |
213 | {0x02, 1, 5625}, | |
214 | {0x03, 3, 125}, | |
215 | {0x04, 6, 25}, | |
216 | {0x05, 12, 5}, | |
217 | {0x06, 25, 0}, | |
218 | {0x07, 50, 0}, | |
219 | {0x08, 100, 0}, | |
220 | {0x09, 200, 0}, | |
221 | {0x0A, 400, 0}, | |
222 | {0x0B, 800, 0}, | |
223 | {0x0C, 1600, 0}, | |
224 | }; | |
225 | ||
226 | static const struct bmi160_odr bmi160_gyro_odr[] = { | |
227 | {0x06, 25, 0}, | |
228 | {0x07, 50, 0}, | |
229 | {0x08, 100, 0}, | |
230 | {0x09, 200, 0}, | |
231 | {0x0A, 400, 0}, | |
232 | {0x0B, 8000, 0}, | |
233 | {0x0C, 1600, 0}, | |
234 | {0x0D, 3200, 0}, | |
235 | }; | |
236 | ||
237 | struct bmi160_odr_item { | |
238 | const struct bmi160_odr *tbl; | |
239 | int num; | |
240 | }; | |
241 | ||
242 | static const struct bmi160_odr_item bmi160_odr_table[] = { | |
243 | [BMI160_ACCEL] = { | |
244 | .tbl = bmi160_accel_odr, | |
245 | .num = ARRAY_SIZE(bmi160_accel_odr), | |
246 | }, | |
247 | [BMI160_GYRO] = { | |
248 | .tbl = bmi160_gyro_odr, | |
249 | .num = ARRAY_SIZE(bmi160_gyro_odr), | |
250 | }, | |
251 | }; | |
252 | ||
253 | static const struct iio_chan_spec bmi160_channels[] = { | |
254 | BMI160_CHANNEL(IIO_ACCEL, X, BMI160_SCAN_ACCEL_X), | |
255 | BMI160_CHANNEL(IIO_ACCEL, Y, BMI160_SCAN_ACCEL_Y), | |
256 | BMI160_CHANNEL(IIO_ACCEL, Z, BMI160_SCAN_ACCEL_Z), | |
257 | BMI160_CHANNEL(IIO_ANGL_VEL, X, BMI160_SCAN_GYRO_X), | |
258 | BMI160_CHANNEL(IIO_ANGL_VEL, Y, BMI160_SCAN_GYRO_Y), | |
259 | BMI160_CHANNEL(IIO_ANGL_VEL, Z, BMI160_SCAN_GYRO_Z), | |
260 | IIO_CHAN_SOFT_TIMESTAMP(BMI160_SCAN_TIMESTAMP), | |
261 | }; | |
262 | ||
263 | static enum bmi160_sensor_type bmi160_to_sensor(enum iio_chan_type iio_type) | |
264 | { | |
265 | switch (iio_type) { | |
266 | case IIO_ACCEL: | |
267 | return BMI160_ACCEL; | |
268 | case IIO_ANGL_VEL: | |
269 | return BMI160_GYRO; | |
270 | default: | |
271 | return -EINVAL; | |
272 | } | |
273 | } | |
274 | ||
275 | static | |
276 | int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, | |
277 | bool mode) | |
278 | { | |
279 | int ret; | |
280 | u8 cmd; | |
281 | ||
282 | if (mode) | |
283 | cmd = bmi160_regs[t].pmu_cmd_normal; | |
284 | else | |
285 | cmd = bmi160_regs[t].pmu_cmd_suspend; | |
286 | ||
287 | ret = regmap_write(data->regmap, BMI160_REG_CMD, cmd); | |
288 | if (ret < 0) | |
289 | return ret; | |
290 | ||
291 | usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max); | |
292 | ||
293 | return 0; | |
294 | } | |
295 | ||
296 | static | |
297 | int bmi160_set_scale(struct bmi160_data *data, enum bmi160_sensor_type t, | |
298 | int uscale) | |
299 | { | |
300 | int i; | |
301 | ||
302 | for (i = 0; i < bmi160_scale_table[t].num; i++) | |
303 | if (bmi160_scale_table[t].tbl[i].uscale == uscale) | |
304 | break; | |
305 | ||
306 | if (i == bmi160_scale_table[t].num) | |
307 | return -EINVAL; | |
308 | ||
309 | return regmap_write(data->regmap, bmi160_regs[t].range, | |
310 | bmi160_scale_table[t].tbl[i].bits); | |
311 | } | |
312 | ||
313 | static | |
314 | int bmi160_get_scale(struct bmi160_data *data, enum bmi160_sensor_type t, | |
315 | int *uscale) | |
316 | { | |
317 | int i, ret, val; | |
318 | ||
319 | ret = regmap_read(data->regmap, bmi160_regs[t].range, &val); | |
320 | if (ret < 0) | |
321 | return ret; | |
322 | ||
323 | for (i = 0; i < bmi160_scale_table[t].num; i++) | |
324 | if (bmi160_scale_table[t].tbl[i].bits == val) { | |
325 | *uscale = bmi160_scale_table[t].tbl[i].uscale; | |
326 | return 0; | |
327 | } | |
328 | ||
329 | return -EINVAL; | |
330 | } | |
331 | ||
332 | static int bmi160_get_data(struct bmi160_data *data, int chan_type, | |
333 | int axis, int *val) | |
334 | { | |
335 | u8 reg; | |
336 | int ret; | |
337 | __le16 sample; | |
338 | enum bmi160_sensor_type t = bmi160_to_sensor(chan_type); | |
339 | ||
340 | reg = bmi160_regs[t].data + (axis - IIO_MOD_X) * sizeof(__le16); | |
341 | ||
342 | ret = regmap_bulk_read(data->regmap, reg, &sample, sizeof(__le16)); | |
343 | if (ret < 0) | |
344 | return ret; | |
345 | ||
346 | *val = sign_extend32(le16_to_cpu(sample), 15); | |
347 | ||
348 | return 0; | |
349 | } | |
350 | ||
351 | static | |
352 | int bmi160_set_odr(struct bmi160_data *data, enum bmi160_sensor_type t, | |
353 | int odr, int uodr) | |
354 | { | |
355 | int i; | |
356 | ||
357 | for (i = 0; i < bmi160_odr_table[t].num; i++) | |
358 | if (bmi160_odr_table[t].tbl[i].odr == odr && | |
359 | bmi160_odr_table[t].tbl[i].uodr == uodr) | |
360 | break; | |
361 | ||
362 | if (i >= bmi160_odr_table[t].num) | |
363 | return -EINVAL; | |
364 | ||
365 | return regmap_update_bits(data->regmap, | |
366 | bmi160_regs[t].config, | |
367 | bmi160_odr_table[t].tbl[i].bits, | |
368 | bmi160_regs[t].config_odr_mask); | |
369 | } | |
370 | ||
371 | static int bmi160_get_odr(struct bmi160_data *data, enum bmi160_sensor_type t, | |
372 | int *odr, int *uodr) | |
373 | { | |
374 | int i, val, ret; | |
375 | ||
376 | ret = regmap_read(data->regmap, bmi160_regs[t].config, &val); | |
377 | if (ret < 0) | |
378 | return ret; | |
379 | ||
380 | val &= bmi160_regs[t].config_odr_mask; | |
381 | ||
382 | for (i = 0; i < bmi160_odr_table[t].num; i++) | |
383 | if (val == bmi160_odr_table[t].tbl[i].bits) | |
384 | break; | |
385 | ||
386 | if (i >= bmi160_odr_table[t].num) | |
387 | return -EINVAL; | |
388 | ||
389 | *odr = bmi160_odr_table[t].tbl[i].odr; | |
390 | *uodr = bmi160_odr_table[t].tbl[i].uodr; | |
391 | ||
392 | return 0; | |
393 | } | |
394 | ||
395 | static irqreturn_t bmi160_trigger_handler(int irq, void *p) | |
396 | { | |
397 | struct iio_poll_func *pf = p; | |
398 | struct iio_dev *indio_dev = pf->indio_dev; | |
399 | struct bmi160_data *data = iio_priv(indio_dev); | |
400 | s16 buf[16]; /* 3 sens x 3 axis x s16 + 3 x s16 pad + 4 x s16 tstamp */ | |
401 | int i, ret, j = 0, base = BMI160_REG_DATA_MAGN_XOUT_L; | |
402 | __le16 sample; | |
403 | ||
404 | for_each_set_bit(i, indio_dev->active_scan_mask, | |
405 | indio_dev->masklength) { | |
406 | ret = regmap_bulk_read(data->regmap, base + i * sizeof(__le16), | |
407 | &sample, sizeof(__le16)); | |
408 | if (ret < 0) | |
409 | goto done; | |
410 | buf[j++] = sample; | |
411 | } | |
412 | ||
413 | iio_push_to_buffers_with_timestamp(indio_dev, buf, iio_get_time_ns()); | |
414 | done: | |
415 | iio_trigger_notify_done(indio_dev->trig); | |
416 | return IRQ_HANDLED; | |
417 | } | |
418 | ||
419 | static int bmi160_read_raw(struct iio_dev *indio_dev, | |
420 | struct iio_chan_spec const *chan, | |
421 | int *val, int *val2, long mask) | |
422 | { | |
423 | int ret; | |
424 | struct bmi160_data *data = iio_priv(indio_dev); | |
425 | ||
426 | switch (mask) { | |
427 | case IIO_CHAN_INFO_RAW: | |
428 | ret = bmi160_get_data(data, chan->type, chan->channel2, val); | |
429 | if (ret < 0) | |
430 | return ret; | |
431 | return IIO_VAL_INT; | |
432 | case IIO_CHAN_INFO_SCALE: | |
433 | *val = 0; | |
434 | ret = bmi160_get_scale(data, | |
435 | bmi160_to_sensor(chan->type), val2); | |
436 | return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO; | |
437 | case IIO_CHAN_INFO_SAMP_FREQ: | |
438 | ret = bmi160_get_odr(data, bmi160_to_sensor(chan->type), | |
439 | val, val2); | |
440 | return ret < 0 ? ret : IIO_VAL_INT_PLUS_MICRO; | |
441 | default: | |
442 | return -EINVAL; | |
443 | } | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | static int bmi160_write_raw(struct iio_dev *indio_dev, | |
449 | struct iio_chan_spec const *chan, | |
450 | int val, int val2, long mask) | |
451 | { | |
452 | struct bmi160_data *data = iio_priv(indio_dev); | |
453 | ||
454 | switch (mask) { | |
455 | case IIO_CHAN_INFO_SCALE: | |
456 | return bmi160_set_scale(data, | |
457 | bmi160_to_sensor(chan->type), val2); | |
458 | break; | |
459 | case IIO_CHAN_INFO_SAMP_FREQ: | |
460 | return bmi160_set_odr(data, bmi160_to_sensor(chan->type), | |
461 | val, val2); | |
462 | default: | |
463 | return -EINVAL; | |
464 | } | |
465 | ||
466 | return 0; | |
467 | } | |
468 | ||
469 | static const struct iio_info bmi160_info = { | |
470 | .driver_module = THIS_MODULE, | |
471 | .read_raw = bmi160_read_raw, | |
472 | .write_raw = bmi160_write_raw, | |
473 | }; | |
474 | ||
475 | static const char *bmi160_match_acpi_device(struct device *dev) | |
476 | { | |
477 | const struct acpi_device_id *id; | |
478 | ||
479 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | |
480 | if (!id) | |
481 | return NULL; | |
482 | ||
483 | return dev_name(dev); | |
484 | } | |
485 | ||
486 | static int bmi160_chip_init(struct bmi160_data *data, bool use_spi) | |
487 | { | |
488 | int ret; | |
489 | unsigned int val; | |
490 | struct device *dev = regmap_get_device(data->regmap); | |
491 | ||
492 | ret = regmap_write(data->regmap, BMI160_REG_CMD, BMI160_CMD_SOFTRESET); | |
493 | if (ret < 0) | |
494 | return ret; | |
495 | ||
496 | usleep_range(BMI160_SOFTRESET_USLEEP, BMI160_SOFTRESET_USLEEP + 1); | |
497 | ||
498 | /* | |
499 | * CS rising edge is needed before starting SPI, so do a dummy read | |
500 | * See Section 3.2.1, page 86 of the datasheet | |
501 | */ | |
502 | if (use_spi) { | |
503 | ret = regmap_read(data->regmap, BMI160_REG_DUMMY, &val); | |
504 | if (ret < 0) | |
505 | return ret; | |
506 | } | |
507 | ||
508 | ret = regmap_read(data->regmap, BMI160_REG_CHIP_ID, &val); | |
509 | if (ret < 0) { | |
510 | dev_err(dev, "Error reading chip id\n"); | |
511 | return ret; | |
512 | } | |
513 | if (val != BMI160_CHIP_ID_VAL) { | |
514 | dev_err(dev, "Wrong chip id, got %x expected %x\n", | |
515 | val, BMI160_CHIP_ID_VAL); | |
516 | return -ENODEV; | |
517 | } | |
518 | ||
519 | ret = bmi160_set_mode(data, BMI160_ACCEL, true); | |
520 | if (ret < 0) | |
521 | return ret; | |
522 | ||
523 | ret = bmi160_set_mode(data, BMI160_GYRO, true); | |
524 | if (ret < 0) | |
525 | return ret; | |
526 | ||
527 | return 0; | |
528 | } | |
529 | ||
530 | static void bmi160_chip_uninit(struct bmi160_data *data) | |
531 | { | |
532 | bmi160_set_mode(data, BMI160_GYRO, false); | |
533 | bmi160_set_mode(data, BMI160_ACCEL, false); | |
534 | } | |
535 | ||
536 | int bmi160_core_probe(struct device *dev, struct regmap *regmap, | |
537 | const char *name, bool use_spi) | |
538 | { | |
539 | struct iio_dev *indio_dev; | |
540 | struct bmi160_data *data; | |
541 | int ret; | |
542 | ||
543 | indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); | |
544 | if (!indio_dev) | |
545 | return -ENOMEM; | |
546 | ||
547 | data = iio_priv(indio_dev); | |
548 | dev_set_drvdata(dev, indio_dev); | |
549 | data->regmap = regmap; | |
550 | ||
551 | ret = bmi160_chip_init(data, use_spi); | |
552 | if (ret < 0) | |
553 | return ret; | |
554 | ||
555 | if (!name && ACPI_HANDLE(dev)) | |
556 | name = bmi160_match_acpi_device(dev); | |
557 | ||
558 | indio_dev->dev.parent = dev; | |
559 | indio_dev->channels = bmi160_channels; | |
560 | indio_dev->num_channels = ARRAY_SIZE(bmi160_channels); | |
561 | indio_dev->name = name; | |
562 | indio_dev->modes = INDIO_DIRECT_MODE; | |
563 | indio_dev->info = &bmi160_info; | |
564 | ||
565 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | |
566 | bmi160_trigger_handler, NULL); | |
567 | if (ret < 0) | |
568 | goto uninit; | |
569 | ||
570 | ret = iio_device_register(indio_dev); | |
571 | if (ret < 0) | |
572 | goto buffer_cleanup; | |
573 | ||
574 | return 0; | |
575 | buffer_cleanup: | |
576 | iio_triggered_buffer_cleanup(indio_dev); | |
577 | uninit: | |
578 | bmi160_chip_uninit(data); | |
579 | return ret; | |
580 | } | |
581 | EXPORT_SYMBOL_GPL(bmi160_core_probe); | |
582 | ||
583 | void bmi160_core_remove(struct device *dev) | |
584 | { | |
585 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
586 | struct bmi160_data *data = iio_priv(indio_dev); | |
587 | ||
588 | iio_device_unregister(indio_dev); | |
589 | iio_triggered_buffer_cleanup(indio_dev); | |
590 | bmi160_chip_uninit(data); | |
591 | } | |
592 | EXPORT_SYMBOL_GPL(bmi160_core_remove); | |
593 | ||
594 | MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com"); | |
595 | MODULE_DESCRIPTION("Bosch BMI160 driver"); | |
596 | MODULE_LICENSE("GPL v2"); |