Commit | Line | Data |
---|---|---|
b4e17822 S |
1 | /* Copyright (C) 2010 Texas Instruments |
2 | Author: Shubhrajyoti Datta <shubhrajyoti@ti.com> | |
0f8c9620 | 3 | Acknowledgement: Jonathan Cameron <jic23@kernel.org> for valuable inputs. |
b4e17822 | 4 | |
357fcff5 PM |
5 | Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>. |
6 | ||
b4e17822 S |
7 | This program is free software; you can redistribute it and/or modify |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this program; if not, write to the Free Software | |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
20 | */ | |
21 | ||
22 | #include <linux/module.h> | |
b4e17822 | 23 | #include <linux/i2c.h> |
06458e27 JC |
24 | #include <linux/iio/iio.h> |
25 | #include <linux/iio/sysfs.h> | |
cb9b9a82 PM |
26 | #include <linux/iio/trigger_consumer.h> |
27 | #include <linux/iio/buffer.h> | |
28 | #include <linux/iio/triggered_buffer.h> | |
4dedf31c | 29 | #include <linux/delay.h> |
b4e17822 | 30 | |
b4e17822 S |
31 | #define HMC5843_CONFIG_REG_A 0x00 |
32 | #define HMC5843_CONFIG_REG_B 0x01 | |
33 | #define HMC5843_MODE_REG 0x02 | |
39c18828 | 34 | #define HMC5843_DATA_OUT_MSB_REGS 0x03 |
b4e17822 | 35 | #define HMC5843_STATUS_REG 0x09 |
9d5ad0c3 | 36 | #define HMC5843_ID_REG 0x0a |
b4e17822 | 37 | |
357fcff5 PM |
38 | enum hmc5843_ids { |
39 | HMC5843_ID, | |
40 | HMC5883_ID, | |
41 | HMC5883L_ID, | |
42 | }; | |
16b91a40 | 43 | |
b4e17822 | 44 | /* |
16b91a40 PM |
45 | * Range gain settings in (+-)Ga |
46 | * Beware: HMC5843 and HMC5883 have different recommended sensor field | |
47 | * ranges; default corresponds to +-1.0 Ga and +-1.3 Ga, respectively | |
48 | */ | |
49 | #define HMC5843_RANGE_GAIN_OFFSET 0x05 | |
50 | #define HMC5843_RANGE_GAIN_DEFAULT 0x01 | |
ae6f54d2 | 51 | #define HMC5843_RANGE_GAINS 8 |
b4e17822 | 52 | |
9728fe3f | 53 | /* Device status */ |
16b91a40 PM |
54 | #define HMC5843_DATA_READY 0x01 |
55 | #define HMC5843_DATA_OUTPUT_LOCK 0x02 | |
b4e17822 | 56 | |
9728fe3f | 57 | /* Mode register configuration */ |
16b91a40 PM |
58 | #define HMC5843_MODE_CONVERSION_CONTINUOUS 0x00 |
59 | #define HMC5843_MODE_CONVERSION_SINGLE 0x01 | |
60 | #define HMC5843_MODE_IDLE 0x02 | |
61 | #define HMC5843_MODE_SLEEP 0x03 | |
62 | #define HMC5843_MODE_MASK 0x03 | |
63 | ||
64 | /* | |
65 | * HMC5843: Minimum data output rate | |
66 | * HMC5883: Typical data output rate | |
67 | */ | |
68 | #define HMC5843_RATE_OFFSET 0x02 | |
8e2e2971 | 69 | #define HMC5843_RATE_DEFAULT 0x04 |
ca4c6172 | 70 | #define HMC5843_RATES 7 |
b4e17822 | 71 | |
9728fe3f | 72 | /* Device measurement configuration */ |
16b91a40 PM |
73 | #define HMC5843_MEAS_CONF_NORMAL 0x00 |
74 | #define HMC5843_MEAS_CONF_POSITIVE_BIAS 0x01 | |
75 | #define HMC5843_MEAS_CONF_NEGATIVE_BIAS 0x02 | |
16b91a40 | 76 | #define HMC5843_MEAS_CONF_MASK 0x03 |
b4e17822 | 77 | |
9728fe3f | 78 | /* Scaling factors: 10000000/Gain */ |
ae6f54d2 | 79 | static const int hmc5843_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { |
494c6b15 | 80 | 6173, 7692, 10309, 12821, 18868, 21739, 25641, 35714 |
b4e17822 | 81 | }; |
494c6b15 | 82 | |
ae6f54d2 | 83 | static const int hmc5883_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { |
357fcff5 PM |
84 | 7812, 9766, 13021, 16287, 24096, 27701, 32573, 45662 |
85 | }; | |
86 | ||
ae6f54d2 | 87 | static const int hmc5883l_regval_to_nanoscale[HMC5843_RANGE_GAINS] = { |
357fcff5 PM |
88 | 7299, 9174, 12195, 15152, 22727, 25641, 30303, 43478 |
89 | }; | |
90 | ||
c7c34af0 PM |
91 | /* |
92 | * From the datasheet: | |
357fcff5 PM |
93 | * Value | HMC5843 | HMC5883/HMC5883L |
94 | * | Data output rate (Hz) | Data output rate (Hz) | |
95 | * 0 | 0.5 | 0.75 | |
96 | * 1 | 1 | 1.5 | |
97 | * 2 | 2 | 3 | |
98 | * 3 | 5 | 7.5 | |
99 | * 4 | 10 (default) | 15 | |
100 | * 5 | 20 | 30 | |
101 | * 6 | 50 | 75 | |
102 | * 7 | Not used | Not used | |
c7c34af0 | 103 | */ |
d4dc0a34 PM |
104 | static const int hmc5843_regval_to_samp_freq[7][2] = { |
105 | {0, 500000}, {1, 0}, {2, 0}, {5, 0}, {10, 0}, {20, 0}, {50, 0} | |
357fcff5 PM |
106 | }; |
107 | ||
d4dc0a34 PM |
108 | static const int hmc5883_regval_to_samp_freq[7][2] = { |
109 | {0, 750000}, {1, 500000}, {3, 0}, {7, 500000}, {15, 0}, {30, 0}, | |
110 | {75, 0} | |
b4e17822 S |
111 | }; |
112 | ||
357fcff5 PM |
113 | /* Describe chip variants */ |
114 | struct hmc5843_chip_info { | |
115 | const struct iio_chan_spec *channels; | |
d4dc0a34 | 116 | const int (*regval_to_samp_freq)[2]; |
357fcff5 PM |
117 | const int *regval_to_nanoscale; |
118 | }; | |
119 | ||
b4e17822 S |
120 | /* Each client has this additional data */ |
121 | struct hmc5843_data { | |
8a5c1913 | 122 | struct i2c_client *client; |
b4e17822 | 123 | struct mutex lock; |
c7c34af0 PM |
124 | u8 rate; |
125 | u8 meas_conf; | |
126 | u8 operating_mode; | |
127 | u8 range; | |
357fcff5 | 128 | const struct hmc5843_chip_info *variant; |
cb9b9a82 | 129 | __be16 buffer[8]; /* 3x 16-bit channels + padding + 64-bit timestamp */ |
b4e17822 S |
130 | }; |
131 | ||
c7c34af0 | 132 | /* The lower two bits contain the current conversion mode */ |
62248758 | 133 | static s32 hmc5843_set_mode(struct hmc5843_data *data, u8 operating_mode) |
b4e17822 | 134 | { |
62248758 PM |
135 | int ret; |
136 | ||
137 | mutex_lock(&data->lock); | |
138 | ret = i2c_smbus_write_byte_data(data->client, HMC5843_MODE_REG, | |
16b91a40 | 139 | operating_mode & HMC5843_MODE_MASK); |
62248758 PM |
140 | if (ret >= 0) |
141 | data->operating_mode = operating_mode; | |
142 | mutex_unlock(&data->lock); | |
143 | ||
144 | return ret; | |
b4e17822 S |
145 | } |
146 | ||
39c18828 | 147 | static int hmc5843_wait_measurement(struct hmc5843_data *data) |
b4e17822 | 148 | { |
b4e17822 | 149 | s32 result; |
4dedf31c | 150 | int tries = 150; |
b4e17822 | 151 | |
4dedf31c | 152 | while (tries-- > 0) { |
8a5c1913 | 153 | result = i2c_smbus_read_byte_data(data->client, |
4dedf31c | 154 | HMC5843_STATUS_REG); |
39c18828 PM |
155 | if (result < 0) |
156 | return result; | |
4dedf31c PM |
157 | if (result & HMC5843_DATA_READY) |
158 | break; | |
159 | msleep(20); | |
160 | } | |
161 | ||
162 | if (tries < 0) { | |
8a5c1913 | 163 | dev_err(&data->client->dev, "data not ready\n"); |
4dedf31c PM |
164 | return -EIO; |
165 | } | |
b4e17822 | 166 | |
39c18828 PM |
167 | return 0; |
168 | } | |
169 | ||
170 | /* Return the measurement value from the specified channel */ | |
171 | static int hmc5843_read_measurement(struct hmc5843_data *data, | |
172 | int idx, int *val) | |
173 | { | |
174 | s32 result; | |
175 | __be16 values[3]; | |
176 | ||
177 | mutex_lock(&data->lock); | |
178 | result = hmc5843_wait_measurement(data); | |
179 | if (result < 0) { | |
180 | mutex_unlock(&data->lock); | |
181 | return result; | |
182 | } | |
183 | result = i2c_smbus_read_i2c_block_data(data->client, | |
184 | HMC5843_DATA_OUT_MSB_REGS, sizeof(values), (u8 *) values); | |
b4e17822 S |
185 | mutex_unlock(&data->lock); |
186 | if (result < 0) | |
187 | return -EINVAL; | |
188 | ||
39c18828 | 189 | *val = sign_extend32(be16_to_cpu(values[idx]), 15); |
494c6b15 | 190 | return IIO_VAL_INT; |
b4e17822 | 191 | } |
494c6b15 | 192 | |
b4e17822 S |
193 | /* |
194 | * API for setting the measurement configuration to | |
195 | * Normal, Positive bias and Negative bias | |
b4e17822 | 196 | * |
c7c34af0 PM |
197 | * From the datasheet: |
198 | * 0 - Normal measurement configuration (default): In normal measurement | |
199 | * configuration the device follows normal measurement flow. Pins BP | |
200 | * and BN are left floating and high impedance. | |
b4e17822 | 201 | * |
c7c34af0 PM |
202 | * 1 - Positive bias configuration: In positive bias configuration, a |
203 | * positive current is forced across the resistive load on pins BP | |
204 | * and BN. | |
b4e17822 | 205 | * |
c7c34af0 PM |
206 | * 2 - Negative bias configuration. In negative bias configuration, a |
207 | * negative current is forced across the resistive load on pins BP | |
208 | * and BN. | |
b4e17822 S |
209 | * |
210 | */ | |
8a5c1913 | 211 | static s32 hmc5843_set_meas_conf(struct hmc5843_data *data, u8 meas_conf) |
b4e17822 | 212 | { |
4f1ca415 PM |
213 | int ret; |
214 | ||
215 | mutex_lock(&data->lock); | |
216 | ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, | |
217 | (meas_conf & HMC5843_MEAS_CONF_MASK) | | |
218 | (data->rate << HMC5843_RATE_OFFSET)); | |
219 | if (ret >= 0) | |
220 | data->meas_conf = meas_conf; | |
221 | mutex_unlock(&data->lock); | |
222 | ||
223 | return ret; | |
b4e17822 S |
224 | } |
225 | ||
226 | static ssize_t hmc5843_show_measurement_configuration(struct device *dev, | |
227 | struct device_attribute *attr, | |
228 | char *buf) | |
229 | { | |
4f1ca415 | 230 | struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); |
b4e17822 S |
231 | return sprintf(buf, "%d\n", data->meas_conf); |
232 | } | |
233 | ||
234 | static ssize_t hmc5843_set_measurement_configuration(struct device *dev, | |
235 | struct device_attribute *attr, | |
236 | const char *buf, | |
237 | size_t count) | |
238 | { | |
4f1ca415 | 239 | struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); |
b4e17822 | 240 | unsigned long meas_conf = 0; |
4f1ca415 | 241 | int ret; |
e278df1c | 242 | |
4f1ca415 PM |
243 | ret = kstrtoul(buf, 10, &meas_conf); |
244 | if (ret) | |
245 | return ret; | |
246 | if (meas_conf >= HMC5843_MEAS_CONF_MASK) | |
e278df1c PM |
247 | return -EINVAL; |
248 | ||
4f1ca415 | 249 | ret = hmc5843_set_meas_conf(data, meas_conf); |
b4e17822 | 250 | |
4f1ca415 | 251 | return (ret < 0) ? ret : count; |
b4e17822 | 252 | } |
c7c34af0 | 253 | |
b4e17822 S |
254 | static IIO_DEVICE_ATTR(meas_conf, |
255 | S_IWUSR | S_IRUGO, | |
256 | hmc5843_show_measurement_configuration, | |
257 | hmc5843_set_measurement_configuration, | |
258 | 0); | |
259 | ||
9a3b2d5e PM |
260 | static ssize_t hmc5843_show_samp_freq_avail(struct device *dev, |
261 | struct device_attribute *attr, char *buf) | |
357fcff5 | 262 | { |
9a3b2d5e | 263 | struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); |
dd28e482 | 264 | size_t len = 0; |
357fcff5 PM |
265 | int i; |
266 | ||
ca4c6172 | 267 | for (i = 0; i < HMC5843_RATES; i++) |
dd28e482 | 268 | len += scnprintf(buf + len, PAGE_SIZE - len, |
9a3b2d5e PM |
269 | "%d.%d ", data->variant->regval_to_samp_freq[i][0], |
270 | data->variant->regval_to_samp_freq[i][1]); | |
dd28e482 | 271 | |
357fcff5 | 272 | /* replace trailing space by newline */ |
dd28e482 PM |
273 | buf[len - 1] = '\n'; |
274 | ||
275 | return len; | |
276 | } | |
357fcff5 | 277 | |
d4dc0a34 | 278 | static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(hmc5843_show_samp_freq_avail); |
b4e17822 | 279 | |
ca4c6172 | 280 | static int hmc5843_set_samp_freq(struct hmc5843_data *data, u8 rate) |
b4e17822 | 281 | { |
ca4c6172 PM |
282 | int ret; |
283 | ||
284 | mutex_lock(&data->lock); | |
285 | ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_A, | |
286 | data->meas_conf | (rate << HMC5843_RATE_OFFSET)); | |
287 | if (ret >= 0) | |
288 | data->rate = rate; | |
289 | mutex_unlock(&data->lock); | |
4fd4d7d8 | 290 | |
ca4c6172 | 291 | return ret; |
b4e17822 S |
292 | } |
293 | ||
9a3b2d5e | 294 | static int hmc5843_get_samp_freq_index(struct hmc5843_data *data, |
d4dc0a34 | 295 | int val, int val2) |
13f6eb69 | 296 | { |
9a3b2d5e PM |
297 | int i; |
298 | ||
ca4c6172 | 299 | for (i = 0; i < HMC5843_RATES; i++) |
9a3b2d5e PM |
300 | if (val == data->variant->regval_to_samp_freq[i][0] && |
301 | val2 == data->variant->regval_to_samp_freq[i][1]) | |
302 | return i; | |
303 | ||
304 | return -EINVAL; | |
13f6eb69 PM |
305 | } |
306 | ||
f3f75519 PM |
307 | static int hmc5843_set_range_gain(struct hmc5843_data *data, u8 range) |
308 | { | |
309 | int ret; | |
310 | ||
311 | mutex_lock(&data->lock); | |
312 | ret = i2c_smbus_write_byte_data(data->client, HMC5843_CONFIG_REG_B, | |
313 | range << HMC5843_RANGE_GAIN_OFFSET); | |
314 | if (ret >= 0) | |
315 | data->range = range; | |
316 | mutex_unlock(&data->lock); | |
317 | ||
318 | return ret; | |
319 | } | |
320 | ||
ae6f54d2 PM |
321 | static ssize_t hmc5843_show_scale_avail(struct device *dev, |
322 | struct device_attribute *attr, char *buf) | |
b4e17822 | 323 | { |
ae6f54d2 PM |
324 | struct hmc5843_data *data = iio_priv(dev_to_iio_dev(dev)); |
325 | ||
326 | size_t len = 0; | |
327 | int i; | |
b4e17822 | 328 | |
ae6f54d2 PM |
329 | for (i = 0; i < HMC5843_RANGE_GAINS; i++) |
330 | len += scnprintf(buf + len, PAGE_SIZE - len, | |
331 | "0.%09d ", data->variant->regval_to_nanoscale[i]); | |
332 | ||
333 | /* replace trailing space by newline */ | |
334 | buf[len - 1] = '\n'; | |
335 | ||
336 | return len; | |
b4e17822 S |
337 | } |
338 | ||
ae6f54d2 PM |
339 | static IIO_DEVICE_ATTR(scale_available, S_IRUGO, |
340 | hmc5843_show_scale_avail, NULL, 0); | |
c7c34af0 | 341 | |
ae6f54d2 PM |
342 | static int hmc5843_get_scale_index(struct hmc5843_data *data, int val, int val2) |
343 | { | |
344 | int i; | |
b4e17822 | 345 | |
ae6f54d2 PM |
346 | if (val != 0) |
347 | return -EINVAL; | |
b4e17822 | 348 | |
ae6f54d2 PM |
349 | for (i = 0; i < HMC5843_RANGE_GAINS; i++) |
350 | if (val2 == data->variant->regval_to_nanoscale[i]) | |
351 | return i; | |
b4e17822 | 352 | |
ae6f54d2 | 353 | return -EINVAL; |
b4e17822 | 354 | } |
c7c34af0 | 355 | |
494c6b15 JC |
356 | static int hmc5843_read_raw(struct iio_dev *indio_dev, |
357 | struct iio_chan_spec const *chan, | |
d4dc0a34 | 358 | int *val, int *val2, long mask) |
b4e17822 | 359 | { |
88fa4de4 | 360 | struct hmc5843_data *data = iio_priv(indio_dev); |
494c6b15 JC |
361 | |
362 | switch (mask) { | |
4d9948b3 | 363 | case IIO_CHAN_INFO_RAW: |
cb9b9a82 | 364 | return hmc5843_read_measurement(data, chan->scan_index, val); |
c8a9f805 | 365 | case IIO_CHAN_INFO_SCALE: |
494c6b15 | 366 | *val = 0; |
357fcff5 | 367 | *val2 = data->variant->regval_to_nanoscale[data->range]; |
494c6b15 | 368 | return IIO_VAL_INT_PLUS_NANO; |
d4dc0a34 PM |
369 | case IIO_CHAN_INFO_SAMP_FREQ: |
370 | *val = data->variant->regval_to_samp_freq[data->rate][0]; | |
371 | *val2 = data->variant->regval_to_samp_freq[data->rate][1]; | |
372 | return IIO_VAL_INT_PLUS_MICRO; | |
73327b4c | 373 | } |
494c6b15 | 374 | return -EINVAL; |
b4e17822 | 375 | } |
494c6b15 | 376 | |
d4dc0a34 PM |
377 | static int hmc5843_write_raw(struct iio_dev *indio_dev, |
378 | struct iio_chan_spec const *chan, | |
379 | int val, int val2, long mask) | |
380 | { | |
381 | struct hmc5843_data *data = iio_priv(indio_dev); | |
f3f75519 | 382 | int rate, range; |
d4dc0a34 PM |
383 | |
384 | switch (mask) { | |
385 | case IIO_CHAN_INFO_SAMP_FREQ: | |
9a3b2d5e | 386 | rate = hmc5843_get_samp_freq_index(data, val, val2); |
d4dc0a34 PM |
387 | if (rate < 0) |
388 | return -EINVAL; | |
389 | ||
ca4c6172 | 390 | return hmc5843_set_samp_freq(data, rate); |
ae6f54d2 PM |
391 | case IIO_CHAN_INFO_SCALE: |
392 | range = hmc5843_get_scale_index(data, val, val2); | |
393 | if (range < 0) | |
394 | return -EINVAL; | |
395 | ||
f3f75519 | 396 | return hmc5843_set_range_gain(data, range); |
ae6f54d2 PM |
397 | default: |
398 | return -EINVAL; | |
399 | } | |
400 | } | |
401 | ||
402 | static int hmc5843_write_raw_get_fmt(struct iio_dev *indio_dev, | |
403 | struct iio_chan_spec const *chan, long mask) | |
404 | { | |
405 | switch (mask) { | |
406 | case IIO_CHAN_INFO_SAMP_FREQ: | |
407 | return IIO_VAL_INT_PLUS_MICRO; | |
408 | case IIO_CHAN_INFO_SCALE: | |
409 | return IIO_VAL_INT_PLUS_NANO; | |
d4dc0a34 PM |
410 | default: |
411 | return -EINVAL; | |
412 | } | |
413 | } | |
414 | ||
cb9b9a82 PM |
415 | static irqreturn_t hmc5843_trigger_handler(int irq, void *p) |
416 | { | |
417 | struct iio_poll_func *pf = p; | |
418 | struct iio_dev *indio_dev = pf->indio_dev; | |
419 | struct hmc5843_data *data = iio_priv(indio_dev); | |
420 | int ret; | |
421 | ||
422 | mutex_lock(&data->lock); | |
423 | ret = hmc5843_wait_measurement(data); | |
424 | if (ret < 0) { | |
425 | mutex_unlock(&data->lock); | |
426 | goto done; | |
427 | } | |
428 | ||
429 | ret = i2c_smbus_read_i2c_block_data(data->client, | |
430 | HMC5843_DATA_OUT_MSB_REGS, 3 * sizeof(__be16), | |
431 | (u8 *) data->buffer); | |
432 | mutex_unlock(&data->lock); | |
433 | if (ret < 0) | |
434 | goto done; | |
435 | ||
436 | iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, | |
437 | iio_get_time_ns()); | |
438 | ||
439 | done: | |
440 | iio_trigger_notify_done(indio_dev->trig); | |
441 | ||
442 | return IRQ_HANDLED; | |
443 | } | |
444 | ||
39c18828 | 445 | #define HMC5843_CHANNEL(axis, idx) \ |
494c6b15 JC |
446 | { \ |
447 | .type = IIO_MAGN, \ | |
448 | .modified = 1, \ | |
449 | .channel2 = IIO_MOD_##axis, \ | |
b3700970 | 450 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ |
d4dc0a34 PM |
451 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ |
452 | BIT(IIO_CHAN_INFO_SAMP_FREQ), \ | |
cb9b9a82 | 453 | .scan_index = idx, \ |
c5fe7a41 JC |
454 | .scan_type = { \ |
455 | .sign = 's', \ | |
456 | .realbits = 16, \ | |
457 | .storagebits = 16, \ | |
458 | .endianness = IIO_BE, \ | |
459 | }, \ | |
494c6b15 JC |
460 | } |
461 | ||
462 | static const struct iio_chan_spec hmc5843_channels[] = { | |
39c18828 PM |
463 | HMC5843_CHANNEL(X, 0), |
464 | HMC5843_CHANNEL(Y, 1), | |
465 | HMC5843_CHANNEL(Z, 2), | |
cb9b9a82 | 466 | IIO_CHAN_SOFT_TIMESTAMP(3), |
494c6b15 | 467 | }; |
b4e17822 | 468 | |
39c18828 | 469 | /* Beware: Y and Z are exchanged on HMC5883 */ |
357fcff5 | 470 | static const struct iio_chan_spec hmc5883_channels[] = { |
39c18828 PM |
471 | HMC5843_CHANNEL(X, 0), |
472 | HMC5843_CHANNEL(Z, 1), | |
473 | HMC5843_CHANNEL(Y, 2), | |
cb9b9a82 | 474 | IIO_CHAN_SOFT_TIMESTAMP(3), |
357fcff5 PM |
475 | }; |
476 | ||
b4e17822 S |
477 | static struct attribute *hmc5843_attributes[] = { |
478 | &iio_dev_attr_meas_conf.dev_attr.attr, | |
ae6f54d2 | 479 | &iio_dev_attr_scale_available.dev_attr.attr, |
357fcff5 | 480 | &iio_dev_attr_sampling_frequency_available.dev_attr.attr, |
b4e17822 S |
481 | NULL |
482 | }; | |
483 | ||
484 | static const struct attribute_group hmc5843_group = { | |
485 | .attrs = hmc5843_attributes, | |
486 | }; | |
487 | ||
357fcff5 PM |
488 | static const struct hmc5843_chip_info hmc5843_chip_info_tbl[] = { |
489 | [HMC5843_ID] = { | |
490 | .channels = hmc5843_channels, | |
d4dc0a34 | 491 | .regval_to_samp_freq = hmc5843_regval_to_samp_freq, |
357fcff5 PM |
492 | .regval_to_nanoscale = hmc5843_regval_to_nanoscale, |
493 | }, | |
494 | [HMC5883_ID] = { | |
495 | .channels = hmc5883_channels, | |
d4dc0a34 | 496 | .regval_to_samp_freq = hmc5883_regval_to_samp_freq, |
357fcff5 PM |
497 | .regval_to_nanoscale = hmc5883_regval_to_nanoscale, |
498 | }, | |
499 | [HMC5883L_ID] = { | |
500 | .channels = hmc5883_channels, | |
d4dc0a34 | 501 | .regval_to_samp_freq = hmc5883_regval_to_samp_freq, |
357fcff5 PM |
502 | .regval_to_nanoscale = hmc5883l_regval_to_nanoscale, |
503 | }, | |
504 | }; | |
505 | ||
9d5ad0c3 | 506 | static int hmc5843_init(struct hmc5843_data *data) |
b4e17822 | 507 | { |
9d5ad0c3 PM |
508 | int ret; |
509 | u8 id[3]; | |
510 | ||
511 | ret = i2c_smbus_read_i2c_block_data(data->client, HMC5843_ID_REG, | |
512 | sizeof(id), id); | |
513 | if (ret < 0) | |
514 | return ret; | |
515 | if (id[0] != 'H' || id[1] != '4' || id[2] != '3') { | |
516 | dev_err(&data->client->dev, "no HMC5843/5883/5883L sensor\n"); | |
517 | return -ENODEV; | |
518 | } | |
519 | ||
520 | ret = hmc5843_set_meas_conf(data, HMC5843_MEAS_CONF_NORMAL); | |
521 | if (ret < 0) | |
522 | return ret; | |
523 | ret = hmc5843_set_samp_freq(data, HMC5843_RATE_DEFAULT); | |
524 | if (ret < 0) | |
525 | return ret; | |
526 | ret = hmc5843_set_range_gain(data, HMC5843_RANGE_GAIN_DEFAULT); | |
527 | if (ret < 0) | |
528 | return ret; | |
529 | return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS); | |
b4e17822 S |
530 | } |
531 | ||
6fe8135f JC |
532 | static const struct iio_info hmc5843_info = { |
533 | .attrs = &hmc5843_group, | |
494c6b15 | 534 | .read_raw = &hmc5843_read_raw, |
d4dc0a34 | 535 | .write_raw = &hmc5843_write_raw, |
ae6f54d2 | 536 | .write_raw_get_fmt = &hmc5843_write_raw_get_fmt, |
6fe8135f JC |
537 | .driver_module = THIS_MODULE, |
538 | }; | |
539 | ||
cb9b9a82 PM |
540 | static const unsigned long hmc5843_scan_masks[] = {0x7, 0}; |
541 | ||
4ae1c61f | 542 | static int hmc5843_probe(struct i2c_client *client, |
b4e17822 S |
543 | const struct i2c_device_id *id) |
544 | { | |
545 | struct hmc5843_data *data; | |
88fa4de4 | 546 | struct iio_dev *indio_dev; |
cb9b9a82 | 547 | int ret; |
b4e17822 | 548 | |
a6dcb71b PM |
549 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); |
550 | if (indio_dev == NULL) | |
551 | return -ENOMEM; | |
b4e17822 | 552 | |
16b91a40 PM |
553 | /* default settings at probe */ |
554 | data = iio_priv(indio_dev); | |
8a5c1913 | 555 | data->client = client; |
8e2e2971 PM |
556 | data->variant = &hmc5843_chip_info_tbl[id->driver_data]; |
557 | mutex_init(&data->lock); | |
b4e17822 | 558 | |
88fa4de4 | 559 | i2c_set_clientdata(client, indio_dev); |
88fa4de4 | 560 | indio_dev->info = &hmc5843_info; |
494c6b15 | 561 | indio_dev->name = id->name; |
88fa4de4 JC |
562 | indio_dev->dev.parent = &client->dev; |
563 | indio_dev->modes = INDIO_DIRECT_MODE; | |
8e2e2971 | 564 | indio_dev->channels = data->variant->channels; |
cb9b9a82 PM |
565 | indio_dev->num_channels = 4; |
566 | indio_dev->available_scan_masks = hmc5843_scan_masks; | |
8e2e2971 | 567 | |
9d5ad0c3 PM |
568 | ret = hmc5843_init(data); |
569 | if (ret < 0) | |
570 | return ret; | |
c7c34af0 | 571 | |
cb9b9a82 PM |
572 | ret = iio_triggered_buffer_setup(indio_dev, NULL, |
573 | hmc5843_trigger_handler, NULL); | |
574 | if (ret < 0) | |
575 | return ret; | |
576 | ||
577 | ret = iio_device_register(indio_dev); | |
578 | if (ret < 0) | |
579 | goto buffer_cleanup; | |
c7c34af0 | 580 | |
b4e17822 | 581 | return 0; |
cb9b9a82 PM |
582 | |
583 | buffer_cleanup: | |
584 | iio_triggered_buffer_cleanup(indio_dev); | |
585 | return ret; | |
b4e17822 S |
586 | } |
587 | ||
447d4f29 | 588 | static int hmc5843_remove(struct i2c_client *client) |
b4e17822 | 589 | { |
cb9b9a82 PM |
590 | struct iio_dev *indio_dev = i2c_get_clientdata(client); |
591 | ||
592 | iio_device_unregister(indio_dev); | |
593 | iio_triggered_buffer_cleanup(indio_dev); | |
594 | ||
094509b1 | 595 | /* sleep mode to save power */ |
62248758 | 596 | hmc5843_set_mode(iio_priv(indio_dev), HMC5843_MODE_SLEEP); |
88fa4de4 | 597 | |
b4e17822 S |
598 | return 0; |
599 | } | |
600 | ||
01788c53 LPC |
601 | #ifdef CONFIG_PM_SLEEP |
602 | static int hmc5843_suspend(struct device *dev) | |
b4e17822 | 603 | { |
62248758 PM |
604 | struct hmc5843_data *data = iio_priv(i2c_get_clientdata( |
605 | to_i2c_client(dev))); | |
a6dcb71b | 606 | |
62248758 | 607 | return hmc5843_set_mode(data, HMC5843_MODE_SLEEP); |
b4e17822 S |
608 | } |
609 | ||
01788c53 | 610 | static int hmc5843_resume(struct device *dev) |
b4e17822 | 611 | { |
8a5c1913 PM |
612 | struct hmc5843_data *data = iio_priv(i2c_get_clientdata( |
613 | to_i2c_client(dev))); | |
0462e2bb | 614 | |
62248758 | 615 | return hmc5843_set_mode(data, HMC5843_MODE_CONVERSION_CONTINUOUS); |
b4e17822 S |
616 | } |
617 | ||
01788c53 LPC |
618 | static SIMPLE_DEV_PM_OPS(hmc5843_pm_ops, hmc5843_suspend, hmc5843_resume); |
619 | #define HMC5843_PM_OPS (&hmc5843_pm_ops) | |
620 | #else | |
621 | #define HMC5843_PM_OPS NULL | |
622 | #endif | |
623 | ||
b4e17822 | 624 | static const struct i2c_device_id hmc5843_id[] = { |
357fcff5 PM |
625 | { "hmc5843", HMC5843_ID }, |
626 | { "hmc5883", HMC5883_ID }, | |
627 | { "hmc5883l", HMC5883L_ID }, | |
b4e17822 S |
628 | { } |
629 | }; | |
55e4390c | 630 | MODULE_DEVICE_TABLE(i2c, hmc5843_id); |
b4e17822 S |
631 | |
632 | static struct i2c_driver hmc5843_driver = { | |
633 | .driver = { | |
634 | .name = "hmc5843", | |
01788c53 | 635 | .pm = HMC5843_PM_OPS, |
b4e17822 S |
636 | }, |
637 | .id_table = hmc5843_id, | |
638 | .probe = hmc5843_probe, | |
e543acf0 | 639 | .remove = hmc5843_remove, |
b4e17822 | 640 | }; |
6e5af184 | 641 | module_i2c_driver(hmc5843_driver); |
b4e17822 | 642 | |
b658a377 | 643 | MODULE_AUTHOR("Shubhrajyoti Datta <shubhrajyoti@ti.com>"); |
357fcff5 | 644 | MODULE_DESCRIPTION("HMC5843/5883/5883L driver"); |
b4e17822 | 645 | MODULE_LICENSE("GPL"); |