xref: /linux/drivers/iio/accel/adxl345_core.c (revision 3d0fe49454652117522f60bfbefb978ba0e5300b)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ADXL345 3-Axis Digital Accelerometer IIO core driver
4  *
5  * Copyright (c) 2017 Eva Rachel Retuya <eraretuya@gmail.com>
6  *
7  * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
8  */
9 
10 #include <linux/module.h>
11 #include <linux/property.h>
12 #include <linux/regmap.h>
13 #include <linux/units.h>
14 
15 #include <linux/iio/iio.h>
16 #include <linux/iio/sysfs.h>
17 
18 #include "adxl345.h"
19 
20 #define ADXL345_REG_DEVID		0x00
21 #define ADXL345_REG_OFSX		0x1e
22 #define ADXL345_REG_OFSY		0x1f
23 #define ADXL345_REG_OFSZ		0x20
24 #define ADXL345_REG_OFS_AXIS(index)	(ADXL345_REG_OFSX + (index))
25 #define ADXL345_REG_BW_RATE		0x2C
26 #define ADXL345_REG_POWER_CTL		0x2D
27 #define ADXL345_REG_DATA_FORMAT		0x31
28 #define ADXL345_REG_DATAX0		0x32
29 #define ADXL345_REG_DATAY0		0x34
30 #define ADXL345_REG_DATAZ0		0x36
31 #define ADXL345_REG_DATA_AXIS(index)	\
32 	(ADXL345_REG_DATAX0 + (index) * sizeof(__le16))
33 
34 #define ADXL345_BW_RATE			GENMASK(3, 0)
35 #define ADXL345_BASE_RATE_NANO_HZ	97656250LL
36 
37 #define ADXL345_POWER_CTL_MEASURE	BIT(3)
38 #define ADXL345_POWER_CTL_STANDBY	0x00
39 
40 #define ADXL345_DATA_FORMAT_FULL_RES	BIT(3) /* Up to 13-bits resolution */
41 #define ADXL345_DATA_FORMAT_2G		0
42 #define ADXL345_DATA_FORMAT_4G		1
43 #define ADXL345_DATA_FORMAT_8G		2
44 #define ADXL345_DATA_FORMAT_16G		3
45 
46 #define ADXL345_DEVID			0xE5
47 
48 struct adxl345_data {
49 	const struct adxl345_chip_info *info;
50 	struct regmap *regmap;
51 	u8 data_range;
52 };
53 
54 #define ADXL345_CHANNEL(index, axis) {					\
55 	.type = IIO_ACCEL,						\
56 	.modified = 1,							\
57 	.channel2 = IIO_MOD_##axis,					\
58 	.address = index,						\
59 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
60 		BIT(IIO_CHAN_INFO_CALIBBIAS),				\
61 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |		\
62 		BIT(IIO_CHAN_INFO_SAMP_FREQ),				\
63 }
64 
65 static const struct iio_chan_spec adxl345_channels[] = {
66 	ADXL345_CHANNEL(0, X),
67 	ADXL345_CHANNEL(1, Y),
68 	ADXL345_CHANNEL(2, Z),
69 };
70 
71 static int adxl345_read_raw(struct iio_dev *indio_dev,
72 			    struct iio_chan_spec const *chan,
73 			    int *val, int *val2, long mask)
74 {
75 	struct adxl345_data *data = iio_priv(indio_dev);
76 	__le16 accel;
77 	long long samp_freq_nhz;
78 	unsigned int regval;
79 	int ret;
80 
81 	switch (mask) {
82 	case IIO_CHAN_INFO_RAW:
83 		/*
84 		 * Data is stored in adjacent registers:
85 		 * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
86 		 * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
87 		 */
88 		ret = regmap_bulk_read(data->regmap,
89 				       ADXL345_REG_DATA_AXIS(chan->address),
90 				       &accel, sizeof(accel));
91 		if (ret < 0)
92 			return ret;
93 
94 		*val = sign_extend32(le16_to_cpu(accel), 12);
95 		return IIO_VAL_INT;
96 	case IIO_CHAN_INFO_SCALE:
97 		*val = 0;
98 		*val2 = data->info->uscale;
99 		return IIO_VAL_INT_PLUS_MICRO;
100 	case IIO_CHAN_INFO_CALIBBIAS:
101 		ret = regmap_read(data->regmap,
102 				  ADXL345_REG_OFS_AXIS(chan->address), &regval);
103 		if (ret < 0)
104 			return ret;
105 		/*
106 		 * 8-bit resolution at +/- 2g, that is 4x accel data scale
107 		 * factor
108 		 */
109 		*val = sign_extend32(regval, 7) * 4;
110 
111 		return IIO_VAL_INT;
112 	case IIO_CHAN_INFO_SAMP_FREQ:
113 		ret = regmap_read(data->regmap, ADXL345_REG_BW_RATE, &regval);
114 		if (ret < 0)
115 			return ret;
116 
117 		samp_freq_nhz = ADXL345_BASE_RATE_NANO_HZ <<
118 				(regval & ADXL345_BW_RATE);
119 		*val = div_s64_rem(samp_freq_nhz, NANOHZ_PER_HZ, val2);
120 
121 		return IIO_VAL_INT_PLUS_NANO;
122 	}
123 
124 	return -EINVAL;
125 }
126 
127 static int adxl345_write_raw(struct iio_dev *indio_dev,
128 			     struct iio_chan_spec const *chan,
129 			     int val, int val2, long mask)
130 {
131 	struct adxl345_data *data = iio_priv(indio_dev);
132 	s64 n;
133 
134 	switch (mask) {
135 	case IIO_CHAN_INFO_CALIBBIAS:
136 		/*
137 		 * 8-bit resolution at +/- 2g, that is 4x accel data scale
138 		 * factor
139 		 */
140 		return regmap_write(data->regmap,
141 				    ADXL345_REG_OFS_AXIS(chan->address),
142 				    val / 4);
143 	case IIO_CHAN_INFO_SAMP_FREQ:
144 		n = div_s64(val * NANOHZ_PER_HZ + val2,
145 			    ADXL345_BASE_RATE_NANO_HZ);
146 
147 		return regmap_update_bits(data->regmap, ADXL345_REG_BW_RATE,
148 					  ADXL345_BW_RATE,
149 					  clamp_val(ilog2(n), 0,
150 						    ADXL345_BW_RATE));
151 	}
152 
153 	return -EINVAL;
154 }
155 
156 static int adxl345_write_raw_get_fmt(struct iio_dev *indio_dev,
157 				     struct iio_chan_spec const *chan,
158 				     long mask)
159 {
160 	switch (mask) {
161 	case IIO_CHAN_INFO_CALIBBIAS:
162 		return IIO_VAL_INT;
163 	case IIO_CHAN_INFO_SAMP_FREQ:
164 		return IIO_VAL_INT_PLUS_NANO;
165 	default:
166 		return -EINVAL;
167 	}
168 }
169 
170 static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
171 "0.09765625 0.1953125 0.390625 0.78125 1.5625 3.125 6.25 12.5 25 50 100 200 400 800 1600 3200"
172 );
173 
174 static struct attribute *adxl345_attrs[] = {
175 	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
176 	NULL
177 };
178 
179 static const struct attribute_group adxl345_attrs_group = {
180 	.attrs = adxl345_attrs,
181 };
182 
183 static const struct iio_info adxl345_info = {
184 	.attrs		= &adxl345_attrs_group,
185 	.read_raw	= adxl345_read_raw,
186 	.write_raw	= adxl345_write_raw,
187 	.write_raw_get_fmt	= adxl345_write_raw_get_fmt,
188 };
189 
190 static int adxl345_powerup(void *regmap)
191 {
192 	return regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_MEASURE);
193 }
194 
195 static void adxl345_powerdown(void *regmap)
196 {
197 	regmap_write(regmap, ADXL345_REG_POWER_CTL, ADXL345_POWER_CTL_STANDBY);
198 }
199 
200 int adxl345_core_probe(struct device *dev, struct regmap *regmap)
201 {
202 	struct adxl345_data *data;
203 	struct iio_dev *indio_dev;
204 	u32 regval;
205 	int ret;
206 
207 	ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
208 	if (ret < 0)
209 		return dev_err_probe(dev, ret, "Error reading device ID\n");
210 
211 	if (regval != ADXL345_DEVID)
212 		return dev_err_probe(dev, -ENODEV, "Invalid device ID: %x, expected %x\n",
213 				     regval, ADXL345_DEVID);
214 
215 	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
216 	if (!indio_dev)
217 		return -ENOMEM;
218 
219 	data = iio_priv(indio_dev);
220 	data->regmap = regmap;
221 	/* Enable full-resolution mode */
222 	data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
223 	data->info = device_get_match_data(dev);
224 	if (!data->info)
225 		return -ENODEV;
226 
227 	ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
228 			   data->data_range);
229 	if (ret < 0)
230 		return dev_err_probe(dev, ret, "Failed to set data range\n");
231 
232 	indio_dev->name = data->info->name;
233 	indio_dev->info = &adxl345_info;
234 	indio_dev->modes = INDIO_DIRECT_MODE;
235 	indio_dev->channels = adxl345_channels;
236 	indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
237 
238 	/* Enable measurement mode */
239 	ret = adxl345_powerup(data->regmap);
240 	if (ret < 0)
241 		return dev_err_probe(dev, ret, "Failed to enable measurement mode\n");
242 
243 	ret = devm_add_action_or_reset(dev, adxl345_powerdown, data->regmap);
244 	if (ret < 0)
245 		return ret;
246 
247 	return devm_iio_device_register(dev, indio_dev);
248 }
249 EXPORT_SYMBOL_NS_GPL(adxl345_core_probe, IIO_ADXL345);
250 
251 MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
252 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
253 MODULE_LICENSE("GPL v2");
254