1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Device driver for the HMC5843 multi-chip module designed |
4 | * for low field magnetic sensing. |
5 | * |
6 | * Copyright (C) 2010 Texas Instruments |
7 | * |
8 | * Author: Shubhrajyoti Datta <shubhrajyoti@ti.com> |
9 | * Acknowledgment: Jonathan Cameron <jic23@kernel.org> for valuable inputs. |
10 | * Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>. |
11 | * Split to multiple files by Josef Gajdusek <atx@atx.name> - 2014 |
12 | */ |
13 | |
14 | #include <linux/module.h> |
15 | #include <linux/regmap.h> |
16 | #include <linux/iio/iio.h> |
17 | #include <linux/iio/sysfs.h> |
18 | #include <linux/iio/trigger_consumer.h> |
19 | #include <linux/iio/buffer.h> |
20 | #include <linux/iio/triggered_buffer.h> |
21 | #include <linux/delay.h> |
22 | |
23 | #include "hmc5843.h" |
24 | |
25 | /* |
26 | * Range gain settings in (+-)Ga |
27 | * Beware: HMC5843 and HMC5883 have different recommended sensor field |
28 | * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively |
29 | */ |
30 | #define HMC5843_RANGE_GAIN_OFFSET 0x05 |
31 | #define HMC5843_RANGE_GAIN_DEFAULT 0x01 |
32 | #define HMC5843_RANGE_GAIN_MASK 0xe0 |
33 | |
34 | /* Device status */ |
35 | #define HMC5843_DATA_READY 0x01 |
36 | #define HMC5843_DATA_OUTPUT_LOCK 0x02 |
37 | |
38 | /* Mode register configuration */ |
39 | #define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00 |
40 | #define HMC5843_MODE_CONVERSION_SINGLE 0x01 |
41 | #define HMC5843_MODE_IDLE 0x02 |
42 | #define HMC5843_MODE_SLEEP 0x03 |
43 | #define HMC5843_MODE_MASK 0x03 |
44 | |
45 | /* |
46 | * HMC5843: Minimum data output rate |
47 | * HMC5883: Typical data output rate |
48 | */ |
49 | #define HMC5843_RATE_OFFSET 0x02 |
50 | #define HMC5843_RATE_DEFAULT 0x04 |
51 | #define HMC5843_RATE_MASK 0x1c |
52 | |
53 | /* Device measurement configuration */ |
54 | #define HMC5843_MEAS_CONF_NORMAL 0x00 |
55 | #define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01 |
56 | #define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02 |
57 | #define HMC5843_MEAS_CONF_MASK 0x03 |
58 | |
59 | /* |
60 | * API for setting the measurement configuration to |
61 | * Normal, Positive bias and Negative bias |
62 | * |
63 | * From the datasheet: |
64 | * 0 - Normal measurement configuration (default): In normal measurement |
65 | * configuration the device follows normal measurement flow. Pins BP |
66 | * and BN are left floating and high impedance. |
67 | * |
68 | * 1 - Positive bias configuration: In positive bias configuration, a |
69 | * positive current is forced across the resistive load on pins BP |
70 | * and BN. |
71 | * |
72 | * 2 - Negative bias configuration. In negative bias configuration, a |
73 | * negative current is forced across the resistive load on pins BP |
74 | * and BN. |
75 | * |
76 | * 3 - Only available on HMC5983. Magnetic sensor is disabled. |
77 | * Temperature sensor is enabled. |
78 | */ |
79 | |
80 | static const char *const hmc5843_meas_conf_modes[] = {"normal" , "positivebias" , |
81 | "negativebias" }; |
82 | |
83 | static const char *const hmc5983_meas_conf_modes[] = {"normal" , "positivebias" , |
84 | "negativebias" , |
85 | "disabled" }; |
86 | /* Scaling factors: 10000000/Gain */ |
87 | static const int hmc5843_regval_to_nanoscale[] = { |
88 | 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 |
89 | }; |
90 | |
91 | static const int hmc5883_regval_to_nanoscale[] = { |
92 | 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 |
93 | }; |
94 | |
95 | static const int hmc5883l_regval_to_nanoscale[] = { |
96 | 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478 |
97 | }; |
98 | |
99 | /* |
100 | * From the datasheet: |
101 | * Value | HMC5843 | HMC5883/HMC5883L |
102 | * | Data output rate (Hz) | Data output rate (Hz) |
103 | * 0 | 0.5 | 0.75 |
104 | * 1 | 1 | 1.5 |
105 | * 2 | 2 | 3 |
106 | * 3 | 5 | 7.5 |
107 | * 4 | 10 (default) | 15 |
108 | * 5 | 20 | 30 |
109 | * 6 | 50 | 75 |
110 | * 7 | Not used | Not used |
111 | */ |
112 | static const int hmc5843_regval_to_samp_freq[][2] = { |
113 | {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} |
114 | }; |
115 | |
116 | static const int hmc5883_regval_to_samp_freq[][2] = { |
117 | {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, |
118 | {75, 0} |
119 | }; |
120 | |
121 | static const int hmc5983_regval_to_samp_freq[][2] = { |
122 | {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, |
123 | {75, 0}, {220, 0} |
124 | }; |
125 | |
126 | /* Describe chip variants */ |
127 | struct hmc5843_chip_info { |
128 | const struct iio_chan_spec *channels; |
129 | const int (*regval_to_samp_freq)[2]; |
130 | const int n_regval_to_samp_freq; |
131 | const int *regval_to_nanoscale; |
132 | const int n_regval_to_nanoscale; |
133 | }; |
134 | |
135 | /* The lower two bits contain the current conversion mode */ |
136 | static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) |
137 | { |
138 | int ret; |
139 | |
140 | mutex_lock(&data->lock); |
141 | ret = regmap_update_bits(map: data->regmap, HMC5843_MODE_REG, |
142 | HMC5843_MODE_MASK, val: operating_mode); |
143 | mutex_unlock(lock: &data->lock); |
144 | |
145 | return ret; |
146 | } |
147 | |
148 | static int hmc5843_wait_measurement(struct hmc5843_data *data) |
149 | { |
150 | int tries = 150; |
151 | unsigned int val; |
152 | int ret; |
153 | |
154 | while (tries-- > 0) { |
155 | ret = regmap_read(map: data->regmap, HMC5843_STATUS_REG, val: &val); |
156 | if (ret < 0) |
157 | return ret; |
158 | if (val & HMC5843_DATA_READY) |
159 | break; |
160 | msleep(msecs: 20); |
161 | } |
162 | |
163 | if (tries < 0) { |
164 | dev_err(data->dev, "data not ready\n" ); |
165 | return -EIO; |
166 | } |
167 | |
168 | return 0; |
169 | } |
170 | |
171 | /* Return the measurement value from the specified channel */ |
172 | static int hmc5843_read_measurement(struct hmc5843_data *data, |
173 | int idx, int *val) |
174 | { |
175 | __be16 values[3]; |
176 | int ret; |
177 | |
178 | mutex_lock(&data->lock); |
179 | ret = hmc5843_wait_measurement(data); |
180 | if (ret < 0) { |
181 | mutex_unlock(lock: &data->lock); |
182 | return ret; |
183 | } |
184 | ret = regmap_bulk_read(map: data->regmap, HMC5843_DATA_OUT_MSB_REGS, |
185 | val: values, val_count: sizeof(values)); |
186 | mutex_unlock(lock: &data->lock); |
187 | if (ret < 0) |
188 | return ret; |
189 | |
190 | *val = sign_extend32(be16_to_cpu(values[idx]), index: 15); |
191 | return IIO_VAL_INT; |
192 | } |
193 | |
194 | static int hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf) |
195 | { |
196 | int ret; |
197 | |
198 | mutex_lock(&data->lock); |
199 | ret = regmap_update_bits(map: data->regmap, HMC5843_CONFIG_REG_A, |
200 | HMC5843_MEAS_CONF_MASK, val: meas_conf); |
201 | mutex_unlock(lock: &data->lock); |
202 | |
203 | return ret; |
204 | } |
205 | |
206 | static |
207 | int hmc5843_show_measurement_configuration(struct iio_dev *indio_dev, |
208 | const struct iio_chan_spec *chan) |
209 | { |
210 | struct hmc5843_data *data = iio_priv(indio_dev); |
211 | unsigned int val; |
212 | int ret; |
213 | |
214 | ret = regmap_read(map: data->regmap, HMC5843_CONFIG_REG_A, val: &val); |
215 | if (ret) |
216 | return ret; |
217 | |
218 | return val & HMC5843_MEAS_CONF_MASK; |
219 | } |
220 | |
221 | static |
222 | int hmc5843_set_measurement_configuration(struct iio_dev *indio_dev, |
223 | const struct iio_chan_spec *chan, |
224 | unsigned int meas_conf) |
225 | { |
226 | struct hmc5843_data *data = iio_priv(indio_dev); |
227 | |
228 | return hmc5843_set_meas_conf(data, meas_conf); |
229 | } |
230 | |
231 | static const struct iio_mount_matrix * |
232 | hmc5843_get_mount_matrix(const struct iio_dev *indio_dev, |
233 | const struct iio_chan_spec *chan) |
234 | { |
235 | struct hmc5843_data *data = iio_priv(indio_dev); |
236 | |
237 | return &data->orientation; |
238 | } |
239 | |
240 | static const struct iio_enum hmc5843_meas_conf_enum = { |
241 | .items = hmc5843_meas_conf_modes, |
242 | .num_items = ARRAY_SIZE(hmc5843_meas_conf_modes), |
243 | .get = hmc5843_show_measurement_configuration, |
244 | .set = hmc5843_set_measurement_configuration, |
245 | }; |
246 | |
247 | static const struct iio_chan_spec_ext_info hmc5843_ext_info[] = { |
248 | IIO_ENUM("meas_conf" , IIO_SHARED_BY_TYPE, &hmc5843_meas_conf_enum), |
249 | IIO_ENUM_AVAILABLE("meas_conf" , IIO_SHARED_BY_TYPE, &hmc5843_meas_conf_enum), |
250 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), |
251 | { } |
252 | }; |
253 | |
254 | static const struct iio_enum hmc5983_meas_conf_enum = { |
255 | .items = hmc5983_meas_conf_modes, |
256 | .num_items = ARRAY_SIZE(hmc5983_meas_conf_modes), |
257 | .get = hmc5843_show_measurement_configuration, |
258 | .set = hmc5843_set_measurement_configuration, |
259 | }; |
260 | |
261 | static const struct iio_chan_spec_ext_info hmc5983_ext_info[] = { |
262 | IIO_ENUM("meas_conf" , IIO_SHARED_BY_TYPE, &hmc5983_meas_conf_enum), |
263 | IIO_ENUM_AVAILABLE("meas_conf" , IIO_SHARED_BY_TYPE, &hmc5983_meas_conf_enum), |
264 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_DIR, hmc5843_get_mount_matrix), |
265 | { } |
266 | }; |
267 | |
268 | static |
269 | ssize_t hmc5843_show_samp_freq_avail(struct device *dev, |
270 | struct device_attribute *attr, char *buf) |
271 | { |
272 | struct hmc5843_data *data = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
273 | size_t len = 0; |
274 | int i; |
275 | |
276 | for (i = 0; i < data->variant->n_regval_to_samp_freq; i++) |
277 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, |
278 | fmt: "%d.%d " , data->variant->regval_to_samp_freq[i][0], |
279 | data->variant->regval_to_samp_freq[i][1]); |
280 | |
281 | /* replace trailing space by newline */ |
282 | buf[len - 1] = '\n'; |
283 | |
284 | return len; |
285 | } |
286 | |
287 | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail); |
288 | |
289 | static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate) |
290 | { |
291 | int ret; |
292 | |
293 | mutex_lock(&data->lock); |
294 | ret = regmap_update_bits(map: data->regmap, HMC5843_CONFIG_REG_A, |
295 | HMC5843_RATE_MASK, |
296 | val: rate << HMC5843_RATE_OFFSET); |
297 | mutex_unlock(lock: &data->lock); |
298 | |
299 | return ret; |
300 | } |
301 | |
302 | static int hmc5843_get_samp_freq_index(struct hmc5843_data *data, |
303 | int val, int val2) |
304 | { |
305 | int i; |
306 | |
307 | for (i = 0; i < data->variant->n_regval_to_samp_freq; i++) |
308 | if (val == data->variant->regval_to_samp_freq[i][0] && |
309 | val2 == data->variant->regval_to_samp_freq[i][1]) |
310 | return i; |
311 | |
312 | return -EINVAL; |
313 | } |
314 | |
315 | static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range) |
316 | { |
317 | int ret; |
318 | |
319 | mutex_lock(&data->lock); |
320 | ret = regmap_update_bits(map: data->regmap, HMC5843_CONFIG_REG_B, |
321 | HMC5843_RANGE_GAIN_MASK, |
322 | val: range << HMC5843_RANGE_GAIN_OFFSET); |
323 | mutex_unlock(lock: &data->lock); |
324 | |
325 | return ret; |
326 | } |
327 | |
328 | static ssize_t hmc5843_show_scale_avail(struct device *dev, |
329 | struct device_attribute *attr, |
330 | char *buf) |
331 | { |
332 | struct hmc5843_data *data = iio_priv(indio_dev: dev_to_iio_dev(dev)); |
333 | |
334 | size_t len = 0; |
335 | int i; |
336 | |
337 | for (i = 0; i < data->variant->n_regval_to_nanoscale; i++) |
338 | len += scnprintf(buf: buf + len, PAGE_SIZE - len, |
339 | fmt: "0.%09d " , data->variant->regval_to_nanoscale[i]); |
340 | |
341 | /* replace trailing space by newline */ |
342 | buf[len - 1] = '\n'; |
343 | |
344 | return len; |
345 | } |
346 | |
347 | static IIO_DEVICE_ATTR(scale_available, S_IRUGO, |
348 | hmc5843_show_scale_avail, NULL, 0); |
349 | |
350 | static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2) |
351 | { |
352 | int i; |
353 | |
354 | if (val) |
355 | return -EINVAL; |
356 | |
357 | for (i = 0; i < data->variant->n_regval_to_nanoscale; i++) |
358 | if (val2 == data->variant->regval_to_nanoscale[i]) |
359 | return i; |
360 | |
361 | return -EINVAL; |
362 | } |
363 | |
364 | static int hmc5843_read_raw(struct iio_dev *indio_dev, |
365 | struct iio_chan_spec const *chan, |
366 | int *val, int *val2, long mask) |
367 | { |
368 | struct hmc5843_data *data = iio_priv(indio_dev); |
369 | unsigned int rval; |
370 | int ret; |
371 | |
372 | switch (mask) { |
373 | case IIO_CHAN_INFO_RAW: |
374 | return hmc5843_read_measurement(data, idx: chan->scan_index, val); |
375 | case IIO_CHAN_INFO_SCALE: |
376 | ret = regmap_read(map: data->regmap, HMC5843_CONFIG_REG_B, val: &rval); |
377 | if (ret < 0) |
378 | return ret; |
379 | rval >>= HMC5843_RANGE_GAIN_OFFSET; |
380 | *val = 0; |
381 | *val2 = data->variant->regval_to_nanoscale[rval]; |
382 | return IIO_VAL_INT_PLUS_NANO; |
383 | case IIO_CHAN_INFO_SAMP_FREQ: |
384 | ret = regmap_read(map: data->regmap, HMC5843_CONFIG_REG_A, val: &rval); |
385 | if (ret < 0) |
386 | return ret; |
387 | rval >>= HMC5843_RATE_OFFSET; |
388 | *val = data->variant->regval_to_samp_freq[rval][0]; |
389 | *val2 = data->variant->regval_to_samp_freq[rval][1]; |
390 | return IIO_VAL_INT_PLUS_MICRO; |
391 | } |
392 | return -EINVAL; |
393 | } |
394 | |
395 | static int hmc5843_write_raw(struct iio_dev *indio_dev, |
396 | struct iio_chan_spec const *chan, |
397 | int val, int val2, long mask) |
398 | { |
399 | struct hmc5843_data *data = iio_priv(indio_dev); |
400 | int rate, range; |
401 | |
402 | switch (mask) { |
403 | case IIO_CHAN_INFO_SAMP_FREQ: |
404 | rate = hmc5843_get_samp_freq_index(data, val, val2); |
405 | if (rate < 0) |
406 | return -EINVAL; |
407 | |
408 | return hmc5843_set_samp_freq(data, rate); |
409 | case IIO_CHAN_INFO_SCALE: |
410 | range = hmc5843_get_scale_index(data, val, val2); |
411 | if (range < 0) |
412 | return -EINVAL; |
413 | |
414 | return hmc5843_set_range_gain(data, range); |
415 | default: |
416 | return -EINVAL; |
417 | } |
418 | } |
419 | |
420 | static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev, |
421 | struct iio_chan_spec const *chan, |
422 | long mask) |
423 | { |
424 | switch (mask) { |
425 | case IIO_CHAN_INFO_SAMP_FREQ: |
426 | return IIO_VAL_INT_PLUS_MICRO; |
427 | case IIO_CHAN_INFO_SCALE: |
428 | return IIO_VAL_INT_PLUS_NANO; |
429 | default: |
430 | return -EINVAL; |
431 | } |
432 | } |
433 | |
434 | static irqreturn_t hmc5843_trigger_handler(int irq, void *p) |
435 | { |
436 | struct iio_poll_func *pf = p; |
437 | struct iio_dev *indio_dev = pf->indio_dev; |
438 | struct hmc5843_data *data = iio_priv(indio_dev); |
439 | int ret; |
440 | |
441 | mutex_lock(&data->lock); |
442 | ret = hmc5843_wait_measurement(data); |
443 | if (ret < 0) { |
444 | mutex_unlock(lock: &data->lock); |
445 | goto done; |
446 | } |
447 | |
448 | ret = regmap_bulk_read(map: data->regmap, HMC5843_DATA_OUT_MSB_REGS, |
449 | val: data->scan.chans, val_count: sizeof(data->scan.chans)); |
450 | |
451 | mutex_unlock(lock: &data->lock); |
452 | if (ret < 0) |
453 | goto done; |
454 | |
455 | iio_push_to_buffers_with_timestamp(indio_dev, data: &data->scan, |
456 | timestamp: iio_get_time_ns(indio_dev)); |
457 | |
458 | done: |
459 | iio_trigger_notify_done(trig: indio_dev->trig); |
460 | |
461 | return IRQ_HANDLED; |
462 | } |
463 | |
464 | #define HMC5843_CHANNEL(axis, idx) \ |
465 | { \ |
466 | .type = IIO_MAGN, \ |
467 | .modified = 1, \ |
468 | .channel2 = IIO_MOD_##axis, \ |
469 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
470 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
471 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
472 | .scan_index = idx, \ |
473 | .scan_type = { \ |
474 | .sign = 's', \ |
475 | .realbits = 16, \ |
476 | .storagebits = 16, \ |
477 | .endianness = IIO_BE, \ |
478 | }, \ |
479 | .ext_info = hmc5843_ext_info, \ |
480 | } |
481 | |
482 | #define HMC5983_CHANNEL(axis, idx) \ |
483 | { \ |
484 | .type = IIO_MAGN, \ |
485 | .modified = 1, \ |
486 | .channel2 = IIO_MOD_##axis, \ |
487 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
488 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
489 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ |
490 | .scan_index = idx, \ |
491 | .scan_type = { \ |
492 | .sign = 's', \ |
493 | .realbits = 16, \ |
494 | .storagebits = 16, \ |
495 | .endianness = IIO_BE, \ |
496 | }, \ |
497 | .ext_info = hmc5983_ext_info, \ |
498 | } |
499 | |
500 | static const struct iio_chan_spec hmc5843_channels[] = { |
501 | HMC5843_CHANNEL(X, 0), |
502 | HMC5843_CHANNEL(Y, 1), |
503 | HMC5843_CHANNEL(Z, 2), |
504 | IIO_CHAN_SOFT_TIMESTAMP(3), |
505 | }; |
506 | |
507 | /* Beware: Y and Z are exchanged on HMC5883 and 5983 */ |
508 | static const struct iio_chan_spec hmc5883_channels[] = { |
509 | HMC5843_CHANNEL(X, 0), |
510 | HMC5843_CHANNEL(Z, 1), |
511 | HMC5843_CHANNEL(Y, 2), |
512 | IIO_CHAN_SOFT_TIMESTAMP(3), |
513 | }; |
514 | |
515 | static const struct iio_chan_spec hmc5983_channels[] = { |
516 | HMC5983_CHANNEL(X, 0), |
517 | HMC5983_CHANNEL(Z, 1), |
518 | HMC5983_CHANNEL(Y, 2), |
519 | IIO_CHAN_SOFT_TIMESTAMP(3), |
520 | }; |
521 | |
522 | static struct attribute *hmc5843_attributes[] = { |
523 | &iio_dev_attr_scale_available.dev_attr.attr, |
524 | &iio_dev_attr_sampling_frequency_available.dev_attr.attr, |
525 | NULL |
526 | }; |
527 | |
528 | static const struct attribute_group hmc5843_group = { |
529 | .attrs = hmc5843_attributes, |
530 | }; |
531 | |
532 | static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { |
533 | [HMC5843_ID] = { |
534 | .channels = hmc5843_channels, |
535 | .regval_to_samp_freq = hmc5843_regval_to_samp_freq, |
536 | .n_regval_to_samp_freq = |
537 | ARRAY_SIZE(hmc5843_regval_to_samp_freq), |
538 | .regval_to_nanoscale = hmc5843_regval_to_nanoscale, |
539 | .n_regval_to_nanoscale = |
540 | ARRAY_SIZE(hmc5843_regval_to_nanoscale), |
541 | }, |
542 | [HMC5883_ID] = { |
543 | .channels = hmc5883_channels, |
544 | .regval_to_samp_freq = hmc5883_regval_to_samp_freq, |
545 | .n_regval_to_samp_freq = |
546 | ARRAY_SIZE(hmc5883_regval_to_samp_freq), |
547 | .regval_to_nanoscale = hmc5883_regval_to_nanoscale, |
548 | .n_regval_to_nanoscale = |
549 | ARRAY_SIZE(hmc5883_regval_to_nanoscale), |
550 | }, |
551 | [HMC5883L_ID] = { |
552 | .channels = hmc5883_channels, |
553 | .regval_to_samp_freq = hmc5883_regval_to_samp_freq, |
554 | .n_regval_to_samp_freq = |
555 | ARRAY_SIZE(hmc5883_regval_to_samp_freq), |
556 | .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, |
557 | .n_regval_to_nanoscale = |
558 | ARRAY_SIZE(hmc5883l_regval_to_nanoscale), |
559 | }, |
560 | [HMC5983_ID] = { |
561 | .channels = hmc5983_channels, |
562 | .regval_to_samp_freq = hmc5983_regval_to_samp_freq, |
563 | .n_regval_to_samp_freq = |
564 | ARRAY_SIZE(hmc5983_regval_to_samp_freq), |
565 | .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, |
566 | .n_regval_to_nanoscale = |
567 | ARRAY_SIZE(hmc5883l_regval_to_nanoscale), |
568 | } |
569 | }; |
570 | |
571 | static int hmc5843_init(struct hmc5843_data *data) |
572 | { |
573 | int ret; |
574 | u8 id[3]; |
575 | |
576 | ret = regmap_bulk_read(map: data->regmap, HMC5843_ID_REG, |
577 | val: id, ARRAY_SIZE(id)); |
578 | if (ret < 0) |
579 | return ret; |
580 | if (id[0] != 'H' || id[1] != '4' || id[2] != '3') { |
581 | dev_err(data->dev, "no HMC5843/5883/5883L/5983 sensor\n" ); |
582 | return -ENODEV; |
583 | } |
584 | |
585 | ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL); |
586 | if (ret < 0) |
587 | return ret; |
588 | ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT); |
589 | if (ret < 0) |
590 | return ret; |
591 | ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT); |
592 | if (ret < 0) |
593 | return ret; |
594 | return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS); |
595 | } |
596 | |
597 | static const struct iio_info hmc5843_info = { |
598 | .attrs = &hmc5843_group, |
599 | .read_raw = &hmc5843_read_raw, |
600 | .write_raw = &hmc5843_write_raw, |
601 | .write_raw_get_fmt = &hmc5843_write_raw_get_fmt, |
602 | }; |
603 | |
604 | static const unsigned long hmc5843_scan_masks[] = {0x7, 0}; |
605 | |
606 | static int hmc5843_common_suspend(struct device *dev) |
607 | { |
608 | return hmc5843_set_mode(data: iio_priv(indio_dev: dev_get_drvdata(dev)), |
609 | HMC5843_MODE_SLEEP); |
610 | } |
611 | |
612 | static int hmc5843_common_resume(struct device *dev) |
613 | { |
614 | return hmc5843_set_mode(data: iio_priv(indio_dev: dev_get_drvdata(dev)), |
615 | HMC5843_MODE_CONVERSION_CONTINUOUS); |
616 | } |
617 | EXPORT_NS_SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_common_suspend, |
618 | hmc5843_common_resume, IIO_HMC5843); |
619 | |
620 | int hmc5843_common_probe(struct device *dev, struct regmap *regmap, |
621 | enum hmc5843_ids id, const char *name) |
622 | { |
623 | struct hmc5843_data *data; |
624 | struct iio_dev *indio_dev; |
625 | int ret; |
626 | |
627 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
628 | if (!indio_dev) |
629 | return -ENOMEM; |
630 | |
631 | dev_set_drvdata(dev, data: indio_dev); |
632 | |
633 | /* default settings at probe */ |
634 | data = iio_priv(indio_dev); |
635 | data->dev = dev; |
636 | data->regmap = regmap; |
637 | data->variant = &hmc5843_chip_info_tbl[id]; |
638 | mutex_init(&data->lock); |
639 | |
640 | ret = iio_read_mount_matrix(dev, matrix: &data->orientation); |
641 | if (ret) |
642 | return ret; |
643 | |
644 | indio_dev->name = name; |
645 | indio_dev->info = &hmc5843_info; |
646 | indio_dev->modes = INDIO_DIRECT_MODE; |
647 | indio_dev->channels = data->variant->channels; |
648 | indio_dev->num_channels = 4; |
649 | indio_dev->available_scan_masks = hmc5843_scan_masks; |
650 | |
651 | ret = hmc5843_init(data); |
652 | if (ret < 0) |
653 | return ret; |
654 | |
655 | ret = iio_triggered_buffer_setup(indio_dev, NULL, |
656 | hmc5843_trigger_handler, NULL); |
657 | if (ret < 0) |
658 | goto buffer_setup_err; |
659 | |
660 | ret = iio_device_register(indio_dev); |
661 | if (ret < 0) |
662 | goto buffer_cleanup; |
663 | |
664 | return 0; |
665 | |
666 | buffer_cleanup: |
667 | iio_triggered_buffer_cleanup(indio_dev); |
668 | buffer_setup_err: |
669 | hmc5843_set_mode(data: iio_priv(indio_dev), HMC5843_MODE_SLEEP); |
670 | return ret; |
671 | } |
672 | EXPORT_SYMBOL_NS(hmc5843_common_probe, IIO_HMC5843); |
673 | |
674 | void hmc5843_common_remove(struct device *dev) |
675 | { |
676 | struct iio_dev *indio_dev = dev_get_drvdata(dev); |
677 | |
678 | iio_device_unregister(indio_dev); |
679 | iio_triggered_buffer_cleanup(indio_dev); |
680 | |
681 | /* sleep mode to save power */ |
682 | hmc5843_set_mode(data: iio_priv(indio_dev), HMC5843_MODE_SLEEP); |
683 | } |
684 | EXPORT_SYMBOL_NS(hmc5843_common_remove, IIO_HMC5843); |
685 | |
686 | MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>" ); |
687 | MODULE_DESCRIPTION("HMC5843/5883/5883L/5983 core driver" ); |
688 | MODULE_LICENSE("GPL" ); |
689 | |