1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * IIO driver for the MiraMEMS DA311 3-axis accelerometer |
4 | * |
5 | * Copyright (c) 2016 Hans de Goede <hdegoede@redhat.com> |
6 | * Copyright (c) 2011-2013 MiraMEMS Sensing Technology Co., Ltd. |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/i2c.h> |
11 | #include <linux/iio/iio.h> |
12 | #include <linux/iio/sysfs.h> |
13 | #include <linux/byteorder/generic.h> |
14 | |
15 | #define DA311_CHIP_ID 0x13 |
16 | |
17 | /* |
18 | * Note register addressed go from 0 - 0x3f and then wrap. |
19 | * For some reason there are 2 banks with 0 - 0x3f addresses, |
20 | * rather then a single 0-0x7f bank. |
21 | */ |
22 | |
23 | /* Bank 0 regs */ |
24 | #define DA311_REG_BANK 0x0000 |
25 | #define DA311_REG_LDO_REG 0x0006 |
26 | #define DA311_REG_CHIP_ID 0x000f |
27 | #define DA311_REG_TEMP_CFG_REG 0x001f |
28 | #define DA311_REG_CTRL_REG1 0x0020 |
29 | #define DA311_REG_CTRL_REG3 0x0022 |
30 | #define DA311_REG_CTRL_REG4 0x0023 |
31 | #define DA311_REG_CTRL_REG5 0x0024 |
32 | #define DA311_REG_CTRL_REG6 0x0025 |
33 | #define DA311_REG_STATUS_REG 0x0027 |
34 | #define DA311_REG_OUT_X_L 0x0028 |
35 | #define DA311_REG_OUT_X_H 0x0029 |
36 | #define DA311_REG_OUT_Y_L 0x002a |
37 | #define DA311_REG_OUT_Y_H 0x002b |
38 | #define DA311_REG_OUT_Z_L 0x002c |
39 | #define DA311_REG_OUT_Z_H 0x002d |
40 | #define DA311_REG_INT1_CFG 0x0030 |
41 | #define DA311_REG_INT1_SRC 0x0031 |
42 | #define DA311_REG_INT1_THS 0x0032 |
43 | #define DA311_REG_INT1_DURATION 0x0033 |
44 | #define DA311_REG_INT2_CFG 0x0034 |
45 | #define DA311_REG_INT2_SRC 0x0035 |
46 | #define DA311_REG_INT2_THS 0x0036 |
47 | #define DA311_REG_INT2_DURATION 0x0037 |
48 | #define DA311_REG_CLICK_CFG 0x0038 |
49 | #define DA311_REG_CLICK_SRC 0x0039 |
50 | #define DA311_REG_CLICK_THS 0x003a |
51 | #define DA311_REG_TIME_LIMIT 0x003b |
52 | #define DA311_REG_TIME_LATENCY 0x003c |
53 | #define DA311_REG_TIME_WINDOW 0x003d |
54 | |
55 | /* Bank 1 regs */ |
56 | #define DA311_REG_SOFT_RESET 0x0105 |
57 | #define DA311_REG_OTP_XOFF_L 0x0110 |
58 | #define DA311_REG_OTP_XOFF_H 0x0111 |
59 | #define DA311_REG_OTP_YOFF_L 0x0112 |
60 | #define DA311_REG_OTP_YOFF_H 0x0113 |
61 | #define DA311_REG_OTP_ZOFF_L 0x0114 |
62 | #define DA311_REG_OTP_ZOFF_H 0x0115 |
63 | #define DA311_REG_OTP_XSO 0x0116 |
64 | #define DA311_REG_OTP_YSO 0x0117 |
65 | #define DA311_REG_OTP_ZSO 0x0118 |
66 | #define DA311_REG_OTP_TRIM_OSC 0x011b |
67 | #define DA311_REG_LPF_ABSOLUTE 0x011c |
68 | #define DA311_REG_TEMP_OFF1 0x0127 |
69 | #define DA311_REG_TEMP_OFF2 0x0128 |
70 | #define DA311_REG_TEMP_OFF3 0x0129 |
71 | #define DA311_REG_OTP_TRIM_THERM_H 0x011a |
72 | |
73 | /* |
74 | * a value of + or -1024 corresponds to + or - 1G |
75 | * scale = 9.81 / 1024 = 0.009580078 |
76 | */ |
77 | |
78 | static const int da311_nscale = 9580078; |
79 | |
80 | #define DA311_CHANNEL(reg, axis) { \ |
81 | .type = IIO_ACCEL, \ |
82 | .address = reg, \ |
83 | .modified = 1, \ |
84 | .channel2 = IIO_MOD_##axis, \ |
85 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
86 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ |
87 | } |
88 | |
89 | static const struct iio_chan_spec da311_channels[] = { |
90 | /* | 0x80 comes from the android driver */ |
91 | DA311_CHANNEL(DA311_REG_OUT_X_L | 0x80, X), |
92 | DA311_CHANNEL(DA311_REG_OUT_Y_L | 0x80, Y), |
93 | DA311_CHANNEL(DA311_REG_OUT_Z_L | 0x80, Z), |
94 | }; |
95 | |
96 | struct da311_data { |
97 | struct i2c_client *client; |
98 | }; |
99 | |
100 | static int da311_register_mask_write(struct i2c_client *client, u16 addr, |
101 | u8 mask, u8 data) |
102 | { |
103 | int ret; |
104 | u8 tmp_data = 0; |
105 | |
106 | if (addr & 0xff00) { |
107 | /* Select bank 1 */ |
108 | ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, value: 0x01); |
109 | if (ret < 0) |
110 | return ret; |
111 | } |
112 | |
113 | if (mask != 0xff) { |
114 | ret = i2c_smbus_read_byte_data(client, command: addr); |
115 | if (ret < 0) |
116 | return ret; |
117 | tmp_data = ret; |
118 | } |
119 | |
120 | tmp_data &= ~mask; |
121 | tmp_data |= data & mask; |
122 | ret = i2c_smbus_write_byte_data(client, command: addr & 0xff, value: tmp_data); |
123 | if (ret < 0) |
124 | return ret; |
125 | |
126 | if (addr & 0xff00) { |
127 | /* Back to bank 0 */ |
128 | ret = i2c_smbus_write_byte_data(client, DA311_REG_BANK, value: 0x00); |
129 | if (ret < 0) |
130 | return ret; |
131 | } |
132 | |
133 | return 0; |
134 | } |
135 | |
136 | /* Init sequence taken from the android driver */ |
137 | static int da311_reset(struct i2c_client *client) |
138 | { |
139 | static const struct { |
140 | u16 addr; |
141 | u8 mask; |
142 | u8 data; |
143 | } init_data[] = { |
144 | { DA311_REG_TEMP_CFG_REG, 0xff, 0x08 }, |
145 | { DA311_REG_CTRL_REG5, 0xff, 0x80 }, |
146 | { DA311_REG_CTRL_REG4, 0x30, 0x00 }, |
147 | { DA311_REG_CTRL_REG1, 0xff, 0x6f }, |
148 | { DA311_REG_TEMP_CFG_REG, 0xff, 0x88 }, |
149 | { DA311_REG_LDO_REG, 0xff, 0x02 }, |
150 | { DA311_REG_OTP_TRIM_OSC, 0xff, 0x27 }, |
151 | { DA311_REG_LPF_ABSOLUTE, 0xff, 0x30 }, |
152 | { DA311_REG_TEMP_OFF1, 0xff, 0x3f }, |
153 | { DA311_REG_TEMP_OFF2, 0xff, 0xff }, |
154 | { DA311_REG_TEMP_OFF3, 0xff, 0x0f }, |
155 | }; |
156 | int i, ret; |
157 | |
158 | /* Reset */ |
159 | ret = da311_register_mask_write(client, DA311_REG_SOFT_RESET, |
160 | mask: 0xff, data: 0xaa); |
161 | if (ret < 0) |
162 | return ret; |
163 | |
164 | for (i = 0; i < ARRAY_SIZE(init_data); i++) { |
165 | ret = da311_register_mask_write(client, |
166 | addr: init_data[i].addr, |
167 | mask: init_data[i].mask, |
168 | data: init_data[i].data); |
169 | if (ret < 0) |
170 | return ret; |
171 | } |
172 | |
173 | return 0; |
174 | } |
175 | |
176 | static int da311_enable(struct i2c_client *client, bool enable) |
177 | { |
178 | u8 data = enable ? 0x00 : 0x20; |
179 | |
180 | return da311_register_mask_write(client, DA311_REG_TEMP_CFG_REG, |
181 | mask: 0x20, data); |
182 | } |
183 | |
184 | static int da311_read_raw(struct iio_dev *indio_dev, |
185 | struct iio_chan_spec const *chan, |
186 | int *val, int *val2, long mask) |
187 | { |
188 | struct da311_data *data = iio_priv(indio_dev); |
189 | int ret; |
190 | |
191 | switch (mask) { |
192 | case IIO_CHAN_INFO_RAW: |
193 | ret = i2c_smbus_read_word_data(client: data->client, command: chan->address); |
194 | if (ret < 0) |
195 | return ret; |
196 | /* |
197 | * Values are 12 bits, stored as 16 bits with the 4 |
198 | * least significant bits always 0. |
199 | */ |
200 | *val = (short)ret >> 4; |
201 | return IIO_VAL_INT; |
202 | case IIO_CHAN_INFO_SCALE: |
203 | *val = 0; |
204 | *val2 = da311_nscale; |
205 | return IIO_VAL_INT_PLUS_NANO; |
206 | default: |
207 | return -EINVAL; |
208 | } |
209 | } |
210 | |
211 | static const struct iio_info da311_info = { |
212 | .read_raw = da311_read_raw, |
213 | }; |
214 | |
215 | static void da311_disable(void *client) |
216 | { |
217 | da311_enable(client, enable: false); |
218 | } |
219 | |
220 | static int da311_probe(struct i2c_client *client) |
221 | { |
222 | int ret; |
223 | struct iio_dev *indio_dev; |
224 | struct da311_data *data; |
225 | |
226 | ret = i2c_smbus_read_byte_data(client, DA311_REG_CHIP_ID); |
227 | if (ret != DA311_CHIP_ID) |
228 | return (ret < 0) ? ret : -ENODEV; |
229 | |
230 | indio_dev = devm_iio_device_alloc(parent: &client->dev, sizeof_priv: sizeof(*data)); |
231 | if (!indio_dev) |
232 | return -ENOMEM; |
233 | |
234 | data = iio_priv(indio_dev); |
235 | data->client = client; |
236 | |
237 | indio_dev->info = &da311_info; |
238 | indio_dev->name = "da311" ; |
239 | indio_dev->modes = INDIO_DIRECT_MODE; |
240 | indio_dev->channels = da311_channels; |
241 | indio_dev->num_channels = ARRAY_SIZE(da311_channels); |
242 | |
243 | ret = da311_reset(client); |
244 | if (ret < 0) |
245 | return ret; |
246 | |
247 | ret = da311_enable(client, enable: true); |
248 | if (ret < 0) |
249 | return ret; |
250 | |
251 | ret = devm_add_action_or_reset(&client->dev, da311_disable, client); |
252 | if (ret) |
253 | return ret; |
254 | |
255 | return devm_iio_device_register(&client->dev, indio_dev); |
256 | } |
257 | |
258 | static int da311_suspend(struct device *dev) |
259 | { |
260 | return da311_enable(to_i2c_client(dev), enable: false); |
261 | } |
262 | |
263 | static int da311_resume(struct device *dev) |
264 | { |
265 | return da311_enable(to_i2c_client(dev), enable: true); |
266 | } |
267 | |
268 | static DEFINE_SIMPLE_DEV_PM_OPS(da311_pm_ops, da311_suspend, da311_resume); |
269 | |
270 | static const struct i2c_device_id da311_i2c_id[] = { |
271 | {"da311" , 0}, |
272 | {} |
273 | }; |
274 | MODULE_DEVICE_TABLE(i2c, da311_i2c_id); |
275 | |
276 | static struct i2c_driver da311_driver = { |
277 | .driver = { |
278 | .name = "da311" , |
279 | .pm = pm_sleep_ptr(&da311_pm_ops), |
280 | }, |
281 | .probe = da311_probe, |
282 | .id_table = da311_i2c_id, |
283 | }; |
284 | |
285 | module_i2c_driver(da311_driver); |
286 | |
287 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>" ); |
288 | MODULE_DESCRIPTION("MiraMEMS DA311 3-Axis Accelerometer driver" ); |
289 | MODULE_LICENSE("GPL v2" ); |
290 | |