Merge tag 'configfs-for-4.15' of git://git.infradead.org/users/hch/configfs
[sfrench/cifs-2.6.git] / drivers / iio / accel / adxl345_core.c
1 /*
2  * ADXL345 3-Axis Digital Accelerometer IIO core driver
3  *
4  * Copyright (c) 2017 Eva Rachel Retuya <eraretuya@gmail.com>
5  *
6  * This file is subject to the terms and conditions of version 2 of
7  * the GNU General Public License. See the file COPYING in the main
8  * directory of this archive for more details.
9  */
10
11 #include <linux/module.h>
12 #include <linux/regmap.h>
13
14 #include <linux/iio/iio.h>
15
16 #include "adxl345.h"
17
18 #define ADXL345_REG_DEVID               0x00
19 #define ADXL345_REG_POWER_CTL           0x2D
20 #define ADXL345_REG_DATA_FORMAT         0x31
21 #define ADXL345_REG_DATAX0              0x32
22 #define ADXL345_REG_DATAY0              0x34
23 #define ADXL345_REG_DATAZ0              0x36
24
25 #define ADXL345_POWER_CTL_MEASURE       BIT(3)
26 #define ADXL345_POWER_CTL_STANDBY       0x00
27
28 #define ADXL345_DATA_FORMAT_FULL_RES    BIT(3) /* Up to 13-bits resolution */
29 #define ADXL345_DATA_FORMAT_2G          0
30 #define ADXL345_DATA_FORMAT_4G          1
31 #define ADXL345_DATA_FORMAT_8G          2
32 #define ADXL345_DATA_FORMAT_16G         3
33
34 #define ADXL345_DEVID                   0xE5
35
36 /*
37  * In full-resolution mode, scale factor is maintained at ~4 mg/LSB
38  * in all g ranges.
39  *
40  * At +/- 16g with 13-bit resolution, scale is computed as:
41  * (16 + 16) * 9.81 / (2^13 - 1) = 0.0383
42  */
43 static const int adxl345_uscale = 38300;
44
45 struct adxl345_data {
46         struct regmap *regmap;
47         u8 data_range;
48 };
49
50 #define ADXL345_CHANNEL(reg, axis) {                                    \
51         .type = IIO_ACCEL,                                              \
52         .modified = 1,                                                  \
53         .channel2 = IIO_MOD_##axis,                                     \
54         .address = reg,                                                 \
55         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),                   \
56         .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
57 }
58
59 static const struct iio_chan_spec adxl345_channels[] = {
60         ADXL345_CHANNEL(ADXL345_REG_DATAX0, X),
61         ADXL345_CHANNEL(ADXL345_REG_DATAY0, Y),
62         ADXL345_CHANNEL(ADXL345_REG_DATAZ0, Z),
63 };
64
65 static int adxl345_read_raw(struct iio_dev *indio_dev,
66                             struct iio_chan_spec const *chan,
67                             int *val, int *val2, long mask)
68 {
69         struct adxl345_data *data = iio_priv(indio_dev);
70         __le16 regval;
71         int ret;
72
73         switch (mask) {
74         case IIO_CHAN_INFO_RAW:
75                 /*
76                  * Data is stored in adjacent registers:
77                  * ADXL345_REG_DATA(X0/Y0/Z0) contain the least significant byte
78                  * and ADXL345_REG_DATA(X0/Y0/Z0) + 1 the most significant byte
79                  */
80                 ret = regmap_bulk_read(data->regmap, chan->address, &regval,
81                                        sizeof(regval));
82                 if (ret < 0)
83                         return ret;
84
85                 *val = sign_extend32(le16_to_cpu(regval), 12);
86                 return IIO_VAL_INT;
87         case IIO_CHAN_INFO_SCALE:
88                 *val = 0;
89                 *val2 = adxl345_uscale;
90
91                 return IIO_VAL_INT_PLUS_MICRO;
92         }
93
94         return -EINVAL;
95 }
96
97 static const struct iio_info adxl345_info = {
98         .read_raw       = adxl345_read_raw,
99 };
100
101 int adxl345_core_probe(struct device *dev, struct regmap *regmap,
102                        const char *name)
103 {
104         struct adxl345_data *data;
105         struct iio_dev *indio_dev;
106         u32 regval;
107         int ret;
108
109         ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
110         if (ret < 0) {
111                 dev_err(dev, "Error reading device ID: %d\n", ret);
112                 return ret;
113         }
114
115         if (regval != ADXL345_DEVID) {
116                 dev_err(dev, "Invalid device ID: %x, expected %x\n",
117                         regval, ADXL345_DEVID);
118                 return -ENODEV;
119         }
120
121         indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
122         if (!indio_dev)
123                 return -ENOMEM;
124
125         data = iio_priv(indio_dev);
126         dev_set_drvdata(dev, indio_dev);
127         data->regmap = regmap;
128         /* Enable full-resolution mode */
129         data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
130
131         ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
132                            data->data_range);
133         if (ret < 0) {
134                 dev_err(dev, "Failed to set data range: %d\n", ret);
135                 return ret;
136         }
137
138         indio_dev->dev.parent = dev;
139         indio_dev->name = name;
140         indio_dev->info = &adxl345_info;
141         indio_dev->modes = INDIO_DIRECT_MODE;
142         indio_dev->channels = adxl345_channels;
143         indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
144
145         /* Enable measurement mode */
146         ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
147                            ADXL345_POWER_CTL_MEASURE);
148         if (ret < 0) {
149                 dev_err(dev, "Failed to enable measurement mode: %d\n", ret);
150                 return ret;
151         }
152
153         ret = iio_device_register(indio_dev);
154         if (ret < 0) {
155                 dev_err(dev, "iio_device_register failed: %d\n", ret);
156                 regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
157                              ADXL345_POWER_CTL_STANDBY);
158         }
159
160         return ret;
161 }
162 EXPORT_SYMBOL_GPL(adxl345_core_probe);
163
164 int adxl345_core_remove(struct device *dev)
165 {
166         struct iio_dev *indio_dev = dev_get_drvdata(dev);
167         struct adxl345_data *data = iio_priv(indio_dev);
168
169         iio_device_unregister(indio_dev);
170
171         return regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
172                             ADXL345_POWER_CTL_STANDBY);
173 }
174 EXPORT_SYMBOL_GPL(adxl345_core_remove);
175
176 MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
177 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
178 MODULE_LICENSE("GPL v2");