1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * BMA220 Digital triaxial acceleration sensor driver |
4 | * |
5 | * Copyright (c) 2016,2020 Intel Corporation. |
6 | */ |
7 | |
8 | #include <linux/bits.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/mod_devicetable.h> |
11 | #include <linux/module.h> |
12 | #include <linux/spi/spi.h> |
13 | |
14 | #include <linux/iio/buffer.h> |
15 | #include <linux/iio/iio.h> |
16 | #include <linux/iio/sysfs.h> |
17 | #include <linux/iio/trigger_consumer.h> |
18 | #include <linux/iio/triggered_buffer.h> |
19 | |
20 | #define BMA220_REG_ID 0x00 |
21 | #define BMA220_REG_ACCEL_X 0x02 |
22 | #define BMA220_REG_ACCEL_Y 0x03 |
23 | #define BMA220_REG_ACCEL_Z 0x04 |
24 | #define BMA220_REG_RANGE 0x11 |
25 | #define BMA220_REG_SUSPEND 0x18 |
26 | |
27 | #define BMA220_CHIP_ID 0xDD |
28 | #define BMA220_READ_MASK BIT(7) |
29 | #define BMA220_RANGE_MASK GENMASK(1, 0) |
30 | #define BMA220_SUSPEND_SLEEP 0xFF |
31 | #define BMA220_SUSPEND_WAKE 0x00 |
32 | |
33 | #define BMA220_DEVICE_NAME "bma220" |
34 | |
35 | #define BMA220_ACCEL_CHANNEL(index, reg, axis) { \ |
36 | .type = IIO_ACCEL, \ |
37 | .address = reg, \ |
38 | .modified = 1, \ |
39 | .channel2 = IIO_MOD_##axis, \ |
40 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
41 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
42 | .scan_index = index, \ |
43 | .scan_type = { \ |
44 | .sign = 's', \ |
45 | .realbits = 6, \ |
46 | .storagebits = 8, \ |
47 | .shift = 2, \ |
48 | .endianness = IIO_CPU, \ |
49 | }, \ |
50 | } |
51 | |
52 | enum bma220_axis { |
53 | AXIS_X, |
54 | AXIS_Y, |
55 | AXIS_Z, |
56 | }; |
57 | |
58 | static const int bma220_scale_table[][2] = { |
59 | {0, 623000}, {1, 248000}, {2, 491000}, {4, 983000}, |
60 | }; |
61 | |
62 | struct bma220_data { |
63 | struct spi_device *spi_device; |
64 | struct mutex lock; |
65 | struct { |
66 | s8 chans[3]; |
67 | /* Ensure timestamp is naturally aligned. */ |
68 | s64 timestamp __aligned(8); |
69 | } scan; |
70 | u8 tx_buf[2] __aligned(IIO_DMA_MINALIGN); |
71 | }; |
72 | |
73 | static const struct iio_chan_spec bma220_channels[] = { |
74 | BMA220_ACCEL_CHANNEL(0, BMA220_REG_ACCEL_X, X), |
75 | BMA220_ACCEL_CHANNEL(1, BMA220_REG_ACCEL_Y, Y), |
76 | BMA220_ACCEL_CHANNEL(2, BMA220_REG_ACCEL_Z, Z), |
77 | IIO_CHAN_SOFT_TIMESTAMP(3), |
78 | }; |
79 | |
80 | static inline int bma220_read_reg(struct spi_device *spi, u8 reg) |
81 | { |
82 | return spi_w8r8(spi, cmd: reg | BMA220_READ_MASK); |
83 | } |
84 | |
85 | static const unsigned long bma220_accel_scan_masks[] = { |
86 | BIT(AXIS_X) | BIT(AXIS_Y) | BIT(AXIS_Z), |
87 | 0 |
88 | }; |
89 | |
90 | static irqreturn_t bma220_trigger_handler(int irq, void *p) |
91 | { |
92 | int ret; |
93 | struct iio_poll_func *pf = p; |
94 | struct iio_dev *indio_dev = pf->indio_dev; |
95 | struct bma220_data *data = iio_priv(indio_dev); |
96 | struct spi_device *spi = data->spi_device; |
97 | |
98 | mutex_lock(&data->lock); |
99 | data->tx_buf[0] = BMA220_REG_ACCEL_X | BMA220_READ_MASK; |
100 | ret = spi_write_then_read(spi, txbuf: data->tx_buf, n_tx: 1, rxbuf: &data->scan.chans, |
101 | ARRAY_SIZE(bma220_channels) - 1); |
102 | if (ret < 0) |
103 | goto err; |
104 | |
105 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
106 | timestamp: pf->timestamp); |
107 | err: |
108 | mutex_unlock(lock: &data->lock); |
109 | iio_trigger_notify_done(trig: indio_dev->trig); |
110 | |
111 | return IRQ_HANDLED; |
112 | } |
113 | |
114 | static int bma220_read_raw(struct iio_dev *indio_dev, |
115 | struct iio_chan_spec const *chan, |
116 | int *val, int *val2, long mask) |
117 | { |
118 | int ret; |
119 | u8 range_idx; |
120 | struct bma220_data *data = iio_priv(indio_dev); |
121 | |
122 | switch (mask) { |
123 | case IIO_CHAN_INFO_RAW: |
124 | ret = bma220_read_reg(spi: data->spi_device, reg: chan->address); |
125 | if (ret < 0) |
126 | return -EINVAL; |
127 | *val = sign_extend32(value: ret >> chan->scan_type.shift, |
128 | index: chan->scan_type.realbits - 1); |
129 | return IIO_VAL_INT; |
130 | case IIO_CHAN_INFO_SCALE: |
131 | ret = bma220_read_reg(spi: data->spi_device, BMA220_REG_RANGE); |
132 | if (ret < 0) |
133 | return ret; |
134 | range_idx = ret & BMA220_RANGE_MASK; |
135 | *val = bma220_scale_table[range_idx][0]; |
136 | *val2 = bma220_scale_table[range_idx][1]; |
137 | return IIO_VAL_INT_PLUS_MICRO; |
138 | } |
139 | |
140 | return -EINVAL; |
141 | } |
142 | |
143 | static int bma220_write_raw(struct iio_dev *indio_dev, |
144 | struct iio_chan_spec const *chan, |
145 | int val, int val2, long mask) |
146 | { |
147 | int i; |
148 | int ret; |
149 | int index = -1; |
150 | struct bma220_data *data = iio_priv(indio_dev); |
151 | |
152 | switch (mask) { |
153 | case IIO_CHAN_INFO_SCALE: |
154 | for (i = 0; i < ARRAY_SIZE(bma220_scale_table); i++) |
155 | if (val == bma220_scale_table[i][0] && |
156 | val2 == bma220_scale_table[i][1]) { |
157 | index = i; |
158 | break; |
159 | } |
160 | if (index < 0) |
161 | return -EINVAL; |
162 | |
163 | mutex_lock(&data->lock); |
164 | data->tx_buf[0] = BMA220_REG_RANGE; |
165 | data->tx_buf[1] = index; |
166 | ret = spi_write(spi: data->spi_device, buf: data->tx_buf, |
167 | len: sizeof(data->tx_buf)); |
168 | if (ret < 0) |
169 | dev_err(&data->spi_device->dev, |
170 | "failed to set measurement range\n" ); |
171 | mutex_unlock(lock: &data->lock); |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | return -EINVAL; |
177 | } |
178 | |
179 | static int bma220_read_avail(struct iio_dev *indio_dev, |
180 | struct iio_chan_spec const *chan, |
181 | const int **vals, int *type, int *length, |
182 | long mask) |
183 | { |
184 | switch (mask) { |
185 | case IIO_CHAN_INFO_SCALE: |
186 | *vals = (int *)bma220_scale_table; |
187 | *type = IIO_VAL_INT_PLUS_MICRO; |
188 | *length = ARRAY_SIZE(bma220_scale_table) * 2; |
189 | return IIO_AVAIL_LIST; |
190 | default: |
191 | return -EINVAL; |
192 | } |
193 | } |
194 | |
195 | static const struct iio_info bma220_info = { |
196 | .read_raw = bma220_read_raw, |
197 | .write_raw = bma220_write_raw, |
198 | .read_avail = bma220_read_avail, |
199 | }; |
200 | |
201 | static int bma220_init(struct spi_device *spi) |
202 | { |
203 | int ret; |
204 | |
205 | ret = bma220_read_reg(spi, BMA220_REG_ID); |
206 | if (ret != BMA220_CHIP_ID) |
207 | return -ENODEV; |
208 | |
209 | /* Make sure the chip is powered on */ |
210 | ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
211 | if (ret == BMA220_SUSPEND_WAKE) |
212 | ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
213 | if (ret < 0) |
214 | return ret; |
215 | if (ret == BMA220_SUSPEND_WAKE) |
216 | return -EBUSY; |
217 | |
218 | return 0; |
219 | } |
220 | |
221 | static int bma220_power(struct spi_device *spi, bool up) |
222 | { |
223 | int i, ret; |
224 | |
225 | /** |
226 | * The chip can be suspended/woken up by a simple register read. |
227 | * So, we need up to 2 register reads of the suspend register |
228 | * to make sure that the device is in the desired state. |
229 | */ |
230 | for (i = 0; i < 2; i++) { |
231 | ret = bma220_read_reg(spi, BMA220_REG_SUSPEND); |
232 | if (ret < 0) |
233 | return ret; |
234 | |
235 | if (up && ret == BMA220_SUSPEND_SLEEP) |
236 | return 0; |
237 | |
238 | if (!up && ret == BMA220_SUSPEND_WAKE) |
239 | return 0; |
240 | } |
241 | |
242 | return -EBUSY; |
243 | } |
244 | |
245 | static void bma220_deinit(void *spi) |
246 | { |
247 | bma220_power(spi, up: false); |
248 | } |
249 | |
250 | static int bma220_probe(struct spi_device *spi) |
251 | { |
252 | int ret; |
253 | struct iio_dev *indio_dev; |
254 | struct bma220_data *data; |
255 | |
256 | indio_dev = devm_iio_device_alloc(parent: &spi->dev, sizeof_priv: sizeof(*data)); |
257 | if (!indio_dev) { |
258 | dev_err(&spi->dev, "iio allocation failed!\n" ); |
259 | return -ENOMEM; |
260 | } |
261 | |
262 | data = iio_priv(indio_dev); |
263 | data->spi_device = spi; |
264 | mutex_init(&data->lock); |
265 | |
266 | indio_dev->info = &bma220_info; |
267 | indio_dev->name = BMA220_DEVICE_NAME; |
268 | indio_dev->modes = INDIO_DIRECT_MODE; |
269 | indio_dev->channels = bma220_channels; |
270 | indio_dev->num_channels = ARRAY_SIZE(bma220_channels); |
271 | indio_dev->available_scan_masks = bma220_accel_scan_masks; |
272 | |
273 | ret = bma220_init(spi: data->spi_device); |
274 | if (ret) |
275 | return ret; |
276 | |
277 | ret = devm_add_action_or_reset(&spi->dev, bma220_deinit, spi); |
278 | if (ret) |
279 | return ret; |
280 | |
281 | ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, |
282 | iio_pollfunc_store_time, |
283 | bma220_trigger_handler, NULL); |
284 | if (ret < 0) { |
285 | dev_err(&spi->dev, "iio triggered buffer setup failed\n" ); |
286 | return ret; |
287 | } |
288 | |
289 | return devm_iio_device_register(&spi->dev, indio_dev); |
290 | } |
291 | |
292 | static int bma220_suspend(struct device *dev) |
293 | { |
294 | struct spi_device *spi = to_spi_device(dev); |
295 | |
296 | return bma220_power(spi, up: false); |
297 | } |
298 | |
299 | static int bma220_resume(struct device *dev) |
300 | { |
301 | struct spi_device *spi = to_spi_device(dev); |
302 | |
303 | return bma220_power(spi, up: true); |
304 | } |
305 | static DEFINE_SIMPLE_DEV_PM_OPS(bma220_pm_ops, bma220_suspend, bma220_resume); |
306 | |
307 | static const struct spi_device_id bma220_spi_id[] = { |
308 | {"bma220" , 0}, |
309 | {} |
310 | }; |
311 | |
312 | static const struct acpi_device_id bma220_acpi_id[] = { |
313 | {"BMA0220" , 0}, |
314 | {} |
315 | }; |
316 | MODULE_DEVICE_TABLE(spi, bma220_spi_id); |
317 | |
318 | static struct spi_driver bma220_driver = { |
319 | .driver = { |
320 | .name = "bma220_spi" , |
321 | .pm = pm_sleep_ptr(&bma220_pm_ops), |
322 | .acpi_match_table = bma220_acpi_id, |
323 | }, |
324 | .probe = bma220_probe, |
325 | .id_table = bma220_spi_id, |
326 | }; |
327 | module_spi_driver(bma220_driver); |
328 | |
329 | MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>" ); |
330 | MODULE_DESCRIPTION("BMA220 acceleration sensor driver" ); |
331 | MODULE_LICENSE("GPL v2" ); |
332 | |