Apply regmap for the basic register reads and writes. Note not currently used at all for the mass reads that occur in the buffer code. Not signed off by: Jonathan Cameorn <jic23@xxxxxxxxx> --- drivers/staging/iio/imu/Kconfig | 1 + drivers/staging/iio/imu/adis16400.h | 2 + drivers/staging/iio/imu/adis16400_core.c | 301 +++++++++++++++++++----------- 3 files changed, 191 insertions(+), 113 deletions(-) diff --git a/drivers/staging/iio/imu/Kconfig b/drivers/staging/iio/imu/Kconfig index e0e0144..9b4b912 100644 --- a/drivers/staging/iio/imu/Kconfig +++ b/drivers/staging/iio/imu/Kconfig @@ -8,6 +8,7 @@ config ADIS16400 depends on SPI select IIO_SW_RING if IIO_RING_BUFFER select IIO_TRIGGER if IIO_RING_BUFFER + select REGMAP_SPI help Say yes here to build support for Analog Devices adis16300, adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, adis16365, diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 1f8f0c6..b36dcbb 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -143,6 +143,7 @@ struct adis16400_chip_info { /** * struct adis16400_state - device instance specific data + * @regmap: register map * @us: actual spi_device * @trig: data ready trigger registered with iio * @tx: transmit buffer @@ -150,6 +151,7 @@ struct adis16400_chip_info { * @buf_lock: mutex to protect tx and rx **/ struct adis16400_state { + struct regmap *regmap; struct spi_device *us; struct iio_trigger *trig; struct mutex buf_lock; diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index b6d824f..66364f5 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -25,6 +25,8 @@ #include <linux/sysfs.h> #include <linux/list.h> #include <linux/module.h> +#include <linux/err.h> +#include <linux/regmap.h> #include "../iio.h" #include "../sysfs.h" @@ -43,71 +45,19 @@ enum adis16400_chip_variant { }; /** - * adis16400_spi_write_reg_8() - write single byte to a register - * @dev: device associated with child of actual device (iio_dev or iio_trig) - * @reg_address: the address of the register to be written - * @val: the value to write - */ -static int adis16400_spi_write_reg_8(struct iio_dev *indio_dev, - u8 reg_address, - u8 val) -{ - int ret; - struct adis16400_state *st = iio_priv(indio_dev); - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_WRITE_REG(reg_address); - st->tx[1] = val; - - ret = spi_write(st->us, st->tx, 2); - mutex_unlock(&st->buf_lock); - - return ret; -} - -/** * adis16400_spi_write_reg_16() - write 2 bytes to a pair of registers * @dev: device associated with child of actual device (iio_dev or iio_trig) * @reg_address: the address of the lower of the two registers. Second register * is assumed to have address one greater. * @val: value to be written - * - * At the moment the spi framework doesn't allow global setting of cs_change. - * This means that use cannot be made of spi_write. */ static int adis16400_spi_write_reg_16(struct iio_dev *indio_dev, u8 lower_reg_address, u16 value) { - int ret; - struct spi_message msg; struct adis16400_state *st = iio_priv(indio_dev); - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .tx_buf = st->tx + 2, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_WRITE_REG(lower_reg_address); - st->tx[1] = value & 0xFF; - st->tx[2] = ADIS16400_WRITE_REG(lower_reg_address + 1); - st->tx[3] = (value >> 8) & 0xFF; - - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); - mutex_unlock(&st->buf_lock); - return ret; + return regmap_write(st->regmap, lower_reg_address, value); } /** @@ -116,49 +66,21 @@ static int adis16400_spi_write_reg_16(struct iio_dev *indio_dev, * @reg_address: the address of the lower of the two registers. Second register * is assumed to have address one greater. * @val: somewhere to pass back the value read - * - * At the moment the spi framework doesn't allow global setting of cs_change. - * This means that use cannot be made of spi_read. - **/ + */ static int adis16400_spi_read_reg_16(struct iio_dev *indio_dev, u8 lower_reg_address, u16 *val) { - struct spi_message msg; struct adis16400_state *st = iio_priv(indio_dev); int ret; - struct spi_transfer xfers[] = { - { - .tx_buf = st->tx, - .bits_per_word = 8, - .len = 2, - .cs_change = 1, - }, { - .rx_buf = st->rx, - .bits_per_word = 8, - .len = 2, - }, - }; - - mutex_lock(&st->buf_lock); - st->tx[0] = ADIS16400_READ_REG(lower_reg_address); - st->tx[1] = 0; - - spi_message_init(&msg); - spi_message_add_tail(&xfers[0], &msg); - spi_message_add_tail(&xfers[1], &msg); - ret = spi_sync(st->us, &msg); - if (ret) { - dev_err(&st->us->dev, - "problem when reading 16 bit register 0x%02X", - lower_reg_address); - goto error_ret; - } - *val = (st->rx[0] << 8) | st->rx[1]; + unsigned int value; -error_ret: - mutex_unlock(&st->buf_lock); - return ret; + ret = regmap_read(st->regmap, lower_reg_address, &value); + if (ret < 0) + return ret; + *val = value; + + return 0; } static ssize_t adis16400_read_frequency(struct device *dev, @@ -172,7 +94,7 @@ static ssize_t adis16400_read_frequency(struct device *dev, ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_SMPL_PRD, &t); - if (ret) + if (ret < 0) return ret; sps = (t & ADIS16400_SMPL_PRD_TIME_BASE) ? 53 : 1638; sps /= (t & ADIS16400_SMPL_PRD_DIV_MASK) + 1; @@ -192,7 +114,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, u8 t; ret = strict_strtol(buf, 10, &val); - if (ret) + if (ret < 0) return ret; mutex_lock(&indio_dev->mlock); @@ -206,7 +128,7 @@ static ssize_t adis16400_write_frequency(struct device *dev, else st->us->max_speed_hz = ADIS16400_SPI_FAST; - ret = adis16400_spi_write_reg_8(indio_dev, + ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SMPL_PRD, t); @@ -218,10 +140,10 @@ static ssize_t adis16400_write_frequency(struct device *dev, static int adis16400_reset(struct iio_dev *indio_dev) { int ret; - ret = adis16400_spi_write_reg_8(indio_dev, + ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_GLOB_CMD, ADIS16400_GLOB_CMD_SW_RESET); - if (ret) + if (ret < 0) dev_err(&indio_dev->dev, "problem resetting device"); return ret; @@ -252,7 +174,7 @@ int adis16400_set_irq(struct iio_dev *indio_dev, bool enable) u16 msc; ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_MSC_CTRL, &msc); - if (ret) + if (ret < 0) goto error_ret; msc |= ADIS16400_MSC_CTRL_DATA_RDY_POL_HIGH; @@ -262,7 +184,7 @@ int adis16400_set_irq(struct iio_dev *indio_dev, bool enable) msc &= ~ADIS16400_MSC_CTRL_DATA_RDY_EN; ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_MSC_CTRL, msc); - if (ret) + if (ret < 0) goto error_ret; error_ret: @@ -276,7 +198,7 @@ static int adis16400_stop_device(struct iio_dev *indio_dev) u16 val = ADIS16400_SLP_CNT_POWER_OFF; ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_SLP_CNT, val); - if (ret) + if (ret < 0) dev_err(&indio_dev->dev, "problem with turning device off: SLP_CNT"); @@ -338,7 +260,7 @@ static int adis16400_self_test(struct iio_dev *indio_dev) ret = adis16400_spi_write_reg_16(indio_dev, ADIS16400_MSC_CTRL, ADIS16400_MSC_CTRL_MEM_TEST); - if (ret) { + if (ret < 0) { dev_err(&indio_dev->dev, "problem starting self test"); goto err_ret; } @@ -362,24 +284,24 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev) spi_setup(st->us); ret = adis16400_set_irq(indio_dev, false); - if (ret) { + if (ret < 0) { dev_err(&indio_dev->dev, "disable irq failed"); goto err_ret; } ret = adis16400_self_test(indio_dev); - if (ret) { + if (ret < 0) { dev_err(&indio_dev->dev, "self test failure"); goto err_ret; } ret = adis16400_check_status(indio_dev); - if (ret) { + if (ret < 0) { adis16400_reset(indio_dev); dev_err(&indio_dev->dev, "device not playing ball -> reset"); msleep(ADIS16400_STARTUP_DELAY); ret = adis16400_check_status(indio_dev); - if (ret) { + if (ret < 0) { dev_err(&indio_dev->dev, "giving up"); goto err_ret; } @@ -387,7 +309,7 @@ static int adis16400_initial_setup(struct iio_dev *indio_dev) if (st->variant->flags & ADIS16400_HAS_PROD_ID) { ret = adis16400_spi_read_reg_16(indio_dev, ADIS16400_PRODUCT_ID, &prod_id); - if (ret) + if (ret < 0) goto err_ret; if ((prod_id & 0xF000) != st->variant->product_id) @@ -492,7 +414,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, ret = adis16400_spi_read_reg_16(indio_dev, adis16400_addresses[chan->address][0], &val16); - if (ret) { + if (ret < 0) { mutex_unlock(&indio_dev->mlock); return ret; } @@ -539,7 +461,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, adis16400_addresses[chan->address][1], &val16); mutex_unlock(&indio_dev->mlock); - if (ret) + if (ret < 0) return ret; val16 = ((val16 & 0xFFF) << 4) >> 4; *val = val16; @@ -1016,6 +938,150 @@ static const struct iio_info adis16400_info = { .attrs = &adis16400_attribute_group, }; +/* This may technically result in read attempts to undefined registers */ +static bool adis16400_reg_readable(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case ADIS16400_FLASH_CNT: + case ADIS16400_SUPPLY_OUT: + case ADIS16400_XGYRO_OUT: + case ADIS16400_YGYRO_OUT: + case ADIS16400_ZGYRO_OUT: + case ADIS16400_XACCL_OUT: + case ADIS16400_YACCL_OUT: + case ADIS16400_ZACCL_OUT: + case ADIS16400_XMAGN_OUT: + case ADIS16400_YMAGN_OUT: + case ADIS16400_ZMAGN_OUT: + case ADIS16400_TEMP_OUT: + case ADIS16400_AUX_ADC: + case ADIS16400_XGYRO_OFF: + case ADIS16400_YGYRO_OFF: + case ADIS16400_ZGYRO_OFF: + case ADIS16400_XACCL_OFF: + case ADIS16400_YACCL_OFF: + case ADIS16400_ZACCL_OFF: + case ADIS16400_XMAGN_HIF: + case ADIS16400_YMAGN_HIF: + case ADIS16400_ZMAGN_HIF: + case ADIS16400_XMAGN_SIF: + case ADIS16400_YMAGN_SIF: + case ADIS16400_ZMAGN_SIF: + case ADIS16400_GPIO_CTRL: + case ADIS16400_MSC_CTRL: + case ADIS16400_SMPL_PRD: + case ADIS16400_SENS_AVG: + case ADIS16400_DIAG_STAT: + case ADIS16400_ALM_MAG1: + case ADIS16400_ALM_MAG2: + case ADIS16400_ALM_SMPL1: + case ADIS16400_ALM_SMPL2: + case ADIS16400_ALM_CTRL: + case ADIS16400_AUX_DAC: + case ADIS16400_PRODUCT_ID: + return true; + default: + return false; + } +} + +static bool adis16400_reg_precious(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case ADIS16400_SUPPLY_OUT: + case ADIS16400_XGYRO_OUT: + case ADIS16400_YGYRO_OUT: + case ADIS16400_ZGYRO_OUT: + case ADIS16400_XACCL_OUT: + case ADIS16400_YACCL_OUT: + case ADIS16400_ZACCL_OUT: + case ADIS16400_XMAGN_OUT: + case ADIS16400_YMAGN_OUT: + case ADIS16400_ZMAGN_OUT: + case ADIS16400_TEMP_OUT: + case ADIS16400_AUX_ADC: + case ADIS16400_DIAG_STAT: + return true; + default: + return 0; + } +} + +static bool adis16400_reg_volatile(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case ADIS16400_FLASH_CNT: + case ADIS16400_SUPPLY_OUT: + case ADIS16400_XGYRO_OUT: + case ADIS16400_YGYRO_OUT: + case ADIS16400_ZGYRO_OUT: + case ADIS16400_XACCL_OUT: + case ADIS16400_YACCL_OUT: + case ADIS16400_ZACCL_OUT: + case ADIS16400_XMAGN_OUT: + case ADIS16400_YMAGN_OUT: + case ADIS16400_ZMAGN_OUT: + case ADIS16400_TEMP_OUT: + case ADIS16400_AUX_ADC: + case ADIS16400_DIAG_STAT: + + return true; + default: + return 0; + } +} + +static bool adis16400_reg_writeable(struct device *dev, + unsigned int reg) +{ + switch (reg) { + case ADIS16400_XGYRO_OFF: + case ADIS16400_YGYRO_OFF: + case ADIS16400_ZGYRO_OFF: + case ADIS16400_XACCL_OFF: + case ADIS16400_YACCL_OFF: + case ADIS16400_ZACCL_OFF: + case ADIS16400_XMAGN_HIF: + case ADIS16400_YMAGN_HIF: + case ADIS16400_ZMAGN_HIF: + case ADIS16400_XMAGN_SIF: + case ADIS16400_YMAGN_SIF: + case ADIS16400_ZMAGN_SIF: + case ADIS16400_GPIO_CTRL: + case ADIS16400_MSC_CTRL: + case ADIS16400_SMPL_PRD: + case ADIS16400_SENS_AVG: + case ADIS16400_SLP_CNT: + case ADIS16400_GLOB_CMD: + case ADIS16400_ALM_MAG1: + case ADIS16400_ALM_MAG2: + case ADIS16400_ALM_SMPL1: + case ADIS16400_ALM_SMPL2: + case ADIS16400_ALM_CTRL: + case ADIS16400_AUX_DAC: + return true; + default: + return false; + } +} + +static const struct regmap_config adis16400_regmap_config = { + .reg_bits = 8, + .reg_pad_bits = 8, + .val_bits = 16, + .half_write = true, + .writeable_reg = &adis16400_reg_writeable, + .readable_reg = &adis16400_reg_readable, + .precious_reg = &adis16400_reg_precious, + .volatile_reg = &adis16400_reg_volatile, + .max_register = 0x56, + .write_flag_mask = 0x80, + .read_flag_mask = 0, +}; + static int __devinit adis16400_probe(struct spi_device *spi) { int ret; @@ -1026,9 +1092,14 @@ static int __devinit adis16400_probe(struct spi_device *spi) goto error_ret; } st = iio_priv(indio_dev); + st->regmap = regmap_init_spi(spi, &adis16400_regmap_config); + if (IS_ERR(st->regmap)) { + ret = PTR_ERR(st->regmap); + goto error_free_dev; + } /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); - + spi->cs_between_transfers = 1; st->us = spi; mutex_init(&st->buf_lock); @@ -1042,29 +1113,29 @@ static int __devinit adis16400_probe(struct spi_device *spi) indio_dev->modes = INDIO_DIRECT_MODE; ret = adis16400_configure_ring(indio_dev); - if (ret) - goto error_free_dev; + if (ret < 0) + goto error_free_regmap; ret = iio_ring_buffer_register(indio_dev, st->variant->channels, st->variant->num_channels); - if (ret) { + if (ret < 0) { dev_err(&spi->dev, "failed to initialize the ring\n"); goto error_unreg_ring_funcs; } if (spi->irq) { ret = adis16400_probe_trigger(indio_dev); - if (ret) + if (ret < 0) goto error_uninitialize_ring; } /* Get the device into a sane initial state */ ret = adis16400_initial_setup(indio_dev); - if (ret) + if (ret < 0) goto error_remove_trigger; ret = iio_device_register(indio_dev); - if (ret) + if (ret < 0) goto error_remove_trigger; return 0; @@ -1076,6 +1147,8 @@ error_uninitialize_ring: iio_ring_buffer_unregister(indio_dev); error_unreg_ring_funcs: adis16400_unconfigure_ring(indio_dev); +error_free_regmap: + regmap_exit(st->regmap); error_free_dev: iio_free_device(indio_dev); error_ret: @@ -1087,14 +1160,16 @@ static int adis16400_remove(struct spi_device *spi) { int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct adis16400_state *st = iio_priv(indio_dev); ret = adis16400_stop_device(indio_dev); - if (ret) + if (ret < 0) goto err_ret; adis16400_remove_trigger(indio_dev); iio_ring_buffer_unregister(indio_dev); adis16400_unconfigure_ring(indio_dev); + regmap_exit(st->regmap); iio_device_unregister(indio_dev); return 0; -- 1.7.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-iio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html