Commit | Line | Data |
---|---|---|
23491b51 DC |
1 | /* |
2 | * STMicroelectronics sensors core library driver | |
3 | * | |
4 | * Copyright 2012-2013 STMicroelectronics Inc. | |
5 | * | |
6 | * Denis Ciocca <denis.ciocca@st.com> | |
7 | * | |
8 | * Licensed under the GPL-2. | |
9 | */ | |
10 | ||
11 | #include <linux/kernel.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/slab.h> | |
14 | #include <linux/delay.h> | |
15 | #include <linux/iio/iio.h> | |
16 | #include <asm/unaligned.h> | |
17 | ||
18 | #include <linux/iio/common/st_sensors.h> | |
19 | ||
20 | ||
21 | #define ST_SENSORS_WAI_ADDRESS 0x0f | |
22 | ||
23 | static int st_sensors_write_data_with_mask(struct iio_dev *indio_dev, | |
24 | u8 reg_addr, u8 mask, u8 data) | |
25 | { | |
26 | int err; | |
27 | u8 new_data; | |
28 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
29 | ||
30 | err = sdata->tf->read_byte(&sdata->tb, sdata->dev, reg_addr, &new_data); | |
31 | if (err < 0) | |
32 | goto st_sensors_write_data_with_mask_error; | |
33 | ||
34 | new_data = ((new_data & (~mask)) | ((data << __ffs(mask)) & mask)); | |
35 | err = sdata->tf->write_byte(&sdata->tb, sdata->dev, reg_addr, new_data); | |
36 | ||
37 | st_sensors_write_data_with_mask_error: | |
38 | return err; | |
39 | } | |
40 | ||
41 | int st_sensors_get_sampling_frequency_avl(struct iio_dev *indio_dev, char *buf) | |
42 | { | |
43 | int i, len = 0; | |
44 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
45 | ||
46 | mutex_lock(&indio_dev->mlock); | |
47 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { | |
48 | if (sdata->sensor->odr.odr_avl[i].hz == 0) | |
49 | break; | |
50 | ||
51 | len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", | |
52 | sdata->sensor->odr.odr_avl[i].hz); | |
53 | } | |
54 | mutex_unlock(&indio_dev->mlock); | |
55 | buf[len - 1] = '\n'; | |
56 | ||
57 | return len; | |
58 | } | |
59 | EXPORT_SYMBOL(st_sensors_get_sampling_frequency_avl); | |
60 | ||
61 | int st_sensors_get_scale_avl(struct iio_dev *indio_dev, char *buf) | |
62 | { | |
63 | int i, len = 0; | |
64 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
65 | ||
66 | mutex_lock(&indio_dev->mlock); | |
67 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | |
68 | if (sdata->sensor->fs.fs_avl[i].num == 0) | |
69 | break; | |
70 | ||
71 | len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ", | |
72 | sdata->sensor->fs.fs_avl[i].gain); | |
73 | } | |
74 | mutex_unlock(&indio_dev->mlock); | |
75 | buf[len - 1] = '\n'; | |
76 | ||
77 | return len; | |
78 | } | |
79 | EXPORT_SYMBOL(st_sensors_get_scale_avl); | |
80 | ||
81 | static int st_sensors_match_odr(struct st_sensors *sensor, | |
82 | unsigned int odr, struct st_sensor_odr_avl *odr_out) | |
83 | { | |
84 | int i, ret = -EINVAL; | |
85 | ||
86 | for (i = 0; i < ST_SENSORS_ODR_LIST_MAX; i++) { | |
87 | if (sensor->odr.odr_avl[i].hz == 0) | |
88 | goto st_sensors_match_odr_error; | |
89 | ||
90 | if (sensor->odr.odr_avl[i].hz == odr) { | |
91 | odr_out->hz = sensor->odr.odr_avl[i].hz; | |
92 | odr_out->value = sensor->odr.odr_avl[i].value; | |
93 | ret = 0; | |
94 | break; | |
95 | } | |
96 | } | |
97 | ||
98 | st_sensors_match_odr_error: | |
99 | return ret; | |
100 | } | |
101 | ||
102 | int st_sensors_set_odr(struct iio_dev *indio_dev, unsigned int odr) | |
103 | { | |
104 | int err; | |
105 | struct st_sensor_odr_avl odr_out; | |
106 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
107 | ||
108 | err = st_sensors_match_odr(sdata->sensor, odr, &odr_out); | |
109 | if (err < 0) | |
110 | goto st_sensors_match_odr_error; | |
111 | ||
112 | if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) && | |
113 | (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) { | |
114 | if (sdata->enabled == true) { | |
115 | err = st_sensors_write_data_with_mask(indio_dev, | |
116 | sdata->sensor->odr.addr, | |
117 | sdata->sensor->odr.mask, | |
118 | odr_out.value); | |
119 | } else { | |
120 | err = 0; | |
121 | } | |
122 | } else { | |
123 | err = st_sensors_write_data_with_mask(indio_dev, | |
124 | sdata->sensor->odr.addr, sdata->sensor->odr.mask, | |
125 | odr_out.value); | |
126 | } | |
127 | if (err >= 0) | |
128 | sdata->odr = odr_out.hz; | |
129 | ||
130 | st_sensors_match_odr_error: | |
131 | return err; | |
132 | } | |
133 | EXPORT_SYMBOL(st_sensors_set_odr); | |
134 | ||
135 | static int st_sensors_match_fs(struct st_sensors *sensor, | |
136 | unsigned int fs, int *index_fs_avl) | |
137 | { | |
138 | int i, ret = -EINVAL; | |
139 | ||
140 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | |
141 | if (sensor->fs.fs_avl[i].num == 0) | |
142 | goto st_sensors_match_odr_error; | |
143 | ||
144 | if (sensor->fs.fs_avl[i].num == fs) { | |
145 | *index_fs_avl = i; | |
146 | ret = 0; | |
147 | break; | |
148 | } | |
149 | } | |
150 | ||
151 | st_sensors_match_odr_error: | |
152 | return ret; | |
153 | } | |
154 | ||
155 | static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) | |
156 | { | |
157 | int err, i; | |
158 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
159 | ||
160 | err = st_sensors_match_fs(sdata->sensor, fs, &i); | |
161 | if (err < 0) | |
162 | goto st_accel_set_fullscale_error; | |
163 | ||
164 | err = st_sensors_write_data_with_mask(indio_dev, | |
165 | sdata->sensor->fs.addr, | |
166 | sdata->sensor->fs.mask, | |
167 | sdata->sensor->fs.fs_avl[i].value); | |
168 | if (err < 0) | |
169 | goto st_accel_set_fullscale_error; | |
170 | ||
171 | sdata->current_fullscale = (struct st_sensor_fullscale_avl *) | |
172 | &sdata->sensor->fs.fs_avl[i]; | |
173 | return err; | |
174 | ||
175 | st_accel_set_fullscale_error: | |
176 | dev_err(&indio_dev->dev, "failed to set new fullscale.\n"); | |
177 | return err; | |
178 | } | |
179 | ||
180 | int st_sensors_set_enable(struct iio_dev *indio_dev, bool enable) | |
181 | { | |
182 | bool found; | |
183 | u8 tmp_value; | |
184 | int err = -EINVAL; | |
185 | struct st_sensor_odr_avl odr_out; | |
186 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
187 | ||
188 | if (enable) { | |
189 | found = false; | |
190 | tmp_value = sdata->sensor->pw.value_on; | |
191 | if ((sdata->sensor->odr.addr == sdata->sensor->pw.addr) && | |
192 | (sdata->sensor->odr.mask == sdata->sensor->pw.mask)) { | |
193 | err = st_sensors_match_odr(sdata->sensor, | |
194 | sdata->odr, &odr_out); | |
195 | if (err < 0) | |
196 | goto set_enable_error; | |
197 | tmp_value = odr_out.value; | |
198 | found = true; | |
199 | } | |
200 | err = st_sensors_write_data_with_mask(indio_dev, | |
201 | sdata->sensor->pw.addr, | |
202 | sdata->sensor->pw.mask, tmp_value); | |
203 | if (err < 0) | |
204 | goto set_enable_error; | |
205 | ||
206 | sdata->enabled = true; | |
207 | ||
208 | if (found) | |
209 | sdata->odr = odr_out.hz; | |
210 | } else { | |
211 | err = st_sensors_write_data_with_mask(indio_dev, | |
212 | sdata->sensor->pw.addr, | |
213 | sdata->sensor->pw.mask, | |
214 | sdata->sensor->pw.value_off); | |
215 | if (err < 0) | |
216 | goto set_enable_error; | |
217 | ||
218 | sdata->enabled = false; | |
219 | } | |
220 | ||
221 | set_enable_error: | |
222 | return err; | |
223 | } | |
224 | EXPORT_SYMBOL(st_sensors_set_enable); | |
225 | ||
226 | int st_sensors_set_axis_enable(struct iio_dev *indio_dev, u8 axis_enable) | |
227 | { | |
228 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
229 | ||
230 | return st_sensors_write_data_with_mask(indio_dev, | |
231 | sdata->sensor->enable_axis.addr, | |
232 | sdata->sensor->enable_axis.mask, axis_enable); | |
233 | } | |
234 | EXPORT_SYMBOL(st_sensors_set_axis_enable); | |
235 | ||
236 | int st_sensors_init_sensor(struct iio_dev *indio_dev) | |
237 | { | |
238 | int err; | |
239 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
240 | ||
241 | mutex_init(&sdata->tb.buf_lock); | |
242 | ||
243 | err = st_sensors_set_enable(indio_dev, false); | |
244 | if (err < 0) | |
245 | goto init_error; | |
246 | ||
247 | err = st_sensors_set_fullscale(indio_dev, | |
248 | sdata->current_fullscale->num); | |
249 | if (err < 0) | |
250 | goto init_error; | |
251 | ||
252 | err = st_sensors_set_odr(indio_dev, sdata->odr); | |
253 | if (err < 0) | |
254 | goto init_error; | |
255 | ||
256 | /* set BDU */ | |
257 | err = st_sensors_write_data_with_mask(indio_dev, | |
258 | sdata->sensor->bdu.addr, sdata->sensor->bdu.mask, true); | |
259 | if (err < 0) | |
260 | goto init_error; | |
261 | ||
262 | err = st_sensors_set_axis_enable(indio_dev, ST_SENSORS_ENABLE_ALL_AXIS); | |
263 | ||
264 | init_error: | |
265 | return err; | |
266 | } | |
267 | EXPORT_SYMBOL(st_sensors_init_sensor); | |
268 | ||
269 | int st_sensors_set_dataready_irq(struct iio_dev *indio_dev, bool enable) | |
270 | { | |
271 | int err; | |
272 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
273 | ||
274 | /* Enable/Disable the interrupt generator 1. */ | |
275 | if (sdata->sensor->drdy_irq.ig1.en_addr > 0) { | |
276 | err = st_sensors_write_data_with_mask(indio_dev, | |
277 | sdata->sensor->drdy_irq.ig1.en_addr, | |
278 | sdata->sensor->drdy_irq.ig1.en_mask, (int)enable); | |
279 | if (err < 0) | |
280 | goto st_accel_set_dataready_irq_error; | |
281 | } | |
282 | ||
283 | /* Enable/Disable the interrupt generator for data ready. */ | |
284 | err = st_sensors_write_data_with_mask(indio_dev, | |
285 | sdata->sensor->drdy_irq.addr, | |
286 | sdata->sensor->drdy_irq.mask, (int)enable); | |
287 | ||
288 | st_accel_set_dataready_irq_error: | |
289 | return err; | |
290 | } | |
291 | EXPORT_SYMBOL(st_sensors_set_dataready_irq); | |
292 | ||
293 | int st_sensors_set_fullscale_by_gain(struct iio_dev *indio_dev, int scale) | |
294 | { | |
295 | int err = -EINVAL, i; | |
296 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
297 | ||
298 | for (i = 0; i < ST_SENSORS_FULLSCALE_AVL_MAX; i++) { | |
299 | if ((sdata->sensor->fs.fs_avl[i].gain == scale) && | |
300 | (sdata->sensor->fs.fs_avl[i].gain != 0)) { | |
301 | err = 0; | |
302 | break; | |
303 | } | |
304 | } | |
305 | if (err < 0) | |
306 | goto st_sensors_match_scale_error; | |
307 | ||
308 | err = st_sensors_set_fullscale(indio_dev, | |
309 | sdata->sensor->fs.fs_avl[i].num); | |
310 | ||
311 | st_sensors_match_scale_error: | |
312 | return err; | |
313 | } | |
314 | EXPORT_SYMBOL(st_sensors_set_fullscale_by_gain); | |
315 | ||
316 | static int st_sensors_read_axis_data(struct iio_dev *indio_dev, | |
317 | u8 ch_addr, int *data) | |
318 | { | |
319 | int err; | |
320 | u8 outdata[ST_SENSORS_BYTE_FOR_CHANNEL]; | |
321 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
322 | ||
323 | err = sdata->tf->read_multiple_byte(&sdata->tb, sdata->dev, | |
324 | ch_addr, ST_SENSORS_BYTE_FOR_CHANNEL, | |
325 | outdata, sdata->multiread_bit); | |
326 | if (err < 0) | |
327 | goto read_error; | |
328 | ||
329 | *data = (s16)get_unaligned_le16(outdata); | |
330 | ||
331 | read_error: | |
332 | return err; | |
333 | } | |
334 | ||
335 | int st_sensors_read_info_raw(struct iio_dev *indio_dev, | |
336 | struct iio_chan_spec const *ch, int *val) | |
337 | { | |
338 | int err; | |
339 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
340 | ||
341 | mutex_lock(&indio_dev->mlock); | |
342 | if (indio_dev->currentmode == INDIO_BUFFER_TRIGGERED) { | |
343 | err = -EBUSY; | |
344 | goto read_error; | |
345 | } else { | |
346 | err = st_sensors_set_enable(indio_dev, true); | |
347 | if (err < 0) | |
348 | goto read_error; | |
349 | ||
350 | msleep((sdata->sensor->bootime * 1000) / sdata->odr); | |
351 | err = st_sensors_read_axis_data(indio_dev, ch->address, val); | |
352 | if (err < 0) | |
353 | goto read_error; | |
354 | ||
355 | *val = *val >> ch->scan_type.shift; | |
356 | } | |
357 | mutex_unlock(&indio_dev->mlock); | |
358 | ||
359 | return err; | |
360 | ||
361 | read_error: | |
362 | mutex_unlock(&indio_dev->mlock); | |
363 | return err; | |
364 | } | |
365 | EXPORT_SYMBOL(st_sensors_read_info_raw); | |
366 | ||
367 | int st_sensors_check_device_support(struct iio_dev *indio_dev, | |
368 | int num_sensors_list, const struct st_sensors *sensors) | |
369 | { | |
370 | u8 wai; | |
371 | int i, n, err; | |
372 | struct st_sensor_data *sdata = iio_priv(indio_dev); | |
373 | ||
374 | err = sdata->tf->read_byte(&sdata->tb, sdata->dev, | |
375 | ST_SENSORS_DEFAULT_WAI_ADDRESS, &wai); | |
376 | if (err < 0) { | |
377 | dev_err(&indio_dev->dev, "failed to read Who-Am-I register.\n"); | |
378 | goto read_wai_error; | |
379 | } | |
380 | ||
381 | for (i = 0; i < num_sensors_list; i++) { | |
382 | if (sensors[i].wai == wai) | |
383 | break; | |
384 | } | |
385 | if (i == num_sensors_list) | |
386 | goto device_not_supported; | |
387 | ||
388 | for (n = 0; n < ARRAY_SIZE(sensors[i].sensors_supported); n++) { | |
389 | if (strcmp(indio_dev->name, | |
390 | &sensors[i].sensors_supported[n][0]) == 0) | |
391 | break; | |
392 | } | |
393 | if (n == ARRAY_SIZE(sensors[i].sensors_supported)) { | |
394 | dev_err(&indio_dev->dev, "device name and WhoAmI mismatch.\n"); | |
395 | goto sensor_name_mismatch; | |
396 | } | |
397 | ||
398 | sdata->sensor = (struct st_sensors *)&sensors[i]; | |
399 | ||
400 | return i; | |
401 | ||
402 | device_not_supported: | |
403 | dev_err(&indio_dev->dev, "device not supported: WhoAmI (0x%x).\n", wai); | |
404 | sensor_name_mismatch: | |
405 | err = -ENODEV; | |
406 | read_wai_error: | |
407 | return err; | |
408 | } | |
409 | EXPORT_SYMBOL(st_sensors_check_device_support); | |
410 | ||
411 | ssize_t st_sensors_sysfs_get_sampling_frequency(struct device *dev, | |
412 | struct device_attribute *attr, char *buf) | |
413 | { | |
414 | struct st_sensor_data *adata = iio_priv(dev_get_drvdata(dev)); | |
415 | ||
416 | return sprintf(buf, "%d\n", adata->odr); | |
417 | } | |
418 | EXPORT_SYMBOL(st_sensors_sysfs_get_sampling_frequency); | |
419 | ||
420 | ssize_t st_sensors_sysfs_set_sampling_frequency(struct device *dev, | |
421 | struct device_attribute *attr, const char *buf, size_t size) | |
422 | { | |
423 | int err; | |
424 | unsigned int odr; | |
425 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
426 | ||
427 | err = kstrtoint(buf, 10, &odr); | |
428 | if (err < 0) | |
429 | goto conversion_error; | |
430 | ||
431 | mutex_lock(&indio_dev->mlock); | |
432 | err = st_sensors_set_odr(indio_dev, odr); | |
433 | mutex_unlock(&indio_dev->mlock); | |
434 | ||
435 | conversion_error: | |
436 | return err < 0 ? err : size; | |
437 | } | |
438 | EXPORT_SYMBOL(st_sensors_sysfs_set_sampling_frequency); | |
439 | ||
440 | ssize_t st_sensors_sysfs_sampling_frequency_avail(struct device *dev, | |
441 | struct device_attribute *attr, char *buf) | |
442 | { | |
443 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
444 | ||
445 | return st_sensors_get_sampling_frequency_avl(indio_dev, buf); | |
446 | } | |
447 | EXPORT_SYMBOL(st_sensors_sysfs_sampling_frequency_avail); | |
448 | ||
449 | ssize_t st_sensors_sysfs_scale_avail(struct device *dev, | |
450 | struct device_attribute *attr, char *buf) | |
451 | { | |
452 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
453 | ||
454 | return st_sensors_get_scale_avl(indio_dev, buf); | |
455 | } | |
456 | EXPORT_SYMBOL(st_sensors_sysfs_scale_avail); | |
457 | ||
458 | MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); | |
459 | MODULE_DESCRIPTION("STMicroelectronics ST-sensors core"); | |
460 | MODULE_LICENSE("GPL v2"); |