diff options
Diffstat (limited to 'drivers/iio')
78 files changed, 3013 insertions, 516 deletions
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig index 5d91a6dda894..24ebe9e76915 100644 --- a/drivers/iio/accel/Kconfig +++ b/drivers/iio/accel/Kconfig @@ -238,7 +238,7 @@ config IIO_ST_ACCEL_3AXIS Say yes here to build support for STMicroelectronics accelerometers: LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL, - LNG2DM, LIS3DE, LIS2DE12 + LNG2DM, LIS3DE, LIS2DE12, LIS2HH12 This driver can also be built as a module. If so, these modules will be created: diff --git a/drivers/iio/accel/kxsd9-i2c.c b/drivers/iio/accel/kxsd9-i2c.c index 38411e1c155b..b6f3de7ef8ea 100644 --- a/drivers/iio/accel/kxsd9-i2c.c +++ b/drivers/iio/accel/kxsd9-i2c.c @@ -21,8 +21,8 @@ static int kxsd9_i2c_probe(struct i2c_client *i2c, regmap = devm_regmap_init_i2c(i2c, &config); if (IS_ERR(regmap)) { - dev_err(&i2c->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&i2c->dev, "Failed to register i2c regmap: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/iio/accel/mxc4005.c b/drivers/iio/accel/mxc4005.c index 3d5bea651923..9d07642c0de1 100644 --- a/drivers/iio/accel/mxc4005.c +++ b/drivers/iio/accel/mxc4005.c @@ -135,7 +135,7 @@ static int mxc4005_read_xyz(struct mxc4005_data *data) int ret; ret = regmap_bulk_read(data->regmap, MXC4005_REG_XOUT_UPPER, - (u8 *) data->buffer, sizeof(data->buffer)); + data->buffer, sizeof(data->buffer)); if (ret < 0) { dev_err(data->dev, "failed to read axes\n"); return ret; @@ -150,7 +150,7 @@ static int mxc4005_read_axis(struct mxc4005_data *data, __be16 reg; int ret; - ret = regmap_bulk_read(data->regmap, addr, (u8 *) ®, sizeof(reg)); + ret = regmap_bulk_read(data->regmap, addr, ®, sizeof(reg)); if (ret < 0) { dev_err(data->dev, "failed to read reg %02x\n", addr); return ret; diff --git a/drivers/iio/accel/st_accel.h b/drivers/iio/accel/st_accel.h index 5b13e293cade..5d356288e001 100644 --- a/drivers/iio/accel/st_accel.h +++ b/drivers/iio/accel/st_accel.h @@ -35,6 +35,7 @@ enum st_accel_type { LIS2DW12, LIS3DHH, LIS2DE12, + LIS2HH12, ST_ACCEL_MAX, }; @@ -59,6 +60,7 @@ enum st_accel_type { #define LIS3DHH_ACCEL_DEV_NAME "lis3dhh" #define LIS3DE_ACCEL_DEV_NAME "lis3de" #define LIS2DE12_ACCEL_DEV_NAME "lis2de12" +#define LIS2HH12_ACCEL_DEV_NAME "lis2hh12" /** * struct st_sensors_platform_data - default accel platform data diff --git a/drivers/iio/accel/st_accel_buffer.c b/drivers/iio/accel/st_accel_buffer.c index 9f2b40474b8e..b5c814ef1637 100644 --- a/drivers/iio/accel/st_accel_buffer.c +++ b/drivers/iio/accel/st_accel_buffer.c @@ -37,8 +37,7 @@ static int st_accel_buffer_postenable(struct iio_dev *indio_dev) if (err < 0) return err; - err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + err = st_sensors_set_axis_enable(indio_dev, indio_dev->active_scan_mask[0]); if (err < 0) goto st_accel_buffer_predisable; diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index 7320275c7e56..43c50167d220 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -904,6 +904,83 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .multi_read_bit = true, .bootime = 2, }, + { + .wai = 0x41, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LIS2HH12_ACCEL_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_accel_16bit_channels, + .odr = { + .addr = 0x20, + .mask = 0x70, + .odr_avl = { + { .hz = 10, .value = 0x01, }, + { .hz = 50, .value = 0x02, }, + { .hz = 100, .value = 0x03, }, + { .hz = 200, .value = 0x04, }, + { .hz = 400, .value = 0x05, }, + { .hz = 800, .value = 0x06, }, + }, + }, + .pw = { + .addr = 0x20, + .mask = 0x70, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .enable_axis = { + .addr = ST_SENSORS_DEFAULT_AXIS_ADDR, + .mask = ST_SENSORS_DEFAULT_AXIS_MASK, + }, + .fs = { + .addr = 0x23, + .mask = 0x30, + .fs_avl = { + [0] = { + .num = ST_ACCEL_FS_AVL_2G, + .value = 0x00, + .gain = IIO_G_TO_M_S_2(61), + }, + [1] = { + .num = ST_ACCEL_FS_AVL_4G, + .value = 0x02, + .gain = IIO_G_TO_M_S_2(122), + }, + [2] = { + .num = ST_ACCEL_FS_AVL_8G, + .value = 0x03, + .gain = IIO_G_TO_M_S_2(244), + }, + }, + }, + .bdu = { + .addr = 0x20, + .mask = 0x08, + }, + .drdy_irq = { + .int1 = { + .addr = 0x22, + .mask = 0x01, + }, + .int2 = { + .addr = 0x25, + .mask = 0x01, + }, + .addr_ihl = 0x24, + .mask_ihl = 0x02, + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x07, + }, + }, + .sim = { + .addr = 0x23, + .value = BIT(0), + }, + .multi_read_bit = true, + .bootime = 2, + }, + }; static int st_accel_read_raw(struct iio_dev *indio_dev, @@ -1170,8 +1247,7 @@ EXPORT_SYMBOL(st_accel_get_settings); int st_accel_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *adata = iio_priv(indio_dev); - struct st_sensors_platform_data *pdata = - (struct st_sensors_platform_data *)adata->dev->platform_data; + struct st_sensors_platform_data *pdata = dev_get_platdata(adata->dev); struct iio_chan_spec *channels; size_t channels_size; int err; @@ -1204,8 +1280,7 @@ int st_accel_common_probe(struct iio_dev *indio_dev) "failed to apply ACPI orientation data: %d\n", err); indio_dev->channels = channels; - adata->current_fullscale = (struct st_sensor_fullscale_avl *) - &adata->sensor_settings->fs.fs_avl[0]; + adata->current_fullscale = &adata->sensor_settings->fs.fs_avl[0]; adata->odr = adata->sensor_settings->odr.odr_avl[0].hz; if (!pdata) diff --git a/drivers/iio/accel/st_accel_i2c.c b/drivers/iio/accel/st_accel_i2c.c index 6b283be26ebc..360e16f2cadb 100644 --- a/drivers/iio/accel/st_accel_i2c.c +++ b/drivers/iio/accel/st_accel_i2c.c @@ -104,6 +104,10 @@ static const struct of_device_id st_accel_of_match[] = { .compatible = "st,lis2de12", .data = LIS2DE12_ACCEL_DEV_NAME, }, + { + .compatible = "st,lis2hh12", + .data = LIS2HH12_ACCEL_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_accel_of_match); @@ -138,6 +142,7 @@ static const struct i2c_device_id st_accel_id_table[] = { { LIS2DW12_ACCEL_DEV_NAME }, { LIS3DE_ACCEL_DEV_NAME }, { LIS2DE12_ACCEL_DEV_NAME }, + { LIS2HH12_ACCEL_DEV_NAME }, {}, }; MODULE_DEVICE_TABLE(i2c, st_accel_id_table); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 12bb8b7ca1ff..c48c00077775 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -246,6 +246,41 @@ config AD799X To compile this driver as a module, choose M here: the module will be called ad799x. +config AD9467 + tristate "Analog Devices AD9467 High Speed ADC driver" + depends on SPI + select ADI_AXI_ADC + help + Say yes here to build support for Analog Devices: + * AD9467 16-Bit, 200 MSPS/250 MSPS Analog-to-Digital Converter + + The driver requires the assistance of the AXI ADC IP core to operate, + since SPI is used for configuration only, while data has to be + streamed into memory via DMA. + + To compile this driver as a module, choose M here: the module will be + called ad9467. + +config ADI_AXI_ADC + tristate "Analog Devices Generic AXI ADC IP core driver" + select IIO_BUFFER + select IIO_BUFFER_HW_CONSUMER + select IIO_BUFFER_DMAENGINE + help + Say yes here to build support for Analog Devices Generic + AXI ADC IP core. The IP core is used for interfacing with + analog-to-digital (ADC) converters that require either a high-speed + serial interface (JESD204B/C) or a source synchronous parallel + interface (LVDS/CMOS). + Typically (for such devices) SPI will be used for configuration only, + while this IP core handles the streaming of data into memory via DMA. + + Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called adi-axi-adc. + config ASPEED_ADC tristate "Aspeed ADC" depends on ARCH_ASPEED || COMPILE_TEST @@ -595,6 +630,16 @@ config MAX1118 To compile this driver as a module, choose M here: the module will be called max1118. +config MAX1241 + tristate "Maxim max1241 ADC driver" + depends on SPI_MASTER + help + Say yes here to build support for Maxim max1241 12-bit, single-channel + ADC. + + To compile this driver as a module, choose M here: the module will be + called max1241. + config MAX1363 tristate "Maxim max1363 ADC driver" depends on I2C diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 637807861112..2f5bc224412b 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -26,6 +26,8 @@ obj-$(CONFIG_AD7793) += ad7793.o obj-$(CONFIG_AD7887) += ad7887.o obj-$(CONFIG_AD7949) += ad7949.o obj-$(CONFIG_AD799X) += ad799x.o +obj-$(CONFIG_AD9467) += ad9467.o +obj-$(CONFIG_ADI_AXI_ADC) += adi-axi-adc.o obj-$(CONFIG_ASPEED_ADC) += aspeed_adc.o obj-$(CONFIG_AT91_ADC) += at91_adc.o obj-$(CONFIG_AT91_SAMA5D2_ADC) += at91-sama5d2_adc.o @@ -57,6 +59,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o ltc2497-core.o obj-$(CONFIG_MAX1027) += max1027.o obj-$(CONFIG_MAX11100) += max11100.o obj-$(CONFIG_MAX1118) += max1118.o +obj-$(CONFIG_MAX1241) += max1241.o obj-$(CONFIG_MAX1363) += max1363.o obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c index 76747488044b..e9984a38fc4c 100644 --- a/drivers/iio/adc/ad7476.c +++ b/drivers/iio/adc/ad7476.c @@ -12,9 +12,11 @@ #include <linux/sysfs.h> #include <linux/spi/spi.h> #include <linux/regulator/consumer.h> +#include <linux/gpio/consumer.h> #include <linux/err.h> #include <linux/module.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -27,6 +29,8 @@ struct ad7476_state; struct ad7476_chip_info { unsigned int int_vref_uv; struct iio_chan_spec channel[2]; + /* channels used when convst gpio is defined */ + struct iio_chan_spec convst_channel[2]; void (*reset)(struct ad7476_state *); }; @@ -34,6 +38,7 @@ struct ad7476_state { struct spi_device *spi; const struct ad7476_chip_info *chip_info; struct regulator *reg; + struct gpio_desc *convst_gpio; struct spi_transfer xfer; struct spi_message msg; /* @@ -64,6 +69,17 @@ enum ad7476_supported_device_ids { ID_ADS7868, }; +static void ad7091_convst(struct ad7476_state *st) +{ + if (!st->convst_gpio) + return; + + gpiod_set_value(st->convst_gpio, 0); + udelay(1); /* CONVST pulse width: 10 ns min */ + gpiod_set_value(st->convst_gpio, 1); + udelay(1); /* Conversion time: 650 ns max */ +} + static irqreturn_t ad7476_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; @@ -71,6 +87,8 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p) struct ad7476_state *st = iio_priv(indio_dev); int b_sent; + ad7091_convst(st); + b_sent = spi_sync(st->spi, &st->msg); if (b_sent < 0) goto done; @@ -93,6 +111,8 @@ static int ad7476_scan_direct(struct ad7476_state *st) { int ret; + ad7091_convst(st); + ret = spi_sync(st->spi, &st->msg); if (ret) return ret; @@ -160,6 +180,8 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, #define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) #define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0) +#define AD7091R_CONVST_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), \ + BIT(IIO_CHAN_INFO_RAW)) #define ADS786X_CHAN(bits) _AD7476_CHAN((bits), 12 - (bits), \ BIT(IIO_CHAN_INFO_RAW)) @@ -167,6 +189,8 @@ static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { [ID_AD7091R] = { .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .convst_channel[0] = AD7091R_CONVST_CHAN(12), + .convst_channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), .reset = ad7091_reset, }, [ID_AD7276] = { @@ -232,6 +256,13 @@ static const struct iio_info ad7476_info = { .read_raw = &ad7476_read_raw, }; +static void ad7476_reg_disable(void *data) +{ + struct ad7476_state *st = data; + + regulator_disable(st->reg); +} + static int ad7476_probe(struct spi_device *spi) { struct ad7476_state *st; @@ -254,6 +285,17 @@ static int ad7476_probe(struct spi_device *spi) if (ret) return ret; + ret = devm_add_action_or_reset(&spi->dev, ad7476_reg_disable, + st); + if (ret) + return ret; + + st->convst_gpio = devm_gpiod_get_optional(&spi->dev, + "adi,conversion-start", + GPIOD_OUT_LOW); + if (IS_ERR(st->convst_gpio)) + return PTR_ERR(st->convst_gpio); + spi_set_drvdata(spi, indio_dev); st->spi = spi; @@ -266,6 +308,9 @@ static int ad7476_probe(struct spi_device *spi) indio_dev->channels = st->chip_info->channel; indio_dev->num_channels = 2; indio_dev->info = &ad7476_info; + + if (st->convst_gpio && st->chip_info->convst_channel) + indio_dev->channels = st->chip_info->convst_channel; /* Setup default message */ st->xfer.rx_buf = &st->data; @@ -295,19 +340,8 @@ error_disable_reg: return ret; } -static int ad7476_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7476_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - regulator_disable(st->reg); - - return 0; -} - static const struct spi_device_id ad7476_id[] = { + {"ad7091", ID_AD7091R}, {"ad7091r", ID_AD7091R}, {"ad7273", ID_AD7277}, {"ad7274", ID_AD7276}, @@ -343,7 +377,6 @@ static struct spi_driver ad7476_driver = { .name = "ad7476", }, .probe = ad7476_probe, - .remove = ad7476_remove, .id_table = ad7476_id, }; module_spi_driver(ad7476_driver); diff --git a/drivers/iio/adc/ad7780.c b/drivers/iio/adc/ad7780.c index 291c1a898129..f47606ebbbbe 100644 --- a/drivers/iio/adc/ad7780.c +++ b/drivers/iio/adc/ad7780.c @@ -206,10 +206,29 @@ static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { .irq_flags = IRQF_TRIGGER_LOW, }; -#define AD7780_CHANNEL(bits, wordsize) \ - AD_SD_CHANNEL(1, 0, 0, bits, 32, (wordsize) - (bits)) -#define AD7170_CHANNEL(bits, wordsize) \ - AD_SD_CHANNEL_NO_SAMP_FREQ(1, 0, 0, bits, 32, (wordsize) - (bits)) +#define _AD7780_CHANNEL(_bits, _wordsize, _mask_all) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = 0, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = _mask_all, \ + .scan_index = 1, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 32, \ + .shift = (_wordsize) - (_bits), \ + .endianness = IIO_BE, \ + }, \ +} + +#define AD7780_CHANNEL(_bits, _wordsize) \ + _AD7780_CHANNEL(_bits, _wordsize, BIT(IIO_CHAN_INFO_SAMP_FREQ)) +#define AD7170_CHANNEL(_bits, _wordsize) \ + _AD7780_CHANNEL(_bits, _wordsize, 0) static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { [ID_AD7170] = { diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c index abb239392631..48432b6f6002 100644 --- a/drivers/iio/adc/ad7791.c +++ b/drivers/iio/adc/ad7791.c @@ -64,25 +64,73 @@ #define AD7791_MODE_SEL_MASK (0x3 << 6) #define AD7791_MODE_SEL(x) ((x) << 6) +#define __AD7991_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, _extend_name, _type, _mask_all) \ + { \ + .type = (_type), \ + .differential = (_channel2 == -1 ? 0 : 1), \ + .indexed = 1, \ + .channel = (_channel1), \ + .channel2 = (_channel2), \ + .address = (_address), \ + .extend_name = (_extend_name), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_all = _mask_all, \ + .scan_index = (_si), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = (_storagebits), \ + .shift = (_shift), \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD7991_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD7991_CHANNEL(_si, _channel, _channel, _address, _bits, \ + _storagebits, _shift, "shorted", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7991_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD7991_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7991_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift) \ + __AD7991_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7991_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ + _shift) \ + __AD7991_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, "supply", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + #define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \ const struct iio_chan_spec name[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ + AD7991_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ (bits), (storagebits), 0), \ - AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \ - AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \ + AD7991_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \ + AD7991_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \ (bits), (storagebits), 0), \ - AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR, \ + AD7991_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR, \ (bits), (storagebits), 0), \ IIO_CHAN_SOFT_TIMESTAMP(4), \ } #define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \ const struct iio_chan_spec name[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ + AD7991_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ (bits), (storagebits), 0), \ - AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \ + AD7991_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \ (bits), (storagebits), 0), \ - AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \ + AD7991_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \ (bits), (storagebits), 0), \ IIO_CHAN_SOFT_TIMESTAMP(3), \ } @@ -444,5 +492,5 @@ static struct spi_driver ad7791_driver = { module_spi_driver(ad7791_driver); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); -MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); +MODULE_DESCRIPTION("Analog Devices AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c index b747db97f78a..7005bde50a76 100644 --- a/drivers/iio/adc/ad7793.c +++ b/drivers/iio/adc/ad7793.c @@ -354,29 +354,28 @@ static IIO_CONST_ATTR_SAMP_FREQ_AVAIL( static IIO_CONST_ATTR_NAMED(sampling_frequency_available_ad7797, sampling_frequency_available, "123 62 50 33 17 16 12 10 8 6 4"); -static ssize_t ad7793_show_scale_available(struct device *dev, - struct device_attribute *attr, char *buf) +static int ad7793_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); struct ad7793_state *st = iio_priv(indio_dev); - int i, len = 0; - for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) - len += sprintf(buf + len, "%d.%09u ", st->scale_avail[i][0], - st->scale_avail[i][1]); - - len += sprintf(buf + len, "\n"); + switch (mask) { + case IIO_CHAN_INFO_SCALE: + *vals = (int *)st->scale_avail; + *type = IIO_VAL_INT_PLUS_NANO; + /* Values are stored in a 2D matrix */ + *length = ARRAY_SIZE(st->scale_avail) * 2; - return len; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } -static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, - in_voltage-voltage_scale_available, S_IRUGO, - ad7793_show_scale_available, NULL, 0); - static struct attribute *ad7793_attributes[] = { &iio_const_attr_sampling_frequency_available.dev_attr.attr, - &iio_dev_attr_in_m_in_scale_available.dev_attr.attr, NULL }; @@ -534,6 +533,7 @@ static const struct iio_info ad7793_info = { .read_raw = &ad7793_read_raw, .write_raw = &ad7793_write_raw, .write_raw_get_fmt = &ad7793_write_raw_get_fmt, + .read_avail = ad7793_read_avail, .attrs = &ad7793_attribute_group, .validate_trigger = ad_sd_validate_trigger, }; @@ -546,47 +546,113 @@ static const struct iio_info ad7797_info = { .validate_trigger = ad_sd_validate_trigger, }; +#define __AD7793_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, _extend_name, _type, _mask_type_av, _mask_all) \ + { \ + .type = (_type), \ + .differential = (_channel2 == -1 ? 0 : 1), \ + .indexed = 1, \ + .channel = (_channel1), \ + .channel2 = (_channel2), \ + .address = (_address), \ + .extend_name = (_extend_name), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_shared_by_type_available = (_mask_type_av), \ + .info_mask_shared_by_all = _mask_all, \ + .scan_index = (_si), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = (_storagebits), \ + .shift = (_shift), \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD7793_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift) \ + __AD7793_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7793_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD7793_CHANNEL(_si, _channel, _channel, _address, _bits, \ + _storagebits, _shift, "shorted", IIO_VOLTAGE, \ + BIT(IIO_CHAN_INFO_SCALE), \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7793_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \ + __AD7793_CHANNEL(_si, 0, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_TEMP, \ + 0, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7793_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ + _shift) \ + __AD7793_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, "supply", IIO_VOLTAGE, \ + 0, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7797_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift) \ + __AD7793_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE, \ + 0, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + +#define AD7797_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD7793_CHANNEL(_si, _channel, _channel, _address, _bits, \ + _storagebits, _shift, "shorted", IIO_VOLTAGE, \ + 0, \ + BIT(IIO_CHAN_INFO_SAMP_FREQ)) + #define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \ const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ - AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ - AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ - AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ - AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ - AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ + AD7793_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ + AD7793_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ + AD7793_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ + AD7793_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ + AD7793_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ + AD7793_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ IIO_CHAN_SOFT_TIMESTAMP(6), \ } #define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \ const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ - AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ - AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ - AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ + AD7793_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ + AD7793_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ + AD7793_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ IIO_CHAN_SOFT_TIMESTAMP(9), \ } #define DECLARE_AD7797_CHANNELS(_name, _b, _sb) \ const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ - AD_SD_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ - AD_SD_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \ - AD_SD_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ + AD7797_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ + AD7797_SHORTED_CHANNEL(1, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ + AD7793_TEMP_CHANNEL(2, AD7793_CH_TEMP, (_b), (_sb), 0), \ + AD7793_SUPPLY_CHANNEL(3, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ IIO_CHAN_SOFT_TIMESTAMP(4), \ } #define DECLARE_AD7799_CHANNELS(_name, _b, _sb) \ const struct iio_chan_spec _name##_channels[] = { \ - AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ - AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ - AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ - AD_SD_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ + AD7793_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ + AD7793_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ + AD7793_SUPPLY_CHANNEL(4, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ IIO_CHAN_SOFT_TIMESTAMP(5), \ } diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c new file mode 100644 index 000000000000..1e8fd83b9bc2 --- /dev/null +++ b/drivers/iio/adc/ad9467.c @@ -0,0 +1,422 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices AD9467 SPI ADC driver + * + * Copyright 2012-2020 Analog Devices Inc. + */ + +#include <linux/module.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/of_device.h> + + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> + +#include <linux/clk.h> + +#include <linux/iio/adc/adi-axi-adc.h> + +/* + * ADI High-Speed ADC common spi interface registers + * See Application-Note AN-877: + * https://www.analog.com/media/en/technical-documentation/application-notes/AN-877.pdf + */ + +#define AN877_ADC_REG_CHIP_PORT_CONF 0x00 +#define AN877_ADC_REG_CHIP_ID 0x01 +#define AN877_ADC_REG_CHIP_GRADE 0x02 +#define AN877_ADC_REG_CHAN_INDEX 0x05 +#define AN877_ADC_REG_TRANSFER 0xFF +#define AN877_ADC_REG_MODES 0x08 +#define AN877_ADC_REG_TEST_IO 0x0D +#define AN877_ADC_REG_ADC_INPUT 0x0F +#define AN877_ADC_REG_OFFSET 0x10 +#define AN877_ADC_REG_OUTPUT_MODE 0x14 +#define AN877_ADC_REG_OUTPUT_ADJUST 0x15 +#define AN877_ADC_REG_OUTPUT_PHASE 0x16 +#define AN877_ADC_REG_OUTPUT_DELAY 0x17 +#define AN877_ADC_REG_VREF 0x18 +#define AN877_ADC_REG_ANALOG_INPUT 0x2C + +/* AN877_ADC_REG_TEST_IO */ +#define AN877_ADC_TESTMODE_OFF 0x0 +#define AN877_ADC_TESTMODE_MIDSCALE_SHORT 0x1 +#define AN877_ADC_TESTMODE_POS_FULLSCALE 0x2 +#define AN877_ADC_TESTMODE_NEG_FULLSCALE 0x3 +#define AN877_ADC_TESTMODE_ALT_CHECKERBOARD 0x4 +#define AN877_ADC_TESTMODE_PN23_SEQ 0x5 +#define AN877_ADC_TESTMODE_PN9_SEQ 0x6 +#define AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE 0x7 +#define AN877_ADC_TESTMODE_USER 0x8 +#define AN877_ADC_TESTMODE_BIT_TOGGLE 0x9 +#define AN877_ADC_TESTMODE_SYNC 0xA +#define AN877_ADC_TESTMODE_ONE_BIT_HIGH 0xB +#define AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY 0xC +#define AN877_ADC_TESTMODE_RAMP 0xF + +/* AN877_ADC_REG_TRANSFER */ +#define AN877_ADC_TRANSFER_SYNC 0x1 + +/* AN877_ADC_REG_OUTPUT_MODE */ +#define AN877_ADC_OUTPUT_MODE_OFFSET_BINARY 0x0 +#define AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT 0x1 +#define AN877_ADC_OUTPUT_MODE_GRAY_CODE 0x2 + +/* AN877_ADC_REG_OUTPUT_PHASE */ +#define AN877_ADC_OUTPUT_EVEN_ODD_MODE_EN 0x20 +#define AN877_ADC_INVERT_DCO_CLK 0x80 + +/* AN877_ADC_REG_OUTPUT_DELAY */ +#define AN877_ADC_DCO_DELAY_ENABLE 0x80 + +/* + * Analog Devices AD9467 16-Bit, 200/250 MSPS ADC + */ + +#define CHIPID_AD9467 0x50 +#define AD9467_DEF_OUTPUT_MODE 0x08 +#define AD9467_REG_VREF_MASK 0x0F + +enum { + ID_AD9467, +}; + +struct ad9467_state { + struct spi_device *spi; + struct clk *clk; + unsigned int output_mode; + + struct gpio_desc *pwrdown_gpio; + struct gpio_desc *reset_gpio; +}; + +static int ad9467_spi_read(struct spi_device *spi, unsigned int reg) +{ + unsigned char tbuf[2], rbuf[1]; + int ret; + + tbuf[0] = 0x80 | (reg >> 8); + tbuf[1] = reg & 0xFF; + + ret = spi_write_then_read(spi, + tbuf, ARRAY_SIZE(tbuf), + rbuf, ARRAY_SIZE(rbuf)); + + if (ret < 0) + return ret; + + return rbuf[0]; +} + +static int ad9467_spi_write(struct spi_device *spi, unsigned int reg, + unsigned int val) +{ + unsigned char buf[3]; + + buf[0] = reg >> 8; + buf[1] = reg & 0xFF; + buf[2] = val; + + return spi_write(spi, buf, ARRAY_SIZE(buf)); +} + +static int ad9467_reg_access(struct adi_axi_adc_conv *conv, unsigned int reg, + unsigned int writeval, unsigned int *readval) +{ + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + struct spi_device *spi = st->spi; + int ret; + + if (readval == NULL) { + ret = ad9467_spi_write(spi, reg, writeval); + ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); + return ret; + } + + ret = ad9467_spi_read(spi, reg); + if (ret < 0) + return ret; + *readval = ret; + + return 0; +} + +static const unsigned int ad9467_scale_table[][2] = { + {2000, 0}, {2100, 6}, {2200, 7}, + {2300, 8}, {2400, 9}, {2500, 10}, +}; + +static void __ad9467_get_scale(struct adi_axi_adc_conv *conv, int index, + unsigned int *val, unsigned int *val2) +{ + const struct adi_axi_adc_chip_info *info = conv->chip_info; + const struct iio_chan_spec *chan = &info->channels[0]; + unsigned int tmp; + + tmp = (info->scale_table[index][0] * 1000000ULL) >> + chan->scan_type.realbits; + *val = tmp / 1000000; + *val2 = tmp % 1000000; +} + +#define AD9467_CHAN(_chan, _si, _bits, _sign) \ +{ \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .scan_index = _si, \ + .scan_type = { \ + .sign = _sign, \ + .realbits = _bits, \ + .storagebits = 16, \ + }, \ +} + +static const struct iio_chan_spec ad9467_channels[] = { + AD9467_CHAN(0, 0, 16, 'S'), +}; + +static const struct adi_axi_adc_chip_info ad9467_chip_tbl[] = { + [ID_AD9467] = { + .id = CHIPID_AD9467, + .max_rate = 250000000UL, + .scale_table = ad9467_scale_table, + .num_scales = ARRAY_SIZE(ad9467_scale_table), + .channels = ad9467_channels, + .num_channels = ARRAY_SIZE(ad9467_channels), + }, +}; + +static int ad9467_get_scale(struct adi_axi_adc_conv *conv, int *val, int *val2) +{ + const struct adi_axi_adc_chip_info *info = conv->chip_info; + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + unsigned int i, vref_val, vref_mask; + + vref_val = ad9467_spi_read(st->spi, AN877_ADC_REG_VREF); + + switch (info->id) { + case CHIPID_AD9467: + vref_mask = AD9467_REG_VREF_MASK; + break; + default: + vref_mask = 0xFFFF; + break; + } + + vref_val &= vref_mask; + + for (i = 0; i < info->num_scales; i++) { + if (vref_val == info->scale_table[i][1]) + break; + } + + if (i == info->num_scales) + return -ERANGE; + + __ad9467_get_scale(conv, i, val, val2); + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int ad9467_set_scale(struct adi_axi_adc_conv *conv, int val, int val2) +{ + const struct adi_axi_adc_chip_info *info = conv->chip_info; + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + unsigned int scale_val[2]; + unsigned int i; + + if (val != 0) + return -EINVAL; + + for (i = 0; i < info->num_scales; i++) { + __ad9467_get_scale(conv, i, &scale_val[0], &scale_val[1]); + if (scale_val[0] != val || scale_val[1] != val2) + continue; + + ad9467_spi_write(st->spi, AN877_ADC_REG_VREF, + info->scale_table[i][1]); + ad9467_spi_write(st->spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); + return 0; + } + + return -EINVAL; +} + +static int ad9467_read_raw(struct adi_axi_adc_conv *conv, + struct iio_chan_spec const *chan, + int *val, int *val2, long m) +{ + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + + switch (m) { + case IIO_CHAN_INFO_SCALE: + return ad9467_get_scale(conv, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + *val = clk_get_rate(st->clk); + + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int ad9467_write_raw(struct adi_axi_adc_conv *conv, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + const struct adi_axi_adc_chip_info *info = conv->chip_info; + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + long r_clk; + + switch (mask) { + case IIO_CHAN_INFO_SCALE: + return ad9467_set_scale(conv, val, val2); + case IIO_CHAN_INFO_SAMP_FREQ: + r_clk = clk_round_rate(st->clk, val); + if (r_clk < 0 || r_clk > info->max_rate) { + dev_warn(&st->spi->dev, + "Error setting ADC sample rate %ld", r_clk); + return -EINVAL; + } + + return clk_set_rate(st->clk, r_clk); + default: + return -EINVAL; + } +} + +static int ad9467_outputmode_set(struct spi_device *spi, unsigned int mode) +{ + int ret; + + ret = ad9467_spi_write(spi, AN877_ADC_REG_OUTPUT_MODE, mode); + if (ret < 0) + return ret; + + return ad9467_spi_write(spi, AN877_ADC_REG_TRANSFER, + AN877_ADC_TRANSFER_SYNC); +} + +static int ad9467_preenable_setup(struct adi_axi_adc_conv *conv) +{ + struct ad9467_state *st = adi_axi_adc_conv_priv(conv); + + return ad9467_outputmode_set(st->spi, st->output_mode); +} + +static int ad9467_setup(struct ad9467_state *st, unsigned int chip_id) +{ + switch (chip_id) { + case CHIPID_AD9467: + st->output_mode = AD9467_DEF_OUTPUT_MODE | + AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT; + return 0; + default: + return -EINVAL; + } +} + +static void ad9467_clk_disable(void *data) +{ + struct ad9467_state *st = data; + + clk_disable_unprepare(st->clk); +} + +static int ad9467_probe(struct spi_device *spi) +{ + const struct adi_axi_adc_chip_info *info; + struct adi_axi_adc_conv *conv; + struct ad9467_state *st; + unsigned int id; + int ret; + + info = of_device_get_match_data(&spi->dev); + if (!info) + return -ENODEV; + + conv = devm_adi_axi_adc_conv_register(&spi->dev, sizeof(*st)); + if (IS_ERR(conv)) + return PTR_ERR(conv); + + st = adi_axi_adc_conv_priv(conv); + st->spi = spi; + + st->clk = devm_clk_get(&spi->dev, "adc-clk"); + if (IS_ERR(st->clk)) + return PTR_ERR(st->clk); + + ret = clk_prepare_enable(st->clk); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(&spi->dev, ad9467_clk_disable, st); + if (ret) + return ret; + + st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown", + GPIOD_OUT_LOW); + if (IS_ERR(st->pwrdown_gpio)) + return PTR_ERR(st->pwrdown_gpio); + + st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(st->reset_gpio)) + return PTR_ERR(st->reset_gpio); + + if (st->reset_gpio) { + udelay(1); + ret = gpiod_direction_output(st->reset_gpio, 1); + if (ret) + return ret; + mdelay(10); + } + + spi_set_drvdata(spi, st); + + conv->chip_info = info; + + id = ad9467_spi_read(spi, AN877_ADC_REG_CHIP_ID); + if (id != conv->chip_info->id) { + dev_err(&spi->dev, "Unrecognized CHIP_ID 0x%X\n", id); + return -ENODEV; + } + + conv->reg_access = ad9467_reg_access; + conv->write_raw = ad9467_write_raw; + conv->read_raw = ad9467_read_raw; + conv->preenable_setup = ad9467_preenable_setup; + + return ad9467_setup(st, id); +} + +static const struct of_device_id ad9467_of_match[] = { + { .compatible = "adi,ad9467", .data = &ad9467_chip_tbl[ID_AD9467], }, + {} +}; +MODULE_DEVICE_TABLE(of, ad9467_of_match); + +static struct spi_driver ad9467_driver = { + .driver = { + .name = "ad9467", + .of_match_table = ad9467_of_match, + }, + .probe = ad9467_probe, +}; +module_spi_driver(ad9467_driver); + +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); +MODULE_DESCRIPTION("Analog Devices AD9467 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c new file mode 100644 index 000000000000..c24c8da99eb4 --- /dev/null +++ b/drivers/iio/adc/adi-axi-adc.c @@ -0,0 +1,482 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices Generic AXI ADC IP core + * Link: https://wiki.analog.com/resources/fpga/docs/axi_adc_ip + * + * Copyright 2012-2020 Analog Devices Inc. + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/buffer-dmaengine.h> + +#include <linux/fpga/adi-axi-common.h> +#include <linux/iio/adc/adi-axi-adc.h> + +/** + * Register definitions: + * https://wiki.analog.com/resources/fpga/docs/axi_adc_ip#register_map + */ + +/* ADC controls */ + +#define ADI_AXI_REG_RSTN 0x0040 +#define ADI_AXI_REG_RSTN_CE_N BIT(2) +#define ADI_AXI_REG_RSTN_MMCM_RSTN BIT(1) +#define ADI_AXI_REG_RSTN_RSTN BIT(0) + +/* ADC Channel controls */ + +#define ADI_AXI_REG_CHAN_CTRL(c) (0x0400 + (c) * 0x40) +#define ADI_AXI_REG_CHAN_CTRL_LB_OWR BIT(11) +#define ADI_AXI_REG_CHAN_CTRL_PN_SEL_OWR BIT(10) +#define ADI_AXI_REG_CHAN_CTRL_IQCOR_EN BIT(9) +#define ADI_AXI_REG_CHAN_CTRL_DCFILT_EN BIT(8) +#define ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT BIT(6) +#define ADI_AXI_REG_CHAN_CTRL_FMT_TYPE BIT(5) +#define ADI_AXI_REG_CHAN_CTRL_FMT_EN BIT(4) +#define ADI_AXI_REG_CHAN_CTRL_PN_TYPE_OWR BIT(1) +#define ADI_AXI_REG_CHAN_CTRL_ENABLE BIT(0) + +#define ADI_AXI_REG_CHAN_CTRL_DEFAULTS \ + (ADI_AXI_REG_CHAN_CTRL_FMT_SIGNEXT | \ + ADI_AXI_REG_CHAN_CTRL_FMT_EN | \ + ADI_AXI_REG_CHAN_CTRL_ENABLE) + +struct adi_axi_adc_core_info { + unsigned int version; +}; + +struct adi_axi_adc_state { + struct mutex lock; + + struct adi_axi_adc_client *client; + void __iomem *regs; +}; + +struct adi_axi_adc_client { + struct list_head entry; + struct adi_axi_adc_conv conv; + struct adi_axi_adc_state *state; + struct device *dev; + const struct adi_axi_adc_core_info *info; +}; + +static LIST_HEAD(registered_clients); +static DEFINE_MUTEX(registered_clients_lock); + +static struct adi_axi_adc_client *conv_to_client(struct adi_axi_adc_conv *conv) +{ + return container_of(conv, struct adi_axi_adc_client, conv); +} + +void *adi_axi_adc_conv_priv(struct adi_axi_adc_conv *conv) +{ + struct adi_axi_adc_client *cl = conv_to_client(conv); + + return (char *)cl + ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); +} +EXPORT_SYMBOL_GPL(adi_axi_adc_conv_priv); + +static void adi_axi_adc_write(struct adi_axi_adc_state *st, + unsigned int reg, + unsigned int val) +{ + iowrite32(val, st->regs + reg); +} + +static unsigned int adi_axi_adc_read(struct adi_axi_adc_state *st, + unsigned int reg) +{ + return ioread32(st->regs + reg); +} + +static int adi_axi_adc_config_dma_buffer(struct device *dev, + struct iio_dev *indio_dev) +{ + struct iio_buffer *buffer; + const char *dma_name; + + if (!device_property_present(dev, "dmas")) + return 0; + + if (device_property_read_string(dev, "dma-names", &dma_name)) + dma_name = "rx"; + + buffer = devm_iio_dmaengine_buffer_alloc(indio_dev->dev.parent, + dma_name); + if (IS_ERR(buffer)) + return PTR_ERR(buffer); + + indio_dev->modes |= INDIO_BUFFER_HARDWARE; + iio_device_attach_buffer(indio_dev, buffer); + + return 0; +} + +static int adi_axi_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + if (!conv->read_raw) + return -EOPNOTSUPP; + + return conv->read_raw(conv, chan, val, val2, mask); +} + +static int adi_axi_adc_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + if (!conv->write_raw) + return -EOPNOTSUPP; + + return conv->write_raw(conv, chan, val, val2, mask); +} + +static int adi_axi_adc_update_scan_mode(struct iio_dev *indio_dev, + const unsigned long *scan_mask) +{ + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + unsigned int i, ctrl; + + for (i = 0; i < conv->chip_info->num_channels; i++) { + ctrl = adi_axi_adc_read(st, ADI_AXI_REG_CHAN_CTRL(i)); + + if (test_bit(i, scan_mask)) + ctrl |= ADI_AXI_REG_CHAN_CTRL_ENABLE; + else + ctrl &= ~ADI_AXI_REG_CHAN_CTRL_ENABLE; + + adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), ctrl); + } + + return 0; +} + +static struct adi_axi_adc_conv *adi_axi_adc_conv_register(struct device *dev, + size_t sizeof_priv) +{ + struct adi_axi_adc_client *cl; + size_t alloc_size; + + alloc_size = ALIGN(sizeof(struct adi_axi_adc_client), IIO_ALIGN); + if (sizeof_priv) + alloc_size += ALIGN(sizeof_priv, IIO_ALIGN); + + cl = kzalloc(alloc_size, GFP_KERNEL); + if (!cl) + return ERR_PTR(-ENOMEM); + + mutex_lock(®istered_clients_lock); + + cl->dev = get_device(dev); + + list_add_tail(&cl->entry, ®istered_clients); + + mutex_unlock(®istered_clients_lock); + + return &cl->conv; +} + +static void adi_axi_adc_conv_unregister(struct adi_axi_adc_conv *conv) +{ + struct adi_axi_adc_client *cl = conv_to_client(conv); + + mutex_lock(®istered_clients_lock); + + list_del(&cl->entry); + put_device(cl->dev); + + mutex_unlock(®istered_clients_lock); + + kfree(cl); +} + +static void devm_adi_axi_adc_conv_release(struct device *dev, void *res) +{ + adi_axi_adc_conv_unregister(*(struct adi_axi_adc_conv **)res); +} + +struct adi_axi_adc_conv *devm_adi_axi_adc_conv_register(struct device *dev, + size_t sizeof_priv) +{ + struct adi_axi_adc_conv **ptr, *conv; + + ptr = devres_alloc(devm_adi_axi_adc_conv_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + conv = adi_axi_adc_conv_register(dev, sizeof_priv); + if (IS_ERR(conv)) { + devres_free(ptr); + return ERR_CAST(conv); + } + + *ptr = conv; + devres_add(dev, ptr); + + return conv; +} +EXPORT_SYMBOL_GPL(devm_adi_axi_adc_conv_register); + +static ssize_t in_voltage_scale_available_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + size_t len = 0; + int i; + + for (i = 0; i < conv->chip_info->num_scales; i++) { + const unsigned int *s = conv->chip_info->scale_table[i]; + + len += scnprintf(buf + len, PAGE_SIZE - len, + "%u.%06u ", s[0], s[1]); + } + buf[len - 1] = '\n'; + + return len; +} + +static IIO_DEVICE_ATTR_RO(in_voltage_scale_available, 0); + +enum { + ADI_AXI_ATTR_SCALE_AVAIL, +}; + +#define ADI_AXI_ATTR(_en_, _file_) \ + [ADI_AXI_ATTR_##_en_] = &iio_dev_attr_##_file_.dev_attr.attr + +static struct attribute *adi_axi_adc_attributes[] = { + ADI_AXI_ATTR(SCALE_AVAIL, in_voltage_scale_available), + NULL +}; + +static umode_t axi_adc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct adi_axi_adc_state *st = iio_priv(indio_dev); + struct adi_axi_adc_conv *conv = &st->client->conv; + + switch (n) { + case ADI_AXI_ATTR_SCALE_AVAIL: + if (!conv->chip_info->num_scales) + return 0; + return attr->mode; + default: + return attr->mode; + } +} + +static const struct attribute_group adi_axi_adc_attribute_group = { + .attrs = adi_axi_adc_attributes, + .is_visible = axi_adc_attr_is_visible, +}; + +static const struct iio_info adi_axi_adc_info = { + .read_raw = &adi_axi_adc_read_raw, + .write_raw = &adi_axi_adc_write_raw, + .attrs = &adi_axi_adc_attribute_group, + .update_scan_mode = &adi_axi_adc_update_scan_mode, +}; + +static const struct adi_axi_adc_core_info adi_axi_adc_10_0_a_info = { + .version = ADI_AXI_PCORE_VER(10, 0, 'a'), +}; + +static struct adi_axi_adc_client *adi_axi_adc_attach_client(struct device *dev) +{ + const struct adi_axi_adc_core_info *info; + struct adi_axi_adc_client *cl; + struct device_node *cln; + + info = of_device_get_match_data(dev); + if (!info) + return ERR_PTR(-ENODEV); + + cln = of_parse_phandle(dev->of_node, "adi,adc-dev", 0); + if (!cln) { + dev_err(dev, "No 'adi,adc-dev' node defined\n"); + return ERR_PTR(-ENODEV); + } + + mutex_lock(®istered_clients_lock); + + list_for_each_entry(cl, ®istered_clients, entry) { + if (!cl->dev) + continue; + + if (cl->dev->of_node != cln) + continue; + + if (!try_module_get(dev->driver->owner)) { + mutex_unlock(®istered_clients_lock); + return ERR_PTR(-ENODEV); + } + + get_device(dev); + cl->info = info; + mutex_unlock(®istered_clients_lock); + return cl; + } + + mutex_unlock(®istered_clients_lock); + + return ERR_PTR(-EPROBE_DEFER); +} + +static int adi_axi_adc_setup_channels(struct device *dev, + struct adi_axi_adc_state *st) +{ + struct adi_axi_adc_conv *conv = &st->client->conv; + int i, ret; + + if (conv->preenable_setup) { + ret = conv->preenable_setup(conv); + if (ret) + return ret; + } + + for (i = 0; i < conv->chip_info->num_channels; i++) { + adi_axi_adc_write(st, ADI_AXI_REG_CHAN_CTRL(i), + ADI_AXI_REG_CHAN_CTRL_DEFAULTS); + } + + return 0; +} + +static void axi_adc_reset(struct adi_axi_adc_state *st) +{ + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, 0); + mdelay(10); + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, ADI_AXI_REG_RSTN_MMCM_RSTN); + mdelay(10); + adi_axi_adc_write(st, ADI_AXI_REG_RSTN, + ADI_AXI_REG_RSTN_RSTN | ADI_AXI_REG_RSTN_MMCM_RSTN); +} + +static void adi_axi_adc_cleanup(void *data) +{ + struct adi_axi_adc_client *cl = data; + + put_device(cl->dev); + module_put(cl->dev->driver->owner); +} + +static int adi_axi_adc_probe(struct platform_device *pdev) +{ + struct adi_axi_adc_conv *conv; + struct iio_dev *indio_dev; + struct adi_axi_adc_client *cl; + struct adi_axi_adc_state *st; + unsigned int ver; + int ret; + + cl = adi_axi_adc_attach_client(&pdev->dev); + if (IS_ERR(cl)) + return PTR_ERR(cl); + + ret = devm_add_action_or_reset(&pdev->dev, adi_axi_adc_cleanup, cl); + if (ret) + return ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); + if (indio_dev == NULL) + return -ENOMEM; + + st = iio_priv(indio_dev); + st->client = cl; + cl->state = st; + mutex_init(&st->lock); + + st->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(st->regs)) + return PTR_ERR(st->regs); + + conv = &st->client->conv; + + axi_adc_reset(st); + + ver = adi_axi_adc_read(st, ADI_AXI_REG_VERSION); + + if (cl->info->version > ver) { + dev_err(&pdev->dev, + "IP core version is too old. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n", + ADI_AXI_PCORE_VER_MAJOR(cl->info->version), + ADI_AXI_PCORE_VER_MINOR(cl->info->version), + ADI_AXI_PCORE_VER_PATCH(cl->info->version), + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + return -ENODEV; + } + + indio_dev->info = &adi_axi_adc_info; + indio_dev->dev.parent = &pdev->dev; + indio_dev->name = "adi-axi-adc"; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = conv->chip_info->num_channels; + indio_dev->channels = conv->chip_info->channels; + + ret = adi_axi_adc_config_dma_buffer(&pdev->dev, indio_dev); + if (ret) + return ret; + + ret = adi_axi_adc_setup_channels(&pdev->dev, st); + if (ret) + return ret; + + ret = devm_iio_device_register(&pdev->dev, indio_dev); + if (ret) + return ret; + + dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n", + ADI_AXI_PCORE_VER_MAJOR(ver), + ADI_AXI_PCORE_VER_MINOR(ver), + ADI_AXI_PCORE_VER_PATCH(ver)); + + return 0; +} + +/* Match table for of_platform binding */ +static const struct of_device_id adi_axi_adc_of_match[] = { + { .compatible = "adi,axi-adc-10.0.a", .data = &adi_axi_adc_10_0_a_info }, + { /* end of list */ } +}; +MODULE_DEVICE_TABLE(of, adi_axi_adc_of_match); + +static struct platform_driver adi_axi_adc_driver = { + .driver = { + .name = KBUILD_MODNAME, + .of_match_table = adi_axi_adc_of_match, + }, + .probe = adi_axi_adc_probe, +}; +module_platform_driver(adi_axi_adc_driver); + +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); +MODULE_DESCRIPTION("Analog Devices Generic AXI ADC IP core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index abe99856c823..0368b6dc6d60 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -1152,7 +1152,6 @@ static int at91_adc_probe(struct platform_device *pdev) int ret; struct iio_dev *idev; struct at91_adc_state *st; - struct resource *res; u32 reg; idev = devm_iio_device_alloc(&pdev->dev, sizeof(struct at91_adc_state)); @@ -1182,9 +1181,7 @@ static int at91_adc_probe(struct platform_device *pdev) if (st->irq < 0) return -ENODEV; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - st->reg_base = devm_ioremap_resource(&pdev->dev, res); + st->reg_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(st->reg_base)) return PTR_ERR(st->reg_base); diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c index fa71489195c6..b0a4dc88ba9b 100644 --- a/drivers/iio/adc/fsl-imx25-gcq.c +++ b/drivers/iio/adc/fsl-imx25-gcq.c @@ -294,7 +294,6 @@ static int mx25_gcq_probe(struct platform_device *pdev) struct mx25_gcq_priv *priv; struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent); struct device *dev = &pdev->dev; - struct resource *res; void __iomem *mem; int ret; int i; @@ -305,8 +304,7 @@ static int mx25_gcq_probe(struct platform_device *pdev) priv = iio_priv(indio_dev); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem = devm_ioremap_resource(dev, res); + mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem)) return PTR_ERR(mem); diff --git a/drivers/iio/adc/intel_mrfld_adc.c b/drivers/iio/adc/intel_mrfld_adc.c index c35a1beb817c..a6d2e1f27e76 100644 --- a/drivers/iio/adc/intel_mrfld_adc.c +++ b/drivers/iio/adc/intel_mrfld_adc.c @@ -75,7 +75,7 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, struct regmap *regmap = adc->regmap; unsigned int req; long timeout; - u8 buf[2]; + __be16 value; int ret; reinit_completion(&adc->completion); @@ -105,11 +105,11 @@ static int mrfld_adc_single_conv(struct iio_dev *indio_dev, goto done; } - ret = regmap_bulk_read(regmap, chan->address, buf, 2); + ret = regmap_bulk_read(regmap, chan->address, &value, sizeof(value)); if (ret) goto done; - *result = get_unaligned_be16(buf); + *result = be16_to_cpu(value); ret = IIO_VAL_INT; done: diff --git a/drivers/iio/adc/max1241.c b/drivers/iio/adc/max1241.c new file mode 100644 index 000000000000..541939c7abca --- /dev/null +++ b/drivers/iio/adc/max1241.c @@ -0,0 +1,227 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * MAX1241 low-power, 12-bit serial ADC + * + * Datasheet: https://datasheets.maximintegrated.com/en/ds/MAX1240-MAX1241.pdf + */ + +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/iio/iio.h> +#include <linux/module.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#define MAX1241_VAL_MASK GENMASK(11, 0) +#define MAX1241_SHUTDOWN_DELAY_USEC 4 + +enum max1241_id { + max1241, +}; + +struct max1241 { + struct spi_device *spi; + struct mutex lock; + struct regulator *vdd; + struct regulator *vref; + struct gpio_desc *shutdown; + + __be16 data ____cacheline_aligned; +}; + +static const struct iio_chan_spec max1241_channels[] = { + { + .type = IIO_VOLTAGE, + .indexed = 1, + .channel = 0, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE), + }, +}; + +static int max1241_read(struct max1241 *adc) +{ + struct spi_transfer xfers[] = { + /* + * Begin conversion by bringing /CS low for at least + * tconv us. + */ + { + .len = 0, + .delay.value = 8, + .delay.unit = SPI_DELAY_UNIT_USECS, + }, + /* + * Then read two bytes of data in our RX buffer. + */ + { + .rx_buf = &adc->data, + .len = 2, + }, + }; + + return spi_sync_transfer(adc->spi, xfers, ARRAY_SIZE(xfers)); +} + +static int max1241_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + int ret, vref_uV; + struct max1241 *adc = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + mutex_lock(&adc->lock); + + if (adc->shutdown) { + gpiod_set_value(adc->shutdown, 0); + udelay(MAX1241_SHUTDOWN_DELAY_USEC); + ret = max1241_read(adc); + gpiod_set_value(adc->shutdown, 1); + } else + ret = max1241_read(adc); + + if (ret) { + mutex_unlock(&adc->lock); + return ret; + } + + *val = (be16_to_cpu(adc->data) >> 3) & MAX1241_VAL_MASK; + + mutex_unlock(&adc->lock); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + vref_uV = regulator_get_voltage(adc->vref); + + if (vref_uV < 0) + return vref_uV; + + *val = vref_uV / 1000; + *val2 = 12; + + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } +} + +static const struct iio_info max1241_info = { + .read_raw = max1241_read_raw, +}; + +static void max1241_disable_vdd_action(void *data) +{ + struct max1241 *adc = data; + struct device *dev = &adc->spi->dev; + int err; + + err = regulator_disable(adc->vdd); + if (err) + dev_err(dev, "could not disable vdd regulator.\n"); +} + +static void max1241_disable_vref_action(void *data) +{ + struct max1241 *adc = data; + struct device *dev = &adc->spi->dev; + int err; + + err = regulator_disable(adc->vref); + if (err) + dev_err(dev, "could not disable vref regulator.\n"); +} + +static int max1241_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct iio_dev *indio_dev; + struct max1241 *adc; + int ret; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->spi = spi; + mutex_init(&adc->lock); + + spi_set_drvdata(spi, indio_dev); + + adc->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(adc->vdd)) { + dev_err(dev, "failed to get vdd regulator\n"); + return PTR_ERR(adc->vdd); + } + + ret = regulator_enable(adc->vdd); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, max1241_disable_vdd_action, adc); + if (ret) { + dev_err(dev, "could not set up vdd regulator cleanup action\n"); + return ret; + } + + adc->vref = devm_regulator_get(dev, "vref"); + if (IS_ERR(adc->vref)) { + dev_err(dev, "failed to get vref regulator\n"); + return PTR_ERR(adc->vref); + } + + ret = regulator_enable(adc->vref); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, max1241_disable_vref_action, adc); + if (ret) { + dev_err(dev, "could not set up vref regulator cleanup action\n"); + return ret; + } + + adc->shutdown = devm_gpiod_get_optional(dev, "shutdown", + GPIOD_OUT_HIGH); + if (IS_ERR(adc->shutdown)) + return PTR_ERR(adc->shutdown); + + if (adc->shutdown) + dev_dbg(dev, "shutdown pin passed, low-power mode enabled"); + else + dev_dbg(dev, "no shutdown pin passed, low-power mode disabled"); + + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->dev.parent = dev; + indio_dev->info = &max1241_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = max1241_channels; + indio_dev->num_channels = ARRAY_SIZE(max1241_channels); + + return devm_iio_device_register(dev, indio_dev); +} + +static const struct spi_device_id max1241_id[] = { + { "max1241", max1241 }, + {} +}; + +static const struct of_device_id max1241_dt_ids[] = { + { .compatible = "maxim,max1241" }, + {} +}; +MODULE_DEVICE_TABLE(of, max1241_dt_ids); + +static struct spi_driver max1241_spi_driver = { + .driver = { + .name = "max1241", + .of_match_table = max1241_dt_ids, + }, + .probe = max1241_probe, + .id_table = max1241_id, +}; +module_spi_driver(max1241_spi_driver); + +MODULE_AUTHOR("Alexandru Lazar <alazar@startmail.com>"); +MODULE_DESCRIPTION("MAX1241 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 5c2cc61b666e..9d92017c79b2 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -150,6 +150,7 @@ struct max1363_chip_info { * @current_mode: the scan mode of this chip * @requestedmask: a valid requested set of channels * @reg: supply regulator + * @lock lock to ensure state is consistent * @monitor_on: whether monitor mode is enabled * @monitor_speed: parameter corresponding to device monitor speed setting * @mask_high: bitmask for enabled high thresholds @@ -169,6 +170,7 @@ struct max1363_state { const struct max1363_mode *current_mode; u32 requestedmask; struct regulator *reg; + struct mutex lock; /* Using monitor modes and buffer at the same time is currently not supported */ @@ -364,7 +366,11 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, struct max1363_state *st = iio_priv(indio_dev); struct i2c_client *client = st->client; - mutex_lock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&st->lock); + /* * If monitor mode is enabled, the method for reading a single * channel will have to be rather different and has not yet @@ -372,7 +378,7 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, * * Also, cannot read directly if buffered capture enabled. */ - if (st->monitor_on || iio_buffer_enabled(indio_dev)) { + if (st->monitor_on) { ret = -EBUSY; goto error_ret; } @@ -404,8 +410,10 @@ static int max1363_read_single_chan(struct iio_dev *indio_dev, data = rxbuf[0]; } *val = data; + error_ret: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); return ret; } @@ -705,9 +713,9 @@ static ssize_t max1363_monitor_store_freq(struct device *dev, if (!found) return -EINVAL; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); st->monitor_speed = i; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return 0; } @@ -810,12 +818,12 @@ static int max1363_read_event_config(struct iio_dev *indio_dev, int val; int number = chan->channel; - mutex_lock(&indio_dev->mlock); + mutex_lock(&st->lock); if (dir == IIO_EV_DIR_FALLING) val = (1 << number) & st->mask_low; else val = (1 << number) & st->mask_high; - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); return val; } @@ -962,7 +970,11 @@ static int max1363_write_event_config(struct iio_dev *indio_dev, u16 unifiedmask; int number = chan->channel; - mutex_lock(&indio_dev->mlock); + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&st->lock); + unifiedmask = st->mask_low | st->mask_high; if (dir == IIO_EV_DIR_FALLING) { @@ -989,7 +1001,8 @@ static int max1363_write_event_config(struct iio_dev *indio_dev, max1363_monitor_mode_update(st, !!(st->mask_high | st->mask_low)); error_ret: - mutex_unlock(&indio_dev->mlock); + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); return ret; } @@ -1587,6 +1600,7 @@ static int max1363_probe(struct i2c_client *client, st = iio_priv(indio_dev); + mutex_init(&st->lock); st->reg = devm_regulator_get(&client->dev, "vcc"); if (IS_ERR(st->reg)) { ret = PTR_ERR(st->reg); diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c index 176e1cb4abb1..0f2c1738a90d 100644 --- a/drivers/iio/adc/sun4i-gpadc-iio.c +++ b/drivers/iio/adc/sun4i-gpadc-iio.c @@ -496,7 +496,6 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev, struct iio_dev *indio_dev) { struct sun4i_gpadc_iio *info = iio_priv(indio_dev); - struct resource *mem; void __iomem *base; int ret; @@ -508,8 +507,7 @@ static int sun4i_gpadc_probe_dt(struct platform_device *pdev, indio_dev->num_channels = ARRAY_SIZE(sun8i_a33_gpadc_channels); indio_dev->channels = sun8i_a33_gpadc_channels; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, mem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c index ec227b358cd6..9897d758cf88 100644 --- a/drivers/iio/adc/xilinx-xadc-core.c +++ b/drivers/iio/adc/xilinx-xadc-core.c @@ -3,7 +3,7 @@ * Xilinx XADC driver * * Copyright 2013-2014 Analog Devices Inc. - * Author: Lars-Peter Clauen <lars@metafoo.de> + * Author: Lars-Peter Clausen <lars@metafoo.de> * * Documentation for the parts can be found at: * - XADC hardmacro: Xilinx UG480 @@ -653,7 +653,7 @@ static int xadc_trigger_set_state(struct iio_trigger *trigger, bool state) mutex_lock(&xadc->mutex); if (state) { - /* Only one of the two triggers can be active at the a time. */ + /* Only one of the two triggers can be active at a time. */ if (xadc->trigger != NULL) { ret = -EBUSY; goto err_out; diff --git a/drivers/iio/adc/xilinx-xadc-events.c b/drivers/iio/adc/xilinx-xadc-events.c index dbfd5da290a4..2357f585720a 100644 --- a/drivers/iio/adc/xilinx-xadc-events.c +++ b/drivers/iio/adc/xilinx-xadc-events.c @@ -3,7 +3,7 @@ * Xilinx XADC driver * * Copyright 2013 Analog Devices Inc. - * Author: Lars-Peter Clauen <lars@metafoo.de> + * Author: Lars-Peter Clausen <lars@metafoo.de> */ #include <linux/iio/events.h> diff --git a/drivers/iio/adc/xilinx-xadc.h b/drivers/iio/adc/xilinx-xadc.h index 4017f18b0a4f..25abed9c0285 100644 --- a/drivers/iio/adc/xilinx-xadc.h +++ b/drivers/iio/adc/xilinx-xadc.h @@ -3,7 +3,7 @@ * Xilinx XADC driver * * Copyright 2013 Analog Devices Inc. - * Author: Lars-Peter Clauen <lars@metafoo.de> + * Author: Lars-Peter Clausen <lars@metafoo.de> */ #ifndef __IIO_XILINX_XADC__ diff --git a/drivers/iio/buffer/industrialio-buffer-dma.c b/drivers/iio/buffer/industrialio-buffer-dma.c index a74bd9c0587c..d348af8b9705 100644 --- a/drivers/iio/buffer/industrialio-buffer-dma.c +++ b/drivers/iio/buffer/industrialio-buffer-dma.c @@ -12,7 +12,6 @@ #include <linux/mutex.h> #include <linux/sched.h> #include <linux/poll.h> -#include <linux/iio/buffer.h> #include <linux/iio/buffer_impl.h> #include <linux/iio/buffer-dma.h> #include <linux/dma-mapping.h> diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index b129693af0fd..6dedf12b69a4 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -134,7 +134,7 @@ static ssize_t iio_dmaengine_buffer_get_length_align(struct device *dev, struct dmaengine_buffer *dmaengine_buffer = iio_buffer_to_dmaengine_buffer(indio_dev->buffer); - return sprintf(buf, "%u\n", dmaengine_buffer->align); + return sprintf(buf, "%zu\n", dmaengine_buffer->align); } static IIO_DEVICE_ATTR(length_align_bytes, 0444, @@ -229,6 +229,45 @@ void iio_dmaengine_buffer_free(struct iio_buffer *buffer) } EXPORT_SYMBOL_GPL(iio_dmaengine_buffer_free); +static void __devm_iio_dmaengine_buffer_free(struct device *dev, void *res) +{ + iio_dmaengine_buffer_free(*(struct iio_buffer **)res); +} + +/** + * devm_iio_dmaengine_buffer_alloc() - Resource-managed iio_dmaengine_buffer_alloc() + * @dev: Parent device for the buffer + * @channel: DMA channel name, typically "rx". + * + * This allocates a new IIO buffer which internally uses the DMAengine framework + * to perform its transfers. The parent device will be used to request the DMA + * channel. + * + * The buffer will be automatically de-allocated once the device gets destroyed. + */ +struct iio_buffer *devm_iio_dmaengine_buffer_alloc(struct device *dev, + const char *channel) +{ + struct iio_buffer **bufferp, *buffer; + + bufferp = devres_alloc(__devm_iio_dmaengine_buffer_free, + sizeof(*bufferp), GFP_KERNEL); + if (!bufferp) + return ERR_PTR(-ENOMEM); + + buffer = iio_dmaengine_buffer_alloc(dev, channel); + if (IS_ERR(buffer)) { + devres_free(bufferp); + return buffer; + } + + *bufferp = buffer; + devres_add(dev, bufferp); + + return buffer; +} +EXPORT_SYMBOL_GPL(devm_iio_dmaengine_buffer_alloc); + MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("DMA buffer for the IIO framework"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/buffer/industrialio-hw-consumer.c b/drivers/iio/buffer/industrialio-hw-consumer.c index 95165697d8ae..f2d27788f666 100644 --- a/drivers/iio/buffer/industrialio-hw-consumer.c +++ b/drivers/iio/buffer/industrialio-hw-consumer.c @@ -142,17 +142,6 @@ static void devm_iio_hw_consumer_release(struct device *dev, void *res) iio_hw_consumer_free(*(struct iio_hw_consumer **)res); } -static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) -{ - struct iio_hw_consumer **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - return *r == data; -} - /** * devm_iio_hw_consumer_alloc - Resource-managed iio_hw_consumer_alloc() * @dev: Pointer to consumer device. @@ -160,9 +149,6 @@ static int devm_iio_hw_consumer_match(struct device *dev, void *res, void *data) * Managed iio_hw_consumer_alloc. iio_hw_consumer allocated with this function * is automatically freed on driver detach. * - * If an iio_hw_consumer allocated with this function needs to be freed - * separately, devm_iio_hw_consumer_free() must be used. - * * returns pointer to allocated iio_hw_consumer on success, NULL on failure. */ struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) @@ -187,23 +173,6 @@ struct iio_hw_consumer *devm_iio_hw_consumer_alloc(struct device *dev) EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_alloc); /** - * devm_iio_hw_consumer_free - Resource-managed iio_hw_consumer_free() - * @dev: Pointer to consumer device. - * @hwc: iio_hw_consumer to free. - * - * Free iio_hw_consumer allocated with devm_iio_hw_consumer_alloc(). - */ -void devm_iio_hw_consumer_free(struct device *dev, struct iio_hw_consumer *hwc) -{ - int rc; - - rc = devres_release(dev, devm_iio_hw_consumer_release, - devm_iio_hw_consumer_match, hwc); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_hw_consumer_free); - -/** * iio_hw_consumer_enable() - Enable IIO hardware consumer * @hwc: iio_hw_consumer to enable. * diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index cb322b2f09cd..e8046c1ecd6b 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -126,17 +126,6 @@ int devm_iio_triggered_buffer_setup(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup); -void devm_iio_triggered_buffer_cleanup(struct device *dev, - struct iio_dev *indio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_triggered_buffer_clean, - devm_iio_device_match, indio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_cleanup); - MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/buffer/kfifo_buf.c b/drivers/iio/buffer/kfifo_buf.c index 3150f8ab984b..1359abed3b31 100644 --- a/drivers/iio/buffer/kfifo_buf.c +++ b/drivers/iio/buffer/kfifo_buf.c @@ -179,16 +179,6 @@ static void devm_iio_kfifo_release(struct device *dev, void *res) iio_kfifo_free(*(struct iio_buffer **)res); } -static int devm_iio_kfifo_match(struct device *dev, void *res, void *data) -{ - struct iio_buffer **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - /** * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate() * @dev: Device to allocate kfifo buffer for @@ -216,16 +206,4 @@ struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev) } EXPORT_SYMBOL(devm_iio_kfifo_allocate); -/** - * devm_iio_fifo_free - Resource-managed iio_kfifo_free() - * @dev: Device the buffer belongs to - * @r: The buffer associated with the device - */ -void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r) -{ - WARN_ON(devres_release(dev, devm_iio_kfifo_release, - devm_iio_kfifo_match, r)); -} -EXPORT_SYMBOL(devm_iio_kfifo_free); - MODULE_LICENSE("GPL"); diff --git a/drivers/iio/chemical/atlas-sensor.c b/drivers/iio/chemical/atlas-sensor.c index 82d470561ad3..973cdb4f1e83 100644 --- a/drivers/iio/chemical/atlas-sensor.c +++ b/drivers/iio/chemical/atlas-sensor.c @@ -426,8 +426,7 @@ static irqreturn_t atlas_trigger_handler(int irq, void *private) int ret; ret = regmap_bulk_read(data->regmap, data->chip->data_reg, - (u8 *) &data->buffer, - sizeof(__be32) * channels); + &data->buffer, sizeof(__be32) * channels); if (!ret) iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, @@ -463,7 +462,7 @@ static int atlas_read_measurement(struct atlas_data *data, int reg, __be32 *val) if (suspended) msleep(data->chip->delay); - ret = regmap_bulk_read(data->regmap, reg, (u8 *) val, sizeof(*val)); + ret = regmap_bulk_read(data->regmap, reg, val, sizeof(*val)); pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); @@ -485,7 +484,7 @@ static int atlas_read_raw(struct iio_dev *indio_dev, switch (chan->type) { case IIO_TEMP: ret = regmap_bulk_read(data->regmap, chan->address, - (u8 *) ®, sizeof(reg)); + ®, sizeof(reg)); break; case IIO_PH: case IIO_CONCENTRATION: diff --git a/drivers/iio/chemical/bme680_core.c b/drivers/iio/chemical/bme680_core.c index ccde4c65ff93..13773e01699b 100644 --- a/drivers/iio/chemical/bme680_core.c +++ b/drivers/iio/chemical/bme680_core.c @@ -114,14 +114,16 @@ static int bme680_read_calib(struct bme680_data *data, __le16 buf; /* Temperature related coefficients */ - ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_T1_LSB_REG\n"); return ret; } calib->par_t1 = le16_to_cpu(buf); - ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_T2_LSB_REG\n"); return ret; @@ -136,14 +138,16 @@ static int bme680_read_calib(struct bme680_data *data, calib->par_t3 = tmp; /* Pressure related coefficients */ - ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P1_LSB_REG\n"); return ret; } calib->par_p1 = le16_to_cpu(buf); - ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P2_LSB_REG\n"); return ret; @@ -157,14 +161,16 @@ static int bme680_read_calib(struct bme680_data *data, } calib->par_p3 = tmp; - ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P4_LSB_REG\n"); return ret; } calib->par_p4 = le16_to_cpu(buf); - ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P5_LSB_REG\n"); return ret; @@ -185,14 +191,16 @@ static int bme680_read_calib(struct bme680_data *data, } calib->par_p7 = tmp; - ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P8_LSB_REG\n"); return ret; } calib->par_p8 = le16_to_cpu(buf); - ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, (u8 *) &buf, 2); + ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_P9_LSB_REG\n"); return ret; @@ -276,8 +284,8 @@ static int bme680_read_calib(struct bme680_data *data, } calib->par_gh1 = tmp; - ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, (u8 *) &buf, - 2); + ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, + &buf, sizeof(buf)); if (ret < 0) { dev_err(dev, "failed to read BME680_GH2_LSB_REG\n"); return ret; @@ -615,7 +623,7 @@ static int bme680_read_temp(struct bme680_data *data, int *val) return ret; ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB, - (u8 *) &tmp, 3); + &tmp, 3); if (ret < 0) { dev_err(dev, "failed to read temperature\n"); return ret; @@ -656,7 +664,7 @@ static int bme680_read_press(struct bme680_data *data, return ret; ret = regmap_bulk_read(data->regmap, BME680_REG_PRESS_MSB, - (u8 *) &tmp, 3); + &tmp, 3); if (ret < 0) { dev_err(dev, "failed to read pressure\n"); return ret; @@ -689,7 +697,7 @@ static int bme680_read_humid(struct bme680_data *data, return ret; ret = regmap_bulk_read(data->regmap, BM6880_REG_HUMIDITY_MSB, - (u8 *) &tmp, 2); + &tmp, sizeof(tmp)); if (ret < 0) { dev_err(dev, "failed to read humidity\n"); return ret; @@ -754,7 +762,7 @@ static int bme680_read_gas(struct bme680_data *data, } ret = regmap_bulk_read(data->regmap, BME680_REG_GAS_MSB, - (u8 *) &tmp, 2); + &tmp, sizeof(tmp)); if (ret < 0) { dev_err(dev, "failed to read gas resistance\n"); return ret; diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 0e35ff06f9af..a0c2cbd60c6f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -150,8 +150,7 @@ static int st_sensors_set_fullscale(struct iio_dev *indio_dev, unsigned int fs) if (err < 0) goto st_accel_set_fullscale_error; - sdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &sdata->sensor_settings->fs.fs_avl[i]; + sdata->current_fullscale = &sdata->sensor_settings->fs.fs_avl[i]; return err; st_accel_set_fullscale_error: @@ -278,8 +277,7 @@ static int st_sensors_set_drdy_int_pin(struct iio_dev *indio_dev, !sdata->sensor_settings->drdy_irq.int2.addr) { if (pdata->drdy_int_pin) dev_info(&indio_dev->dev, - "DRDY on pin INT%d specified, but sensor " - "does not support interrupts\n", + "DRDY on pin INT%d specified, but sensor does not support interrupts\n", pdata->drdy_int_pin); return 0; } diff --git a/drivers/iio/common/st_sensors/st_sensors_i2c.c b/drivers/iio/common/st_sensors/st_sensors_i2c.c index 286830fb5d35..b400560bac93 100644 --- a/drivers/iio/common/st_sensors/st_sensors_i2c.c +++ b/drivers/iio/common/st_sensors/st_sensors_i2c.c @@ -49,8 +49,8 @@ int st_sensors_i2c_configure(struct iio_dev *indio_dev, sdata->regmap = devm_regmap_init_i2c(client, config); if (IS_ERR(sdata->regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap (%d)\n", - (int)PTR_ERR(sdata->regmap)); + dev_err(&client->dev, "Failed to register i2c regmap (%ld)\n", + PTR_ERR(sdata->regmap)); return PTR_ERR(sdata->regmap); } diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c index 1275fb0eda31..ee70515bb89f 100644 --- a/drivers/iio/common/st_sensors/st_sensors_spi.c +++ b/drivers/iio/common/st_sensors/st_sensors_spi.c @@ -44,7 +44,7 @@ static bool st_sensors_is_spi_3_wire(struct spi_device *spi) if (device_property_read_bool(dev, "spi-3wire")) return true; - pdata = (struct st_sensors_platform_data *)dev->platform_data; + pdata = dev_get_platdata(dev); if (pdata && pdata->spi_3wire) return true; @@ -101,8 +101,8 @@ int st_sensors_spi_configure(struct iio_dev *indio_dev, sdata->regmap = devm_regmap_init_spi(spi, config); if (IS_ERR(sdata->regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap (%d)\n", - (int)PTR_ERR(sdata->regmap)); + dev_err(&spi->dev, "Failed to register spi regmap (%ld)\n", + PTR_ERR(sdata->regmap)); return PTR_ERR(sdata->regmap); } diff --git a/drivers/iio/common/st_sensors/st_sensors_trigger.c b/drivers/iio/common/st_sensors/st_sensors_trigger.c index e817537cdfb5..0507283bd4c1 100644 --- a/drivers/iio/common/st_sensors/st_sensors_trigger.c +++ b/drivers/iio/common/st_sensors/st_sensors_trigger.c @@ -44,8 +44,7 @@ static int st_sensors_new_samples_available(struct iio_dev *indio_dev, sdata->sensor_settings->drdy_irq.stat_drdy.addr, &status); if (ret < 0) { - dev_err(sdata->dev, - "error checking samples available\n"); + dev_err(sdata->dev, "error checking samples available\n"); return ret; } @@ -148,9 +147,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, case IRQF_TRIGGER_LOW: if (!sdata->sensor_settings->drdy_irq.addr_ihl) { dev_err(&indio_dev->dev, - "falling/low specified for IRQ " - "but hardware supports only rising/high: " - "will request rising/high\n"); + "falling/low specified for IRQ but hardware supports only rising/high: will request rising/high\n"); if (irq_trig == IRQF_TRIGGER_FALLING) irq_trig = IRQF_TRIGGER_RISING; if (irq_trig == IRQF_TRIGGER_LOW) @@ -163,8 +160,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, if (err < 0) goto iio_trigger_free; dev_info(&indio_dev->dev, - "interrupts on the falling edge or " - "active low level\n"); + "interrupts on the falling edge or active low level\n"); } break; case IRQF_TRIGGER_RISING: @@ -178,8 +174,7 @@ int st_sensors_allocate_trigger(struct iio_dev *indio_dev, default: /* This is the most preferred mode, if possible */ dev_err(&indio_dev->dev, - "unsupported IRQ trigger specified (%lx), enforce " - "rising edge\n", irq_trig); + "unsupported IRQ trigger specified (%lx), enforce rising edge\n", irq_trig); irq_trig = IRQF_TRIGGER_RISING; } diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 7eaf77707b0b..6daeddf37f60 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -61,7 +61,7 @@ config BMG160 help Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor driver connected via I2C or SPI. This driver also supports BMI055 - gyroscope. + and BMI088 gyroscope. This driver can also be built as a module. If so, the module will be called bmg160_i2c or bmg160_spi. diff --git a/drivers/iio/gyro/bmg160_i2c.c b/drivers/iio/gyro/bmg160_i2c.c index 4fc9c6a3321f..b3fa46bd02cb 100644 --- a/drivers/iio/gyro/bmg160_i2c.c +++ b/drivers/iio/gyro/bmg160_i2c.c @@ -21,8 +21,8 @@ static int bmg160_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &bmg160_regmap_i2c_conf); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", + regmap); return PTR_ERR(regmap); } @@ -42,6 +42,7 @@ static int bmg160_i2c_remove(struct i2c_client *client) static const struct acpi_device_id bmg160_acpi_match[] = { {"BMG0160", 0}, {"BMI055B", 0}, + {"BMI088B", 0}, {}, }; @@ -50,6 +51,7 @@ MODULE_DEVICE_TABLE(acpi, bmg160_acpi_match); static const struct i2c_device_id bmg160_i2c_id[] = { {"bmg160", 0}, {"bmi055_gyro", 0}, + {"bmi088_gyro", 0}, {} }; diff --git a/drivers/iio/gyro/bmg160_spi.c b/drivers/iio/gyro/bmg160_spi.c index 182a59c42507..745962e1e423 100644 --- a/drivers/iio/gyro/bmg160_spi.c +++ b/drivers/iio/gyro/bmg160_spi.c @@ -19,8 +19,8 @@ static int bmg160_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &bmg160_regmap_spi_conf); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap: %pe\n", + regmap); return PTR_ERR(regmap); } @@ -37,6 +37,7 @@ static int bmg160_spi_remove(struct spi_device *spi) static const struct spi_device_id bmg160_spi_id[] = { {"bmg160", 0}, {"bmi055_gyro", 0}, + {"bmi088_gyro", 0}, {} }; diff --git a/drivers/iio/gyro/mpu3050-i2c.c b/drivers/iio/gyro/mpu3050-i2c.c index afa8018b9238..ef5bcbc4b45b 100644 --- a/drivers/iio/gyro/mpu3050-i2c.c +++ b/drivers/iio/gyro/mpu3050-i2c.c @@ -51,8 +51,8 @@ static int mpu3050_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &mpu3050_i2c_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/iio/gyro/st_gyro_buffer.c b/drivers/iio/gyro/st_gyro_buffer.c index 7465ad62391c..9c92ff7a82be 100644 --- a/drivers/iio/gyro/st_gyro_buffer.c +++ b/drivers/iio/gyro/st_gyro_buffer.c @@ -37,8 +37,7 @@ static int st_gyro_buffer_postenable(struct iio_dev *indio_dev) if (err < 0) return err; - err = st_sensors_set_axis_enable(indio_dev, - (u8)indio_dev->active_scan_mask[0]); + err = st_sensors_set_axis_enable(indio_dev, indio_dev->active_scan_mask[0]); if (err < 0) goto st_gyro_buffer_predisable; diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index 26c50b24bc08..c8aa051995d3 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -460,6 +460,7 @@ EXPORT_SYMBOL(st_gyro_get_settings); int st_gyro_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *gdata = iio_priv(indio_dev); + struct st_sensors_platform_data *pdata; int err; indio_dev->modes = INDIO_DIRECT_MODE; @@ -477,12 +478,12 @@ int st_gyro_common_probe(struct iio_dev *indio_dev) indio_dev->channels = gdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; - gdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &gdata->sensor_settings->fs.fs_avl[0]; + gdata->current_fullscale = &gdata->sensor_settings->fs.fs_avl[0]; gdata->odr = gdata->sensor_settings->odr.odr_avl[0].hz; - err = st_sensors_init_sensor(indio_dev, - (struct st_sensors_platform_data *)&gyro_pdata); + pdata = (struct st_sensors_platform_data *)&gyro_pdata; + + err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) goto st_gyro_power_off; diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 84010501762d..546fc37ad75d 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -16,7 +16,7 @@ #include <linux/irq.h> #include <linux/i2c.h> #include <linux/mutex.h> -#include <linux/of.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> @@ -267,11 +267,10 @@ static int max30100_get_current_idx(unsigned int val, int *reg) static int max30100_led_init(struct max30100_data *data) { struct device *dev = &data->client->dev; - struct device_node *np = dev->of_node; unsigned int val[2]; int reg, ret; - ret = of_property_read_u32_array(np, "maxim,led-current-microamp", + ret = device_property_read_u32_array(dev, "maxim,led-current-microamp", (unsigned int *) &val, 2); if (ret) { /* Default to 24 mA RED LED, 50 mA IR LED */ @@ -502,7 +501,7 @@ MODULE_DEVICE_TABLE(of, max30100_dt_ids); static struct i2c_driver max30100_driver = { .driver = { .name = MAX30100_DRV_NAME, - .of_match_table = of_match_ptr(max30100_dt_ids), + .of_match_table = max30100_dt_ids, }, .probe = max30100_probe, .remove = max30100_remove, diff --git a/drivers/iio/humidity/hts221_buffer.c b/drivers/iio/humidity/hts221_buffer.c index 81d50a861c22..9fb3f33614d4 100644 --- a/drivers/iio/humidity/hts221_buffer.c +++ b/drivers/iio/humidity/hts221_buffer.c @@ -74,10 +74,9 @@ static irqreturn_t hts221_trigger_handler_thread(int irq, void *private) int hts221_allocate_trigger(struct hts221_hw *hw) { + struct st_sensors_platform_data *pdata = dev_get_platdata(hw->dev); struct iio_dev *iio_dev = iio_priv_to_dev(hw); bool irq_active_low = false, open_drain = false; - struct device_node *np = hw->dev->of_node; - struct st_sensors_platform_data *pdata; unsigned long irq_type; int err; @@ -106,8 +105,7 @@ int hts221_allocate_trigger(struct hts221_hw *hw) if (err < 0) return err; - pdata = (struct st_sensors_platform_data *)hw->dev->platform_data; - if ((np && of_property_read_bool(np, "drive-open-drain")) || + if (device_property_read_bool(hw->dev, "drive-open-drain") || (pdata && pdata->open_drain)) { irq_type |= IRQF_SHARED; open_drain = true; diff --git a/drivers/iio/humidity/hts221_i2c.c b/drivers/iio/humidity/hts221_i2c.c index 4272b7030c44..cab39c4756f8 100644 --- a/drivers/iio/humidity/hts221_i2c.c +++ b/drivers/iio/humidity/hts221_i2c.c @@ -32,8 +32,8 @@ static int hts221_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &hts221_i2c_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap %ld\n", + PTR_ERR(regmap)); return PTR_ERR(regmap); } @@ -63,7 +63,7 @@ static struct i2c_driver hts221_driver = { .driver = { .name = "hts221_i2c", .pm = &hts221_pm_ops, - .of_match_table = of_match_ptr(hts221_i2c_of_match), + .of_match_table = hts221_i2c_of_match, .acpi_match_table = ACPI_PTR(hts221_acpi_match), }, .probe = hts221_i2c_probe, diff --git a/drivers/iio/humidity/hts221_spi.c b/drivers/iio/humidity/hts221_spi.c index 055dba8897d2..729e86e433b1 100644 --- a/drivers/iio/humidity/hts221_spi.c +++ b/drivers/iio/humidity/hts221_spi.c @@ -31,8 +31,8 @@ static int hts221_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &hts221_spi_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap %ld\n", + PTR_ERR(regmap)); return PTR_ERR(regmap); } @@ -56,7 +56,7 @@ static struct spi_driver hts221_driver = { .driver = { .name = "hts221_spi", .pm = &hts221_pm_ops, - .of_match_table = of_match_ptr(hts221_spi_of_match), + .of_match_table = hts221_spi_of_match, }, .probe = hts221_spi_probe, .id_table = hts221_spi_id_table, diff --git a/drivers/iio/imu/adis.c b/drivers/iio/imu/adis.c index a8afd01de4f3..2e7d0d337f8f 100644 --- a/drivers/iio/imu/adis.c +++ b/drivers/iio/imu/adis.c @@ -419,7 +419,7 @@ int __adis_initial_startup(struct adis *adis) if (prod_id != adis->data->prod_id) dev_warn(&adis->spi->dev, - "Device ID(%u) and product ID(%u) do not match.", + "Device ID(%u) and product ID(%u) do not match.\n", adis->data->prod_id, prod_id); return 0; diff --git a/drivers/iio/imu/adis16400.c b/drivers/iio/imu/adis16400.c index 05e70c1c4835..4445c242709c 100644 --- a/drivers/iio/imu/adis16400.c +++ b/drivers/iio/imu/adis16400.c @@ -258,7 +258,7 @@ static int adis16400_show_product_id(void *arg, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(adis16400_product_id_fops, +DEFINE_DEBUGFS_ATTRIBUTE(adis16400_product_id_fops, adis16400_show_product_id, NULL, "%lld\n"); static int adis16400_show_flash_count(void *arg, u64 *val) @@ -275,7 +275,7 @@ static int adis16400_show_flash_count(void *arg, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(adis16400_flash_count_fops, +DEFINE_DEBUGFS_ATTRIBUTE(adis16400_flash_count_fops, adis16400_show_flash_count, NULL, "%lld\n"); static int adis16400_debugfs_init(struct iio_dev *indio_dev) @@ -283,15 +283,16 @@ static int adis16400_debugfs_init(struct iio_dev *indio_dev) struct adis16400_state *st = iio_priv(indio_dev); if (st->variant->flags & ADIS16400_HAS_SERIAL_NUMBER) - debugfs_create_file("serial_number", 0400, - indio_dev->debugfs_dentry, st, - &adis16400_serial_number_fops); + debugfs_create_file_unsafe("serial_number", 0400, + indio_dev->debugfs_dentry, st, + &adis16400_serial_number_fops); if (st->variant->flags & ADIS16400_HAS_PROD_ID) - debugfs_create_file("product_id", 0400, + debugfs_create_file_unsafe("product_id", 0400, + indio_dev->debugfs_dentry, st, + &adis16400_product_id_fops); + debugfs_create_file_unsafe("flash_count", 0400, indio_dev->debugfs_dentry, st, - &adis16400_product_id_fops); - debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, - st, &adis16400_flash_count_fops); + &adis16400_flash_count_fops); return 0; } diff --git a/drivers/iio/imu/adis16460.c b/drivers/iio/imu/adis16460.c index 0027683d0256..0957f5cfe9c0 100644 --- a/drivers/iio/imu/adis16460.c +++ b/drivers/iio/imu/adis16460.c @@ -87,8 +87,8 @@ static int adis16460_show_serial_number(void *arg, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(adis16460_serial_number_fops, - adis16460_show_serial_number, NULL, "0x%.4llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(adis16460_serial_number_fops, + adis16460_show_serial_number, NULL, "0x%.4llx\n"); static int adis16460_show_product_id(void *arg, u64 *val) { @@ -105,8 +105,8 @@ static int adis16460_show_product_id(void *arg, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(adis16460_product_id_fops, - adis16460_show_product_id, NULL, "%llu\n"); +DEFINE_DEBUGFS_ATTRIBUTE(adis16460_product_id_fops, + adis16460_show_product_id, NULL, "%llu\n"); static int adis16460_show_flash_count(void *arg, u64 *val) { @@ -123,19 +123,22 @@ static int adis16460_show_flash_count(void *arg, u64 *val) return 0; } -DEFINE_SIMPLE_ATTRIBUTE(adis16460_flash_count_fops, - adis16460_show_flash_count, NULL, "%lld\n"); +DEFINE_DEBUGFS_ATTRIBUTE(adis16460_flash_count_fops, + adis16460_show_flash_count, NULL, "%lld\n"); static int adis16460_debugfs_init(struct iio_dev *indio_dev) { struct adis16460 *adis16460 = iio_priv(indio_dev); - debugfs_create_file("serial_number", 0400, indio_dev->debugfs_dentry, - adis16460, &adis16460_serial_number_fops); - debugfs_create_file("product_id", 0400, indio_dev->debugfs_dentry, - adis16460, &adis16460_product_id_fops); - debugfs_create_file("flash_count", 0400, indio_dev->debugfs_dentry, - adis16460, &adis16460_flash_count_fops); + debugfs_create_file_unsafe("serial_number", 0400, + indio_dev->debugfs_dentry, adis16460, + &adis16460_serial_number_fops); + debugfs_create_file_unsafe("product_id", 0400, + indio_dev->debugfs_dentry, adis16460, + &adis16460_product_id_fops); + debugfs_create_file_unsafe("flash_count", 0400, + indio_dev->debugfs_dentry, adis16460, + &adis16460_flash_count_fops); return 0; } diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index e36f5e82d400..26398614eddf 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -24,8 +24,8 @@ static int bmi160_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &bmi160_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index c19e3df35559..61389b41c6d9 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -20,8 +20,8 @@ static int bmi160_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &bmi160_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap: %pe\n", + regmap); return PTR_ERR(regmap); } return bmi160_core_probe(&spi->dev, regmap, id->name, true); diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c index 2f8560ba4572..c27d06035c8b 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_acpi.c @@ -135,6 +135,7 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client) st->mux_client = NULL; if (ACPI_HANDLE(&client->dev)) { struct i2c_board_info info; + struct i2c_client *mux_client; struct acpi_device *adev; int ret = -1; @@ -172,9 +173,10 @@ int inv_mpu_acpi_create_mux_client(struct i2c_client *client) } else return 0; /* no secondary addr, which is OK */ } - st->mux_client = i2c_new_device(st->muxc->adapter[0], &info); - if (!st->mux_client) - return -ENODEV; + mux_client = i2c_new_client_device(st->muxc->adapter[0], &info); + if (IS_ERR(mux_client)) + return PTR_ERR(mux_client); + st->mux_client = mux_client; } return 0; diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c index 7cb9ff3d3e94..d3819b516ec6 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c @@ -526,7 +526,7 @@ static int inv_mpu6050_sensor_set(struct inv_mpu6050_state *st, int reg, __be16 d = cpu_to_be16(val); ind = (axis - IIO_MOD_X) * 2; - result = regmap_bulk_write(st->map, reg + ind, (u8 *)&d, 2); + result = regmap_bulk_write(st->map, reg + ind, &d, sizeof(d)); if (result) return -EINVAL; @@ -540,7 +540,7 @@ static int inv_mpu6050_sensor_show(struct inv_mpu6050_state *st, int reg, __be16 d; ind = (axis - IIO_MOD_X) * 2; - result = regmap_bulk_read(st->map, reg + ind, (u8 *)&d, 2); + result = regmap_bulk_read(st->map, reg + ind, &d, sizeof(d)); if (result) return -EINVAL; *val = (short)be16_to_cpup(&d); @@ -1248,12 +1248,31 @@ static const struct attribute_group inv_attribute_group = { .attrs = inv_attributes }; +static int inv_mpu6050_reg_access(struct iio_dev *indio_dev, + unsigned int reg, + unsigned int writeval, + unsigned int *readval) +{ + struct inv_mpu6050_state *st = iio_priv(indio_dev); + int ret; + + mutex_lock(&st->lock); + if (readval) + ret = regmap_read(st->map, reg, readval); + else + ret = regmap_write(st->map, reg, writeval); + mutex_unlock(&st->lock); + + return ret; +} + static const struct iio_info mpu_info = { .read_raw = &inv_mpu6050_read_raw, .write_raw = &inv_mpu6050_write_raw, .write_raw_get_fmt = &inv_write_raw_get_fmt, .attrs = &inv_attribute_group, .validate_trigger = inv_mpu6050_validate_trigger, + .debugfs_reg_access = &inv_mpu6050_reg_access, }; /** diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c index 6993d3b87bb0..28cfae1e61cf 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_i2c.c @@ -122,8 +122,8 @@ static int inv_mpu_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c index 673b198e6368..6f968ce687e1 100644 --- a/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c +++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_spi.c @@ -53,8 +53,8 @@ static int inv_mpu_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &inv_mpu_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap: %pe\n", + regmap); return PTR_ERR(regmap); } diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index f2113a63721a..38b613072da2 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -111,7 +111,7 @@ struct st_lsm6dsx_odr { u8 val; }; -#define ST_LSM6DSX_ODR_LIST_SIZE 6 +#define ST_LSM6DSX_ODR_LIST_SIZE 8 struct st_lsm6dsx_odr_table_entry { struct st_lsm6dsx_reg reg; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index 95ddd19d1aa7..947ca3a7dcaf 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -88,6 +88,69 @@ static const struct st_lsm6dsx_ext_dev_settings st_lsm6dsx_ext_dev_table[] = { .len = 6, }, }, + /* LIS3MDL */ + { + .i2c_addr = { 0x1e }, + .wai = { + .addr = 0x0f, + .val = 0x3d, + }, + .id = ST_LSM6DSX_ID_MAGN, + .odr_table = { + .reg = { + .addr = 0x20, + .mask = GENMASK(4, 2), + }, + .odr_avl[0] = { 1000, 0x0 }, + .odr_avl[1] = { 2000, 0x1 }, + .odr_avl[2] = { 3000, 0x2 }, + .odr_avl[3] = { 5000, 0x3 }, + .odr_avl[4] = { 10000, 0x4 }, + .odr_avl[5] = { 20000, 0x5 }, + .odr_avl[6] = { 40000, 0x6 }, + .odr_avl[7] = { 80000, 0x7 }, + .odr_len = 8, + }, + .fs_table = { + .reg = { + .addr = 0x21, + .mask = GENMASK(6, 5), + }, + .fs_avl[0] = { + .gain = 146, + .val = 0x00, + }, /* 4000 uG/LSB */ + .fs_avl[1] = { + .gain = 292, + .val = 0x01, + }, /* 8000 uG/LSB */ + .fs_avl[2] = { + .gain = 438, + .val = 0x02, + }, /* 12000 uG/LSB */ + .fs_avl[3] = { + .gain = 584, + .val = 0x03, + }, /* 16000 uG/LSB */ + .fs_len = 4, + }, + .pwr_table = { + .reg = { + .addr = 0x22, + .mask = GENMASK(1, 0), + }, + .off_val = 0x2, + .on_val = 0x0, + }, + .bdu = { + .addr = 0x24, + .mask = BIT(6), + }, + .out = { + .addr = 0x28, + .len = 6, + }, + }, }; static void st_lsm6dsx_shub_wait_complete(struct st_lsm6dsx_hw *hw) @@ -518,6 +581,36 @@ st_lsm6dsx_shub_read_raw(struct iio_dev *iio_dev, } static int +st_lsm6dsx_shub_set_full_scale(struct st_lsm6dsx_sensor *sensor, + u32 gain) +{ + const struct st_lsm6dsx_fs_table_entry *fs_table; + int i, err; + + fs_table = &sensor->ext_info.settings->fs_table; + if (!fs_table->reg.addr) + return -ENOTSUPP; + + for (i = 0; i < fs_table->fs_len; i++) { + if (fs_table->fs_avl[i].gain == gain) + break; + } + + if (i == fs_table->fs_len) + return -EINVAL; + + err = st_lsm6dsx_shub_write_with_mask(sensor, fs_table->reg.addr, + fs_table->reg.mask, + fs_table->fs_avl[i].val); + if (err < 0) + return err; + + sensor->gain = gain; + + return 0; +} + +static int st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) @@ -539,6 +632,9 @@ st_lsm6dsx_shub_write_raw(struct iio_dev *iio_dev, sensor->odr = val; break; } + case IIO_CHAN_INFO_SCALE: + err = st_lsm6dsx_shub_set_full_scale(sensor, val2); + break; default: err = -EINVAL; break; diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 4ada5592aa2b..221157136af6 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -316,8 +316,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev, const unsigned long *mask; unsigned long *trialmask; - trialmask = kcalloc(BITS_TO_LONGS(indio_dev->masklength), - sizeof(*trialmask), GFP_KERNEL); + trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL); if (trialmask == NULL) return -ENOMEM; if (!indio_dev->masklength) { @@ -687,6 +686,13 @@ static int iio_verify_update(struct iio_dev *indio_dev, bool scan_timestamp; unsigned int modes; + if (insert_buffer && + bitmap_empty(insert_buffer->scan_mask, indio_dev->masklength)) { + dev_dbg(&indio_dev->dev, + "At least one scan element must be enabled first\n"); + return -EINVAL; + } + memset(config, 0, sizeof(*config)); config->watermark = ~0; @@ -1277,11 +1283,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group; - if (buffer->scan_el_attrs != NULL) { - attr = buffer->scan_el_attrs->attrs; - while (*attr++ != NULL) - attrcount_orig++; - } attrcount = attrcount_orig; INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list); channels = indio_dev->channels; @@ -1319,9 +1320,6 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev) ret = -ENOMEM; goto error_free_scan_mask; } - if (buffer->scan_el_attrs) - memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs, - sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig); attrn = attrcount_orig; list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2352c426bfb5..6add449b38bc 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -572,46 +572,46 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, switch (type) { case IIO_VAL_INT: - return snprintf(buf, len, "%d", vals[0]); + return scnprintf(buf, len, "%d", vals[0]); case IIO_VAL_INT_PLUS_MICRO_DB: scale_db = true; /* fall through */ case IIO_VAL_INT_PLUS_MICRO: if (vals[1] < 0) - return snprintf(buf, len, "-%d.%06u%s", abs(vals[0]), + return scnprintf(buf, len, "-%d.%06u%s", abs(vals[0]), -vals[1], scale_db ? " dB" : ""); else - return snprintf(buf, len, "%d.%06u%s", vals[0], vals[1], + return scnprintf(buf, len, "%d.%06u%s", vals[0], vals[1], scale_db ? " dB" : ""); case IIO_VAL_INT_PLUS_NANO: if (vals[1] < 0) - return snprintf(buf, len, "-%d.%09u", abs(vals[0]), + return scnprintf(buf, len, "-%d.%09u", abs(vals[0]), -vals[1]); else - return snprintf(buf, len, "%d.%09u", vals[0], vals[1]); + return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]); case IIO_VAL_FRACTIONAL: tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]); tmp1 = vals[1]; tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1); - return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); + return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); case IIO_VAL_FRACTIONAL_LOG2: tmp = shift_right((s64)vals[0] * 1000000000LL, vals[1]); tmp0 = (int)div_s64_rem(tmp, 1000000000LL, &tmp1); - return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); + return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); case IIO_VAL_INT_MULTIPLE: { int i; int l = 0; for (i = 0; i < size; ++i) { - l += snprintf(&buf[l], len - l, "%d ", vals[i]); + l += scnprintf(&buf[l], len - l, "%d ", vals[i]); if (l >= len) break; } return l; } case IIO_VAL_CHAR: - return snprintf(buf, len, "%c", (char)vals[0]); + return scnprintf(buf, len, "%c", (char)vals[0]); default: return 0; } @@ -682,10 +682,10 @@ static ssize_t iio_format_avail_list(char *buf, const int *vals, if (len >= PAGE_SIZE) return -EFBIG; if (i < length - 1) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, " "); else - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); if (len >= PAGE_SIZE) return -EFBIG; @@ -698,10 +698,10 @@ static ssize_t iio_format_avail_list(char *buf, const int *vals, if (len >= PAGE_SIZE) return -EFBIG; if (i < length / 2 - 1) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, " "); else - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "\n"); if (len >= PAGE_SIZE) return -EFBIG; @@ -725,10 +725,10 @@ static ssize_t iio_format_avail_range(char *buf, const int *vals, int type) if (len >= PAGE_SIZE) return -EFBIG; if (i < 2) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, " "); else - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "]\n"); if (len >= PAGE_SIZE) return -EFBIG; @@ -741,10 +741,10 @@ static ssize_t iio_format_avail_range(char *buf, const int *vals, int type) if (len >= PAGE_SIZE) return -EFBIG; if (i < 2) - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, " "); else - len += snprintf(buf + len, PAGE_SIZE - len, + len += scnprintf(buf + len, PAGE_SIZE - len, "]\n"); if (len >= PAGE_SIZE) return -EFBIG; @@ -1552,17 +1552,6 @@ static void devm_iio_device_release(struct device *dev, void *res) iio_device_free(*(struct iio_dev **)res); } -int devm_iio_device_match(struct device *dev, void *res, void *data) -{ - struct iio_dev **r = res; - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - return *r == data; -} -EXPORT_SYMBOL_GPL(devm_iio_device_match); - /** * devm_iio_device_alloc - Resource-managed iio_device_alloc() * @dev: Device to allocate iio_dev for @@ -1571,9 +1560,6 @@ EXPORT_SYMBOL_GPL(devm_iio_device_match); * Managed iio_device_alloc. iio_dev allocated with this function is * automatically freed on driver detach. * - * If an iio_dev allocated with this function needs to be freed separately, - * devm_iio_device_free() must be used. - * * RETURNS: * Pointer to allocated iio_dev on success, NULL on failure. */ @@ -1599,23 +1585,6 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv) EXPORT_SYMBOL_GPL(devm_iio_device_alloc); /** - * devm_iio_device_free - Resource-managed iio_device_free() - * @dev: Device this iio_dev belongs to - * @iio_dev: the iio_dev associated with the device - * - * Free iio_dev allocated with devm_iio_device_alloc(). - */ -void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_device_release, - devm_iio_device_match, iio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_device_free); - -/** * iio_chrdev_open() - chrdev file open for buffer access and ioctls * @inode: Inode structure for identifying the device in the file system * @filp: File structure for iio device used to keep and later access @@ -1717,6 +1686,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) { int ret; + if (!indio_dev->info) + return -EINVAL; + indio_dev->driver_module = this_mod; /* If the calling driver did not initialize of_node, do it here */ if (!indio_dev->dev.of_node && indio_dev->dev.parent) @@ -1729,9 +1701,6 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (ret < 0) return ret; - if (!indio_dev->info) - return -EINVAL; - /* configure elements for the chrdev */ indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); @@ -1837,23 +1806,6 @@ int __devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev, EXPORT_SYMBOL_GPL(__devm_iio_device_register); /** - * devm_iio_device_unregister - Resource-managed iio_device_unregister() - * @dev: Device this iio_dev belongs to - * @indio_dev: the iio_dev associated with the device - * - * Unregister iio_dev registered with devm_iio_device_register(). - */ -void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev) -{ - int rc; - - rc = devres_release(dev, devm_iio_device_unreg, - devm_iio_device_match, indio_dev); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_device_unregister); - -/** * iio_device_claim_direct_mode - Keep device in direct mode * @indio_dev: the iio_dev associated with the device * diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index 3908a9a90035..53d1931f6be8 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -585,18 +585,6 @@ static void devm_iio_trigger_release(struct device *dev, void *res) iio_trigger_free(*(struct iio_trigger **)res); } -static int devm_iio_trigger_match(struct device *dev, void *res, void *data) -{ - struct iio_trigger **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - - return *r == data; -} - /** * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() * @dev: Device to allocate iio_trigger for @@ -608,9 +596,6 @@ static int devm_iio_trigger_match(struct device *dev, void *res, void *data) * Managed iio_trigger_alloc. iio_trigger allocated with this function is * automatically freed on driver detach. * - * If an iio_trigger allocated with this function needs to be freed separately, - * devm_iio_trigger_free() must be used. - * * RETURNS: * Pointer to allocated iio_trigger on success, NULL on failure. */ @@ -640,23 +625,6 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc); -/** - * devm_iio_trigger_free - Resource-managed iio_trigger_free() - * @dev: Device this iio_dev belongs to - * @iio_trig: the iio_trigger associated with the device - * - * Free iio_trigger allocated with devm_iio_trigger_alloc(). - */ -void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig) -{ - int rc; - - rc = devres_release(dev, devm_iio_trigger_release, - devm_iio_trigger_match, iio_trig); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_trigger_free); - static void devm_iio_trigger_unreg(struct device *dev, void *res) { iio_trigger_unregister(*(struct iio_trigger **)res); @@ -673,9 +641,6 @@ static void devm_iio_trigger_unreg(struct device *dev, void *res) * calls iio_trigger_register() internally. Refer to that function for more * information. * - * If an iio_trigger registered with this function needs to be unregistered - * separately, devm_iio_trigger_unregister() must be used. - * * RETURNS: * 0 on success, negative error number on failure. */ @@ -701,24 +666,6 @@ int __devm_iio_trigger_register(struct device *dev, } EXPORT_SYMBOL_GPL(__devm_iio_trigger_register); -/** - * devm_iio_trigger_unregister - Resource-managed iio_trigger_unregister() - * @dev: device this iio_trigger belongs to - * @trig_info: the trigger associated with the device - * - * Unregister trigger registered with devm_iio_trigger_register(). - */ -void devm_iio_trigger_unregister(struct device *dev, - struct iio_trigger *trig_info) -{ - int rc; - - rc = devres_release(dev, devm_iio_trigger_unreg, devm_iio_trigger_match, - trig_info); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_iio_trigger_unregister); - bool iio_trigger_using_own(struct iio_dev *indio_dev) { return indio_dev->trig->attached_own_device; diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index 5a8351c9a426..ede99e0d5371 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -360,18 +360,6 @@ static void devm_iio_channel_free(struct device *dev, void *res) iio_channel_release(channel); } -static int devm_iio_channel_match(struct device *dev, void *res, void *data) -{ - struct iio_channel **r = res; - - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - - return *r == data; -} - struct iio_channel *devm_iio_channel_get(struct device *dev, const char *channel_name) { @@ -394,13 +382,6 @@ struct iio_channel *devm_iio_channel_get(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_channel_get); -void devm_iio_channel_release(struct device *dev, struct iio_channel *channel) -{ - WARN_ON(devres_release(dev, devm_iio_channel_free, - devm_iio_channel_match, channel)); -} -EXPORT_SYMBOL_GPL(devm_iio_channel_release); - struct iio_channel *iio_channel_get_all(struct device *dev) { const char *name; @@ -514,14 +495,6 @@ struct iio_channel *devm_iio_channel_get_all(struct device *dev) } EXPORT_SYMBOL_GPL(devm_iio_channel_get_all); -void devm_iio_channel_release_all(struct device *dev, - struct iio_channel *channels) -{ - WARN_ON(devres_release(dev, devm_iio_channel_free_all, - devm_iio_channel_match, channels)); -} -EXPORT_SYMBOL_GPL(devm_iio_channel_release_all); - static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, enum iio_chan_info_enum info) { diff --git a/drivers/iio/light/isl29125.c b/drivers/iio/light/isl29125.c index e37894f0ae0b..95611f5eff01 100644 --- a/drivers/iio/light/isl29125.c +++ b/drivers/iio/light/isl29125.c @@ -213,13 +213,24 @@ static const struct iio_info isl29125_info = { .attrs = &isl29125_attribute_group, }; -static int isl29125_buffer_preenable(struct iio_dev *indio_dev) +static int isl29125_buffer_postenable(struct iio_dev *indio_dev) { struct isl29125_data *data = iio_priv(indio_dev); + int err; + + err = iio_triggered_buffer_postenable(indio_dev); + if (err) + return err; data->conf1 |= ISL29125_MODE_RGB; - return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + err = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1); + if (err) { + iio_triggered_buffer_predisable(indio_dev); + return err; + } + + return 0; } static int isl29125_buffer_predisable(struct iio_dev *indio_dev) @@ -227,19 +238,18 @@ static int isl29125_buffer_predisable(struct iio_dev *indio_dev) struct isl29125_data *data = iio_priv(indio_dev); int ret; - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret < 0) - return ret; - data->conf1 &= ~ISL29125_MODE_MASK; data->conf1 |= ISL29125_MODE_PD; - return i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, + ret = i2c_smbus_write_byte_data(data->client, ISL29125_CONF1, data->conf1); + + iio_triggered_buffer_predisable(indio_dev); + + return ret; } static const struct iio_buffer_setup_ops isl29125_buffer_setup_ops = { - .preenable = isl29125_buffer_preenable, - .postenable = &iio_triggered_buffer_postenable, + .postenable = isl29125_buffer_postenable, .predisable = isl29125_buffer_predisable, }; diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c index 71f99d2a22c1..0626927251bb 100644 --- a/drivers/iio/light/ltr501.c +++ b/drivers/iio/light/ltr501.c @@ -1263,7 +1263,7 @@ static irqreturn_t ltr501_trigger_handler(int irq, void *p) if (mask & LTR501_STATUS_ALS_RDY) { ret = regmap_bulk_read(data->regmap, LTR501_ALS_DATA1, - (u8 *)als_buf, sizeof(als_buf)); + als_buf, sizeof(als_buf)); if (ret < 0) return ret; if (test_bit(0, indio_dev->active_scan_mask)) diff --git a/drivers/iio/light/st_uvis25_i2c.c b/drivers/iio/light/st_uvis25_i2c.c index 4889bbeb0c73..400724069d19 100644 --- a/drivers/iio/light/st_uvis25_i2c.c +++ b/drivers/iio/light/st_uvis25_i2c.c @@ -31,8 +31,8 @@ static int st_uvis25_i2c_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &st_uvis25_i2c_regmap_config); if (IS_ERR(regmap)) { - dev_err(&client->dev, "Failed to register i2c regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&client->dev, "Failed to register i2c regmap %ld\n", + PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/light/st_uvis25_spi.c b/drivers/iio/light/st_uvis25_spi.c index a9ceae4f58b3..cd3761a3ee3f 100644 --- a/drivers/iio/light/st_uvis25_spi.c +++ b/drivers/iio/light/st_uvis25_spi.c @@ -31,8 +31,8 @@ static int st_uvis25_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &st_uvis25_spi_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap %ld\n", + PTR_ERR(regmap)); return PTR_ERR(regmap); } diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index d8c40a83097d..27a5c28aac7f 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -69,7 +69,7 @@ #define TSL2563_TIMING_GAIN16 0x10 #define TSL2563_TIMING_GAIN1 0x00 -#define TSL2563_INT_DISBLED 0x00 +#define TSL2563_INT_DISABLED 0x00 #define TSL2563_INT_LEVEL 0x10 #define TSL2563_INT_PERSIST(n) ((n) & 0x0F) diff --git a/drivers/iio/light/tsl2772.c b/drivers/iio/light/tsl2772.c index be37fcbd4654..9fbde9b71b63 100644 --- a/drivers/iio/light/tsl2772.c +++ b/drivers/iio/light/tsl2772.c @@ -932,7 +932,7 @@ static ssize_t in_illuminance0_target_input_show(struct device *dev, { struct tsl2772_chip *chip = iio_priv(dev_to_iio_dev(dev)); - return snprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); + return scnprintf(buf, PAGE_SIZE, "%d\n", chip->settings.als_cal_target); } static ssize_t in_illuminance0_target_input_store(struct device *dev, @@ -986,7 +986,7 @@ static ssize_t in_illuminance0_lux_table_show(struct device *dev, int offset = 0; while (i < TSL2772_MAX_LUX_TABLE_SIZE) { - offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,", + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "%u,%u,", chip->tsl2772_device_lux[i].ch0, chip->tsl2772_device_lux[i].ch1); if (chip->tsl2772_device_lux[i].ch0 == 0) { @@ -1000,7 +1000,7 @@ static ssize_t in_illuminance0_lux_table_show(struct device *dev, i++; } - offset += snprintf(buf + offset, PAGE_SIZE, "\n"); + offset += scnprintf(buf + offset, PAGE_SIZE - offset, "\n"); return offset; } diff --git a/drivers/iio/light/vcnl4000.c b/drivers/iio/light/vcnl4000.c index ec803c1e81df..985cc39ede8e 100644 --- a/drivers/iio/light/vcnl4000.c +++ b/drivers/iio/light/vcnl4000.c @@ -83,6 +83,7 @@ struct vcnl4000_data { struct mutex vcnl4000_lock; struct vcnl4200_channel vcnl4200_al; struct vcnl4200_channel vcnl4200_ps; + uint32_t near_level; }; struct vcnl4000_chip_spec { @@ -343,6 +344,25 @@ static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = { }, }; +static ssize_t vcnl4000_read_near_level(struct iio_dev *indio_dev, + uintptr_t priv, + const struct iio_chan_spec *chan, + char *buf) +{ + struct vcnl4000_data *data = iio_priv(indio_dev); + + return sprintf(buf, "%u\n", data->near_level); +} + +static const struct iio_chan_spec_ext_info vcnl4000_ext_info[] = { + { + .name = "nearlevel", + .shared = IIO_SEPARATE, + .read = vcnl4000_read_near_level, + }, + { /* sentinel */ } +}; + static const struct iio_chan_spec vcnl4000_channels[] = { { .type = IIO_LIGHT, @@ -351,6 +371,7 @@ static const struct iio_chan_spec vcnl4000_channels[] = { }, { .type = IIO_PROXIMITY, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .ext_info = vcnl4000_ext_info, } }; @@ -440,6 +461,10 @@ static int vcnl4000_probe(struct i2c_client *client, dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n", data->chip_spec->prod, data->rev); + if (device_property_read_u32(&client->dev, "proximity-near-level", + &data->near_level)) + data->near_level = 0; + indio_dev->dev.parent = &client->dev; indio_dev->info = &vcnl4000_info; indio_dev->channels = vcnl4000_channels; diff --git a/drivers/iio/magnetometer/ak8974.c b/drivers/iio/magnetometer/ak8974.c index d32996702110..372c80c25dd4 100644 --- a/drivers/iio/magnetometer/ak8974.c +++ b/drivers/iio/magnetometer/ak8974.c @@ -746,7 +746,12 @@ static int ak8974_probe(struct i2c_client *i2c, ARRAY_SIZE(ak8974->regs), ak8974->regs); if (ret < 0) { - dev_err(&i2c->dev, "cannot get regulators\n"); + if (ret != -EPROBE_DEFER) + dev_err(&i2c->dev, "cannot get regulators: %d\n", ret); + else + dev_dbg(&i2c->dev, + "regulators unavailable, deferring probe\n"); + return ret; } diff --git a/drivers/iio/magnetometer/bmc150_magn_spi.c b/drivers/iio/magnetometer/bmc150_magn_spi.c index ed9be0490d77..c6ed3ea8460a 100644 --- a/drivers/iio/magnetometer/bmc150_magn_spi.c +++ b/drivers/iio/magnetometer/bmc150_magn_spi.c @@ -22,8 +22,8 @@ static int bmc150_magn_spi_probe(struct spi_device *spi) regmap = devm_regmap_init_spi(spi, &bmc150_magn_regmap_config); if (IS_ERR(regmap)) { - dev_err(&spi->dev, "Failed to register spi regmap %d\n", - (int)PTR_ERR(regmap)); + dev_err(&spi->dev, "Failed to register spi regmap: %pe\n", + regmap); return PTR_ERR(regmap); } return bmc150_magn_probe(&spi->dev, regmap, spi->irq, id->name); diff --git a/drivers/iio/magnetometer/mmc35240.c b/drivers/iio/magnetometer/mmc35240.c index 425cdd07b4e5..1787d656d009 100644 --- a/drivers/iio/magnetometer/mmc35240.c +++ b/drivers/iio/magnetometer/mmc35240.c @@ -239,7 +239,7 @@ static int mmc35240_init(struct mmc35240_data *data) return ret; ret = regmap_bulk_read(data->regmap, MMC35240_OTP_START_ADDR, - (u8 *)otp_data, sizeof(otp_data)); + otp_data, sizeof(otp_data)); if (ret < 0) return ret; @@ -295,7 +295,7 @@ static int mmc35240_read_measurement(struct mmc35240_data *data, __le16 buf[3]) if (ret < 0) return ret; - return regmap_bulk_read(data->regmap, MMC35240_REG_XOUT_L, (u8 *)buf, + return regmap_bulk_read(data->regmap, MMC35240_REG_XOUT_L, buf, 3 * sizeof(__le16)); } diff --git a/drivers/iio/magnetometer/st_magn_core.c b/drivers/iio/magnetometer/st_magn_core.c index e68184a93a6d..79de721e6015 100644 --- a/drivers/iio/magnetometer/st_magn_core.c +++ b/drivers/iio/magnetometer/st_magn_core.c @@ -506,8 +506,7 @@ int st_magn_common_probe(struct iio_dev *indio_dev) indio_dev->channels = mdata->sensor_settings->ch; indio_dev->num_channels = ST_SENSORS_NUMBER_ALL_CHANNELS; - mdata->current_fullscale = (struct st_sensor_fullscale_avl *) - &mdata->sensor_settings->fs.fs_avl[0]; + mdata->current_fullscale = &mdata->sensor_settings->fs.fs_avl[0]; mdata->odr = mdata->sensor_settings->odr.odr_avl[0].hz; err = st_sensors_init_sensor(indio_dev, NULL); diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 29c209cc1108..a33048390118 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -337,8 +337,7 @@ static int bmp280_read_temp(struct bmp280_data *data, __be32 tmp = 0; s32 adc_temp, comp_temp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, - (u8 *) &tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, &tmp, 3); if (ret < 0) { dev_err(data->dev, "failed to read temperature\n"); return ret; @@ -377,8 +376,7 @@ static int bmp280_read_press(struct bmp280_data *data, if (ret < 0) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, - (u8 *) &tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, &tmp, 3); if (ret < 0) { dev_err(data->dev, "failed to read pressure\n"); return ret; @@ -400,8 +398,8 @@ static int bmp280_read_press(struct bmp280_data *data, static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) { + __be16 tmp; int ret; - __be16 tmp = 0; s32 adc_humidity; u32 comp_humidity; @@ -410,8 +408,7 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) if (ret < 0) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, - (u8 *) &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, &tmp, 2); if (ret < 0) { dev_err(data->dev, "failed to read humidity\n"); return ret; @@ -575,57 +572,38 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, return ret; } -static ssize_t bmp280_show_avail(char *buf, const int *vals, const int n) +static int bmp280_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) { - size_t len = 0; - int i; - - for (i = 0; i < n; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", vals[i]); - - buf[len - 1] = '\n'; - - return len; -} - -static ssize_t bmp280_show_temp_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); - - return bmp280_show_avail(buf, data->chip_info->oversampling_temp_avail, - data->chip_info->num_oversampling_temp_avail); -} - -static ssize_t bmp280_show_press_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); + struct bmp280_data *data = iio_priv(indio_dev); - return bmp280_show_avail(buf, data->chip_info->oversampling_press_avail, - data->chip_info->num_oversampling_press_avail); + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_PRESSURE: + *vals = data->chip_info->oversampling_press_avail; + *length = data->chip_info->num_oversampling_press_avail; + break; + case IIO_TEMP: + *vals = data->chip_info->oversampling_temp_avail; + *length = data->chip_info->num_oversampling_temp_avail; + break; + default: + return -EINVAL; + } + *type = IIO_VAL_INT; + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } } -static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, - S_IRUGO, bmp280_show_temp_oversampling_avail, NULL, 0); - -static IIO_DEVICE_ATTR(in_pressure_oversampling_ratio_available, - S_IRUGO, bmp280_show_press_oversampling_avail, NULL, 0); - -static struct attribute *bmp280_attributes[] = { - &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, - &iio_dev_attr_in_pressure_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group bmp280_attrs_group = { - .attrs = bmp280_attributes, -}; - static const struct iio_info bmp280_info = { .read_raw = &bmp280_read_raw, + .read_avail = &bmp280_read_avail, .write_raw = &bmp280_write_raw, - .attrs = &bmp280_attrs_group, }; static int bmp280_chip_config(struct bmp280_data *data) @@ -713,7 +691,7 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) unsigned int ctrl; if (data->use_eoc) - init_completion(&data->done); + reinit_completion(&data->done); ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); if (ret) @@ -752,14 +730,14 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) { + __be16 tmp; int ret; - __be16 tmp = 0; ret = bmp180_measure(data, BMP180_MEAS_TEMP); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, &tmp, 2); if (ret) return ret; @@ -856,7 +834,7 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, (u8 *)&tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, &tmp, 3); if (ret) return ret; @@ -965,10 +943,12 @@ static int bmp085_fetch_eoc_irq(struct device *dev, irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); if (irq_trig != IRQF_TRIGGER_RISING) { - dev_err(dev, "non-rising trigger given for EOC interrupt, " - "trying to enforce it\n"); + dev_err(dev, "non-rising trigger given for EOC interrupt, trying to enforce it\n"); irq_trig = IRQF_TRIGGER_RISING; } + + init_completion(&data->done); + ret = devm_request_threaded_irq(dev, irq, bmp085_eoc_irq, @@ -1082,9 +1062,9 @@ int bmp280_common_probe(struct device *dev, usleep_range(data->start_up_time, data->start_up_time + 100); /* Bring chip out of reset if there is an assigned GPIO line */ - gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); /* Deassert the signal */ - if (!IS_ERR(gpiod)) { + if (gpiod) { dev_info(dev, "release reset\n"); gpiod_set_value(gpiod, 0); } diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index bd972cec4830..789a2928504a 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -683,8 +683,7 @@ EXPORT_SYMBOL(st_press_get_settings); int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); - struct st_sensors_platform_data *pdata = - (struct st_sensors_platform_data *)press_data->dev->platform_data; + struct st_sensors_platform_data *pdata = dev_get_platdata(press_data->dev); int err; indio_dev->modes = INDIO_DIRECT_MODE; @@ -708,9 +707,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; - press_data->current_fullscale = - (struct st_sensor_fullscale_avl *) - &press_data->sensor_settings->fs.fs_avl[0]; + press_data->current_fullscale = &press_data->sensor_settings->fs.fs_avl[0]; press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig index 37606d400805..d57e8cc17e42 100644 --- a/drivers/iio/proximity/Kconfig +++ b/drivers/iio/proximity/Kconfig @@ -101,6 +101,19 @@ config SRF04 To compile this driver as a module, choose M here: the module will be called srf04. +config SX9310 + tristate "SX9310/SX9311 Semtech proximity sensor" + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select REGMAP_I2C + depends on I2C + help + Say Y here to build a driver for Semtech's SX9310/SX9311 capacitive + proximity/button sensor. + + To compile this driver as a module, choose M here: the + module will be called sx9310. + config SX9500 tristate "SX9500 Semtech proximity sensor" select IIO_BUFFER diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile index c591b019304e..25e5a04da101 100644 --- a/drivers/iio/proximity/Makefile +++ b/drivers/iio/proximity/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PING) += ping.o obj-$(CONFIG_RFD77402) += rfd77402.o obj-$(CONFIG_SRF04) += srf04.o obj-$(CONFIG_SRF08) += srf08.o +obj-$(CONFIG_SX9310) += sx9310.o obj-$(CONFIG_SX9500) += sx9500.o obj-$(CONFIG_VL53L0X_I2C) += vl53l0x-i2c.o diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c new file mode 100644 index 000000000000..d161f3061e35 --- /dev/null +++ b/drivers/iio/proximity/sx9310.c @@ -0,0 +1,1069 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2018 Google LLC. + * + * Driver for Semtech's SX9310/SX9311 capacitive proximity/button solution. + * Based on SX9500 driver and Semtech driver using the input framework + * <https://my.syncplicity.com/share/teouwsim8niiaud/ + * linux-driver-SX9310_NoSmartHSensing>. + * Reworked April 2019 by Evan Green <evgreen@chromium.org> + * and January 2020 by Daniel Campello <campello@chromium.org> + */ + +#include <linux/acpi.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/pm.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/events.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/trigger.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/trigger_consumer.h> + +/* Register definitions. */ +#define SX9310_REG_IRQ_SRC 0x00 +#define SX9310_REG_STAT0 0x01 +#define SX9310_REG_STAT1 0x02 +#define SX9310_REG_IRQ_MSK 0x03 +#define SX9310_CONVDONE_IRQ BIT(3) +#define SX9310_FAR_IRQ BIT(5) +#define SX9310_CLOSE_IRQ BIT(6) +#define SX9310_EVENT_IRQ (SX9310_FAR_IRQ | \ + SX9310_CLOSE_IRQ) +#define SX9310_REG_IRQ_FUNC 0x04 + +#define SX9310_REG_PROX_CTRL0 0x10 +#define SX9310_REG_PROX_CTRL0_PROXSTAT2 0x10 +#define SX9310_REG_PROX_CTRL0_EN_MASK 0x0F +#define SX9310_REG_PROX_CTRL1 0x11 +#define SX9310_REG_PROX_CTRL2 0x12 +#define SX9310_REG_PROX_CTRL2_COMBMODE_ALL 0x80 +#define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC 0x04 +#define SX9310_REG_PROX_CTRL3 0x13 +#define SX9310_REG_PROX_CTRL3_GAIN0_X8 0x0c +#define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02 +#define SX9310_REG_PROX_CTRL4 0x14 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07 +#define SX9310_REG_PROX_CTRL5 0x15 +#define SX9310_REG_PROX_CTRL5_RANGE_SMALL 0xc0 +#define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 0x04 +#define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02 +#define SX9310_REG_PROX_CTRL6 0x16 +#define SX9310_REG_PROX_CTRL6_COMP_COMMON 0x20 +#define SX9310_REG_PROX_CTRL7 0x17 +#define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 0x08 +#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05 +#define SX9310_REG_PROX_CTRL8 0x18 +#define SX9310_REG_PROX_CTRL9 0x19 +#define SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 0x40 +#define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 0x88 +#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900 0x03 +#define SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500 0x05 +#define SX9310_REG_PROX_CTRL10 0x1a +#define SX9310_REG_PROX_CTRL10_HYST_6PCT 0x10 +#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 0x12 +#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8 0x03 +#define SX9310_REG_PROX_CTRL11 0x1b +#define SX9310_REG_PROX_CTRL12 0x1c +#define SX9310_REG_PROX_CTRL13 0x1d +#define SX9310_REG_PROX_CTRL14 0x1e +#define SX9310_REG_PROX_CTRL15 0x1f +#define SX9310_REG_PROX_CTRL16 0x20 +#define SX9310_REG_PROX_CTRL17 0x21 +#define SX9310_REG_PROX_CTRL18 0x22 +#define SX9310_REG_PROX_CTRL19 0x23 +#define SX9310_REG_SAR_CTRL0 0x2a +#define SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES 0x40 +#define SX9310_REG_SAR_CTRL0_SARHYST_8 0x10 +#define SX9310_REG_SAR_CTRL1 0x2b +/* Each increment of the slope register is 0.0078125. */ +#define SX9310_REG_SAR_CTRL1_SLOPE(_hnslope) (_hnslope / 78125) +#define SX9310_REG_SAR_CTRL2 0x2c +#define SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT 0x3c + +#define SX9310_REG_SENSOR_SEL 0x30 + +#define SX9310_REG_USE_MSB 0x31 +#define SX9310_REG_USE_LSB 0x32 + +#define SX9310_REG_AVG_MSB 0x33 +#define SX9310_REG_AVG_LSB 0x34 + +#define SX9310_REG_DIFF_MSB 0x35 +#define SX9310_REG_DIFF_LSB 0x36 + +#define SX9310_REG_OFFSET_MSB 0x37 +#define SX9310_REG_OFFSET_LSB 0x38 + +#define SX9310_REG_SAR_MSB 0x39 +#define SX9310_REG_SAR_LSB 0x3a + +#define SX9310_REG_I2CADDR 0x40 +#define SX9310_REG_PAUSE 0x41 +#define SX9310_REG_WHOAMI 0x42 +#define SX9310_WHOAMI_VALUE 0x01 +#define SX9311_WHOAMI_VALUE 0x02 + +#define SX9310_REG_RESET 0x7f +#define SX9310_SOFT_RESET 0xde + +#define SX9310_SCAN_PERIOD_MASK GENMASK(7, 4) +#define SX9310_SCAN_PERIOD_SHIFT 4 + +#define SX9310_COMPSTAT_MASK GENMASK(3, 0) + +/* 4 hardware channels, as defined in STAT0: COMB, CS2, CS1 and CS0. */ +#define SX9310_NUM_CHANNELS 4 +#define SX9310_CHAN_ENABLED_MASK GENMASK(3, 0) + +struct sx9310_data { + /* Serialize access to registers and channel configuration */ + struct mutex mutex; + struct i2c_client *client; + struct iio_trigger *trig; + struct regmap *regmap; + /* + * Last reading of the proximity status for each channel. + * We only send an event to user space when this changes. + */ + bool prox_stat[SX9310_NUM_CHANNELS]; + bool trigger_enabled; + __be16 buffer[SX9310_NUM_CHANNELS + + 4]; /* 64-bit data + 64-bit timestamp */ + /* Remember enabled channels and sample rate during suspend. */ + unsigned int suspend_ctrl0; + struct completion completion; + unsigned int chan_read, chan_event; + int channel_users[SX9310_NUM_CHANNELS]; + int whoami; +}; + +static const struct iio_event_spec sx9310_events[] = { + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_EITHER, + .mask_separate = BIT(IIO_EV_INFO_ENABLE), + }, +}; + +#define SX9310_NAMED_CHANNEL(idx, name) \ + { \ + .type = IIO_PROXIMITY, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .indexed = 1, \ + .channel = idx, \ + .extend_name = name, \ + .address = SX9310_REG_DIFF_MSB, \ + .event_spec = sx9310_events, \ + .num_event_specs = ARRAY_SIZE(sx9310_events), \ + .scan_index = idx, \ + .scan_type = { \ + .sign = 's', \ + .realbits = 12, \ + .storagebits = 16, \ + .endianness = IIO_BE, \ + }, \ + } +#define SX9310_CHANNEL(idx) SX9310_NAMED_CHANNEL(idx, NULL) + +static const struct iio_chan_spec sx9310_channels[] = { + SX9310_CHANNEL(0), /* CS0 */ + SX9310_CHANNEL(1), /* CS1 */ + SX9310_CHANNEL(2), /* CS2 */ + SX9310_NAMED_CHANNEL(3, "comb"), /* COMB */ + + IIO_CHAN_SOFT_TIMESTAMP(4), +}; + +/* + * Each entry contains the integer part (val) and the fractional part, in micro + * seconds. It conforms to the IIO output IIO_VAL_INT_PLUS_MICRO. + */ +static const struct { + int val; + int val2; +} sx9310_samp_freq_table[] = { + { 500, 0 }, /* 0000: Min (no idle time) */ + { 66, 666666 }, /* 0001: 15 ms */ + { 33, 333333 }, /* 0010: 30 ms (Typ.) */ + { 22, 222222 }, /* 0011: 45 ms */ + { 16, 666666 }, /* 0100: 60 ms */ + { 11, 111111 }, /* 0101: 90 ms */ + { 8, 333333 }, /* 0110: 120 ms */ + { 5, 0 }, /* 0111: 200 ms */ + { 2, 500000 }, /* 1000: 400 ms */ + { 1, 666666 }, /* 1001: 600 ms */ + { 1, 250000 }, /* 1010: 800 ms */ + { 1, 0 }, /* 1011: 1 s */ + { 0, 500000 }, /* 1100: 2 s */ + { 0, 333333 }, /* 1101: 3 s */ + { 0, 250000 }, /* 1110: 4 s */ + { 0, 200000 }, /* 1111: 5 s */ +}; +static const unsigned int sx9310_scan_period_table[] = { + 2, 15, 30, 45, 60, 90, 120, 200, + 400, 600, 800, 1000, 2000, 3000, 4000, 5000, +}; + +static ssize_t sx9310_show_samp_freq_avail(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + size_t len = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) + len += scnprintf(buf + len, PAGE_SIZE - len, "%d.%d ", + sx9310_samp_freq_table[i].val, + sx9310_samp_freq_table[i].val2); + buf[len - 1] = '\n'; + return len; +} +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(sx9310_show_samp_freq_avail); + +static const struct regmap_range sx9310_writable_reg_ranges[] = { + regmap_reg_range(SX9310_REG_IRQ_MSK, SX9310_REG_IRQ_FUNC), + regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19), + regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2), + regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SENSOR_SEL), + regmap_reg_range(SX9310_REG_OFFSET_MSB, SX9310_REG_OFFSET_LSB), + regmap_reg_range(SX9310_REG_PAUSE, SX9310_REG_PAUSE), + regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), +}; + +static const struct regmap_access_table sx9310_writeable_regs = { + .yes_ranges = sx9310_writable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9310_writable_reg_ranges), +}; + +static const struct regmap_range sx9310_readable_reg_ranges[] = { + regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_IRQ_FUNC), + regmap_reg_range(SX9310_REG_PROX_CTRL0, SX9310_REG_PROX_CTRL19), + regmap_reg_range(SX9310_REG_SAR_CTRL0, SX9310_REG_SAR_CTRL2), + regmap_reg_range(SX9310_REG_SENSOR_SEL, SX9310_REG_SAR_LSB), + regmap_reg_range(SX9310_REG_I2CADDR, SX9310_REG_WHOAMI), + regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), +}; + +static const struct regmap_access_table sx9310_readable_regs = { + .yes_ranges = sx9310_readable_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9310_readable_reg_ranges), +}; + +static const struct regmap_range sx9310_volatile_reg_ranges[] = { + regmap_reg_range(SX9310_REG_IRQ_SRC, SX9310_REG_STAT1), + regmap_reg_range(SX9310_REG_USE_MSB, SX9310_REG_DIFF_LSB), + regmap_reg_range(SX9310_REG_SAR_MSB, SX9310_REG_SAR_LSB), + regmap_reg_range(SX9310_REG_RESET, SX9310_REG_RESET), +}; + +static const struct regmap_access_table sx9310_volatile_regs = { + .yes_ranges = sx9310_volatile_reg_ranges, + .n_yes_ranges = ARRAY_SIZE(sx9310_volatile_reg_ranges), +}; + +static const struct regmap_config sx9310_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = SX9310_REG_RESET, + .cache_type = REGCACHE_RBTREE, + + .wr_table = &sx9310_writeable_regs, + .rd_table = &sx9310_readable_regs, + .volatile_table = &sx9310_volatile_regs, +}; + +static int sx9310_update_chan_en(struct sx9310_data *data, + unsigned int chan_read, + unsigned int chan_event) +{ + int ret; + + if ((data->chan_read | data->chan_event) != (chan_read | chan_event)) { + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0, + SX9310_CHAN_ENABLED_MASK, + chan_read | chan_event); + if (ret) + return ret; + } + data->chan_read = chan_read; + data->chan_event = chan_event; + return 0; +} + +static int sx9310_get_read_channel(struct sx9310_data *data, int channel) +{ + return sx9310_update_chan_en(data, data->chan_read | BIT(channel), + data->chan_event); +} + +static int sx9310_put_read_channel(struct sx9310_data *data, int channel) +{ + return sx9310_update_chan_en(data, data->chan_read & ~BIT(channel), + data->chan_event); +} + +static int sx9310_get_event_channel(struct sx9310_data *data, int channel) +{ + return sx9310_update_chan_en(data, data->chan_read, + data->chan_event | BIT(channel)); +} + +static int sx9310_put_event_channel(struct sx9310_data *data, int channel) +{ + return sx9310_update_chan_en(data, data->chan_read, + data->chan_event & ~BIT(channel)); +} + +static int sx9310_enable_irq(struct sx9310_data *data, unsigned int irq) +{ + return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, irq); +} + +static int sx9310_disable_irq(struct sx9310_data *data, unsigned int irq) +{ + return regmap_update_bits(data->regmap, SX9310_REG_IRQ_MSK, irq, 0); +} + +static int sx9310_read_prox_data(struct sx9310_data *data, + const struct iio_chan_spec *chan, __be16 *val) +{ + int ret; + + ret = regmap_write(data->regmap, SX9310_REG_SENSOR_SEL, chan->channel); + if (ret < 0) + return ret; + + return regmap_bulk_read(data->regmap, chan->address, val, 2); +} + +/* + * If we have no interrupt support, we have to wait for a scan period + * after enabling a channel to get a result. + */ +static int sx9310_wait_for_sample(struct sx9310_data *data) +{ + int ret; + unsigned int val; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &val); + if (ret < 0) + return ret; + + val = (val & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT; + + msleep(sx9310_scan_period_table[val]); + + return 0; +} + +static int sx9310_read_proximity(struct sx9310_data *data, + const struct iio_chan_spec *chan, int *val) +{ + int ret = 0; + __be16 rawval; + + mutex_lock(&data->mutex); + + ret = sx9310_get_read_channel(data, chan->channel); + if (ret < 0) + goto out; + + ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ); + if (ret < 0) + goto out_put_channel; + + mutex_unlock(&data->mutex); + + if (data->client->irq > 0) { + ret = wait_for_completion_interruptible(&data->completion); + reinit_completion(&data->completion); + } else { + ret = sx9310_wait_for_sample(data); + } + + mutex_lock(&data->mutex); + + if (ret < 0) + goto out_disable_irq; + + ret = sx9310_read_prox_data(data, chan, &rawval); + if (ret < 0) + goto out_disable_irq; + + *val = sign_extend32(be16_to_cpu(rawval), + (chan->address == SX9310_REG_DIFF_MSB ? 11 : 15)); + + ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); + if (ret < 0) + goto out_put_channel; + + ret = sx9310_put_read_channel(data, chan->channel); + if (ret < 0) + goto out; + + mutex_unlock(&data->mutex); + + return IIO_VAL_INT; + +out_disable_irq: + sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); +out_put_channel: + sx9310_put_read_channel(data, chan->channel); +out: + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2) +{ + unsigned int regval; + int ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, ®val); + + if (ret < 0) + return ret; + + regval = (regval & SX9310_SCAN_PERIOD_MASK) >> SX9310_SCAN_PERIOD_SHIFT; + *val = sx9310_samp_freq_table[regval].val; + *val2 = sx9310_samp_freq_table[regval].val2; + + return IIO_VAL_INT_PLUS_MICRO; +} + +static int sx9310_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, + int *val2, long mask) +{ + struct sx9310_data *data = iio_priv(indio_dev); + int ret; + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx9310_read_proximity(data, chan, val); + iio_device_release_direct_mode(indio_dev); + return ret; + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9310_read_samp_freq(data, val, val2); + default: + return -EINVAL; + } +} + +static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(sx9310_samp_freq_table); i++) + if (val == sx9310_samp_freq_table[i].val && + val2 == sx9310_samp_freq_table[i].val2) + break; + + if (i == ARRAY_SIZE(sx9310_samp_freq_table)) + return -EINVAL; + + mutex_lock(&data->mutex); + + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL0, + SX9310_SCAN_PERIOD_MASK, + i << SX9310_SCAN_PERIOD_SHIFT); + + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, + long mask) +{ + struct sx9310_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + if (mask != IIO_CHAN_INFO_SAMP_FREQ) + return -EINVAL; + + return sx9310_set_samp_freq(data, val, val2); +} + +static irqreturn_t sx9310_irq_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sx9310_data *data = iio_priv(indio_dev); + + if (data->trigger_enabled) + iio_trigger_poll(data->trig); + + /* + * Even if no event is enabled, we need to wake the thread to + * clear the interrupt state by reading SX9310_REG_IRQ_SRC. It + * is not possible to do that here because regmap_read takes a + * mutex. + */ + return IRQ_WAKE_THREAD; +} + +static void sx9310_push_events(struct iio_dev *indio_dev) +{ + int ret; + unsigned int val, chan; + struct sx9310_data *data = iio_priv(indio_dev); + s64 timestamp = iio_get_time_ns(indio_dev); + + /* Read proximity state on all channels */ + ret = regmap_read(data->regmap, SX9310_REG_STAT0, &val); + if (ret < 0) { + dev_err(&data->client->dev, "i2c transfer error in irq\n"); + return; + } + + for (chan = 0; chan < SX9310_NUM_CHANNELS; chan++) { + int dir; + u64 ev; + bool new_prox = val & BIT(chan); + + if (!(data->chan_event & BIT(chan))) + continue; + if (new_prox == data->prox_stat[chan]) + /* No change on this channel. */ + continue; + + dir = new_prox ? IIO_EV_DIR_FALLING : IIO_EV_DIR_RISING; + ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, chan, + IIO_EV_TYPE_THRESH, dir); + + iio_push_event(indio_dev, ev, timestamp); + data->prox_stat[chan] = new_prox; + } +} + +static irqreturn_t sx9310_irq_thread_handler(int irq, void *private) +{ + struct iio_dev *indio_dev = private; + struct sx9310_data *data = iio_priv(indio_dev); + int ret; + unsigned int val; + + mutex_lock(&data->mutex); + + ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val); + if (ret < 0) { + dev_err(&data->client->dev, "i2c transfer error in irq\n"); + goto out; + } + + if (val & SX9310_EVENT_IRQ) + sx9310_push_events(indio_dev); + + if (val & SX9310_CONVDONE_IRQ) + complete(&data->completion); + +out: + mutex_unlock(&data->mutex); + + return IRQ_HANDLED; +} + +static int sx9310_read_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir) +{ + struct sx9310_data *data = iio_priv(indio_dev); + + return !!(data->chan_event & BIT(chan->channel)); +} + +static int sx9310_write_event_config(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, int state) +{ + struct sx9310_data *data = iio_priv(indio_dev); + int ret; + + /* If the state hasn't changed, there's nothing to do. */ + if (!!(data->chan_event & BIT(chan->channel)) == state) + return 0; + + mutex_lock(&data->mutex); + if (state) { + ret = sx9310_get_event_channel(data, chan->channel); + if (ret < 0) + goto out_unlock; + if (!(data->chan_event & ~BIT(chan->channel))) { + ret = sx9310_enable_irq(data, SX9310_EVENT_IRQ); + if (ret < 0) + sx9310_put_event_channel(data, chan->channel); + } + } else { + ret = sx9310_put_event_channel(data, chan->channel); + if (ret < 0) + goto out_unlock; + if (!data->chan_event) { + ret = sx9310_disable_irq(data, SX9310_EVENT_IRQ); + if (ret < 0) + sx9310_get_event_channel(data, chan->channel); + } + } + +out_unlock: + mutex_unlock(&data->mutex); + return ret; +} + +static struct attribute *sx9310_attributes[] = { + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, + NULL, +}; + +static const struct attribute_group sx9310_attribute_group = { + .attrs = sx9310_attributes, +}; + +static const struct iio_info sx9310_info = { + .attrs = &sx9310_attribute_group, + .read_raw = sx9310_read_raw, + .write_raw = sx9310_write_raw, + .read_event_config = sx9310_read_event_config, + .write_event_config = sx9310_write_event_config, +}; + +static int sx9310_set_trigger_state(struct iio_trigger *trig, bool state) +{ + struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig); + struct sx9310_data *data = iio_priv(indio_dev); + int ret = 0; + + mutex_lock(&data->mutex); + + if (state) + ret = sx9310_enable_irq(data, SX9310_CONVDONE_IRQ); + else if (!data->chan_read) + ret = sx9310_disable_irq(data, SX9310_CONVDONE_IRQ); + if (ret < 0) + goto out; + + data->trigger_enabled = state; + +out: + mutex_unlock(&data->mutex); + + return ret; +} + +static const struct iio_trigger_ops sx9310_trigger_ops = { + .set_trigger_state = sx9310_set_trigger_state, +}; + +static irqreturn_t sx9310_trigger_handler(int irq, void *private) +{ + struct iio_poll_func *pf = private; + struct iio_dev *indio_dev = pf->indio_dev; + struct sx9310_data *data = iio_priv(indio_dev); + __be16 val; + int bit, ret, i = 0; + + mutex_lock(&data->mutex); + + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) { + ret = sx9310_read_prox_data(data, &indio_dev->channels[bit], + &val); + if (ret < 0) + goto out; + + data->buffer[i++] = val; + } + + iio_push_to_buffers_with_timestamp(indio_dev, data->buffer, + pf->timestamp); + +out: + mutex_unlock(&data->mutex); + + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static int sx9310_buffer_preenable(struct iio_dev *indio_dev) +{ + struct sx9310_data *data = iio_priv(indio_dev); + unsigned int channels = 0; + int bit, ret; + + mutex_lock(&data->mutex); + for_each_set_bit(bit, indio_dev->active_scan_mask, + indio_dev->masklength) + channels |= BIT(indio_dev->channels[bit].channel); + + ret = sx9310_update_chan_en(data, channels, data->chan_event); + mutex_unlock(&data->mutex); + return ret; +} + +static int sx9310_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct sx9310_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + ret = sx9310_update_chan_en(data, 0, data->chan_event); + mutex_unlock(&data->mutex); + return ret; +} + +static const struct iio_buffer_setup_ops sx9310_buffer_setup_ops = { + .preenable = sx9310_buffer_preenable, + .postenable = iio_triggered_buffer_postenable, + .predisable = iio_triggered_buffer_predisable, + .postdisable = sx9310_buffer_postdisable, +}; + +struct sx9310_reg_default { + u8 reg; + u8 def; +}; + +#define SX_INIT(_reg, _def) \ + { \ + .reg = SX9310_REG_##_reg, \ + .def = _def, \ + } + +static const struct sx9310_reg_default sx9310_default_regs[] = { + SX_INIT(IRQ_MSK, 0x00), + SX_INIT(IRQ_FUNC, 0x00), + /* + * The lower 4 bits should not be set as it enable sensors measurements. + * Turning the detection on before the configuration values are set to + * good values can cause the device to return erroneous readings. + */ + SX_INIT(PROX_CTRL0, SX9310_REG_PROX_CTRL0_PROXSTAT2), + SX_INIT(PROX_CTRL1, 0x00), + SX_INIT(PROX_CTRL2, SX9310_REG_PROX_CTRL2_COMBMODE_ALL | + SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC), + SX_INIT(PROX_CTRL3, SX9310_REG_PROX_CTRL3_GAIN0_X8 | + SX9310_REG_PROX_CTRL3_GAIN12_X4), + SX_INIT(PROX_CTRL4, SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST), + SX_INIT(PROX_CTRL5, SX9310_REG_PROX_CTRL5_RANGE_SMALL | + SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 | + SX9310_REG_PROX_CTRL5_RAWFILT_1P25), + SX_INIT(PROX_CTRL6, SX9310_REG_PROX_CTRL6_COMP_COMMON), + SX_INIT(PROX_CTRL7, SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 | + SX9310_REG_PROX_CTRL7_AVGPOSFILT_512), + SX_INIT(PROX_CTRL8, SX9310_REG_PROX_CTRL8_9_PTHRESH_96 | + SX9310_REG_PROX_CTRL8_9_BODYTHRESH_1500), + SX_INIT(PROX_CTRL9, SX9310_REG_PROX_CTRL8_9_PTHRESH12_28 | + SX9310_REG_PROX_CTRL8_9_BODYTHRESH_900), + SX_INIT(PROX_CTRL10, SX9310_REG_PROX_CTRL10_HYST_6PCT | + SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_8 | + SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_8), + SX_INIT(PROX_CTRL11, 0x00), + SX_INIT(PROX_CTRL12, 0x00), + SX_INIT(PROX_CTRL13, 0x00), + SX_INIT(PROX_CTRL14, 0x00), + SX_INIT(PROX_CTRL15, 0x00), + SX_INIT(PROX_CTRL16, 0x00), + SX_INIT(PROX_CTRL17, 0x00), + SX_INIT(PROX_CTRL18, 0x00), + SX_INIT(PROX_CTRL19, 0x00), + SX_INIT(SAR_CTRL0, SX9310_REG_SAR_CTRL0_SARDEB_4_SAMPLES | + SX9310_REG_SAR_CTRL0_SARHYST_8), + SX_INIT(SAR_CTRL1, SX9310_REG_SAR_CTRL1_SLOPE(10781250)), + SX_INIT(SAR_CTRL2, SX9310_REG_SAR_CTRL2_SAROFFSET_DEFAULT), +}; + +/* Activate all channels and perform an initial compensation. */ +static int sx9310_init_compensation(struct iio_dev *indio_dev) +{ + struct sx9310_data *data = iio_priv(indio_dev); + int i, ret; + unsigned int val; + unsigned int ctrl0; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, &ctrl0); + if (ret < 0) + return ret; + + /* run the compensation phase on all channels */ + ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, + ctrl0 | SX9310_REG_PROX_CTRL0_EN_MASK); + if (ret < 0) + return ret; + + for (i = 100; i >= 0; i--) { + msleep(20); + ret = regmap_read(data->regmap, SX9310_REG_STAT1, &val); + if (ret < 0) + goto out; + if (!(val & SX9310_COMPSTAT_MASK)) + break; + } + + if (i < 0) { + dev_err(&data->client->dev, + "initial compensation timed out: 0x%02x", val); + ret = -ETIMEDOUT; + } + +out: + regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); + return ret; +} + +static int sx9310_init_device(struct iio_dev *indio_dev) +{ + struct sx9310_data *data = iio_priv(indio_dev); + const struct sx9310_reg_default *initval; + int ret; + unsigned int i, val; + + ret = regmap_write(data->regmap, SX9310_REG_RESET, SX9310_SOFT_RESET); + if (ret < 0) + return ret; + + usleep_range(1000, 2000); /* power-up time is ~1ms. */ + + /* Clear reset interrupt state by reading SX9310_REG_IRQ_SRC. */ + ret = regmap_read(data->regmap, SX9310_REG_IRQ_SRC, &val); + if (ret < 0) + return ret; + + /* Program some sane defaults. */ + for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) { + initval = &sx9310_default_regs[i]; + ret = regmap_write(data->regmap, initval->reg, initval->def); + if (ret < 0) + return ret; + } + + return sx9310_init_compensation(indio_dev); +} + +static int sx9310_set_indio_dev_name(struct device *dev, + struct iio_dev *indio_dev, + const struct i2c_device_id *id, int whoami) +{ + const struct acpi_device_id *acpi_id; + + /* id will be NULL when enumerated via ACPI */ + if (id) { + if (id->driver_data != whoami) + dev_err(dev, "WHOAMI does not match i2c_device_id: %s", + id->name); + } else if (ACPI_HANDLE(dev)) { + acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); + if (!acpi_id) + return -ENODEV; + if (acpi_id->driver_data != whoami) + dev_err(dev, "WHOAMI does not match acpi_device_id: %s", + acpi_id->id); + } else + return -ENODEV; + + switch (whoami) { + case SX9310_WHOAMI_VALUE: + indio_dev->name = "sx9310"; + break; + case SX9311_WHOAMI_VALUE: + indio_dev->name = "sx9311"; + break; + default: + dev_err(dev, "unexpected WHOAMI response: %u", whoami); + return -ENODEV; + } + + return 0; +} + +static int sx9310_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret; + struct iio_dev *indio_dev; + struct sx9310_data *data; + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); + if (indio_dev == NULL) + return -ENOMEM; + + data = iio_priv(indio_dev); + data->client = client; + mutex_init(&data->mutex); + init_completion(&data->completion); + + data->regmap = devm_regmap_init_i2c(client, &sx9310_regmap_config); + if (IS_ERR(data->regmap)) + return PTR_ERR(data->regmap); + + ret = regmap_read(data->regmap, SX9310_REG_WHOAMI, &data->whoami); + if (ret < 0) { + dev_err(&client->dev, "error in reading WHOAMI register: %d", + ret); + return ret; + } + + ret = sx9310_set_indio_dev_name(&client->dev, indio_dev, id, + data->whoami); + if (ret < 0) + return ret; + + ACPI_COMPANION_SET(&indio_dev->dev, ACPI_COMPANION(&client->dev)); + indio_dev->dev.parent = &client->dev; + indio_dev->channels = sx9310_channels; + indio_dev->num_channels = ARRAY_SIZE(sx9310_channels); + indio_dev->info = &sx9310_info; + indio_dev->modes = INDIO_DIRECT_MODE; + i2c_set_clientdata(client, indio_dev); + + ret = sx9310_init_device(indio_dev); + if (ret < 0) + return ret; + + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + sx9310_irq_handler, + sx9310_irq_thread_handler, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "sx9310_event", indio_dev); + if (ret < 0) + return ret; + + data->trig = + devm_iio_trigger_alloc(&client->dev, "%s-dev%d", + indio_dev->name, indio_dev->id); + if (!data->trig) + return -ENOMEM; + + data->trig->dev.parent = &client->dev; + data->trig->ops = &sx9310_trigger_ops; + iio_trigger_set_drvdata(data->trig, indio_dev); + + ret = devm_iio_trigger_register(&client->dev, data->trig); + if (ret) + return ret; + } + + ret = devm_iio_triggered_buffer_setup(&client->dev, indio_dev, + iio_pollfunc_store_time, + sx9310_trigger_handler, + &sx9310_buffer_setup_ops); + if (ret < 0) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int __maybe_unused sx9310_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct sx9310_data *data = iio_priv(indio_dev); + u8 ctrl0; + int ret; + + disable_irq_nosync(data->client->irq); + + mutex_lock(&data->mutex); + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL0, + &data->suspend_ctrl0); + + if (ret) + goto out; + + ctrl0 = data->suspend_ctrl0 & ~SX9310_REG_PROX_CTRL0_EN_MASK; + ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, ctrl0); + if (ret) + goto out; + + ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 0); + +out: + mutex_unlock(&data->mutex); + return ret; +} + +static int __maybe_unused sx9310_resume(struct device *dev) +{ + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); + struct sx9310_data *data = iio_priv(indio_dev); + int ret; + + mutex_lock(&data->mutex); + ret = regmap_write(data->regmap, SX9310_REG_PAUSE, 1); + if (ret) + goto out; + + ret = regmap_write(data->regmap, SX9310_REG_PROX_CTRL0, + data->suspend_ctrl0); + +out: + mutex_unlock(&data->mutex); + + enable_irq(data->client->irq); + + return ret; +} + +static const struct dev_pm_ops sx9310_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(sx9310_suspend, sx9310_resume) +}; + +static const struct acpi_device_id sx9310_acpi_match[] = { + { "STH9310", SX9310_WHOAMI_VALUE }, + { "STH9311", SX9311_WHOAMI_VALUE }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, sx9310_acpi_match); + +static const struct of_device_id sx9310_of_match[] = { + { .compatible = "semtech,sx9310" }, + { .compatible = "semtech,sx9311" }, + {}, +}; +MODULE_DEVICE_TABLE(of, sx9310_of_match); + +static const struct i2c_device_id sx9310_id[] = { + { "sx9310", SX9310_WHOAMI_VALUE }, + { "sx9311", SX9311_WHOAMI_VALUE }, + {}, +}; +MODULE_DEVICE_TABLE(i2c, sx9310_id); + +static struct i2c_driver sx9310_driver = { + .driver = { + .name = "sx9310", + .acpi_match_table = ACPI_PTR(sx9310_acpi_match), + .of_match_table = of_match_ptr(sx9310_of_match), + .pm = &sx9310_pm_ops, + }, + .probe = sx9310_probe, + .id_table = sx9310_id, +}; +module_i2c_driver(sx9310_driver); + +MODULE_AUTHOR("Gwendal Grignou <gwendal@chromium.org>"); +MODULE_AUTHOR("Daniel Campello <campello@chromium.org>"); +MODULE_DESCRIPTION("Driver for Semtech SX9310/SX9311 proximity sensor"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/temperature/ltc2983.c b/drivers/iio/temperature/ltc2983.c index d39c0d6b77f1..8976e8d59826 100644 --- a/drivers/iio/temperature/ltc2983.c +++ b/drivers/iio/temperature/ltc2983.c @@ -390,8 +390,8 @@ static struct ltc2983_custom_sensor *__ltc2983_custom_sensor_new( * For custom steinhart, the full u32 is taken. For all the others * the MSB is discarded. */ - const u8 n_size = (is_steinhart == true) ? 4 : 3; - const u8 e_size = (is_steinhart == true) ? sizeof(u32) : sizeof(u64); + const u8 n_size = is_steinhart ? 4 : 3; + const u8 e_size = is_steinhart ? sizeof(u32) : sizeof(u64); n_entries = of_property_count_elems_of_size(np, propname, e_size); /* n_entries must be an even number */ diff --git a/drivers/iio/trigger/iio-trig-hrtimer.c b/drivers/iio/trigger/iio-trig-hrtimer.c index a5e670726717..f59bf8d58586 100644 --- a/drivers/iio/trigger/iio-trig-hrtimer.c +++ b/drivers/iio/trigger/iio-trig-hrtimer.c @@ -4,7 +4,7 @@ * * Copyright (C) Intuitive Aerial AB * Written by Marten Svanfeldt, marten@intuitiveaerial.com - * Copyright (C) 2012, Analog Device Inc. + * Copyright (C) 2012, Analog Devices Inc. * Author: Lars-Peter Clausen <lars@metafoo.de> * Copyright (C) 2015, Intel Corporation */ |