blob: 8f0867495ef5d7f0d6d8826ab2f592bc31e2e2f6 [file] [log] [blame]
Thomas Gleixner80503b22019-05-24 12:04:09 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +00002/*
3 * Common library for ADIS16XXX devices
4 *
5 * Copyright 2012 Analog Devices Inc.
6 * Author: Lars-Peter Clausen <lars@metafoo.de>
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +00007 */
8
9#include <linux/delay.h>
10#include <linux/mutex.h>
11#include <linux/device.h>
12#include <linux/kernel.h>
13#include <linux/spi/spi.h>
14#include <linux/slab.h>
15#include <linux/sysfs.h>
16#include <linux/module.h>
17#include <asm/unaligned.h>
18
19#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21#include <linux/iio/buffer.h>
Lars-Peter Clausenec04cb02012-11-13 13:28:00 +000022#include <linux/iio/imu/adis.h>
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000023
24#define ADIS_MSC_CTRL_DATA_RDY_EN BIT(2)
25#define ADIS_MSC_CTRL_DATA_RDY_POL_HIGH BIT(1)
26#define ADIS_MSC_CTRL_DATA_RDY_DIO2 BIT(0)
27#define ADIS_GLOB_CMD_SW_RESET BIT(7)
28
Alexandru Ardelean770d4652019-11-22 15:24:12 +020029/**
30 * __adis_write_reg() - write N bytes to register (unlocked version)
31 * @adis: The adis device
32 * @reg: The address of the lower of the two registers
33 * @value: The value to write to device (up to 4 bytes)
34 * @size: The size of the @value (in bytes)
35 */
36int __adis_write_reg(struct adis *adis, unsigned int reg,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000037 unsigned int value, unsigned int size)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000038{
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +000039 unsigned int page = reg / ADIS_PAGE_SIZE;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000040 int ret, i;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000041 struct spi_message msg;
42 struct spi_transfer xfers[] = {
43 {
44 .tx_buf = adis->tx,
45 .bits_per_word = 8,
46 .len = 2,
47 .cs_change = 1,
48 .delay_usecs = adis->data->write_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +030049 .cs_change_delay.value = adis->data->cs_change_delay,
50 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000051 }, {
52 .tx_buf = adis->tx + 2,
53 .bits_per_word = 8,
54 .len = 2,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000055 .cs_change = 1,
56 .delay_usecs = adis->data->write_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +030057 .cs_change_delay.value = adis->data->cs_change_delay,
58 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000059 }, {
60 .tx_buf = adis->tx + 4,
61 .bits_per_word = 8,
62 .len = 2,
63 .cs_change = 1,
64 .delay_usecs = adis->data->write_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +030065 .cs_change_delay.value = adis->data->cs_change_delay,
66 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000067 }, {
68 .tx_buf = adis->tx + 6,
69 .bits_per_word = 8,
70 .len = 2,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000071 .delay_usecs = adis->data->write_delay,
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +000072 }, {
73 .tx_buf = adis->tx + 8,
74 .bits_per_word = 8,
75 .len = 2,
76 .delay_usecs = adis->data->write_delay,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000077 },
78 };
79
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +000080 spi_message_init(&msg);
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +000081
82 if (adis->current_page != page) {
83 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
84 adis->tx[1] = page;
85 spi_message_add_tail(&xfers[0], &msg);
86 }
87
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000088 switch (size) {
89 case 4:
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +000090 adis->tx[8] = ADIS_WRITE_REG(reg + 3);
91 adis->tx[9] = (value >> 24) & 0xff;
92 adis->tx[6] = ADIS_WRITE_REG(reg + 2);
93 adis->tx[7] = (value >> 16) & 0xff;
Gustavo A. R. Silva82d65f92018-07-03 14:35:50 -050094 /* fall through */
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000095 case 2:
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +000096 adis->tx[4] = ADIS_WRITE_REG(reg + 1);
97 adis->tx[5] = (value >> 8) & 0xff;
Gustavo A. R. Silva82d65f92018-07-03 14:35:50 -050098 /* fall through */
Lars-Peter Clausen57a12282012-11-20 13:36:00 +000099 case 1:
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000100 adis->tx[2] = ADIS_WRITE_REG(reg);
101 adis->tx[3] = value & 0xff;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000102 break;
103 default:
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200104 return -EINVAL;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000105 }
106
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000107 xfers[size].cs_change = 0;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000108
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000109 for (i = 1; i <= size; i++)
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000110 spi_message_add_tail(&xfers[i], &msg);
111
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000112 ret = spi_sync(adis->spi, &msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000113 if (ret) {
114 dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
115 reg, ret);
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000116 } else {
117 adis->current_page = page;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000118 }
119
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000120 return ret;
121}
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200122EXPORT_SYMBOL_GPL(__adis_write_reg);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000123
124/**
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200125 * __adis_read_reg() - read N bytes from register (unlocked version)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000126 * @adis: The adis device
127 * @reg: The address of the lower of the two registers
128 * @val: The value read back from the device
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200129 * @size: The size of the @val buffer
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000130 */
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200131int __adis_read_reg(struct adis *adis, unsigned int reg,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000132 unsigned int *val, unsigned int size)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000133{
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000134 unsigned int page = reg / ADIS_PAGE_SIZE;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000135 struct spi_message msg;
136 int ret;
137 struct spi_transfer xfers[] = {
138 {
139 .tx_buf = adis->tx,
140 .bits_per_word = 8,
141 .len = 2,
142 .cs_change = 1,
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000143 .delay_usecs = adis->data->write_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +0300144 .cs_change_delay.value = adis->data->cs_change_delay,
145 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000146 }, {
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000147 .tx_buf = adis->tx + 2,
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000148 .bits_per_word = 8,
149 .len = 2,
150 .cs_change = 1,
151 .delay_usecs = adis->data->read_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +0300152 .cs_change_delay.value = adis->data->cs_change_delay,
153 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000154 }, {
155 .tx_buf = adis->tx + 4,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000156 .rx_buf = adis->rx,
157 .bits_per_word = 8,
158 .len = 2,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000159 .cs_change = 1,
160 .delay_usecs = adis->data->read_delay,
Alexandru Ardelean329f0da2019-09-26 13:51:31 +0300161 .cs_change_delay.value = adis->data->cs_change_delay,
162 .cs_change_delay.unit = SPI_DELAY_UNIT_USECS,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000163 }, {
164 .rx_buf = adis->rx + 2,
165 .bits_per_word = 8,
166 .len = 2,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000167 .delay_usecs = adis->data->read_delay,
168 },
169 };
170
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000171 spi_message_init(&msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000172
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000173 if (adis->current_page != page) {
174 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
175 adis->tx[1] = page;
176 spi_message_add_tail(&xfers[0], &msg);
177 }
178
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000179 switch (size) {
180 case 4:
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000181 adis->tx[2] = ADIS_READ_REG(reg + 2);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000182 adis->tx[3] = 0;
183 spi_message_add_tail(&xfers[1], &msg);
Gustavo A. R. Silva82d65f92018-07-03 14:35:50 -0500184 /* fall through */
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000185 case 2:
186 adis->tx[4] = ADIS_READ_REG(reg);
187 adis->tx[5] = 0;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000188 spi_message_add_tail(&xfers[2], &msg);
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000189 spi_message_add_tail(&xfers[3], &msg);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000190 break;
191 default:
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200192 return -EINVAL;
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000193 }
194
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000195 ret = spi_sync(adis->spi, &msg);
196 if (ret) {
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000197 dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000198 reg, ret);
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200199 return ret;
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000200 } else {
201 adis->current_page = page;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000202 }
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000203
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000204 switch (size) {
205 case 4:
206 *val = get_unaligned_be32(adis->rx);
207 break;
208 case 2:
209 *val = get_unaligned_be16(adis->rx + 2);
210 break;
211 }
212
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000213 return ret;
214}
Alexandru Ardelean770d4652019-11-22 15:24:12 +0200215EXPORT_SYMBOL_GPL(__adis_read_reg);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000216
Lars-Peter Clausen78026a62012-11-20 13:36:00 +0000217#ifdef CONFIG_DEBUG_FS
218
219int adis_debugfs_reg_access(struct iio_dev *indio_dev,
220 unsigned int reg, unsigned int writeval, unsigned int *readval)
221{
222 struct adis *adis = iio_device_get_drvdata(indio_dev);
223
224 if (readval) {
225 uint16_t val16;
226 int ret;
227
228 ret = adis_read_reg_16(adis, reg, &val16);
Alexandru Ardelean38262c02019-11-01 11:35:04 +0200229 if (ret == 0)
230 *readval = val16;
Lars-Peter Clausen78026a62012-11-20 13:36:00 +0000231
232 return ret;
233 } else {
234 return adis_write_reg_16(adis, reg, writeval);
235 }
236}
237EXPORT_SYMBOL(adis_debugfs_reg_access);
238
239#endif
240
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000241/**
242 * adis_enable_irq() - Enable or disable data ready IRQ
243 * @adis: The adis device
244 * @enable: Whether to enable the IRQ
245 *
246 * Returns 0 on success, negative error code otherwise
247 */
248int adis_enable_irq(struct adis *adis, bool enable)
249{
250 int ret = 0;
251 uint16_t msc;
252
Alexandru Ardelean100bfa32019-11-22 15:24:13 +0200253 mutex_lock(&adis->state_lock);
Lars-Peter Clausen2f3abe62012-11-20 13:36:00 +0000254
Alexandru Ardelean100bfa32019-11-22 15:24:13 +0200255 if (adis->data->enable_irq) {
256 ret = adis->data->enable_irq(adis, enable);
257 goto out_unlock;
258 }
259
260 ret = __adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000261 if (ret)
Alexandru Ardelean100bfa32019-11-22 15:24:13 +0200262 goto out_unlock;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000263
264 msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
265 msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
266 if (enable)
267 msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
268 else
269 msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
270
Alexandru Ardelean100bfa32019-11-22 15:24:13 +0200271 ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000272
Alexandru Ardelean100bfa32019-11-22 15:24:13 +0200273out_unlock:
274 mutex_unlock(&adis->state_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000275 return ret;
276}
277EXPORT_SYMBOL(adis_enable_irq);
278
279/**
Alexandru Ardelean6a4d6a72019-11-22 15:24:14 +0200280 * __adis_check_status() - Check the device for error conditions (unlocked)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000281 * @adis: The adis device
282 *
283 * Returns 0 on success, a negative error code otherwise
284 */
Alexandru Ardelean6a4d6a72019-11-22 15:24:14 +0200285int __adis_check_status(struct adis *adis)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000286{
287 uint16_t status;
288 int ret;
289 int i;
290
Alexandru Ardelean6a4d6a72019-11-22 15:24:14 +0200291 ret = __adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
Alexandru Ardelean6a39ab32019-11-01 11:35:00 +0200292 if (ret)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000293 return ret;
294
295 status &= adis->data->status_error_mask;
296
297 if (status == 0)
298 return 0;
299
300 for (i = 0; i < 16; ++i) {
301 if (status & BIT(i)) {
302 dev_err(&adis->spi->dev, "%s.\n",
303 adis->data->status_error_msgs[i]);
304 }
305 }
306
307 return -EIO;
308}
Alexandru Ardelean6a4d6a72019-11-22 15:24:14 +0200309EXPORT_SYMBOL_GPL(__adis_check_status);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000310
311/**
Alexandru Ardelean762ab092019-11-22 15:24:15 +0200312 * __adis_reset() - Reset the device (unlocked version)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000313 * @adis: The adis device
314 *
315 * Returns 0 on success, a negative error code otherwise
316 */
Alexandru Ardelean762ab092019-11-22 15:24:15 +0200317int __adis_reset(struct adis *adis)
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000318{
319 int ret;
Nuno Sá380b1072020-01-07 13:17:04 +0200320 const struct adis_timeout *timeouts = adis->data->timeouts;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000321
Alexandru Ardelean762ab092019-11-22 15:24:15 +0200322 ret = __adis_write_reg_8(adis, adis->data->glob_cmd_reg,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000323 ADIS_GLOB_CMD_SW_RESET);
Nuno Sá380b1072020-01-07 13:17:04 +0200324 if (ret) {
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000325 dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
Nuno Sá380b1072020-01-07 13:17:04 +0200326 return ret;
327 }
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000328
Nuno Sá380b1072020-01-07 13:17:04 +0200329 msleep(timeouts->sw_reset_ms);
330
331 return 0;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000332}
Alexandru Ardelean762ab092019-11-22 15:24:15 +0200333EXPORT_SYMBOL_GPL(__adis_reset);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000334
335static int adis_self_test(struct adis *adis)
336{
337 int ret;
Nuno Sá380b1072020-01-07 13:17:04 +0200338 const struct adis_timeout *timeouts = adis->data->timeouts;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000339
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200340 ret = __adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000341 adis->data->self_test_mask);
342 if (ret) {
343 dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
344 ret);
345 return ret;
346 }
347
Nuno Sá380b1072020-01-07 13:17:04 +0200348 msleep(timeouts->self_test_ms);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000349
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200350 ret = __adis_check_status(adis);
Lars-Peter Clausenaf8a4122016-04-15 16:59:38 +0200351
352 if (adis->data->self_test_no_autoclear)
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200353 __adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
Lars-Peter Clausenaf8a4122016-04-15 16:59:38 +0200354
355 return ret;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000356}
357
358/**
359 * adis_inital_startup() - Performs device self-test
360 * @adis: The adis device
361 *
362 * Returns 0 if the device is operational, a negative error code otherwise.
363 *
364 * This function should be called early on in the device initialization sequence
365 * to ensure that the device is in a sane and known state and that it is usable.
366 */
367int adis_initial_startup(struct adis *adis)
368{
369 int ret;
370
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200371 mutex_lock(&adis->state_lock);
372
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000373 ret = adis_self_test(adis);
374 if (ret) {
375 dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200376 __adis_reset(adis);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000377 ret = adis_self_test(adis);
378 if (ret) {
379 dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200380 goto out_unlock;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000381 }
382 }
383
Alexandru Ardeleancb5a07f2019-11-22 15:24:16 +0200384out_unlock:
385 mutex_unlock(&adis->state_lock);
386 return ret;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000387}
388EXPORT_SYMBOL_GPL(adis_initial_startup);
389
390/**
391 * adis_single_conversion() - Performs a single sample conversion
392 * @indio_dev: The IIO device
393 * @chan: The IIO channel
394 * @error_mask: Mask for the error bit
395 * @val: Result of the conversion
396 *
397 * Returns IIO_VAL_INT on success, a negative error code otherwise.
398 *
399 * The function performs a single conversion on a given channel and post
400 * processes the value accordingly to the channel spec. If a error_mask is given
401 * the function will check if the mask is set in the returned raw value. If it
402 * is set the function will perform a self-check. If the device does not report
403 * a error bit in the channels raw value set error_mask to 0.
404 */
405int adis_single_conversion(struct iio_dev *indio_dev,
406 const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
407{
408 struct adis *adis = iio_device_get_drvdata(indio_dev);
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000409 unsigned int uval;
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000410 int ret;
411
Alexandru Ardeleanc5485a52019-11-22 15:24:17 +0200412 mutex_lock(&adis->state_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000413
Alexandru Ardeleanc5485a52019-11-22 15:24:17 +0200414 ret = __adis_read_reg(adis, chan->address, &uval,
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000415 chan->scan_type.storagebits / 8);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000416 if (ret)
417 goto err_unlock;
418
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000419 if (uval & error_mask) {
Alexandru Ardeleanc5485a52019-11-22 15:24:17 +0200420 ret = __adis_check_status(adis);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000421 if (ret)
422 goto err_unlock;
423 }
424
425 if (chan->scan_type.sign == 's')
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000426 *val = sign_extend32(uval, chan->scan_type.realbits - 1);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000427 else
Lars-Peter Clausen57a12282012-11-20 13:36:00 +0000428 *val = uval & ((1 << chan->scan_type.realbits) - 1);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000429
430 ret = IIO_VAL_INT;
431err_unlock:
Alexandru Ardeleanc5485a52019-11-22 15:24:17 +0200432 mutex_unlock(&adis->state_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000433 return ret;
434}
435EXPORT_SYMBOL_GPL(adis_single_conversion);
436
437/**
438 * adis_init() - Initialize adis device structure
439 * @adis: The adis device
440 * @indio_dev: The iio device
441 * @spi: The spi device
442 * @data: Chip specific data
443 *
444 * Returns 0 on success, a negative error code otherwise.
445 *
446 * This function must be called, before any other adis helper function may be
447 * called.
448 */
449int adis_init(struct adis *adis, struct iio_dev *indio_dev,
450 struct spi_device *spi, const struct adis_data *data)
451{
Nuno Sá380b1072020-01-07 13:17:04 +0200452 if (!data || !data->timeouts) {
453 dev_err(&spi->dev, "No config data or timeouts not defined!\n");
454 return -EINVAL;
455 }
456
Alexandru Ardelean6a9afcb2019-11-22 15:24:11 +0200457 mutex_init(&adis->state_lock);
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000458 adis->spi = spi;
459 adis->data = data;
460 iio_device_set_drvdata(indio_dev, adis);
461
Lars-Peter Clausen484a0bf2012-11-20 13:36:00 +0000462 if (data->has_paging) {
463 /* Need to set the page before first read/write */
464 adis->current_page = -1;
465 } else {
466 /* Page will always be 0 */
467 adis->current_page = 0;
468 }
469
Lars-Peter Clausenccd2b522012-11-13 13:28:00 +0000470 return adis_enable_irq(adis, false);
471}
472EXPORT_SYMBOL_GPL(adis_init);
473
474MODULE_LICENSE("GPL");
475MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
476MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");