root/drivers/iio/imu/adis.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. adis_write_reg
  2. adis_read_reg
  3. adis_debugfs_reg_access
  4. adis_enable_irq
  5. adis_check_status
  6. adis_reset
  7. adis_self_test
  8. adis_initial_startup
  9. adis_single_conversion
  10. adis_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Common library for ADIS16XXX devices
   4  *
   5  * Copyright 2012 Analog Devices Inc.
   6  *   Author: Lars-Peter Clausen <lars@metafoo.de>
   7  */
   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>
  22 #include <linux/iio/imu/adis.h>
  23 
  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 
  29 int adis_write_reg(struct adis *adis, unsigned int reg,
  30         unsigned int value, unsigned int size)
  31 {
  32         unsigned int page = reg / ADIS_PAGE_SIZE;
  33         int ret, i;
  34         struct spi_message msg;
  35         struct spi_transfer xfers[] = {
  36                 {
  37                         .tx_buf = adis->tx,
  38                         .bits_per_word = 8,
  39                         .len = 2,
  40                         .cs_change = 1,
  41                         .delay_usecs = adis->data->write_delay,
  42                         .cs_change_delay = adis->data->cs_change_delay,
  43                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
  44                 }, {
  45                         .tx_buf = adis->tx + 2,
  46                         .bits_per_word = 8,
  47                         .len = 2,
  48                         .cs_change = 1,
  49                         .delay_usecs = adis->data->write_delay,
  50                         .cs_change_delay = adis->data->cs_change_delay,
  51                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
  52                 }, {
  53                         .tx_buf = adis->tx + 4,
  54                         .bits_per_word = 8,
  55                         .len = 2,
  56                         .cs_change = 1,
  57                         .delay_usecs = adis->data->write_delay,
  58                         .cs_change_delay = adis->data->cs_change_delay,
  59                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
  60                 }, {
  61                         .tx_buf = adis->tx + 6,
  62                         .bits_per_word = 8,
  63                         .len = 2,
  64                         .delay_usecs = adis->data->write_delay,
  65                 }, {
  66                         .tx_buf = adis->tx + 8,
  67                         .bits_per_word = 8,
  68                         .len = 2,
  69                         .delay_usecs = adis->data->write_delay,
  70                 },
  71         };
  72 
  73         mutex_lock(&adis->txrx_lock);
  74 
  75         spi_message_init(&msg);
  76 
  77         if (adis->current_page != page) {
  78                 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
  79                 adis->tx[1] = page;
  80                 spi_message_add_tail(&xfers[0], &msg);
  81         }
  82 
  83         switch (size) {
  84         case 4:
  85                 adis->tx[8] = ADIS_WRITE_REG(reg + 3);
  86                 adis->tx[9] = (value >> 24) & 0xff;
  87                 adis->tx[6] = ADIS_WRITE_REG(reg + 2);
  88                 adis->tx[7] = (value >> 16) & 0xff;
  89                 /* fall through */
  90         case 2:
  91                 adis->tx[4] = ADIS_WRITE_REG(reg + 1);
  92                 adis->tx[5] = (value >> 8) & 0xff;
  93                 /* fall through */
  94         case 1:
  95                 adis->tx[2] = ADIS_WRITE_REG(reg);
  96                 adis->tx[3] = value & 0xff;
  97                 break;
  98         default:
  99                 ret = -EINVAL;
 100                 goto out_unlock;
 101         }
 102 
 103         xfers[size].cs_change = 0;
 104 
 105         for (i = 1; i <= size; i++)
 106                 spi_message_add_tail(&xfers[i], &msg);
 107 
 108         ret = spi_sync(adis->spi, &msg);
 109         if (ret) {
 110                 dev_err(&adis->spi->dev, "Failed to write register 0x%02X: %d\n",
 111                                 reg, ret);
 112         } else {
 113                 adis->current_page = page;
 114         }
 115 
 116 out_unlock:
 117         mutex_unlock(&adis->txrx_lock);
 118 
 119         return ret;
 120 }
 121 EXPORT_SYMBOL_GPL(adis_write_reg);
 122 
 123 /**
 124  * adis_read_reg() - read 2 bytes from a 16-bit register
 125  * @adis: The adis device
 126  * @reg: The address of the lower of the two registers
 127  * @val: The value read back from the device
 128  */
 129 int adis_read_reg(struct adis *adis, unsigned int reg,
 130         unsigned int *val, unsigned int size)
 131 {
 132         unsigned int page = reg / ADIS_PAGE_SIZE;
 133         struct spi_message msg;
 134         int ret;
 135         struct spi_transfer xfers[] = {
 136                 {
 137                         .tx_buf = adis->tx,
 138                         .bits_per_word = 8,
 139                         .len = 2,
 140                         .cs_change = 1,
 141                         .delay_usecs = adis->data->write_delay,
 142                         .cs_change_delay = adis->data->cs_change_delay,
 143                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
 144                 }, {
 145                         .tx_buf = adis->tx + 2,
 146                         .bits_per_word = 8,
 147                         .len = 2,
 148                         .cs_change = 1,
 149                         .delay_usecs = adis->data->read_delay,
 150                         .cs_change_delay = adis->data->cs_change_delay,
 151                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
 152                 }, {
 153                         .tx_buf = adis->tx + 4,
 154                         .rx_buf = adis->rx,
 155                         .bits_per_word = 8,
 156                         .len = 2,
 157                         .cs_change = 1,
 158                         .delay_usecs = adis->data->read_delay,
 159                         .cs_change_delay = adis->data->cs_change_delay,
 160                         .cs_change_delay_unit = SPI_DELAY_UNIT_USECS,
 161                 }, {
 162                         .rx_buf = adis->rx + 2,
 163                         .bits_per_word = 8,
 164                         .len = 2,
 165                         .delay_usecs = adis->data->read_delay,
 166                 },
 167         };
 168 
 169         mutex_lock(&adis->txrx_lock);
 170         spi_message_init(&msg);
 171 
 172         if (adis->current_page != page) {
 173                 adis->tx[0] = ADIS_WRITE_REG(ADIS_REG_PAGE_ID);
 174                 adis->tx[1] = page;
 175                 spi_message_add_tail(&xfers[0], &msg);
 176         }
 177 
 178         switch (size) {
 179         case 4:
 180                 adis->tx[2] = ADIS_READ_REG(reg + 2);
 181                 adis->tx[3] = 0;
 182                 spi_message_add_tail(&xfers[1], &msg);
 183                 /* fall through */
 184         case 2:
 185                 adis->tx[4] = ADIS_READ_REG(reg);
 186                 adis->tx[5] = 0;
 187                 spi_message_add_tail(&xfers[2], &msg);
 188                 spi_message_add_tail(&xfers[3], &msg);
 189                 break;
 190         default:
 191                 ret = -EINVAL;
 192                 goto out_unlock;
 193         }
 194 
 195         ret = spi_sync(adis->spi, &msg);
 196         if (ret) {
 197                 dev_err(&adis->spi->dev, "Failed to read register 0x%02X: %d\n",
 198                                 reg, ret);
 199                 goto out_unlock;
 200         } else {
 201                 adis->current_page = page;
 202         }
 203 
 204         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 
 213 out_unlock:
 214         mutex_unlock(&adis->txrx_lock);
 215 
 216         return ret;
 217 }
 218 EXPORT_SYMBOL_GPL(adis_read_reg);
 219 
 220 #ifdef CONFIG_DEBUG_FS
 221 
 222 int adis_debugfs_reg_access(struct iio_dev *indio_dev,
 223         unsigned int reg, unsigned int writeval, unsigned int *readval)
 224 {
 225         struct adis *adis = iio_device_get_drvdata(indio_dev);
 226 
 227         if (readval) {
 228                 uint16_t val16;
 229                 int ret;
 230 
 231                 ret = adis_read_reg_16(adis, reg, &val16);
 232                 *readval = val16;
 233 
 234                 return ret;
 235         } else {
 236                 return adis_write_reg_16(adis, reg, writeval);
 237         }
 238 }
 239 EXPORT_SYMBOL(adis_debugfs_reg_access);
 240 
 241 #endif
 242 
 243 /**
 244  * adis_enable_irq() - Enable or disable data ready IRQ
 245  * @adis: The adis device
 246  * @enable: Whether to enable the IRQ
 247  *
 248  * Returns 0 on success, negative error code otherwise
 249  */
 250 int adis_enable_irq(struct adis *adis, bool enable)
 251 {
 252         int ret = 0;
 253         uint16_t msc;
 254 
 255         if (adis->data->enable_irq)
 256                 return adis->data->enable_irq(adis, enable);
 257 
 258         ret = adis_read_reg_16(adis, adis->data->msc_ctrl_reg, &msc);
 259         if (ret)
 260                 goto error_ret;
 261 
 262         msc |= ADIS_MSC_CTRL_DATA_RDY_POL_HIGH;
 263         msc &= ~ADIS_MSC_CTRL_DATA_RDY_DIO2;
 264         if (enable)
 265                 msc |= ADIS_MSC_CTRL_DATA_RDY_EN;
 266         else
 267                 msc &= ~ADIS_MSC_CTRL_DATA_RDY_EN;
 268 
 269         ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg, msc);
 270 
 271 error_ret:
 272         return ret;
 273 }
 274 EXPORT_SYMBOL(adis_enable_irq);
 275 
 276 /**
 277  * adis_check_status() - Check the device for error conditions
 278  * @adis: The adis device
 279  *
 280  * Returns 0 on success, a negative error code otherwise
 281  */
 282 int adis_check_status(struct adis *adis)
 283 {
 284         uint16_t status;
 285         int ret;
 286         int i;
 287 
 288         ret = adis_read_reg_16(adis, adis->data->diag_stat_reg, &status);
 289         if (ret < 0)
 290                 return ret;
 291 
 292         status &= adis->data->status_error_mask;
 293 
 294         if (status == 0)
 295                 return 0;
 296 
 297         for (i = 0; i < 16; ++i) {
 298                 if (status & BIT(i)) {
 299                         dev_err(&adis->spi->dev, "%s.\n",
 300                                 adis->data->status_error_msgs[i]);
 301                 }
 302         }
 303 
 304         return -EIO;
 305 }
 306 EXPORT_SYMBOL_GPL(adis_check_status);
 307 
 308 /**
 309  * adis_reset() - Reset the device
 310  * @adis: The adis device
 311  *
 312  * Returns 0 on success, a negative error code otherwise
 313  */
 314 int adis_reset(struct adis *adis)
 315 {
 316         int ret;
 317 
 318         ret = adis_write_reg_8(adis, adis->data->glob_cmd_reg,
 319                         ADIS_GLOB_CMD_SW_RESET);
 320         if (ret)
 321                 dev_err(&adis->spi->dev, "Failed to reset device: %d\n", ret);
 322 
 323         return ret;
 324 }
 325 EXPORT_SYMBOL_GPL(adis_reset);
 326 
 327 static int adis_self_test(struct adis *adis)
 328 {
 329         int ret;
 330 
 331         ret = adis_write_reg_16(adis, adis->data->msc_ctrl_reg,
 332                         adis->data->self_test_mask);
 333         if (ret) {
 334                 dev_err(&adis->spi->dev, "Failed to initiate self test: %d\n",
 335                         ret);
 336                 return ret;
 337         }
 338 
 339         msleep(adis->data->startup_delay);
 340 
 341         ret = adis_check_status(adis);
 342 
 343         if (adis->data->self_test_no_autoclear)
 344                 adis_write_reg_16(adis, adis->data->msc_ctrl_reg, 0x00);
 345 
 346         return ret;
 347 }
 348 
 349 /**
 350  * adis_inital_startup() - Performs device self-test
 351  * @adis: The adis device
 352  *
 353  * Returns 0 if the device is operational, a negative error code otherwise.
 354  *
 355  * This function should be called early on in the device initialization sequence
 356  * to ensure that the device is in a sane and known state and that it is usable.
 357  */
 358 int adis_initial_startup(struct adis *adis)
 359 {
 360         int ret;
 361 
 362         ret = adis_self_test(adis);
 363         if (ret) {
 364                 dev_err(&adis->spi->dev, "Self-test failed, trying reset.\n");
 365                 adis_reset(adis);
 366                 msleep(adis->data->startup_delay);
 367                 ret = adis_self_test(adis);
 368                 if (ret) {
 369                         dev_err(&adis->spi->dev, "Second self-test failed, giving up.\n");
 370                         return ret;
 371                 }
 372         }
 373 
 374         return 0;
 375 }
 376 EXPORT_SYMBOL_GPL(adis_initial_startup);
 377 
 378 /**
 379  * adis_single_conversion() - Performs a single sample conversion
 380  * @indio_dev: The IIO device
 381  * @chan: The IIO channel
 382  * @error_mask: Mask for the error bit
 383  * @val: Result of the conversion
 384  *
 385  * Returns IIO_VAL_INT on success, a negative error code otherwise.
 386  *
 387  * The function performs a single conversion on a given channel and post
 388  * processes the value accordingly to the channel spec. If a error_mask is given
 389  * the function will check if the mask is set in the returned raw value. If it
 390  * is set the function will perform a self-check. If the device does not report
 391  * a error bit in the channels raw value set error_mask to 0.
 392  */
 393 int adis_single_conversion(struct iio_dev *indio_dev,
 394         const struct iio_chan_spec *chan, unsigned int error_mask, int *val)
 395 {
 396         struct adis *adis = iio_device_get_drvdata(indio_dev);
 397         unsigned int uval;
 398         int ret;
 399 
 400         mutex_lock(&indio_dev->mlock);
 401 
 402         ret = adis_read_reg(adis, chan->address, &uval,
 403                         chan->scan_type.storagebits / 8);
 404         if (ret)
 405                 goto err_unlock;
 406 
 407         if (uval & error_mask) {
 408                 ret = adis_check_status(adis);
 409                 if (ret)
 410                         goto err_unlock;
 411         }
 412 
 413         if (chan->scan_type.sign == 's')
 414                 *val = sign_extend32(uval, chan->scan_type.realbits - 1);
 415         else
 416                 *val = uval & ((1 << chan->scan_type.realbits) - 1);
 417 
 418         ret = IIO_VAL_INT;
 419 err_unlock:
 420         mutex_unlock(&indio_dev->mlock);
 421         return ret;
 422 }
 423 EXPORT_SYMBOL_GPL(adis_single_conversion);
 424 
 425 /**
 426  * adis_init() - Initialize adis device structure
 427  * @adis:       The adis device
 428  * @indio_dev:  The iio device
 429  * @spi:        The spi device
 430  * @data:       Chip specific data
 431  *
 432  * Returns 0 on success, a negative error code otherwise.
 433  *
 434  * This function must be called, before any other adis helper function may be
 435  * called.
 436  */
 437 int adis_init(struct adis *adis, struct iio_dev *indio_dev,
 438         struct spi_device *spi, const struct adis_data *data)
 439 {
 440         mutex_init(&adis->txrx_lock);
 441         adis->spi = spi;
 442         adis->data = data;
 443         iio_device_set_drvdata(indio_dev, adis);
 444 
 445         if (data->has_paging) {
 446                 /* Need to set the page before first read/write */
 447                 adis->current_page = -1;
 448         } else {
 449                 /* Page will always be 0 */
 450                 adis->current_page = 0;
 451         }
 452 
 453         return adis_enable_irq(adis, false);
 454 }
 455 EXPORT_SYMBOL_GPL(adis_init);
 456 
 457 MODULE_LICENSE("GPL");
 458 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 459 MODULE_DESCRIPTION("Common library code for ADIS16XXX devices");

/* [<][>][^][v][top][bottom][index][help] */