1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * ADXL313 3-Axis Digital Accelerometer
4 *
5 * Copyright (c) 2021 Lucas Stankus <lucas.p.stankus@gmail.com>
6 *
7 * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL313.pdf
8 */
9
10#include <linux/bitfield.h>
11#include <linux/module.h>
12#include <linux/regmap.h>
13
14#include "adxl313.h"
15
16static const struct regmap_range adxl312_readable_reg_range[] = {
17 regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_DEVID0),
18 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
19 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
20 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),
21};
22
23static const struct regmap_range adxl313_readable_reg_range[] = {
24 regmap_reg_range(ADXL313_REG_DEVID0, ADXL313_REG_XID),
25 regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
26 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
27 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
28 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_FIFO_STATUS),
29};
30
31const struct regmap_access_table adxl312_readable_regs_table = {
32 .yes_ranges = adxl312_readable_reg_range,
33 .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range),
34};
35EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, IIO_ADXL313);
36
37const struct regmap_access_table adxl313_readable_regs_table = {
38 .yes_ranges = adxl313_readable_reg_range,
39 .n_yes_ranges = ARRAY_SIZE(adxl313_readable_reg_range),
40};
41EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313);
42
43const struct regmap_access_table adxl314_readable_regs_table = {
44 .yes_ranges = adxl312_readable_reg_range,
45 .n_yes_ranges = ARRAY_SIZE(adxl312_readable_reg_range),
46};
47EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, IIO_ADXL313);
48
49static int adxl312_check_id(struct device *dev,
50 struct adxl313_data *data)
51{
52 unsigned int regval;
53 int ret;
54
55 ret = regmap_read(map: data->regmap, ADXL313_REG_DEVID0, val: &regval);
56 if (ret)
57 return ret;
58
59 if (regval != ADXL313_DEVID0_ADXL312_314)
60 dev_warn(dev, "Invalid manufacturer ID: %#02x\n", regval);
61
62 return 0;
63}
64
65static int adxl313_check_id(struct device *dev,
66 struct adxl313_data *data)
67{
68 unsigned int regval;
69 int ret;
70
71 ret = regmap_read(map: data->regmap, ADXL313_REG_DEVID0, val: &regval);
72 if (ret)
73 return ret;
74
75 if (regval != ADXL313_DEVID0)
76 dev_warn(dev, "Invalid manufacturer ID: 0x%02x\n", regval);
77
78 /* Check DEVID1 and PARTID */
79 if (regval == ADXL313_DEVID0) {
80 ret = regmap_read(map: data->regmap, ADXL313_REG_DEVID1, val: &regval);
81 if (ret)
82 return ret;
83
84 if (regval != ADXL313_DEVID1)
85 dev_warn(dev, "Invalid mems ID: 0x%02x\n", regval);
86
87 ret = regmap_read(map: data->regmap, ADXL313_REG_PARTID, val: &regval);
88 if (ret)
89 return ret;
90
91 if (regval != ADXL313_PARTID)
92 dev_warn(dev, "Invalid device ID: 0x%02x\n", regval);
93 }
94
95 return 0;
96}
97
98const struct adxl313_chip_info adxl31x_chip_info[] = {
99 [ADXL312] = {
100 .name = "adxl312",
101 .type = ADXL312,
102 .scale_factor = 28425072,
103 .variable_range = true,
104 .soft_reset = false,
105 .check_id = &adxl312_check_id,
106 },
107 [ADXL313] = {
108 .name = "adxl313",
109 .type = ADXL313,
110 .scale_factor = 9576806,
111 .variable_range = true,
112 .soft_reset = true,
113 .check_id = &adxl313_check_id,
114 },
115 [ADXL314] = {
116 .name = "adxl314",
117 .type = ADXL314,
118 .scale_factor = 478858719,
119 .variable_range = false,
120 .soft_reset = false,
121 .check_id = &adxl312_check_id,
122 },
123};
124EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, IIO_ADXL313);
125
126static const struct regmap_range adxl312_writable_reg_range[] = {
127 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
128 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
129 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),
130 regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),
131 regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),
132};
133
134static const struct regmap_range adxl313_writable_reg_range[] = {
135 regmap_reg_range(ADXL313_REG_SOFT_RESET, ADXL313_REG_SOFT_RESET),
136 regmap_reg_range(ADXL313_REG_OFS_AXIS(0), ADXL313_REG_OFS_AXIS(2)),
137 regmap_reg_range(ADXL313_REG_THRESH_ACT, ADXL313_REG_ACT_INACT_CTL),
138 regmap_reg_range(ADXL313_REG_BW_RATE, ADXL313_REG_INT_MAP),
139 regmap_reg_range(ADXL313_REG_DATA_FORMAT, ADXL313_REG_DATA_FORMAT),
140 regmap_reg_range(ADXL313_REG_FIFO_CTL, ADXL313_REG_FIFO_CTL),
141};
142
143const struct regmap_access_table adxl312_writable_regs_table = {
144 .yes_ranges = adxl312_writable_reg_range,
145 .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range),
146};
147EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, IIO_ADXL313);
148
149const struct regmap_access_table adxl313_writable_regs_table = {
150 .yes_ranges = adxl313_writable_reg_range,
151 .n_yes_ranges = ARRAY_SIZE(adxl313_writable_reg_range),
152};
153EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313);
154
155const struct regmap_access_table adxl314_writable_regs_table = {
156 .yes_ranges = adxl312_writable_reg_range,
157 .n_yes_ranges = ARRAY_SIZE(adxl312_writable_reg_range),
158};
159EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, IIO_ADXL313);
160
161static const int adxl313_odr_freqs[][2] = {
162 [0] = { 6, 250000 },
163 [1] = { 12, 500000 },
164 [2] = { 25, 0 },
165 [3] = { 50, 0 },
166 [4] = { 100, 0 },
167 [5] = { 200, 0 },
168 [6] = { 400, 0 },
169 [7] = { 800, 0 },
170 [8] = { 1600, 0 },
171 [9] = { 3200, 0 },
172};
173
174#define ADXL313_ACCEL_CHANNEL(index, axis) { \
175 .type = IIO_ACCEL, \
176 .address = index, \
177 .modified = 1, \
178 .channel2 = IIO_MOD_##axis, \
179 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
180 BIT(IIO_CHAN_INFO_CALIBBIAS), \
181 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
182 BIT(IIO_CHAN_INFO_SAMP_FREQ), \
183 .info_mask_shared_by_type_available = \
184 BIT(IIO_CHAN_INFO_SAMP_FREQ), \
185 .scan_type = { \
186 .realbits = 13, \
187 }, \
188}
189
190static const struct iio_chan_spec adxl313_channels[] = {
191 ADXL313_ACCEL_CHANNEL(0, X),
192 ADXL313_ACCEL_CHANNEL(1, Y),
193 ADXL313_ACCEL_CHANNEL(2, Z),
194};
195
196static int adxl313_set_odr(struct adxl313_data *data,
197 unsigned int freq1, unsigned int freq2)
198{
199 unsigned int i;
200
201 for (i = 0; i < ARRAY_SIZE(adxl313_odr_freqs); i++) {
202 if (adxl313_odr_freqs[i][0] == freq1 &&
203 adxl313_odr_freqs[i][1] == freq2)
204 break;
205 }
206
207 if (i == ARRAY_SIZE(adxl313_odr_freqs))
208 return -EINVAL;
209
210 return regmap_update_bits(map: data->regmap, ADXL313_REG_BW_RATE,
211 ADXL313_RATE_MSK,
212 FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i));
213}
214
215static int adxl313_read_axis(struct adxl313_data *data,
216 struct iio_chan_spec const *chan)
217{
218 int ret;
219
220 mutex_lock(&data->lock);
221
222 ret = regmap_bulk_read(map: data->regmap,
223 ADXL313_REG_DATA_AXIS(chan->address),
224 val: &data->transf_buf, val_count: sizeof(data->transf_buf));
225 if (ret)
226 goto unlock_ret;
227
228 ret = le16_to_cpu(data->transf_buf);
229
230unlock_ret:
231 mutex_unlock(lock: &data->lock);
232 return ret;
233}
234
235static int adxl313_read_freq_avail(struct iio_dev *indio_dev,
236 struct iio_chan_spec const *chan,
237 const int **vals, int *type, int *length,
238 long mask)
239{
240 switch (mask) {
241 case IIO_CHAN_INFO_SAMP_FREQ:
242 *vals = (const int *)adxl313_odr_freqs;
243 *length = ARRAY_SIZE(adxl313_odr_freqs) * 2;
244 *type = IIO_VAL_INT_PLUS_MICRO;
245 return IIO_AVAIL_LIST;
246 default:
247 return -EINVAL;
248 }
249}
250
251static int adxl313_read_raw(struct iio_dev *indio_dev,
252 struct iio_chan_spec const *chan,
253 int *val, int *val2, long mask)
254{
255 struct adxl313_data *data = iio_priv(indio_dev);
256 unsigned int regval;
257 int ret;
258
259 switch (mask) {
260 case IIO_CHAN_INFO_RAW:
261 ret = adxl313_read_axis(data, chan);
262 if (ret < 0)
263 return ret;
264
265 *val = sign_extend32(value: ret, index: chan->scan_type.realbits - 1);
266 return IIO_VAL_INT;
267 case IIO_CHAN_INFO_SCALE:
268 *val = 0;
269
270 *val2 = data->chip_info->scale_factor;
271
272 return IIO_VAL_INT_PLUS_NANO;
273 case IIO_CHAN_INFO_CALIBBIAS:
274 ret = regmap_read(map: data->regmap,
275 ADXL313_REG_OFS_AXIS(chan->address), val: &regval);
276 if (ret)
277 return ret;
278
279 /*
280 * 8-bit resolution at minimum range, that is 4x accel data scale
281 * factor at full resolution
282 */
283 *val = sign_extend32(value: regval, index: 7) * 4;
284 return IIO_VAL_INT;
285 case IIO_CHAN_INFO_SAMP_FREQ:
286 ret = regmap_read(map: data->regmap, ADXL313_REG_BW_RATE, val: &regval);
287 if (ret)
288 return ret;
289
290 ret = FIELD_GET(ADXL313_RATE_MSK, regval) - ADXL313_RATE_BASE;
291 *val = adxl313_odr_freqs[ret][0];
292 *val2 = adxl313_odr_freqs[ret][1];
293 return IIO_VAL_INT_PLUS_MICRO;
294 default:
295 return -EINVAL;
296 }
297}
298
299static int adxl313_write_raw(struct iio_dev *indio_dev,
300 struct iio_chan_spec const *chan,
301 int val, int val2, long mask)
302{
303 struct adxl313_data *data = iio_priv(indio_dev);
304
305 switch (mask) {
306 case IIO_CHAN_INFO_CALIBBIAS:
307 /*
308 * 8-bit resolution at minimum range, that is 4x accel data scale
309 * factor at full resolution
310 */
311 if (clamp_val(val, -128 * 4, 127 * 4) != val)
312 return -EINVAL;
313
314 return regmap_write(map: data->regmap,
315 ADXL313_REG_OFS_AXIS(chan->address),
316 val: val / 4);
317 case IIO_CHAN_INFO_SAMP_FREQ:
318 return adxl313_set_odr(data, freq1: val, freq2: val2);
319 default:
320 return -EINVAL;
321 }
322}
323
324static const struct iio_info adxl313_info = {
325 .read_raw = adxl313_read_raw,
326 .write_raw = adxl313_write_raw,
327 .read_avail = adxl313_read_freq_avail,
328};
329
330static int adxl313_setup(struct device *dev, struct adxl313_data *data,
331 int (*setup)(struct device *, struct regmap *))
332{
333 int ret;
334
335 /*
336 * If sw reset available, ensures the device is in a consistent
337 * state after start up
338 */
339 if (data->chip_info->soft_reset) {
340 ret = regmap_write(map: data->regmap, ADXL313_REG_SOFT_RESET,
341 ADXL313_SOFT_RESET);
342 if (ret)
343 return ret;
344 }
345
346 if (setup) {
347 ret = setup(dev, data->regmap);
348 if (ret)
349 return ret;
350 }
351
352 ret = data->chip_info->check_id(dev, data);
353 if (ret)
354 return ret;
355
356 /* Sets the range to maximum, full resolution, if applicable */
357 if (data->chip_info->variable_range) {
358 ret = regmap_update_bits(map: data->regmap, ADXL313_REG_DATA_FORMAT,
359 ADXL313_RANGE_MSK,
360 FIELD_PREP(ADXL313_RANGE_MSK, ADXL313_RANGE_MAX));
361 if (ret)
362 return ret;
363
364 /* Enables full resolution */
365 ret = regmap_update_bits(map: data->regmap, ADXL313_REG_DATA_FORMAT,
366 ADXL313_FULL_RES, ADXL313_FULL_RES);
367 if (ret)
368 return ret;
369 }
370
371 /* Enables measurement mode */
372 return regmap_update_bits(map: data->regmap, ADXL313_REG_POWER_CTL,
373 ADXL313_POWER_CTL_MSK,
374 ADXL313_MEASUREMENT_MODE);
375}
376
377/**
378 * adxl313_core_probe() - probe and setup for adxl313 accelerometer
379 * @dev: Driver model representation of the device
380 * @regmap: Register map of the device
381 * @chip_info: Structure containing device specific data
382 * @setup: Setup routine to be executed right before the standard device
383 * setup, can also be set to NULL if not required
384 *
385 * Return: 0 on success, negative errno on error cases
386 */
387int adxl313_core_probe(struct device *dev,
388 struct regmap *regmap,
389 const struct adxl313_chip_info *chip_info,
390 int (*setup)(struct device *, struct regmap *))
391{
392 struct adxl313_data *data;
393 struct iio_dev *indio_dev;
394 int ret;
395
396 indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data));
397 if (!indio_dev)
398 return -ENOMEM;
399
400 data = iio_priv(indio_dev);
401 data->regmap = regmap;
402 data->chip_info = chip_info;
403
404 mutex_init(&data->lock);
405
406 indio_dev->name = chip_info->name;
407 indio_dev->info = &adxl313_info;
408 indio_dev->modes = INDIO_DIRECT_MODE;
409 indio_dev->channels = adxl313_channels;
410 indio_dev->num_channels = ARRAY_SIZE(adxl313_channels);
411
412 ret = adxl313_setup(dev, data, setup);
413 if (ret) {
414 dev_err(dev, "ADXL313 setup failed\n");
415 return ret;
416 }
417
418 return devm_iio_device_register(dev, indio_dev);
419}
420EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313);
421
422MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
423MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");
424MODULE_LICENSE("GPL v2");
425

source code of linux/drivers/iio/accel/adxl313_core.c