xref: /linux/drivers/iio/accel/adxl313_core.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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 
16 static 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 
23 static 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 
31 const 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 };
35 EXPORT_SYMBOL_NS_GPL(adxl312_readable_regs_table, IIO_ADXL313);
36 
37 const 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 };
41 EXPORT_SYMBOL_NS_GPL(adxl313_readable_regs_table, IIO_ADXL313);
42 
43 const 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 };
47 EXPORT_SYMBOL_NS_GPL(adxl314_readable_regs_table, IIO_ADXL313);
48 
adxl312_check_id(struct device * dev,struct adxl313_data * data)49 static 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(data->regmap, ADXL313_REG_DEVID0, &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 
adxl313_check_id(struct device * dev,struct adxl313_data * data)65 static 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(data->regmap, ADXL313_REG_DEVID0, &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(data->regmap, ADXL313_REG_DEVID1, &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(data->regmap, ADXL313_REG_PARTID, &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 
98 const 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 };
124 EXPORT_SYMBOL_NS_GPL(adxl31x_chip_info, IIO_ADXL313);
125 
126 static 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 
134 static 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 
143 const 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 };
147 EXPORT_SYMBOL_NS_GPL(adxl312_writable_regs_table, IIO_ADXL313);
148 
149 const 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 };
153 EXPORT_SYMBOL_NS_GPL(adxl313_writable_regs_table, IIO_ADXL313);
154 
155 const 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 };
159 EXPORT_SYMBOL_NS_GPL(adxl314_writable_regs_table, IIO_ADXL313);
160 
161 static 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 
190 static 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 
adxl313_set_odr(struct adxl313_data * data,unsigned int freq1,unsigned int freq2)196 static 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(data->regmap, ADXL313_REG_BW_RATE,
211 				  ADXL313_RATE_MSK,
212 				  FIELD_PREP(ADXL313_RATE_MSK, ADXL313_RATE_BASE + i));
213 }
214 
adxl313_read_axis(struct adxl313_data * data,struct iio_chan_spec const * chan)215 static 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(data->regmap,
223 			       ADXL313_REG_DATA_AXIS(chan->address),
224 			       &data->transf_buf, sizeof(data->transf_buf));
225 	if (ret)
226 		goto unlock_ret;
227 
228 	ret = le16_to_cpu(data->transf_buf);
229 
230 unlock_ret:
231 	mutex_unlock(&data->lock);
232 	return ret;
233 }
234 
adxl313_read_freq_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)235 static 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 
adxl313_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)251 static 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(ret, 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(data->regmap,
275 				  ADXL313_REG_OFS_AXIS(chan->address), &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(regval, 7) * 4;
284 		return IIO_VAL_INT;
285 	case IIO_CHAN_INFO_SAMP_FREQ:
286 		ret = regmap_read(data->regmap, ADXL313_REG_BW_RATE, &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 
adxl313_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)299 static 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(data->regmap,
315 				    ADXL313_REG_OFS_AXIS(chan->address),
316 				    val / 4);
317 	case IIO_CHAN_INFO_SAMP_FREQ:
318 		return adxl313_set_odr(data, val, val2);
319 	default:
320 		return -EINVAL;
321 	}
322 }
323 
324 static 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 
adxl313_setup(struct device * dev,struct adxl313_data * data,int (* setup)(struct device *,struct regmap *))330 static 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(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(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(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(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  */
adxl313_core_probe(struct device * dev,struct regmap * regmap,const struct adxl313_chip_info * chip_info,int (* setup)(struct device *,struct regmap *))387 int 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(dev, 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 }
420 EXPORT_SYMBOL_NS_GPL(adxl313_core_probe, IIO_ADXL313);
421 
422 MODULE_AUTHOR("Lucas Stankus <lucas.p.stankus@gmail.com>");
423 MODULE_DESCRIPTION("ADXL313 3-Axis Digital Accelerometer core driver");
424 MODULE_LICENSE("GPL v2");
425