1 // SPDX-License-Identifier: GPL-2.0
3 * 3-axis accelerometer driver supporting following Bosch-Sensortec chips:
8 * Copyright (c) 2018-2021, Topic Embedded Products
11 #include <linux/bitfield.h>
12 #include <linux/delay.h>
13 #include <linux/iio/iio.h>
14 #include <linux/iio/sysfs.h>
15 #include <linux/interrupt.h>
16 #include <linux/module.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/regmap.h>
20 #include <linux/slab.h>
21 #include <linux/unaligned.h>
23 #include "bmi088-accel.h"
25 #define BMI088_ACCEL_REG_CHIP_ID 0x00
26 #define BMI088_ACCEL_REG_ERROR 0x02
28 #define BMI088_ACCEL_REG_INT_STATUS 0x1D
29 #define BMI088_ACCEL_INT_STATUS_BIT_DRDY BIT(7)
31 #define BMI088_ACCEL_REG_RESET 0x7E
32 #define BMI088_ACCEL_RESET_VAL 0xB6
34 #define BMI088_ACCEL_REG_PWR_CTRL 0x7D
35 #define BMI088_ACCEL_REG_PWR_CONF 0x7C
37 #define BMI088_ACCEL_REG_INT_MAP_DATA 0x58
38 #define BMI088_ACCEL_INT_MAP_DATA_BIT_INT1_DRDY BIT(2)
39 #define BMI088_ACCEL_INT_MAP_DATA_BIT_INT2_FWM BIT(5)
41 #define BMI088_ACCEL_REG_INT1_IO_CONF 0x53
42 #define BMI088_ACCEL_INT1_IO_CONF_BIT_ENABLE_OUT BIT(3)
43 #define BMI088_ACCEL_INT1_IO_CONF_BIT_LVL BIT(1)
45 #define BMI088_ACCEL_REG_INT2_IO_CONF 0x54
46 #define BMI088_ACCEL_INT2_IO_CONF_BIT_ENABLE_OUT BIT(3)
47 #define BMI088_ACCEL_INT2_IO_CONF_BIT_LVL BIT(1)
49 #define BMI088_ACCEL_REG_ACC_CONF 0x40
50 #define BMI088_ACCEL_MODE_ODR_MASK 0x0f
52 #define BMI088_ACCEL_REG_ACC_RANGE 0x41
53 #define BMI088_ACCEL_RANGE_3G 0x00
54 #define BMI088_ACCEL_RANGE_6G 0x01
55 #define BMI088_ACCEL_RANGE_12G 0x02
56 #define BMI088_ACCEL_RANGE_24G 0x03
58 #define BMI088_ACCEL_REG_TEMP 0x22
59 #define BMI088_ACCEL_REG_TEMP_SHIFT 5
60 #define BMI088_ACCEL_TEMP_UNIT 125
61 #define BMI088_ACCEL_TEMP_OFFSET 23000
63 #define BMI088_ACCEL_REG_XOUT_L 0x12
64 #define BMI088_ACCEL_AXIS_TO_REG(axis) \
65 (BMI088_ACCEL_REG_XOUT_L + (axis * 2))
67 #define BMI088_ACCEL_MAX_STARTUP_TIME_US 1000
68 #define BMI088_AUTO_SUSPEND_DELAY_MS 2000
70 #define BMI088_ACCEL_REG_FIFO_STATUS 0x0E
71 #define BMI088_ACCEL_REG_FIFO_CONFIG0 0x48
72 #define BMI088_ACCEL_REG_FIFO_CONFIG1 0x49
73 #define BMI088_ACCEL_REG_FIFO_DATA 0x3F
74 #define BMI088_ACCEL_FIFO_LENGTH 100
76 #define BMI088_ACCEL_FIFO_MODE_FIFO 0x40
77 #define BMI088_ACCEL_FIFO_MODE_STREAM 0x80
79 #define BMIO088_ACCEL_ACC_RANGE_MSK GENMASK(1, 0)
81 enum bmi088_accel_axis
{
87 static const int bmi088_sample_freqs
[] = {
98 /* Available OSR (over sampling rate) sets the 3dB cut-off frequency */
99 enum bmi088_osr_modes
{
100 BMI088_ACCEL_MODE_OSR_NORMAL
= 0xA,
101 BMI088_ACCEL_MODE_OSR_2
= 0x9,
102 BMI088_ACCEL_MODE_OSR_4
= 0x8,
105 /* Available ODR (output data rates) in Hz */
106 enum bmi088_odr_modes
{
107 BMI088_ACCEL_MODE_ODR_12_5
= 0x5,
108 BMI088_ACCEL_MODE_ODR_25
= 0x6,
109 BMI088_ACCEL_MODE_ODR_50
= 0x7,
110 BMI088_ACCEL_MODE_ODR_100
= 0x8,
111 BMI088_ACCEL_MODE_ODR_200
= 0x9,
112 BMI088_ACCEL_MODE_ODR_400
= 0xa,
113 BMI088_ACCEL_MODE_ODR_800
= 0xb,
114 BMI088_ACCEL_MODE_ODR_1600
= 0xc,
117 struct bmi088_accel_chip_info
{
120 const struct iio_chan_spec
*channels
;
122 const int scale_table
[4][2];
125 struct bmi088_accel_data
{
126 struct regmap
*regmap
;
127 const struct bmi088_accel_chip_info
*chip_info
;
128 u8 buffer
[2] __aligned(IIO_DMA_MINALIGN
); /* shared DMA safe buffer */
131 static const struct regmap_range bmi088_volatile_ranges
[] = {
132 /* All registers below 0x40 are volatile, except the CHIP ID. */
133 regmap_reg_range(BMI088_ACCEL_REG_ERROR
, 0x3f),
134 /* Mark the RESET as volatile too, it is self-clearing */
135 regmap_reg_range(BMI088_ACCEL_REG_RESET
, BMI088_ACCEL_REG_RESET
),
138 static const struct regmap_access_table bmi088_volatile_table
= {
139 .yes_ranges
= bmi088_volatile_ranges
,
140 .n_yes_ranges
= ARRAY_SIZE(bmi088_volatile_ranges
),
143 const struct regmap_config bmi088_regmap_conf
= {
146 .max_register
= 0x7E,
147 .volatile_table
= &bmi088_volatile_table
,
148 .cache_type
= REGCACHE_RBTREE
,
150 EXPORT_SYMBOL_NS_GPL(bmi088_regmap_conf
, "IIO_BMI088");
152 static int bmi088_accel_power_up(struct bmi088_accel_data
*data
)
156 /* Enable accelerometer and temperature sensor */
157 ret
= regmap_write(data
->regmap
, BMI088_ACCEL_REG_PWR_CTRL
, 0x4);
161 /* Datasheet recommends to wait at least 5ms before communication */
162 usleep_range(5000, 6000);
164 /* Disable suspend mode */
165 ret
= regmap_write(data
->regmap
, BMI088_ACCEL_REG_PWR_CONF
, 0x0);
169 /* Recommended at least 1ms before further communication */
170 usleep_range(1000, 1200);
175 static int bmi088_accel_power_down(struct bmi088_accel_data
*data
)
179 /* Enable suspend mode */
180 ret
= regmap_write(data
->regmap
, BMI088_ACCEL_REG_PWR_CONF
, 0x3);
184 /* Recommended at least 1ms before further communication */
185 usleep_range(1000, 1200);
187 /* Disable accelerometer and temperature sensor */
188 ret
= regmap_write(data
->regmap
, BMI088_ACCEL_REG_PWR_CTRL
, 0x0);
192 /* Datasheet recommends to wait at least 5ms before communication */
193 usleep_range(5000, 6000);
198 static int bmi088_accel_get_sample_freq(struct bmi088_accel_data
*data
,
204 ret
= regmap_read(data
->regmap
, BMI088_ACCEL_REG_ACC_CONF
,
209 value
&= BMI088_ACCEL_MODE_ODR_MASK
;
210 value
-= BMI088_ACCEL_MODE_ODR_12_5
;
213 if (value
>= ARRAY_SIZE(bmi088_sample_freqs
) - 1)
216 *val
= bmi088_sample_freqs
[value
];
217 *val2
= bmi088_sample_freqs
[value
+ 1];
219 return IIO_VAL_INT_PLUS_MICRO
;
222 static int bmi088_accel_set_sample_freq(struct bmi088_accel_data
*data
, int val
)
227 while (index
< ARRAY_SIZE(bmi088_sample_freqs
) &&
228 bmi088_sample_freqs
[index
] != val
)
231 if (index
>= ARRAY_SIZE(bmi088_sample_freqs
))
234 regval
= (index
>> 1) + BMI088_ACCEL_MODE_ODR_12_5
;
236 return regmap_update_bits(data
->regmap
, BMI088_ACCEL_REG_ACC_CONF
,
237 BMI088_ACCEL_MODE_ODR_MASK
, regval
);
240 static int bmi088_accel_set_scale(struct bmi088_accel_data
*data
, int val
, int val2
)
244 for (i
= 0; i
< 4; i
++)
245 if (val
== data
->chip_info
->scale_table
[i
][0] &&
246 val2
== data
->chip_info
->scale_table
[i
][1])
252 return regmap_write(data
->regmap
, BMI088_ACCEL_REG_ACC_RANGE
, i
);
255 static int bmi088_accel_get_temp(struct bmi088_accel_data
*data
, int *val
)
260 ret
= regmap_bulk_read(data
->regmap
, BMI088_ACCEL_REG_TEMP
,
261 &data
->buffer
, sizeof(__be16
));
265 /* data->buffer is cacheline aligned */
266 temp
= be16_to_cpu(*(__be16
*)data
->buffer
);
268 *val
= temp
>> BMI088_ACCEL_REG_TEMP_SHIFT
;
273 static int bmi088_accel_get_axis(struct bmi088_accel_data
*data
,
274 struct iio_chan_spec
const *chan
,
280 ret
= regmap_bulk_read(data
->regmap
,
281 BMI088_ACCEL_AXIS_TO_REG(chan
->scan_index
),
282 data
->buffer
, sizeof(__le16
));
286 raw_val
= le16_to_cpu(*(__le16
*)data
->buffer
);
292 static int bmi088_accel_read_raw(struct iio_dev
*indio_dev
,
293 struct iio_chan_spec
const *chan
,
294 int *val
, int *val2
, long mask
)
296 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
297 struct device
*dev
= regmap_get_device(data
->regmap
);
302 case IIO_CHAN_INFO_RAW
:
303 switch (chan
->type
) {
305 ret
= pm_runtime_resume_and_get(dev
);
309 ret
= bmi088_accel_get_temp(data
, val
);
310 goto out_read_raw_pm_put
;
312 ret
= pm_runtime_resume_and_get(dev
);
316 ret
= iio_device_claim_direct_mode(indio_dev
);
318 goto out_read_raw_pm_put
;
320 ret
= bmi088_accel_get_axis(data
, chan
, val
);
321 iio_device_release_direct_mode(indio_dev
);
325 goto out_read_raw_pm_put
;
329 case IIO_CHAN_INFO_OFFSET
:
330 switch (chan
->type
) {
332 /* Offset applies before scale */
333 *val
= BMI088_ACCEL_TEMP_OFFSET
/BMI088_ACCEL_TEMP_UNIT
;
338 case IIO_CHAN_INFO_SCALE
:
339 switch (chan
->type
) {
341 /* 0.125 degrees per LSB */
342 *val
= BMI088_ACCEL_TEMP_UNIT
;
345 ret
= pm_runtime_resume_and_get(dev
);
349 ret
= regmap_read(data
->regmap
,
350 BMI088_ACCEL_REG_ACC_RANGE
, ®
);
352 goto out_read_raw_pm_put
;
354 reg
= FIELD_GET(BMIO088_ACCEL_ACC_RANGE_MSK
, reg
);
355 *val
= data
->chip_info
->scale_table
[reg
][0];
356 *val2
= data
->chip_info
->scale_table
[reg
][1];
357 ret
= IIO_VAL_INT_PLUS_MICRO
;
359 goto out_read_raw_pm_put
;
363 case IIO_CHAN_INFO_SAMP_FREQ
:
364 ret
= pm_runtime_resume_and_get(dev
);
368 ret
= bmi088_accel_get_sample_freq(data
, val
, val2
);
369 goto out_read_raw_pm_put
;
377 pm_runtime_mark_last_busy(dev
);
378 pm_runtime_put_autosuspend(dev
);
383 static int bmi088_accel_read_avail(struct iio_dev
*indio_dev
,
384 struct iio_chan_spec
const *chan
,
385 const int **vals
, int *type
, int *length
,
388 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
391 case IIO_CHAN_INFO_SCALE
:
392 *vals
= (const int *)data
->chip_info
->scale_table
;
394 *type
= IIO_VAL_INT_PLUS_MICRO
;
395 return IIO_AVAIL_LIST
;
396 case IIO_CHAN_INFO_SAMP_FREQ
:
397 *type
= IIO_VAL_INT_PLUS_MICRO
;
398 *vals
= bmi088_sample_freqs
;
399 *length
= ARRAY_SIZE(bmi088_sample_freqs
);
400 return IIO_AVAIL_LIST
;
406 static int bmi088_accel_write_raw(struct iio_dev
*indio_dev
,
407 struct iio_chan_spec
const *chan
,
408 int val
, int val2
, long mask
)
410 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
411 struct device
*dev
= regmap_get_device(data
->regmap
);
415 case IIO_CHAN_INFO_SCALE
:
416 ret
= pm_runtime_resume_and_get(dev
);
420 ret
= bmi088_accel_set_scale(data
, val
, val2
);
421 pm_runtime_mark_last_busy(dev
);
422 pm_runtime_put_autosuspend(dev
);
424 case IIO_CHAN_INFO_SAMP_FREQ
:
425 ret
= pm_runtime_resume_and_get(dev
);
429 ret
= bmi088_accel_set_sample_freq(data
, val
);
430 pm_runtime_mark_last_busy(dev
);
431 pm_runtime_put_autosuspend(dev
);
438 #define BMI088_ACCEL_CHANNEL(_axis) { \
441 .channel2 = IIO_MOD_##_axis, \
442 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
443 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
444 BIT(IIO_CHAN_INFO_SAMP_FREQ), \
445 .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
446 BIT(IIO_CHAN_INFO_SCALE), \
447 .scan_index = AXIS_##_axis, \
450 static const struct iio_chan_spec bmi088_accel_channels
[] = {
453 .info_mask_separate
= BIT(IIO_CHAN_INFO_RAW
) |
454 BIT(IIO_CHAN_INFO_SCALE
) |
455 BIT(IIO_CHAN_INFO_OFFSET
),
458 BMI088_ACCEL_CHANNEL(X
),
459 BMI088_ACCEL_CHANNEL(Y
),
460 BMI088_ACCEL_CHANNEL(Z
),
461 IIO_CHAN_SOFT_TIMESTAMP(3),
464 static const struct bmi088_accel_chip_info bmi088_accel_chip_info_tbl
[] = {
466 .name
= "bmi085-accel",
468 .channels
= bmi088_accel_channels
,
469 .num_channels
= ARRAY_SIZE(bmi088_accel_channels
),
470 .scale_table
= {{0, 598}, {0, 1196}, {0, 2393}, {0, 4785}},
473 .name
= "bmi088-accel",
475 .channels
= bmi088_accel_channels
,
476 .num_channels
= ARRAY_SIZE(bmi088_accel_channels
),
477 .scale_table
= {{0, 897}, {0, 1794}, {0, 3589}, {0, 7178}},
480 .name
= "bmi090l-accel",
482 .channels
= bmi088_accel_channels
,
483 .num_channels
= ARRAY_SIZE(bmi088_accel_channels
),
484 .scale_table
= {{0, 897}, {0, 1794}, {0, 3589}, {0, 7178}},
488 static const struct iio_info bmi088_accel_info
= {
489 .read_raw
= bmi088_accel_read_raw
,
490 .write_raw
= bmi088_accel_write_raw
,
491 .read_avail
= bmi088_accel_read_avail
,
494 static const unsigned long bmi088_accel_scan_masks
[] = {
495 BIT(AXIS_X
) | BIT(AXIS_Y
) | BIT(AXIS_Z
),
499 static int bmi088_accel_chip_init(struct bmi088_accel_data
*data
, enum bmi_device_type type
)
501 struct device
*dev
= regmap_get_device(data
->regmap
);
505 if (type
>= BOSCH_UNKNOWN
)
508 /* Do a dummy read to enable SPI interface, won't harm I2C */
509 regmap_read(data
->regmap
, BMI088_ACCEL_REG_INT_STATUS
, &val
);
512 * Reset chip to get it in a known good state. A delay of 1ms after
513 * reset is required according to the data sheet
515 ret
= regmap_write(data
->regmap
, BMI088_ACCEL_REG_RESET
,
516 BMI088_ACCEL_RESET_VAL
);
520 usleep_range(1000, 2000);
522 /* Do a dummy read again after a reset to enable the SPI interface */
523 regmap_read(data
->regmap
, BMI088_ACCEL_REG_INT_STATUS
, &val
);
526 ret
= regmap_read(data
->regmap
, BMI088_ACCEL_REG_CHIP_ID
, &val
);
528 dev_err(dev
, "Error: Reading chip id\n");
532 /* Validate chip ID */
533 for (i
= 0; i
< ARRAY_SIZE(bmi088_accel_chip_info_tbl
); i
++)
534 if (bmi088_accel_chip_info_tbl
[i
].chip_id
== val
)
537 if (i
== ARRAY_SIZE(bmi088_accel_chip_info_tbl
))
538 data
->chip_info
= &bmi088_accel_chip_info_tbl
[type
];
540 data
->chip_info
= &bmi088_accel_chip_info_tbl
[i
];
543 dev_warn(dev
, "unexpected chip id 0x%X\n", val
);
548 int bmi088_accel_core_probe(struct device
*dev
, struct regmap
*regmap
,
549 int irq
, enum bmi_device_type type
)
551 struct bmi088_accel_data
*data
;
552 struct iio_dev
*indio_dev
;
555 indio_dev
= devm_iio_device_alloc(dev
, sizeof(*data
));
559 data
= iio_priv(indio_dev
);
560 dev_set_drvdata(dev
, indio_dev
);
562 data
->regmap
= regmap
;
564 ret
= bmi088_accel_chip_init(data
, type
);
568 indio_dev
->channels
= data
->chip_info
->channels
;
569 indio_dev
->num_channels
= data
->chip_info
->num_channels
;
570 indio_dev
->name
= data
->chip_info
->name
;
571 indio_dev
->available_scan_masks
= bmi088_accel_scan_masks
;
572 indio_dev
->modes
= INDIO_DIRECT_MODE
;
573 indio_dev
->info
= &bmi088_accel_info
;
575 /* Enable runtime PM */
576 pm_runtime_get_noresume(dev
);
577 pm_runtime_set_suspended(dev
);
578 pm_runtime_enable(dev
);
579 /* We need ~6ms to startup, so set the delay to 6 seconds */
580 pm_runtime_set_autosuspend_delay(dev
, 6000);
581 pm_runtime_use_autosuspend(dev
);
584 ret
= iio_device_register(indio_dev
);
586 dev_err(dev
, "Unable to register iio device\n");
590 EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_probe
, "IIO_BMI088");
593 void bmi088_accel_core_remove(struct device
*dev
)
595 struct iio_dev
*indio_dev
= dev_get_drvdata(dev
);
596 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
598 iio_device_unregister(indio_dev
);
600 pm_runtime_disable(dev
);
601 pm_runtime_set_suspended(dev
);
602 bmi088_accel_power_down(data
);
604 EXPORT_SYMBOL_NS_GPL(bmi088_accel_core_remove
, "IIO_BMI088");
606 static int bmi088_accel_runtime_suspend(struct device
*dev
)
608 struct iio_dev
*indio_dev
= dev_get_drvdata(dev
);
609 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
611 return bmi088_accel_power_down(data
);
614 static int bmi088_accel_runtime_resume(struct device
*dev
)
616 struct iio_dev
*indio_dev
= dev_get_drvdata(dev
);
617 struct bmi088_accel_data
*data
= iio_priv(indio_dev
);
619 return bmi088_accel_power_up(data
);
622 EXPORT_NS_GPL_RUNTIME_DEV_PM_OPS(bmi088_accel_pm_ops
,
623 bmi088_accel_runtime_suspend
,
624 bmi088_accel_runtime_resume
, NULL
,
627 MODULE_AUTHOR("Niek van Agt <niek.van.agt@topicproducts.com>");
628 MODULE_LICENSE("GPL v2");
629 MODULE_DESCRIPTION("BMI088 accelerometer driver (core)");