Merge tag 'drm-misc-next-2017-05-16' of git://anongit.freedesktop.org/git/drm-misc...
[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         .driver_module  = THIS_MODULE,
99         .read_raw       = adxl345_read_raw,
100 };
101
102 int adxl345_core_probe(struct device *dev, struct regmap *regmap,
103                        const char *name)
104 {
105         struct adxl345_data *data;
106         struct iio_dev *indio_dev;
107         u32 regval;
108         int ret;
109
110         ret = regmap_read(regmap, ADXL345_REG_DEVID, &regval);
111         if (ret < 0) {
112                 dev_err(dev, "Error reading device ID: %d\n", ret);
113                 return ret;
114         }
115
116         if (regval != ADXL345_DEVID) {
117                 dev_err(dev, "Invalid device ID: %x, expected %x\n",
118                         regval, ADXL345_DEVID);
119                 return -ENODEV;
120         }
121
122         indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
123         if (!indio_dev)
124                 return -ENOMEM;
125
126         data = iio_priv(indio_dev);
127         dev_set_drvdata(dev, indio_dev);
128         data->regmap = regmap;
129         /* Enable full-resolution mode */
130         data->data_range = ADXL345_DATA_FORMAT_FULL_RES;
131
132         ret = regmap_write(data->regmap, ADXL345_REG_DATA_FORMAT,
133                            data->data_range);
134         if (ret < 0) {
135                 dev_err(dev, "Failed to set data range: %d\n", ret);
136                 return ret;
137         }
138
139         indio_dev->dev.parent = dev;
140         indio_dev->name = name;
141         indio_dev->info = &adxl345_info;
142         indio_dev->modes = INDIO_DIRECT_MODE;
143         indio_dev->channels = adxl345_channels;
144         indio_dev->num_channels = ARRAY_SIZE(adxl345_channels);
145
146         /* Enable measurement mode */
147         ret = regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
148                            ADXL345_POWER_CTL_MEASURE);
149         if (ret < 0) {
150                 dev_err(dev, "Failed to enable measurement mode: %d\n", ret);
151                 return ret;
152         }
153
154         ret = iio_device_register(indio_dev);
155         if (ret < 0) {
156                 dev_err(dev, "iio_device_register failed: %d\n", ret);
157                 regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
158                              ADXL345_POWER_CTL_STANDBY);
159         }
160
161         return ret;
162 }
163 EXPORT_SYMBOL_GPL(adxl345_core_probe);
164
165 int adxl345_core_remove(struct device *dev)
166 {
167         struct iio_dev *indio_dev = dev_get_drvdata(dev);
168         struct adxl345_data *data = iio_priv(indio_dev);
169
170         iio_device_unregister(indio_dev);
171
172         return regmap_write(data->regmap, ADXL345_REG_POWER_CTL,
173                             ADXL345_POWER_CTL_STANDBY);
174 }
175 EXPORT_SYMBOL_GPL(adxl345_core_remove);
176
177 MODULE_AUTHOR("Eva Rachel Retuya <eraretuya@gmail.com>");
178 MODULE_DESCRIPTION("ADXL345 3-Axis Digital Accelerometer core driver");
179 MODULE_LICENSE("GPL v2");