diff options
author | Greg Kroah-Hartman | 2020-11-24 08:30:08 +0100 |
---|---|---|
committer | Greg Kroah-Hartman | 2020-11-24 08:30:08 +0100 |
commit | 749c1e1481e1d242ded9dd1bf210ddb7c0d22a4f (patch) | |
tree | d3d8ea19491e1be977019ea2ad02441524fa4c26 /drivers | |
parent | f65b243d6ab856d768aa8039da8a2a47603b8847 (diff) | |
parent | 16be06aa1a28b3bc967f0f32e7e4668889bd5131 (diff) |
Merge tag 'iio-for-5.11a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
First set of new device support, features and cleanups for IIO in the 5.11 cycle
Usual mixed bag of new drivers / device support + cleanups etc with the
addition of a fairly big set of yaml conversions.
Txt to yaml format conversions.
In some cases dropped separate binding and moved to trivial devices (drop).
Listed by manufacturer
- dht11 temperature(drop)
- adi,ad2s90 adi,ad5272 adi,ad5592r adi,ad5758 adi,ad5933 adi,ad7303
adi,adis16480 adi,adf4350
- ams,as3935
- asahi-kasei,ak8974
- atmel,sama5d2-adc
- avago,apds9300 avago,apds9960
- bosch,bma180 bosch,bmc150_magn bosch,bme680 bosch,bmg180
- brcm,iproc-static-adc
- capella,cm36651
- domintech,dmard06(drop)
- fsl,mag3110 fsl,mma8452 fsl,vf610-dac
- hoperf,hp03
- honeywell,hmc5843
- kionix,kxcjk1013
- maxim,ds1803(drop) maxim,ds4424 maxim,max30100 maxim,max30102
maxim,max31856 maxim,max31855k maxim,max44009
maxim,max5481 maxim,max5821
- meas,htu21(drop) meas,ms5367(drop) meas,ms5611 meas,tsys01(drop)
- mediatek,mt2701-auxadc
- melexis,mlx90614 melexis,mlx90632
- memsic,mmc35240(drop)
- microchip,mcp41010 microchip,mcp4131 microchip,mcp4725
- murata,zap2326
- nxp,fxas21002c nxp,lpc1850-dac
- pni,rm3100
- qcom,pm8018-adc qcom,spmi-iadc
- renesas,isl29501 renesas,rcar-gyroadc
- samsung,sensorhub-rinato
- sensiron,sgp30
- sentech,sx9500
- sharp,gp2ap020a00f
- st,hts221 st,lsm6dsx st,st-sensors(many!) st,uvis25 st,vcl53l0x st,vl6180
- ti,adc084s021 ti,ads124s08
ti,dac5571 ti,dac7311 ti,dac7512 ti,dac7612
ti,hdc1000(drop) ti,palmas-gpadc ti,opt3001 ti,tmp07
- upisemi,us51882
- vishay,vcnl4035
- x-powers,axp209
New device support
* adi,ad5685
- Add support for AD5338R dual output 10-bit DAC
- Add DT-binding doc.
* mediatek,mt6360
- New driver for this SoC ADC with bindings and using new channel label
support in the IIO core.
* st,lsm6dsx
- Add support for LSM6DST
Core:
* Add "label" to device channels, provided via a new core callback. Including
DT docs for when that is the source, and ABI docs.
* Add devm_iio_triggered_buffer_setup_ext to take extra attributes.
* dmaengine, unwrap use of iio_buffer_set_attrs()
* Drop iio_buffer_set_attrs()
* Centralize ioctl call handling. Later fix to ensure -EINVAL returned if
no handler has run.
* Fix an issue with IIO_VAL_FRACTIONAL and negative values - doesn't affect
any known existing drivers, but will impact a future one.
* kernel-doc fix in trigger.h
* file-ops ordering cleanup
Features
* semtech,sx9310
- Add control of hardware gain, proximity thresholds, hysteresis and
debounce.
- Increase what information on hardware configuration can be provided
via DT.
Cleanup and minor features
* adi,ad5685
- Add of_match_table
* adi,ad7292
- Drop pointless spi_set_drvdata() call
* adi,ad7298
- Drop platform data and tidy up external reference config.
* adi,ad7303
- Drop platform data handling as unused.
* adi,ad7768
- Add new label attribute for channels provided from dt.
* adi,ad7887
- devm_ usage in probe simplifying remove and error handling.
* adi,adis16201
- Drop pointless spi_set_drvdata() call
* adi,adis16209
- Drop pointless spi_set_drvdata() call
* adi,adis16240
- White space fixup
* adi,adxl372
- use new devm_iio_triggered-buffer_setup_ext()
* amlogic,meson-saradc
- Drop pointless semicolon.
* amstaos,tsl2563
- Put back i2c_device_id table as needed for greybus probing.
* atmel,at91_adc
- Use of_device_get_match_data() instead of open coding it.
- Constify some driver data
- Add KCONFIG dep on CONFIG_OF and drop of_match_ptr()
- Drop platform data as mostly dead code.
- Tidy up reference voltage logic
* atmel-sama5d2
- Drop a pointless semicolon
- Merge buffer and trigger init into a separate function
- Use new devm_iio_triggered_buff_setup_ext()
* avago,apds9960
- Drop a pointless semicolon
* bosch,bmc150
- Drop a pointless semicolon
- Use new iio_triggered_buffer_setup_ext()
* bosch,bmp280
- Drop a pointless semicolon
* fsl,mma8452
- Constification
* (google),cros_ec
- Use new devm_iio_triggered_buffer_setup_ext()
* hid-sensors
- Use new iio_triggered_buffer_setup_ext()
* ingenic,adc
- Drop a pointless semicolon
* invensense,icm426xx
- Fix MAINTAINERS entry missing :
* mediatek,mt6577_audxac
- Add binding doc for mt8516 compatible with mt8173
* motorola,cpcap-adc
- Fix an implicit fallthrough marking that clang needs to avoid warning.
* samsung,exynos-adc
- Stop relying on users counter form input device in ISR.
* st,lsm6dsx
- add vdd and vddio regulator control (including binding update)
* st,stm32-adc
- Tidy up code for dma transfers.
- Adapt clock duty cycle for proper functioning. Note no known problems
with existing boards.
* st,vl53l0x-i2c
- Put back i2c_device_id table as needed for greybus probing.
* vishay,vcnl4035
- Put back i2c_device_id table as needed for greybus probing.
* tag 'iio-for-5.11a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (126 commits)
dt-bindings:iio:adc:x-powers,axp209-adc: txt to yaml conversion
dt-bindings:iio:adc:renesas,rcar-gyroadc: txt to yaml conversion.
dt-bindings:iio:adc:atmel,sama5d2-adc: txt to yaml conversion
dt-bindings:iio:magnetometer:pni,rm3100: txt to yaml conversion.
dt-bindings:iio:magnetometer:honeywell,hmc5843: txt to yaml format conversion
dt-bindings:iio:magnetometer:bosch,bmc150_magn: txt to yaml conversion.
dt-bindings:iio:magnetometer:asahi-kasei,ak8974: txt to yaml format conversion
dt-bindings:iio:magnetometer:fsl,mag3110: txt to yaml conversion
dt-bindings:iio:light:st,vl6180: txt to yaml format conversion.
dt-bindings:iio:light:vishay,vcnl4035: txt to yaml conversion
dt-bindings:iio:light:st,uvis25: txt to yaml conversion for this UV sensor
dt-bindings:iio:light:upisemi,us51882: txt to yaml conversion.
dt-bindings:iio:light:ti,opt3001: txt to yaml conversion
dt-bindings:iio:light:maxim,max44009: txt to yaml conversion.
dt-bindings:iio:light:sharp,gp2ap020a00f: txt to yaml conversion.
dt-bindings:iio:light:capella,cm36651: txt to yaml conversion.
dt-bindings:iio:light:avago,apds9960: txt to yaml conversion
dt-bindings:iio:light:avago,apds9300: txt to yaml conversion.
dt-bindings:iio:imu:st,lsm6dsx: txt to yaml conversion
dt-bindings:iio:imu:adi,adis16480: txt to yaml conversion
...
Diffstat (limited to 'drivers')
47 files changed, 1544 insertions, 275 deletions
diff --git a/drivers/iio/accel/adis16201.c b/drivers/iio/accel/adis16201.c index f955cccb3e77..3633a4e302c6 100644 --- a/drivers/iio/accel/adis16201.c +++ b/drivers/iio/accel/adis16201.c @@ -268,7 +268,6 @@ static int adis16201_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); indio_dev->name = spi->dev.driver->name; indio_dev->info = &adis16201_info; diff --git a/drivers/iio/accel/adis16209.c b/drivers/iio/accel/adis16209.c index 4a841aec6268..6c2d4a967de7 100644 --- a/drivers/iio/accel/adis16209.c +++ b/drivers/iio/accel/adis16209.c @@ -279,7 +279,6 @@ static int adis16209_probe(struct spi_device *spi) return -ENOMEM; st = iio_priv(indio_dev); - spi_set_drvdata(spi, indio_dev); indio_dev->name = spi->dev.driver->name; indio_dev->info = &adis16209_info; diff --git a/drivers/iio/accel/adxl372.c b/drivers/iio/accel/adxl372.c index aed2a4930fb0..8ba1453b8dbf 100644 --- a/drivers/iio/accel/adxl372.c +++ b/drivers/iio/accel/adxl372.c @@ -1211,15 +1211,14 @@ int adxl372_probe(struct device *dev, struct regmap *regmap, return ret; } - ret = devm_iio_triggered_buffer_setup(dev, - indio_dev, NULL, - adxl372_trigger_handler, - &adxl372_buffer_ops); + ret = devm_iio_triggered_buffer_setup_ext(dev, + indio_dev, NULL, + adxl372_trigger_handler, + &adxl372_buffer_ops, + adxl372_fifo_attributes); if (ret < 0) return ret; - iio_buffer_set_attrs(indio_dev->buffer, adxl372_fifo_attributes); - if (st->irq) { st->dready_trig = devm_iio_trigger_alloc(dev, "%s-dev%d", diff --git a/drivers/iio/accel/bmc150-accel-core.c b/drivers/iio/accel/bmc150-accel-core.c index 48435865fdaf..c641ee552038 100644 --- a/drivers/iio/accel/bmc150-accel-core.c +++ b/drivers/iio/accel/bmc150-accel-core.c @@ -1558,6 +1558,7 @@ static int bmc150_accel_chip_init(struct bmc150_accel_data *data) int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, const char *name, bool block_supported) { + const struct attribute **fifo_attrs; struct bmc150_accel_data *data; struct iio_dev *indio_dev; int ret; @@ -1590,10 +1591,19 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmc150_accel_info; - ret = iio_triggered_buffer_setup(indio_dev, - &iio_pollfunc_store_time, - bmc150_accel_trigger_handler, - &bmc150_accel_buffer_ops); + if (block_supported) { + indio_dev->modes |= INDIO_BUFFER_SOFTWARE; + indio_dev->info = &bmc150_accel_info_fifo; + fifo_attrs = bmc150_accel_fifo_attributes; + } else { + fifo_attrs = NULL; + } + + ret = iio_triggered_buffer_setup_ext(indio_dev, + &iio_pollfunc_store_time, + bmc150_accel_trigger_handler, + &bmc150_accel_buffer_ops, + fifo_attrs); if (ret < 0) { dev_err(dev, "Failed: iio triggered buffer setup\n"); return ret; @@ -1628,13 +1638,6 @@ int bmc150_accel_core_probe(struct device *dev, struct regmap *regmap, int irq, ret = bmc150_accel_triggers_setup(indio_dev, data); if (ret) goto err_buffer_cleanup; - - if (block_supported) { - indio_dev->modes |= INDIO_BUFFER_SOFTWARE; - indio_dev->info = &bmc150_accel_info_fifo; - iio_buffer_set_attrs(indio_dev->buffer, - bmc150_accel_fifo_attributes); - } } ret = pm_runtime_set_active(dev); diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c index bf1d2c8afdbd..b0176d936423 100644 --- a/drivers/iio/accel/mma8452.c +++ b/drivers/iio/accel/mma8452.c @@ -1187,7 +1187,7 @@ static struct attribute *mma8452_event_attributes[] = { NULL, }; -static struct attribute_group mma8452_event_attribute_group = { +static const struct attribute_group mma8452_event_attribute_group = { .attrs = mma8452_event_attributes, }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 91ae90514aff..15587a1bc80d 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -295,7 +295,7 @@ config ASPEED_ADC config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 || COMPILE_TEST - depends on INPUT && SYSFS + depends on INPUT && SYSFS && OF select IIO_BUFFER select IIO_TRIGGERED_BUFFER help @@ -703,6 +703,17 @@ config MCP3911 This driver can also be built as a module. If so, the module will be called mcp3911. +config MEDIATEK_MT6360_ADC + tristate "Mediatek MT6360 ADC driver" + depends on MFD_MT6360 + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say Y here to enable MT6360 ADC support. + Integrated for System Monitoring includes + is used in smartphones and tablets and supports a 11 channel + general purpose ADC. + config MEDIATEK_MT6577_AUXADC tristate "MediaTek AUXADC driver" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 90f94ada7b30..5fca90ada0ec 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -65,6 +65,7 @@ obj-$(CONFIG_MAX9611) += max9611.o obj-$(CONFIG_MCP320X) += mcp320x.o obj-$(CONFIG_MCP3422) += mcp3422.o obj-$(CONFIG_MCP3911) += mcp3911.o +obj-$(CONFIG_MEDIATEK_MT6360_ADC) += mt6360-adc.o obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o obj-$(CONFIG_MESON_SARADC) += meson_saradc.o diff --git a/drivers/iio/adc/ad7292.c b/drivers/iio/adc/ad7292.c index ab204e9199e9..70e33dd1c9f7 100644 --- a/drivers/iio/adc/ad7292.c +++ b/drivers/iio/adc/ad7292.c @@ -276,8 +276,6 @@ static int ad7292_probe(struct spi_device *spi) return -EINVAL; } - spi_set_drvdata(spi, indio_dev); - st->reg = devm_regulator_get_optional(&spi->dev, "vref"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); diff --git a/drivers/iio/adc/ad7298.c b/drivers/iio/adc/ad7298.c index 48d43cb0f932..fa1047f74a1f 100644 --- a/drivers/iio/adc/ad7298.c +++ b/drivers/iio/adc/ad7298.c @@ -23,8 +23,6 @@ #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> -#include <linux/platform_data/ad7298.h> - #define AD7298_WRITE BIT(15) /* write to the control register */ #define AD7298_REPEAT BIT(14) /* repeated conversion enable */ #define AD7298_CH(x) BIT(13 - (x)) /* channel select */ @@ -283,7 +281,6 @@ static const struct iio_info ad7298_info = { static int ad7298_probe(struct spi_device *spi) { - struct ad7298_platform_data *pdata = spi->dev.platform_data; struct ad7298_state *st; struct iio_dev *indio_dev; int ret; @@ -294,14 +291,18 @@ static int ad7298_probe(struct spi_device *spi) st = iio_priv(indio_dev); - if (pdata && pdata->ext_ref) + st->reg = devm_regulator_get_optional(&spi->dev, "vref"); + if (!IS_ERR(st->reg)) { st->ext_ref = AD7298_EXTREF; + } else { + ret = PTR_ERR(st->reg); + if (ret != -ENODEV) + return ret; - if (st->ext_ref) { - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) - return PTR_ERR(st->reg); + st->reg = NULL; + } + if (st->reg) { ret = regulator_enable(st->reg); if (ret) return ret; diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c index 0e93b0766eb4..5c0cbee03230 100644 --- a/drivers/iio/adc/ad7768-1.c +++ b/drivers/iio/adc/ad7768-1.c @@ -161,6 +161,7 @@ struct ad7768_state { struct completion completion; struct iio_trigger *trig; struct gpio_desc *gpio_sync_in; + const char *labels[ARRAY_SIZE(ad7768_channels)]; /* * DMA (thus cache coherency maintenance) requires the * transfer buffers to live in their own cache lines. @@ -407,6 +408,14 @@ static int ad7768_write_raw(struct iio_dev *indio_dev, } } +static int ad7768_read_label(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, char *label) +{ + struct ad7768_state *st = iio_priv(indio_dev); + + return sprintf(label, "%s\n", st->labels[chan->channel]); +} + static struct attribute *ad7768_attributes[] = { &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL @@ -420,6 +429,7 @@ static const struct iio_info ad7768_info = { .attrs = &ad7768_group, .read_raw = &ad7768_read_raw, .write_raw = &ad7768_write_raw, + .read_label = ad7768_read_label, .debugfs_reg_access = &ad7768_reg_access, }; @@ -532,6 +542,33 @@ static void ad7768_clk_disable(void *data) clk_disable_unprepare(st->mclk); } +static int ad7768_set_channel_label(struct iio_dev *indio_dev, + int num_channels) +{ + struct ad7768_state *st = iio_priv(indio_dev); + struct device *device = indio_dev->dev.parent; + struct fwnode_handle *fwnode; + struct fwnode_handle *child; + const char *label; + int crt_ch = 0; + + fwnode = dev_fwnode(device); + fwnode_for_each_child_node(fwnode, child) { + if (fwnode_property_read_u32(child, "reg", &crt_ch)) + continue; + + if (crt_ch >= num_channels) + continue; + + if (fwnode_property_read_string(child, "label", &label)) + continue; + + st->labels[crt_ch] = label; + } + + return 0; +} + static int ad7768_probe(struct spi_device *spi) { struct ad7768_state *st; @@ -604,6 +641,10 @@ static int ad7768_probe(struct spi_device *spi) init_completion(&st->completion); + ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels)); + if (ret) + return ret; + ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt, IRQF_TRIGGER_RISING | IRQF_ONESHOT, diff --git a/drivers/iio/adc/ad7887.c b/drivers/iio/adc/ad7887.c index 037bcb47693c..4f6f0e0e03ee 100644 --- a/drivers/iio/adc/ad7887.c +++ b/drivers/iio/adc/ad7887.c @@ -232,6 +232,13 @@ static const struct iio_info ad7887_info = { .read_raw = &ad7887_read_raw, }; +static void ad7887_reg_disable(void *data) +{ + struct regulator *reg = data; + + regulator_disable(reg); +} + static int ad7887_probe(struct spi_device *spi) { struct ad7887_platform_data *pdata = spi->dev.platform_data; @@ -246,14 +253,22 @@ static int ad7887_probe(struct spi_device *spi) st = iio_priv(indio_dev); - if (!pdata || !pdata->use_onchip_ref) { - st->reg = devm_regulator_get(&spi->dev, "vref"); - if (IS_ERR(st->reg)) + st->reg = devm_regulator_get_optional(&spi->dev, "vref"); + if (IS_ERR(st->reg)) { + if (PTR_ERR(st->reg) != -ENODEV) return PTR_ERR(st->reg); + st->reg = NULL; + } + + if (st->reg) { ret = regulator_enable(st->reg); if (ret) return ret; + + ret = devm_add_action_or_reset(&spi->dev, ad7887_reg_disable, st->reg); + if (ret) + return ret; } st->chip_info = @@ -269,7 +284,7 @@ static int ad7887_probe(struct spi_device *spi) /* Setup default message */ mode = AD7887_PM_MODE4; - if (!pdata || !pdata->use_onchip_ref) + if (!st->reg) mode |= AD7887_REF_DIS; if (pdata && pdata->en_dual) mode |= AD7887_DUAL; @@ -312,36 +327,13 @@ static int ad7887_probe(struct spi_device *spi) indio_dev->num_channels = st->chip_info->num_channels; } - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev, + &iio_pollfunc_store_time, &ad7887_trigger_handler, &ad7887_ring_setup_ops); if (ret) - goto error_disable_reg; - - ret = iio_device_register(indio_dev); - if (ret) - goto error_unregister_ring; - - return 0; -error_unregister_ring: - iio_triggered_buffer_cleanup(indio_dev); -error_disable_reg: - if (st->reg) - regulator_disable(st->reg); - - return ret; -} - -static int ad7887_remove(struct spi_device *spi) -{ - struct iio_dev *indio_dev = spi_get_drvdata(spi); - struct ad7887_state *st = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - if (st->reg) - regulator_disable(st->reg); + return ret; - return 0; + return devm_iio_device_register(&spi->dev, indio_dev); } static const struct spi_device_id ad7887_id[] = { @@ -355,7 +347,6 @@ static struct spi_driver ad7887_driver = { .name = "ad7887", }, .probe = ad7887_probe, - .remove = ad7887_remove, .id_table = ad7887_id, }; module_spi_driver(ad7887_driver); diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c index b917a4714a9c..6edcc99009d1 100644 --- a/drivers/iio/adc/at91-sama5d2_adc.c +++ b/drivers/iio/adc/at91-sama5d2_adc.c @@ -1013,21 +1013,6 @@ static struct iio_trigger *at91_adc_allocate_trigger(struct iio_dev *indio, return trig; } - -static int at91_adc_trigger_init(struct iio_dev *indio) -{ - struct at91_adc_state *st = iio_priv(indio); - - st->trig = at91_adc_allocate_trigger(indio, st->selected_trig->name); - if (IS_ERR(st->trig)) { - dev_err(&indio->dev, - "could not allocate trigger\n"); - return PTR_ERR(st->trig); - } - - return 0; -} - static void at91_adc_trigger_handler_nodma(struct iio_dev *indio_dev, struct iio_poll_func *pf) { @@ -1155,13 +1140,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) return IRQ_HANDLED; } -static int at91_adc_buffer_init(struct iio_dev *indio) -{ - return devm_iio_triggered_buffer_setup(&indio->dev, indio, - &iio_pollfunc_store_time, - &at91_adc_trigger_handler, &at91_buffer_setup_ops); -} - static unsigned at91_adc_startup_time(unsigned startup_time_min, unsigned adc_clk_khz) { @@ -1472,7 +1450,7 @@ static int at91_adc_write_raw(struct iio_dev *indio_dev, return 0; default: return -EINVAL; - }; + } } static void at91_adc_dma_init(struct platform_device *pdev) @@ -1691,6 +1669,44 @@ static const struct iio_info at91_adc_info = { .hwfifo_set_watermark = &at91_adc_set_watermark, }; +static int at91_adc_buffer_and_trigger_init(struct device *dev, + struct iio_dev *indio) +{ + struct at91_adc_state *st = iio_priv(indio); + const struct attribute **fifo_attrs; + int ret; + + if (st->selected_trig->hw_trig) + fifo_attrs = at91_adc_fifo_attributes; + else + fifo_attrs = NULL; + + ret = devm_iio_triggered_buffer_setup_ext(&indio->dev, indio, + &iio_pollfunc_store_time, + &at91_adc_trigger_handler, &at91_buffer_setup_ops, fifo_attrs); + if (ret < 0) { + dev_err(dev, "couldn't initialize the buffer.\n"); + return ret; + } + + if (!st->selected_trig->hw_trig) + return 0; + + st->trig = at91_adc_allocate_trigger(indio, st->selected_trig->name); + if (IS_ERR(st->trig)) { + dev_err(dev, "could not allocate trigger\n"); + return PTR_ERR(st->trig); + } + + /* + * Initially the iio buffer has a length of 2 and + * a watermark of 1 + */ + st->dma_st.watermark = 1; + + return 0; +} + static int at91_adc_probe(struct platform_device *pdev) { struct iio_dev *indio_dev; @@ -1826,27 +1842,9 @@ static int at91_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, indio_dev); - ret = at91_adc_buffer_init(indio_dev); - if (ret < 0) { - dev_err(&pdev->dev, "couldn't initialize the buffer.\n"); + ret = at91_adc_buffer_and_trigger_init(&pdev->dev, indio_dev); + if (ret < 0) goto per_clk_disable_unprepare; - } - - if (st->selected_trig->hw_trig) { - ret = at91_adc_trigger_init(indio_dev); - if (ret < 0) { - dev_err(&pdev->dev, "couldn't setup the triggers.\n"); - goto per_clk_disable_unprepare; - } - /* - * Initially the iio buffer has a length of 2 and - * a watermark of 1 - */ - st->dma_st.watermark = 1; - - iio_buffer_set_attrs(indio_dev->buffer, - at91_adc_fifo_attributes); - } if (dma_coerce_mask_and_coherent(&indio_dev->dev, DMA_BIT_MASK(32))) dev_info(&pdev->dev, "cannot set DMA mask to 32-bit\n"); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 9b2c548fae95..601708168082 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -22,8 +22,6 @@ #include <linux/slab.h> #include <linux/wait.h> -#include <linux/platform_data/at91_adc.h> - #include <linux/iio/iio.h> #include <linux/iio/buffer.h> #include <linux/iio/trigger.h> @@ -153,6 +151,25 @@ #define TOUCH_SHTIM 0xa #define TOUCH_SCTIM_US 10 /* 10us for the Touchscreen Switches Closure Time */ +enum atmel_adc_ts_type { + ATMEL_ADC_TOUCHSCREEN_NONE = 0, + ATMEL_ADC_TOUCHSCREEN_4WIRE = 4, + ATMEL_ADC_TOUCHSCREEN_5WIRE = 5, +}; + +/** + * struct at91_adc_trigger - description of triggers + * @name: name of the trigger advertised to the user + * @value: value to set in the ADC's trigger setup register + * to enable the trigger + * @is_external: Does the trigger rely on an external pin? + */ +struct at91_adc_trigger { + const char *name; + u8 value; + bool is_external; +}; + /** * struct at91_adc_reg_desc - Various informations relative to registers * @channel_base: Base offset for the channel data registers @@ -202,7 +219,7 @@ struct at91_adc_state { struct mutex lock; u8 num_channels; void __iomem *reg_base; - struct at91_adc_reg_desc *registers; + const struct at91_adc_reg_desc *registers; u32 startup_time; u8 sample_hold_time; bool sleep_mode; @@ -214,7 +231,7 @@ struct at91_adc_state { u32 res; /* resolution used for convertions */ bool low_res; /* the resolution corresponds to the lowest one */ wait_queue_head_t wq_data_avail; - struct at91_adc_caps *caps; + const struct at91_adc_caps *caps; /* * Following ADC channels are shared by touchscreen: @@ -550,7 +567,7 @@ static int at91_adc_configure_trigger(struct iio_trigger *trig, bool state) { struct iio_dev *idev = iio_trigger_get_drvdata(trig); struct at91_adc_state *st = iio_priv(idev); - struct at91_adc_reg_desc *reg = st->registers; + const struct at91_adc_reg_desc *reg = st->registers; u32 status = at91_adc_readl(st, reg->trigger_register); int value; u8 bit; @@ -829,8 +846,6 @@ static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz) return ticks; } -static const struct of_device_id at91_adc_dt_ids[]; - static int at91_adc_probe_dt_ts(struct device_node *node, struct at91_adc_state *st, struct device *dev) { @@ -875,11 +890,7 @@ static int at91_adc_probe_dt(struct iio_dev *idev, int i = 0, ret; u32 prop; - if (!node) - return -EINVAL; - - st->caps = (struct at91_adc_caps *) - of_match_device(at91_adc_dt_ids, &pdev->dev)->data; + st->caps = of_device_get_match_data(&pdev->dev); st->use_external = of_property_read_bool(node, "atmel,adc-use-external-triggers"); @@ -960,30 +971,6 @@ error_ret: return ret; } -static int at91_adc_probe_pdata(struct at91_adc_state *st, - struct platform_device *pdev) -{ - struct at91_adc_data *pdata = pdev->dev.platform_data; - - if (!pdata) - return -EINVAL; - - st->caps = (struct at91_adc_caps *) - platform_get_device_id(pdev)->driver_data; - - st->use_external = pdata->use_external_triggers; - st->vref_mv = pdata->vref; - st->channels_mask = pdata->channels_used; - st->num_channels = st->caps->num_channels; - st->startup_time = pdata->startup_time; - st->trigger_number = pdata->trigger_number; - st->trigger_list = pdata->trigger_list; - st->registers = &st->caps->registers; - st->touchscreen_type = pdata->touchscreen_type; - - return 0; -} - static const struct iio_info at91_adc_info = { .read_raw = &at91_adc_read_raw, }; @@ -1160,15 +1147,9 @@ static int at91_adc_probe(struct platform_device *pdev) st = iio_priv(idev); - if (pdev->dev.of_node) - ret = at91_adc_probe_dt(idev, pdev); - else - ret = at91_adc_probe_pdata(st, pdev); - - if (ret) { - dev_err(&pdev->dev, "No platform data available.\n"); - return -EINVAL; - } + ret = at91_adc_probe_dt(idev, pdev); + if (ret) + return ret; platform_set_drvdata(pdev, idev); @@ -1469,7 +1450,7 @@ static struct platform_driver at91_adc_driver = { .id_table = at91_adc_ids, .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(at91_adc_dt_ids), + .of_match_table = at91_adc_dt_ids, .pm = &at91_adc_pm_ops, }, }; diff --git a/drivers/iio/adc/cpcap-adc.c b/drivers/iio/adc/cpcap-adc.c index 64c3cc382311..f19c9aa93f17 100644 --- a/drivers/iio/adc/cpcap-adc.c +++ b/drivers/iio/adc/cpcap-adc.c @@ -557,6 +557,7 @@ static void cpcap_adc_setup_bank(struct cpcap_adc *ddata, break; case CPCAP_ADC_BATTP_PI16 ... CPCAP_ADC_BATTI_PI17: value1 |= CPCAP_BIT_RAND1; + break; default: break; } diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index 99f4404e9fd1..784c10deeb1a 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -7,6 +7,7 @@ * Copyright (C) 2013 Naveen Krishna Chatradhi <ch.naveen@samsung.com> */ +#include <linux/compiler.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/interrupt.h> @@ -135,6 +136,8 @@ struct exynos_adc { u32 value; unsigned int version; + bool ts_enabled; + bool read_ts; u32 ts_x; u32 ts_y; @@ -651,7 +654,7 @@ static irqreturn_t exynos_ts_isr(int irq, void *dev_id) bool pressed; int ret; - while (info->input->users) { + while (READ_ONCE(info->ts_enabled)) { ret = exynos_read_s3c64xx_ts(dev, &x, &y); if (ret == -ETIMEDOUT) break; @@ -731,6 +734,7 @@ static int exynos_adc_ts_open(struct input_dev *dev) { struct exynos_adc *info = input_get_drvdata(dev); + WRITE_ONCE(info->ts_enabled, true); enable_irq(info->tsirq); return 0; @@ -740,6 +744,7 @@ static void exynos_adc_ts_close(struct input_dev *dev) { struct exynos_adc *info = input_get_drvdata(dev); + WRITE_ONCE(info->ts_enabled, false); disable_irq(info->tsirq); } diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c index 1aafbe2cfe67..34c03a264f74 100644 --- a/drivers/iio/adc/ingenic-adc.c +++ b/drivers/iio/adc/ingenic-adc.c @@ -562,7 +562,7 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev, return IIO_AVAIL_LIST; default: return -EINVAL; - }; + } } static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index e03988698755..66dc452d643a 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -593,13 +593,11 @@ static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING, ONE_SAMPLE, val); - break; case IIO_CHAN_INFO_AVERAGE_RAW: return meson_sar_adc_get_sample(indio_dev, chan, MEAN_AVERAGING, EIGHT_SAMPLES, val); - break; case IIO_CHAN_INFO_SCALE: if (chan->type == IIO_VOLTAGE) { diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c new file mode 100644 index 000000000000..f57db3056fbe --- /dev/null +++ b/drivers/iio/adc/mt6360-adc.c @@ -0,0 +1,372 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/ktime.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/unaligned/be_byteshift.h> + +#include <linux/iio/buffer.h> +#include <linux/iio/iio.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define MT6360_REG_PMUCHGCTRL3 0x313 +#define MT6360_REG_PMUADCCFG 0x356 +#define MT6360_REG_PMUADCIDLET 0x358 +#define MT6360_REG_PMUADCRPT1 0x35A + +/* PMUCHGCTRL3 0x313 */ +#define MT6360_AICR_MASK GENMASK(7, 2) +#define MT6360_AICR_SHFT 2 +#define MT6360_AICR_400MA 0x6 +/* PMUADCCFG 0x356 */ +#define MT6360_ADCEN_MASK BIT(15) +/* PMUADCRPT1 0x35A */ +#define MT6360_PREFERCH_MASK GENMASK(7, 4) +#define MT6360_PREFERCH_SHFT 4 +#define MT6360_RPTCH_MASK GENMASK(3, 0) +#define MT6360_NO_PREFER 15 + +/* Time in ms */ +#define ADC_WAIT_TIME_MS 25 +#define ADC_CONV_TIMEOUT_MS 100 +#define ADC_LOOP_TIME_US 2000 + +enum { + MT6360_CHAN_USBID = 0, + MT6360_CHAN_VBUSDIV5, + MT6360_CHAN_VBUSDIV2, + MT6360_CHAN_VSYS, + MT6360_CHAN_VBAT, + MT6360_CHAN_IBUS, + MT6360_CHAN_IBAT, + MT6360_CHAN_CHG_VDDP, + MT6360_CHAN_TEMP_JC, + MT6360_CHAN_VREF_TS, + MT6360_CHAN_TS, + MT6360_CHAN_MAX +}; + +struct mt6360_adc_data { + struct device *dev; + struct regmap *regmap; + /* Due to only one set of ADC control, this lock is used to prevent the race condition */ + struct mutex adc_lock; + ktime_t last_off_timestamps[MT6360_CHAN_MAX]; +}; + +static int mt6360_adc_read_channel(struct mt6360_adc_data *mad, int channel, int *val) +{ + __be16 adc_enable; + u8 rpt[3]; + ktime_t predict_end_t, timeout; + unsigned int pre_wait_time; + int ret; + + mutex_lock(&mad->adc_lock); + + /* Select the preferred ADC channel */ + ret = regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK, + channel << MT6360_PREFERCH_SHFT); + if (ret) + goto out_adc_lock; + + adc_enable = cpu_to_be16(MT6360_ADCEN_MASK | BIT(channel)); + ret = regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable)); + if (ret) + goto out_adc_lock; + + predict_end_t = ktime_add_ms(mad->last_off_timestamps[channel], 2 * ADC_WAIT_TIME_MS); + + if (ktime_after(ktime_get(), predict_end_t)) + pre_wait_time = ADC_WAIT_TIME_MS; + else + pre_wait_time = 3 * ADC_WAIT_TIME_MS; + + if (msleep_interruptible(pre_wait_time)) { + ret = -ERESTARTSYS; + goto out_adc_conv; + } + + timeout = ktime_add_ms(ktime_get(), ADC_CONV_TIMEOUT_MS); + while (true) { + ret = regmap_raw_read(mad->regmap, MT6360_REG_PMUADCRPT1, rpt, sizeof(rpt)); + if (ret) + goto out_adc_conv; + + /* + * There are two functions, ZCV and TypeC OTP, running ADC VBAT and TS in + * background, and ADC samples are taken on a fixed frequency no matter read the + * previous one or not. + * To avoid conflict, We set minimum time threshold after enable ADC and + * check report channel is the same. + * The worst case is run the same ADC twice and background function is also running, + * ADC conversion sequence is desire channel before start ADC, background ADC, + * desire channel after start ADC. + * So the minimum correct data is three times of typical conversion time. + */ + if ((rpt[0] & MT6360_RPTCH_MASK) == channel) + break; + + if (ktime_compare(ktime_get(), timeout) > 0) { + ret = -ETIMEDOUT; + goto out_adc_conv; + } + + usleep_range(ADC_LOOP_TIME_US / 2, ADC_LOOP_TIME_US); + } + + *val = rpt[1] << 8 | rpt[2]; + ret = IIO_VAL_INT; + +out_adc_conv: + /* Only keep ADC enable */ + adc_enable = cpu_to_be16(MT6360_ADCEN_MASK); + regmap_raw_write(mad->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable)); + mad->last_off_timestamps[channel] = ktime_get(); + /* Config prefer channel to NO_PREFER */ + regmap_update_bits(mad->regmap, MT6360_REG_PMUADCRPT1, MT6360_PREFERCH_MASK, + MT6360_NO_PREFER << MT6360_PREFERCH_SHFT); +out_adc_lock: + mutex_unlock(&mad->adc_lock); + + return ret; +} + +static int mt6360_adc_read_scale(struct mt6360_adc_data *mad, int channel, int *val, int *val2) +{ + unsigned int regval; + int ret; + + switch (channel) { + case MT6360_CHAN_USBID: + case MT6360_CHAN_VSYS: + case MT6360_CHAN_VBAT: + case MT6360_CHAN_CHG_VDDP: + case MT6360_CHAN_VREF_TS: + case MT6360_CHAN_TS: + *val = 1250; + return IIO_VAL_INT; + case MT6360_CHAN_VBUSDIV5: + *val = 6250; + return IIO_VAL_INT; + case MT6360_CHAN_VBUSDIV2: + case MT6360_CHAN_IBUS: + case MT6360_CHAN_IBAT: + *val = 2500; + + if (channel == MT6360_CHAN_IBUS) { + /* IBUS will be affected by input current limit for the different Ron */ + /* Check whether the config is <400mA or not */ + ret = regmap_read(mad->regmap, MT6360_REG_PMUCHGCTRL3, ®val); + if (ret) + return ret; + + regval = (regval & MT6360_AICR_MASK) >> MT6360_AICR_SHFT; + if (regval < MT6360_AICR_400MA) + *val = 1900; + } + + return IIO_VAL_INT; + case MT6360_CHAN_TEMP_JC: + *val = 105; + *val2 = 100; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int mt6360_adc_read_offset(struct mt6360_adc_data *mad, int channel, int *val) +{ + *val = (channel == MT6360_CHAN_TEMP_JC) ? -80 : 0; + return IIO_VAL_INT; +} + +static int mt6360_adc_read_raw(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct mt6360_adc_data *mad = iio_priv(iio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return mt6360_adc_read_channel(mad, chan->channel, val); + case IIO_CHAN_INFO_SCALE: + return mt6360_adc_read_scale(mad, chan->channel, val, val2); + case IIO_CHAN_INFO_OFFSET: + return mt6360_adc_read_offset(mad, chan->channel, val); + } + + return -EINVAL; +} + +static const char *mt6360_channel_labels[MT6360_CHAN_MAX] = { + "usbid", "vbusdiv5", "vbusdiv2", "vsys", "vbat", "ibus", "ibat", "chg_vddp", + "temp_jc", "vref_ts", "ts", +}; + +static int mt6360_adc_read_label(struct iio_dev *iio_dev, const struct iio_chan_spec *chan, + char *label) +{ + return snprintf(label, PAGE_SIZE, "%s\n", mt6360_channel_labels[chan->channel]); +} + +static const struct iio_info mt6360_adc_iio_info = { + .read_raw = mt6360_adc_read_raw, + .read_label = mt6360_adc_read_label, +}; + +#define MT6360_ADC_CHAN(_idx, _type) { \ + .type = _type, \ + .channel = MT6360_CHAN_##_idx, \ + .scan_index = MT6360_CHAN_##_idx, \ + .datasheet_name = #_idx, \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 16, \ + .storagebits = 16, \ + .endianness = IIO_CPU, \ + }, \ + .indexed = 1, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_OFFSET), \ +} + +static const struct iio_chan_spec mt6360_adc_channels[] = { + MT6360_ADC_CHAN(USBID, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBUSDIV5, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBUSDIV2, IIO_VOLTAGE), + MT6360_ADC_CHAN(VSYS, IIO_VOLTAGE), + MT6360_ADC_CHAN(VBAT, IIO_VOLTAGE), + MT6360_ADC_CHAN(IBUS, IIO_CURRENT), + MT6360_ADC_CHAN(IBAT, IIO_CURRENT), + MT6360_ADC_CHAN(CHG_VDDP, IIO_VOLTAGE), + MT6360_ADC_CHAN(TEMP_JC, IIO_TEMP), + MT6360_ADC_CHAN(VREF_TS, IIO_VOLTAGE), + MT6360_ADC_CHAN(TS, IIO_VOLTAGE), + IIO_CHAN_SOFT_TIMESTAMP(MT6360_CHAN_MAX), +}; + +static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct mt6360_adc_data *mad = iio_priv(indio_dev); + struct { + u16 values[MT6360_CHAN_MAX]; + int64_t timestamp; + } data __aligned(8); + int i = 0, bit, val, ret; + + memset(&data, 0, sizeof(data)); + for_each_set_bit(bit, indio_dev->active_scan_mask, indio_dev->masklength) { + ret = mt6360_adc_read_channel(mad, bit, &val); + if (ret < 0) { + dev_warn(&indio_dev->dev, "Failed to get channel %d conversion val\n", bit); + goto out; + } + + data.values[i++] = val; + } + iio_push_to_buffers_with_timestamp(indio_dev, &data, iio_get_time_ns(indio_dev)); +out: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static inline int mt6360_adc_reset(struct mt6360_adc_data *info) +{ + __be16 adc_enable; + ktime_t all_off_time; + int i, ret; + + /* Clear ADC idle wait time to 0 */ + ret = regmap_write(info->regmap, MT6360_REG_PMUADCIDLET, 0); + if (ret) + return ret; + + /* Only keep ADC enable, but keep all channels off */ + adc_enable = cpu_to_be16(MT6360_ADCEN_MASK); + ret = regmap_raw_write(info->regmap, MT6360_REG_PMUADCCFG, &adc_enable, sizeof(adc_enable)); + if (ret) + return ret; + + /* Reset all channel off time to the current one */ + all_off_time = ktime_get(); + for (i = 0; i < MT6360_CHAN_MAX; i++) + info->last_off_timestamps[i] = all_off_time; + + return 0; +} + +static int mt6360_adc_probe(struct platform_device *pdev) +{ + struct mt6360_adc_data *mad; + struct regmap *regmap; + struct iio_dev *indio_dev; + int ret; + + regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!regmap) { + dev_err(&pdev->dev, "Failed to get parent regmap\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*mad)); + if (!indio_dev) + return -ENOMEM; + + mad = iio_priv(indio_dev); + mad->dev = &pdev->dev; + mad->regmap = regmap; + mutex_init(&mad->adc_lock); + + ret = mt6360_adc_reset(mad); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to reset adc\n"); + return ret; + } + + indio_dev->name = dev_name(&pdev->dev); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &mt6360_adc_iio_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = mt6360_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(mt6360_adc_channels); + + ret = devm_iio_triggered_buffer_setup(&pdev->dev, indio_dev, NULL, + mt6360_adc_trigger_handler, NULL); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate iio trigger buffer\n"); + return ret; + } + + return devm_iio_device_register(&pdev->dev, indio_dev); +} + +static const struct of_device_id __maybe_unused mt6360_adc_of_id[] = { + { .compatible = "mediatek,mt6360-adc", }, + {} +}; +MODULE_DEVICE_TABLE(of, mt6360_adc_of_id); + +static struct platform_driver mt6360_adc_driver = { + .driver = { + .name = "mt6360-adc", + .of_match_table = mt6360_adc_of_id, + }, + .probe = mt6360_adc_probe, +}; +module_platform_driver(mt6360_adc_driver); + +MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>"); +MODULE_DESCRIPTION("MT6360 ADC Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index a83199b212a4..9d1ad6e38e85 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -200,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, { u32 ckmode, presc, val; unsigned long rate; - int i, div; + int i, div, duty; /* stm32h7 bus clock is common for all ADC instances (mandatory) */ if (!priv->bclk) { @@ -224,6 +224,11 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, return -EINVAL; } + /* If duty is an error, kindly use at least /2 divider */ + duty = clk_get_scaled_duty_cycle(priv->aclk, 100); + if (duty < 0) + dev_warn(&pdev->dev, "adc clock duty: %d\n", duty); + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; presc = stm32h7_adc_ckmodes_spec[i].presc; @@ -232,6 +237,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (ckmode) continue; + /* + * For proper operation, clock duty cycle range is 49% + * to 51%. Apply at least /2 prescaler otherwise. + */ + if (div == 1 && (duty < 49 || duty > 51)) + continue; + if ((rate / div) <= priv->max_clk_rate) goto out; } @@ -244,6 +256,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, return -EINVAL; } + duty = clk_get_scaled_duty_cycle(priv->bclk, 100); + if (duty < 0) + dev_warn(&pdev->dev, "bus clock duty: %d\n", duty); + for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) { ckmode = stm32h7_adc_ckmodes_spec[i].ckmode; presc = stm32h7_adc_ckmodes_spec[i].presc; @@ -252,6 +268,9 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, if (!ckmode) continue; + if (div == 1 && (duty < 49 || duty > 51)) + continue; + if ((rate / div) <= priv->max_clk_rate) goto out; } diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 16c02c30dec7..c067c994dae2 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1353,7 +1353,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) * dma cyclic transfers are used, buffer is split into two periods. * There should be : * - always one buffer (period) dma is working on - * - one buffer (period) driver can push with iio_trigger_poll(). + * - one buffer (period) driver can push data. */ watermark = min(watermark, val * (unsigned)(sizeof(u16))); adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv); @@ -1616,31 +1616,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); - if (!adc->dma_chan) { - /* reset buffer index */ - adc->bufi = 0; - iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, - pf->timestamp); - } else { - int residue = stm32_adc_dma_residue(adc); - - while (residue >= indio_dev->scan_bytes) { - u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi]; - - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - pf->timestamp); - residue -= indio_dev->scan_bytes; - adc->bufi += indio_dev->scan_bytes; - if (adc->bufi >= adc->rx_buf_sz) - adc->bufi = 0; - } - } - + /* reset buffer index */ + adc->bufi = 0; + iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer, + pf->timestamp); iio_trigger_notify_done(indio_dev->trig); /* re-enable eoc irq */ - if (!adc->dma_chan) - stm32_adc_conv_irq_enable(adc); + stm32_adc_conv_irq_enable(adc); return IRQ_HANDLED; } diff --git a/drivers/iio/buffer/industrialio-buffer-dmaengine.c b/drivers/iio/buffer/industrialio-buffer-dmaengine.c index 93b4e9e6bb55..b0cb9a35f5cd 100644 --- a/drivers/iio/buffer/industrialio-buffer-dmaengine.c +++ b/drivers/iio/buffer/industrialio-buffer-dmaengine.c @@ -200,9 +200,8 @@ static struct iio_buffer *iio_dmaengine_buffer_alloc(struct device *dev, iio_dma_buffer_init(&dmaengine_buffer->queue, chan->device->dev, &iio_dmaengine_default_ops); - iio_buffer_set_attrs(&dmaengine_buffer->queue.buffer, - iio_dmaengine_buffer_attrs); + dmaengine_buffer->queue.buffer.attrs = iio_dmaengine_buffer_attrs; dmaengine_buffer->queue.buffer.access = &iio_dmaengine_buffer_ops; return &dmaengine_buffer->queue.buffer; diff --git a/drivers/iio/buffer/industrialio-triggered-buffer.c b/drivers/iio/buffer/industrialio-triggered-buffer.c index 6c20a83f887e..92b8aea3e063 100644 --- a/drivers/iio/buffer/industrialio-triggered-buffer.c +++ b/drivers/iio/buffer/industrialio-triggered-buffer.c @@ -9,18 +9,20 @@ #include <linux/module.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> +#include <linux/iio/buffer_impl.h> #include <linux/iio/kfifo_buf.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> /** - * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc + * iio_triggered_buffer_setup_ext() - Setup triggered buffer and pollfunc * @indio_dev: IIO device structure * @h: Function which will be used as pollfunc top half * @thread: Function which will be used as pollfunc bottom half * @setup_ops: Buffer setup functions to use for this device. * If NULL the default setup functions for triggered * buffers will be used. + * @buffer_attrs: Extra sysfs buffer attributes for this IIO buffer * * This function combines some common tasks which will normally be performed * when setting up a triggered buffer. It will allocate the buffer and the @@ -33,10 +35,11 @@ * To free the resources allocated by this function call * iio_triggered_buffer_cleanup(). */ -int iio_triggered_buffer_setup(struct iio_dev *indio_dev, +int iio_triggered_buffer_setup_ext(struct iio_dev *indio_dev, irqreturn_t (*h)(int irq, void *p), irqreturn_t (*thread)(int irq, void *p), - const struct iio_buffer_setup_ops *setup_ops) + const struct iio_buffer_setup_ops *setup_ops, + const struct attribute **buffer_attrs) { struct iio_buffer *buffer; int ret; @@ -67,6 +70,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev, /* Flag that polled ring buffering is possible */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; + buffer->attrs = buffer_attrs; + return 0; error_kfifo_free: @@ -74,10 +79,10 @@ error_kfifo_free: error_ret: return ret; } -EXPORT_SYMBOL(iio_triggered_buffer_setup); +EXPORT_SYMBOL(iio_triggered_buffer_setup_ext); /** - * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup() + * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup_ext() * @indio_dev: IIO device structure */ void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev) @@ -92,11 +97,12 @@ static void devm_iio_triggered_buffer_clean(struct device *dev, void *res) iio_triggered_buffer_cleanup(*(struct iio_dev **)res); } -int devm_iio_triggered_buffer_setup(struct device *dev, - struct iio_dev *indio_dev, - irqreturn_t (*h)(int irq, void *p), - irqreturn_t (*thread)(int irq, void *p), - const struct iio_buffer_setup_ops *ops) +int devm_iio_triggered_buffer_setup_ext(struct device *dev, + struct iio_dev *indio_dev, + irqreturn_t (*h)(int irq, void *p), + irqreturn_t (*thread)(int irq, void *p), + const struct iio_buffer_setup_ops *ops, + const struct attribute **buffer_attrs) { struct iio_dev **ptr; int ret; @@ -108,7 +114,8 @@ int devm_iio_triggered_buffer_setup(struct device *dev, *ptr = indio_dev; - ret = iio_triggered_buffer_setup(indio_dev, h, thread, ops); + ret = iio_triggered_buffer_setup_ext(indio_dev, h, thread, ops, + buffer_attrs); if (!ret) devres_add(dev, ptr); else @@ -116,7 +123,7 @@ int devm_iio_triggered_buffer_setup(struct device *dev, return ret; } -EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup); +EXPORT_SYMBOL_GPL(devm_iio_triggered_buffer_setup_ext); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers"); diff --git a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c index e3f507771f17..c833ec0ef214 100644 --- a/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c +++ b/drivers/iio/common/cros_ec_sensors/cros_ec_sensors_core.c @@ -359,19 +359,22 @@ int cros_ec_sensors_core_init(struct platform_device *pdev, if (ret) return ret; } else { + const struct attribute **fifo_attrs; + + if (has_hw_fifo) + fifo_attrs = cros_ec_sensor_fifo_attributes; + else + fifo_attrs = NULL; + /* * The only way to get samples in buffer is to set a * software trigger (systrig, hrtimer). */ - ret = devm_iio_triggered_buffer_setup( + ret = devm_iio_triggered_buffer_setup_ext( dev, indio_dev, NULL, trigger_capture, - NULL); + NULL, fifo_attrs); if (ret) return ret; - - if (has_hw_fifo) - iio_buffer_set_attrs(indio_dev->buffer, - cros_ec_sensor_fifo_attributes); } } diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index ff375790b7e8..064c32bec9c7 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -84,15 +84,6 @@ static const struct attribute *hid_sensor_fifo_attributes[] = { NULL, }; -static void hid_sensor_setup_batch_mode(struct iio_dev *indio_dev, - struct hid_sensor_common *st) -{ - if (!hid_sensor_batch_mode_supported(st)) - return; - - iio_buffer_set_attrs(indio_dev->buffer, hid_sensor_fifo_attributes); -} - static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state) { int state_val; @@ -247,11 +238,18 @@ static const struct iio_trigger_ops hid_sensor_trigger_ops = { int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, struct hid_sensor_common *attrb) { + const struct attribute **fifo_attrs; int ret; struct iio_trigger *trig; - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - NULL, NULL); + if (hid_sensor_batch_mode_supported(attrb)) + fifo_attrs = hid_sensor_fifo_attributes; + else + fifo_attrs = NULL; + + ret = iio_triggered_buffer_setup_ext(indio_dev, + &iio_pollfunc_store_time, + NULL, NULL, fifo_attrs); if (ret) { dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n"); return ret; @@ -276,8 +274,6 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, attrb->trigger = trig; indio_dev->trig = iio_trigger_get(trig); - hid_sensor_setup_batch_mode(indio_dev, attrb); - ret = pm_runtime_set_active(&indio_dev->dev); if (ret) goto error_unreg_trigger; diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index dae8d27e772d..6f6074a5d3db 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -141,9 +141,10 @@ config AD5696_I2C depends on I2C select AD5686 help - Say yes here to build support for Analog Devices AD5671R, AD5675R, - AD5694, AD5694R, AD5695R, AD5696, AD5696R Voltage Output Digital to - Analog Converter. + Say yes here to build support for Analog Devices AD5311R, AD5338R, + AD5671R, AD5675R, AD5691R, AD5692R, AD5693, AD5693R, AD5694, AD5694R, + AD5695R, AD5696, and AD5696R Digital to Analog converters. + To compile this driver as a module, choose M here: the module will be called ad5696. diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 148d9541f517..7d6792ac1020 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -210,6 +210,12 @@ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(0, 0, bits, _shift), \ } +#define DECLARE_AD5338_CHANNELS(name, bits, _shift) \ +static const struct iio_chan_spec name[] = { \ + AD5868_CHANNEL(0, 1, bits, _shift), \ + AD5868_CHANNEL(1, 8, bits, _shift), \ +} + #define DECLARE_AD5686_CHANNELS(name, bits, _shift) \ static const struct iio_chan_spec name[] = { \ AD5868_CHANNEL(0, 1, bits, _shift), \ @@ -252,6 +258,7 @@ static const struct iio_chan_spec name[] = { \ DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); +DECLARE_AD5338_CHANNELS(ad5338r_channels, 10, 6); DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); DECLARE_AD5679_CHANNELS(ad5674r_channels, 12, 4); DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); @@ -276,6 +283,12 @@ static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { .num_channels = 1, .regmap_type = AD5693_REGMAP, }, + [ID_AD5338R] = { + .channels = ad5338r_channels, + .int_vref_mv = 2500, + .num_channels = 2, + .regmap_type = AD5686_REGMAP, + }, [ID_AD5671R] = { .channels = ad5672_channels, .int_vref_mv = 2500, diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index a15f2970577e..d9c8ba413fe9 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -52,6 +52,7 @@ enum ad5686_supported_device_ids { ID_AD5310R, ID_AD5311R, + ID_AD5338R, ID_AD5671R, ID_AD5672R, ID_AD5674R, diff --git a/drivers/iio/dac/ad5696-i2c.c b/drivers/iio/dac/ad5696-i2c.c index ccf794caef43..a39eda7c02d2 100644 --- a/drivers/iio/dac/ad5696-i2c.c +++ b/drivers/iio/dac/ad5696-i2c.c @@ -72,6 +72,7 @@ static int ad5686_i2c_remove(struct i2c_client *i2c) static const struct i2c_device_id ad5686_i2c_id[] = { {"ad5311r", ID_AD5311R}, + {"ad5338r", ID_AD5338R}, {"ad5671r", ID_AD5671R}, {"ad5675r", ID_AD5675R}, {"ad5691r", ID_AD5691R}, @@ -87,9 +88,28 @@ static const struct i2c_device_id ad5686_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, ad5686_i2c_id); +static const struct of_device_id ad5686_of_match[] = { + { .compatible = "adi,ad5311r" }, + { .compatible = "adi,ad5338r" }, + { .compatible = "adi,ad5671r" }, + { .compatible = "adi,ad5675r" }, + { .compatible = "adi,ad5691r" }, + { .compatible = "adi,ad5692r" }, + { .compatible = "adi,ad5693" }, + { .compatible = "adi,ad5693r" }, + { .compatible = "adi,ad5694" }, + { .compatible = "adi,ad5694r" }, + { .compatible = "adi,ad5695r" }, + { .compatible = "adi,ad5696" }, + { .compatible = "adi,ad5696r" }, + {} +}; +MODULE_DEVICE_TABLE(of, ad5686_of_match); + static struct i2c_driver ad5686_i2c_driver = { .driver = { .name = "ad5696", + .of_match_table = ad5686_of_match, }, .probe = ad5686_i2c_probe, .remove = ad5686_i2c_remove, diff --git a/drivers/iio/dac/ad7303.c b/drivers/iio/dac/ad7303.c index 2e46def9d8ee..dbb4645ab6b1 100644 --- a/drivers/iio/dac/ad7303.c +++ b/drivers/iio/dac/ad7303.c @@ -17,8 +17,6 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include <linux/platform_data/ad7303.h> - #define AD7303_CFG_EXTERNAL_VREF BIT(15) #define AD7303_CFG_POWER_DOWN(ch) BIT(11 + (ch)) #define AD7303_CFG_ADDR_OFFSET 10 diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h index fd9a5f1d5e51..fced02cadcc3 100644 --- a/drivers/iio/iio_core.h +++ b/drivers/iio/iio_core.h @@ -17,6 +17,20 @@ struct iio_dev; extern struct device_type iio_device_type; +#define IIO_IOCTL_UNHANDLED 1 +struct iio_ioctl_handler { + struct list_head entry; + long (*ioctl)(struct iio_dev *indio_dev, struct file *filp, + unsigned int cmd, unsigned long arg); +}; + +long iio_device_ioctl(struct iio_dev *indio_dev, struct file *filp, + unsigned int cmd, unsigned long arg); + +void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, + struct iio_ioctl_handler *h); +void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h); + int __iio_add_chan_devattr(const char *postfix, struct iio_chan_spec const *chan, ssize_t (*func)(struct device *dev, @@ -74,7 +88,6 @@ static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {} int iio_device_register_eventset(struct iio_dev *indio_dev); void iio_device_unregister_eventset(struct iio_dev *indio_dev); void iio_device_wakeup_eventset(struct iio_dev *indio_dev); -int iio_event_getfd(struct iio_dev *indio_dev); struct iio_event_interface; bool iio_event_enabled(const struct iio_event_interface *ev_int); diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 222ebb26f013..431076dc0d2c 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -486,7 +486,6 @@ static int bmi160_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_SCALE: return bmi160_set_scale(data, bmi160_to_sensor(chan->type), val2); - break; case IIO_CHAN_INFO_SAMP_FREQ: return bmi160_set_odr(data, bmi160_to_sensor(chan->type), val, val2); diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig index 28f59d09208a..76c7abbd1ae8 100644 --- a/drivers/iio/imu/st_lsm6dsx/Kconfig +++ b/drivers/iio/imu/st_lsm6dsx/Kconfig @@ -12,8 +12,8 @@ config IIO_ST_LSM6DSX Say yes here to build support for STMicroelectronics LSM6DSx imu sensor. Supported devices: lsm6ds3, lsm6ds3h, lsm6dsl, lsm6dsm, ism330dlc, lsm6dso, lsm6dsox, asm330lhh, lsm6dsr, lsm6ds3tr-c, - ism330dhcx, lsm6dsrx, lsm6ds0 and the accelerometer/gyroscope - of lsm9ds1. + ism330dhcx, lsm6dsrx, lsm6ds0, the accelerometer/gyroscope + of lsm9ds1 and lsm6dst. To compile this driver as a module, choose M here: the module will be called st_lsm6dsx. diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h index 9275346a9cc1..1f31657a7a0e 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h @@ -28,6 +28,7 @@ #define ST_LSM9DS1_DEV_NAME "lsm9ds1-imu" #define ST_LSM6DS0_DEV_NAME "lsm6ds0" #define ST_LSM6DSRX_DEV_NAME "lsm6dsrx" +#define ST_LSM6DST_DEV_NAME "lsm6dst" enum st_lsm6dsx_hw_id { ST_LSM6DS3_ID, @@ -44,6 +45,7 @@ enum st_lsm6dsx_hw_id { ST_LSM9DS1_ID, ST_LSM6DS0_ID, ST_LSM6DSRX_ID, + ST_LSM6DST_ID, ST_LSM6DSX_MAX_ID, }; diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 12ed0a2e55e4..49923503b75a 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -14,7 +14,7 @@ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the * value of the decimation factor and ODR set for each FIFO data set. * - * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX: + * LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/LSM6DSRX/ISM330DHCX/LSM6DST: * The FIFO buffer can be configured to store data from gyroscope and * accelerometer. Each sample is queued with a tag (1B) indicating data * source (gyroscope, accelerometer, hw timer). diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c index 42f485634d04..5e584c6026f1 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c @@ -26,7 +26,7 @@ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000 * - FIFO size: 4KB * - * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX: + * - LSM6DSO/LSM6DSOX/ASM330LHH/LSM6DSR/ISM330DHCX/LSM6DST: * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416, * 833 * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16 @@ -1334,6 +1334,211 @@ static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = { .wakeup_src_x_mask = BIT(2), } }, + { + .wai = 0x6d, + .reset = { + .addr = 0x12, + .mask = BIT(0), + }, + .boot = { + .addr = 0x12, + .mask = BIT(7), + }, + .bdu = { + .addr = 0x12, + .mask = BIT(6), + }, + .max_fifo_size = 512, + .id = { + { + .hw_id = ST_LSM6DST_ID, + .name = ST_LSM6DST_DEV_NAME, + }, + }, + .channels = { + [ST_LSM6DSX_ID_ACC] = { + .chan = st_lsm6dsx_acc_channels, + .len = ARRAY_SIZE(st_lsm6dsx_acc_channels), + }, + [ST_LSM6DSX_ID_GYRO] = { + .chan = st_lsm6dsx_gyro_channels, + .len = ARRAY_SIZE(st_lsm6dsx_gyro_channels), + }, + }, + .drdy_mask = { + .addr = 0x13, + .mask = BIT(3), + }, + .odr_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, + .odr_avl[6] = { 833000, 0x07 }, + .odr_len = 7, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(7, 4), + }, + .odr_avl[0] = { 12500, 0x01 }, + .odr_avl[1] = { 26000, 0x02 }, + .odr_avl[2] = { 52000, 0x03 }, + .odr_avl[3] = { 104000, 0x04 }, + .odr_avl[4] = { 208000, 0x05 }, + .odr_avl[5] = { 416000, 0x06 }, + .odr_avl[6] = { 833000, 0x07 }, + .odr_len = 7, + }, + }, + .fs_table = { + [ST_LSM6DSX_ID_ACC] = { + .reg = { + .addr = 0x10, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_G_TO_M_S_2(61000), 0x0 }, + .fs_avl[1] = { IIO_G_TO_M_S_2(122000), 0x2 }, + .fs_avl[2] = { IIO_G_TO_M_S_2(244000), 0x3 }, + .fs_avl[3] = { IIO_G_TO_M_S_2(488000), 0x1 }, + .fs_len = 4, + }, + [ST_LSM6DSX_ID_GYRO] = { + .reg = { + .addr = 0x11, + .mask = GENMASK(3, 2), + }, + .fs_avl[0] = { IIO_DEGREE_TO_RAD(8750000), 0x0 }, + .fs_avl[1] = { IIO_DEGREE_TO_RAD(17500000), 0x1 }, + .fs_avl[2] = { IIO_DEGREE_TO_RAD(35000000), 0x2 }, + .fs_avl[3] = { IIO_DEGREE_TO_RAD(70000000), 0x3 }, + .fs_len = 4, + }, + }, + .irq_config = { + .irq1 = { + .addr = 0x0d, + .mask = BIT(3), + }, + .irq2 = { + .addr = 0x0e, + .mask = BIT(3), + }, + .lir = { + .addr = 0x56, + .mask = BIT(0), + }, + .clear_on_read = { + .addr = 0x56, + .mask = BIT(6), + }, + .irq1_func = { + .addr = 0x5e, + .mask = BIT(5), + }, + .irq2_func = { + .addr = 0x5f, + .mask = BIT(5), + }, + .hla = { + .addr = 0x12, + .mask = BIT(5), + }, + .od = { + .addr = 0x12, + .mask = BIT(4), + }, + }, + .batch = { + [ST_LSM6DSX_ID_ACC] = { + .addr = 0x09, + .mask = GENMASK(3, 0), + }, + [ST_LSM6DSX_ID_GYRO] = { + .addr = 0x09, + .mask = GENMASK(7, 4), + }, + }, + .fifo_ops = { + .update_fifo = st_lsm6dsx_update_fifo, + .read_fifo = st_lsm6dsx_read_tagged_fifo, + .fifo_th = { + .addr = 0x07, + .mask = GENMASK(8, 0), + }, + .fifo_diff = { + .addr = 0x3a, + .mask = GENMASK(9, 0), + }, + .th_wl = 1, + }, + .ts_settings = { + .timer_en = { + .addr = 0x19, + .mask = BIT(5), + }, + .decimator = { + .addr = 0x0a, + .mask = GENMASK(7, 6), + }, + .freq_fine = 0x63, + }, + .shub_settings = { + .page_mux = { + .addr = 0x01, + .mask = BIT(6), + }, + .master_en = { + .sec_page = true, + .addr = 0x14, + .mask = BIT(2), + }, + .pullup_en = { + .sec_page = true, + .addr = 0x14, + .mask = BIT(3), + }, + .aux_sens = { + .addr = 0x14, + .mask = GENMASK(1, 0), + }, + .wr_once = { + .addr = 0x14, + .mask = BIT(6), + }, + .num_ext_dev = 3, + .shub_out = { + .sec_page = true, + .addr = 0x02, + }, + .slv0_addr = 0x15, + .dw_slv0_addr = 0x21, + .batch_en = BIT(3), + }, + .event_settings = { + .enable_reg = { + .addr = 0x58, + .mask = BIT(7), + }, + .wakeup_reg = { + .addr = 0x5b, + .mask = GENMASK(5, 0), + }, + .wakeup_src_reg = 0x1b, + .wakeup_src_status_mask = BIT(3), + .wakeup_src_z_mask = BIT(0), + .wakeup_src_y_mask = BIT(1), + .wakeup_src_x_mask = BIT(2), + }, + }, }; int st_lsm6dsx_set_page(struct st_lsm6dsx_hw *hw, bool enable) diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c index 0fb32131afce..e0f945dde12d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c @@ -94,6 +94,10 @@ static const struct of_device_id st_lsm6dsx_i2c_of_match[] = { .compatible = "st,lsm6dsrx", .data = (void *)ST_LSM6DSRX_ID, }, + { + .compatible = "st,lsm6dst", + .data = (void *)ST_LSM6DST_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match); @@ -113,6 +117,7 @@ static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = { { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, + { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, {}, }; MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table); diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c index eb1086e4a951..c57895be8afe 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c @@ -94,6 +94,10 @@ static const struct of_device_id st_lsm6dsx_spi_of_match[] = { .compatible = "st,lsm6dsrx", .data = (void *)ST_LSM6DSRX_ID, }, + { + .compatible = "st,lsm6dst", + .data = (void *)ST_LSM6DST_ID, + }, {}, }; MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match); @@ -113,6 +117,7 @@ static const struct spi_device_id st_lsm6dsx_spi_id_table[] = { { ST_LSM9DS1_DEV_NAME, ST_LSM9DS1_ID }, { ST_LSM6DS0_DEV_NAME, ST_LSM6DS0_ID }, { ST_LSM6DSRX_DEV_NAME, ST_LSM6DSRX_ID }, + { ST_LSM6DST_DEV_NAME, ST_LSM6DST_ID }, {}, }; MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index a4f6bb96d4f4..9663dec3dcf3 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -210,18 +210,6 @@ void iio_buffer_init(struct iio_buffer *buffer) } EXPORT_SYMBOL(iio_buffer_init); -/** - * iio_buffer_set_attrs - Set buffer specific attributes - * @buffer: The buffer for which we are setting attributes - * @attrs: Pointer to a null terminated list of pointers to attributes - */ -void iio_buffer_set_attrs(struct iio_buffer *buffer, - const struct attribute **attrs) -{ - buffer->attrs = attrs; -} -EXPORT_SYMBOL_GPL(iio_buffer_set_attrs); - static ssize_t iio_show_scan_index(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 261d3b17edc9..7cae46f9bc0d 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -594,6 +594,7 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, { unsigned long long tmp; int tmp0, tmp1; + s64 tmp2; bool scale_db = false; switch (type) { @@ -616,10 +617,13 @@ static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type, else return scnprintf(buf, len, "%d.%09u", vals[0], vals[1]); case IIO_VAL_FRACTIONAL: - tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]); + tmp2 = div_s64((s64)vals[0] * 1000000000LL, vals[1]); tmp1 = vals[1]; - tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1); - return scnprintf(buf, len, "%d.%09u", tmp0, abs(tmp1)); + tmp0 = (int)div_s64_rem(tmp2, 1000000000, &tmp1); + if ((tmp2 < 0) && (tmp0 == 0)) + return snprintf(buf, len, "-0.%09u", abs(tmp1)); + else + return snprintf(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); @@ -669,6 +673,19 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals) } EXPORT_SYMBOL_GPL(iio_format_value); +static ssize_t iio_read_channel_label(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); + + if (!indio_dev->info->read_label) + return -EINVAL; + + return indio_dev->info->read_label(indio_dev, this_attr->c, buf); +} + static ssize_t iio_read_channel_info(struct device *dev, struct device_attribute *attr, char *buf) @@ -1137,6 +1154,29 @@ error_iio_dev_attr_free: return ret; } +static int iio_device_add_channel_label(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + int ret; + + if (!indio_dev->info->read_label) + return 0; + + ret = __iio_add_chan_devattr("label", + chan, + &iio_read_channel_label, + NULL, + 0, + IIO_SEPARATE, + &indio_dev->dev, + &iio_dev_opaque->channel_attr_list); + if (ret < 0) + return ret; + + return 1; +} + static int iio_device_add_info_mask_type(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, enum iio_shared_by shared_by, @@ -1270,6 +1310,11 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev, return ret; attrcount += ret; + ret = iio_device_add_channel_label(indio_dev, chan); + if (ret < 0) + return ret; + attrcount += ret; + if (chan->ext_info) { unsigned int i = 0; for (ext_info = chan->ext_info; ext_info->name; ext_info++) { @@ -1567,6 +1612,7 @@ struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv) } dev_set_name(&dev->dev, "iio:device%d", dev->id); INIT_LIST_HEAD(&iio_dev_opaque->buffer_list); + INIT_LIST_HEAD(&iio_dev_opaque->ioctl_handlers); return dev; } @@ -1660,37 +1706,61 @@ static int iio_chrdev_release(struct inode *inode, struct file *filp) return 0; } -/* Somewhat of a cross file organization violation - ioctls here are actually - * event related */ +void iio_device_ioctl_handler_register(struct iio_dev *indio_dev, + struct iio_ioctl_handler *h) +{ + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + + list_add_tail(&h->entry, &iio_dev_opaque->ioctl_handlers); +} + +void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h) +{ + list_del(&h->entry); +} + static long iio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct iio_dev *indio_dev = filp->private_data; - int __user *ip = (int __user *)arg; - int fd; + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_ioctl_handler *h; + int ret = -ENODEV; + + mutex_lock(&indio_dev->info_exist_lock); + /** + * The NULL check here is required to prevent crashing when a device + * is being removed while userspace would still have open file handles + * to try to access this device. + */ if (!indio_dev->info) - return -ENODEV; - - if (cmd == IIO_GET_EVENT_FD_IOCTL) { - fd = iio_event_getfd(indio_dev); - if (fd < 0) - return fd; - if (copy_to_user(ip, &fd, sizeof(fd))) - return -EFAULT; - return 0; + goto out_unlock; + + ret = -EINVAL; + list_for_each_entry(h, &iio_dev_opaque->ioctl_handlers, entry) { + ret = h->ioctl(indio_dev, filp, cmd, arg); + if (ret != IIO_IOCTL_UNHANDLED) + break; } - return -EINVAL; + + if (ret == IIO_IOCTL_UNHANDLED) + ret = -EINVAL; + +out_unlock: + mutex_unlock(&indio_dev->info_exist_lock); + + return ret; } static const struct file_operations iio_buffer_fileops = { - .read = iio_buffer_read_outer_addr, - .release = iio_chrdev_release, - .open = iio_chrdev_open, - .poll = iio_buffer_poll_addr, .owner = THIS_MODULE, .llseek = noop_llseek, + .read = iio_buffer_read_outer_addr, + .poll = iio_buffer_poll_addr, .unlocked_ioctl = iio_ioctl, .compat_ioctl = compat_ptr_ioctl, + .open = iio_chrdev_open, + .release = iio_chrdev_release, }; static int iio_check_unique_scan_index(struct iio_dev *indio_dev) @@ -1796,6 +1866,9 @@ EXPORT_SYMBOL(__iio_device_register); **/ void iio_device_unregister(struct iio_dev *indio_dev) { + struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); + struct iio_ioctl_handler *h, *t; + cdev_device_del(&indio_dev->chrdev, &indio_dev->dev); mutex_lock(&indio_dev->info_exist_lock); @@ -1806,6 +1879,9 @@ void iio_device_unregister(struct iio_dev *indio_dev) indio_dev->info = NULL; + list_for_each_entry_safe(h, t, &iio_dev_opaque->ioctl_handlers, entry) + list_del(&h->entry); + iio_device_wakeup_eventset(indio_dev); iio_buffer_wakeup_poll(indio_dev); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index 99ba657b8568..7e532117ac55 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -31,6 +31,7 @@ * @flags: file operations related flags including busy flag. * @group: event interface sysfs attribute group * @read_lock: lock to protect kfifo read operations + * @ioctl_handler: handler for event ioctl() calls */ struct iio_event_interface { wait_queue_head_t wait; @@ -40,6 +41,7 @@ struct iio_event_interface { unsigned long flags; struct attribute_group group; struct mutex read_lock; + struct iio_ioctl_handler ioctl_handler; }; bool iio_event_enabled(const struct iio_event_interface *ev_int) @@ -187,7 +189,7 @@ static const struct file_operations iio_event_chrdev_fileops = { .llseek = noop_llseek, }; -int iio_event_getfd(struct iio_dev *indio_dev) +static int iio_event_getfd(struct iio_dev *indio_dev) { struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev); struct iio_event_interface *ev_int = iio_dev_opaque->event_interface; @@ -473,6 +475,24 @@ static void iio_setup_ev_int(struct iio_event_interface *ev_int) mutex_init(&ev_int->read_lock); } +static long iio_event_ioctl(struct iio_dev *indio_dev, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int __user *ip = (int __user *)arg; + int fd; + + if (cmd == IIO_GET_EVENT_FD_IOCTL) { + fd = iio_event_getfd(indio_dev); + if (fd < 0) + return fd; + if (copy_to_user(ip, &fd, sizeof(fd))) + return -EFAULT; + return 0; + } + + return IIO_IOCTL_UNHANDLED; +} + static const char *iio_event_group_name = "events"; int iio_device_register_eventset(struct iio_dev *indio_dev) { @@ -526,6 +546,10 @@ int iio_device_register_eventset(struct iio_dev *indio_dev) ev_int->group.attrs[attrn++] = &p->dev_attr.attr; indio_dev->groups[indio_dev->groupcounter++] = &ev_int->group; + ev_int->ioctl_handler.ioctl = iio_event_ioctl; + iio_device_ioctl_handler_register(&iio_dev_opaque->indio_dev, + &ev_int->ioctl_handler); + return 0; error_free_setup_event_lines: @@ -558,6 +582,8 @@ void iio_device_unregister_eventset(struct iio_dev *indio_dev) if (ev_int == NULL) return; + + iio_device_ioctl_handler_unregister(&ev_int->ioctl_handler); iio_free_chan_devattr_list(&ev_int->dev_attr_list); kfree(ev_int->group.attrs); kfree(ev_int); diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c index 9afb3fcc74e6..547e7f9d6920 100644 --- a/drivers/iio/light/apds9960.c +++ b/drivers/iio/light/apds9960.c @@ -561,7 +561,7 @@ static int apds9960_write_raw(struct iio_dev *indio_dev, } default: return -EINVAL; - }; + } return 0; } diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index abc8d7db8dc1..5bf2bfbc5379 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -12,6 +12,8 @@ */ #include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/property.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/irq.h> @@ -703,7 +705,6 @@ static int tsl2563_probe(struct i2c_client *client, struct iio_dev *indio_dev; struct tsl2563_chip *chip; struct tsl2563_platform_data *pdata = client->dev.platform_data; - struct device_node *np = client->dev.of_node; int err = 0; u8 id = 0; @@ -738,13 +739,14 @@ static int tsl2563_probe(struct i2c_client *client, chip->calib0 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); chip->calib1 = tsl2563_calib_from_sysfs(CALIB_BASE_SYSFS); - if (pdata) + if (pdata) { chip->cover_comp_gain = pdata->cover_comp_gain; - else if (np) - of_property_read_u32(np, "amstaos,cover-comp-gain", - &chip->cover_comp_gain); - else - chip->cover_comp_gain = 1; + } else { + err = device_property_read_u32(&client->dev, "amstaos,cover-comp-gain", + &chip->cover_comp_gain); + if (err) + chip->cover_comp_gain = 1; + } dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); indio_dev->name = client->name; diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 765c44adac57..73a28e30dddc 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -652,6 +652,12 @@ static const struct dev_pm_ops vcnl4035_pm_ops = { vcnl4035_runtime_resume, NULL) }; +static const struct i2c_device_id vcnl4035_id[] = { + { "vcnl4035", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, vcnl4035_id); + static const struct of_device_id vcnl4035_of_match[] = { { .compatible = "vishay,vcnl4035", }, { } @@ -666,6 +672,7 @@ static struct i2c_driver vcnl4035_driver = { }, .probe = vcnl4035_probe, .remove = vcnl4035_remove, + .id_table = vcnl4035_id, }; module_i2c_driver(vcnl4035_driver); diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index fc6840f9c1fa..73e55ec815ec 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -190,7 +190,7 @@ static bool bmc150_magn_is_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bmc150_magn_is_volatile_reg(struct device *dev, unsigned int reg) diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index 08c00ac32bda..da136dbadc8f 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -13,7 +13,7 @@ static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg) @@ -51,7 +51,7 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) diff --git a/drivers/iio/proximity/sx9310.c b/drivers/iio/proximity/sx9310.c index 6d3f4ab8c6b2..a2f820997afc 100644 --- a/drivers/iio/proximity/sx9310.c +++ b/drivers/iio/proximity/sx9310.c @@ -16,6 +16,7 @@ #include <linux/i2c.h> #include <linux/irq.h> #include <linux/kernel.h> +#include <linux/log2.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/pm.h> @@ -48,30 +49,55 @@ #define SX9310_REG_PROX_CTRL0_SCANPERIOD_15MS 0x01 #define SX9310_REG_PROX_CTRL1 0x11 #define SX9310_REG_PROX_CTRL2 0x12 +#define SX9310_REG_PROX_CTRL2_COMBMODE_MASK GENMASK(7, 6) +#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3 (0x03 << 6) #define SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2 (0x02 << 6) +#define SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1 (0x01 << 6) +#define SX9310_REG_PROX_CTRL2_COMBMODE_CS3 (0x00 << 6) +#define SX9310_REG_PROX_CTRL2_SHIELDEN_MASK GENMASK(3, 2) #define SX9310_REG_PROX_CTRL2_SHIELDEN_DYNAMIC (0x01 << 2) +#define SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND (0x02 << 2) #define SX9310_REG_PROX_CTRL3 0x13 +#define SX9310_REG_PROX_CTRL3_GAIN0_MASK GENMASK(3, 2) #define SX9310_REG_PROX_CTRL3_GAIN0_X8 (0x03 << 2) +#define SX9310_REG_PROX_CTRL3_GAIN12_MASK GENMASK(1, 0) #define SX9310_REG_PROX_CTRL3_GAIN12_X4 0x02 #define SX9310_REG_PROX_CTRL4 0x14 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_MASK GENMASK(2, 0) #define SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST 0x07 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE 0x06 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_FINE 0x05 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM 0x04 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE 0x03 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE 0x02 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE 0x01 +#define SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST 0x00 #define SX9310_REG_PROX_CTRL5 0x15 #define SX9310_REG_PROX_CTRL5_RANGE_SMALL (0x03 << 6) +#define SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK GENMASK(3, 2) #define SX9310_REG_PROX_CTRL5_STARTUPSENS_CS1 (0x01 << 2) +#define SX9310_REG_PROX_CTRL5_RAWFILT_MASK GENMASK(1, 0) +#define SX9310_REG_PROX_CTRL5_RAWFILT_SHIFT 0 #define SX9310_REG_PROX_CTRL5_RAWFILT_1P25 0x02 #define SX9310_REG_PROX_CTRL6 0x16 #define SX9310_REG_PROX_CTRL6_AVGTHRESH_DEFAULT 0x20 #define SX9310_REG_PROX_CTRL7 0x17 #define SX9310_REG_PROX_CTRL7_AVGNEGFILT_2 (0x01 << 3) +#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK GENMASK(2, 0) +#define SX9310_REG_PROX_CTRL7_AVGPOSFILT_SHIFT 0 #define SX9310_REG_PROX_CTRL7_AVGPOSFILT_512 0x05 #define SX9310_REG_PROX_CTRL8 0x18 +#define SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK GENMASK(7, 3) #define SX9310_REG_PROX_CTRL9 0x19 #define SX9310_REG_PROX_CTRL8_9_PTHRESH_28 (0x08 << 3) #define SX9310_REG_PROX_CTRL8_9_PTHRESH_96 (0x11 << 3) #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_MASK GENMASK(5, 4) #define SX9310_REG_PROX_CTRL10_HYST_6PCT (0x01 << 4) +#define SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK GENMASK(3, 2) +#define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK GENMASK(1, 0) #define SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_2 0x01 #define SX9310_REG_PROX_CTRL11 0x1b #define SX9310_REG_PROX_CTRL12 0x1c @@ -144,16 +170,31 @@ struct sx9310_data { static const struct iio_event_spec sx9310_events[] = { { .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_RISING, + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_THRESH, + .dir = IIO_EV_DIR_FALLING, + .mask_shared_by_all = BIT(IIO_EV_INFO_PERIOD), + }, + { + .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_EITHER, - .mask_separate = BIT(IIO_EV_INFO_ENABLE), + .mask_separate = BIT(IIO_EV_INFO_ENABLE) | + BIT(IIO_EV_INFO_HYSTERESIS) | + BIT(IIO_EV_INFO_VALUE), }, }; #define SX9310_NAMED_CHANNEL(idx, name) \ { \ .type = IIO_PROXIMITY, \ - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \ + .info_mask_separate_available = \ + BIT(IIO_CHAN_INFO_HARDWAREGAIN), \ .indexed = 1, \ .channel = idx, \ .extend_name = name, \ @@ -426,6 +467,34 @@ out: return ret; } +static int sx9310_read_gain(struct sx9310_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int regval, gain; + int ret; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL3, ®val); + if (ret) + return ret; + + switch (chan->channel) { + case 0: + case 3: + gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN0_MASK, regval); + break; + case 1: + case 2: + gain = FIELD_GET(SX9310_REG_PROX_CTRL3_GAIN12_MASK, regval); + break; + default: + return -EINVAL; + } + + *val = 1 << gain; + + return IIO_VAL_INT; +} + static int sx9310_read_samp_freq(struct sx9310_data *data, int *val, int *val2) { unsigned int regval; @@ -461,6 +530,14 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, ret = sx9310_read_proximity(data, chan, val); iio_device_release_direct_mode(indio_dev); return ret; + case IIO_CHAN_INFO_HARDWAREGAIN: + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = sx9310_read_gain(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: @@ -468,6 +545,283 @@ static int sx9310_read_raw(struct iio_dev *indio_dev, } } +static const int sx9310_gain_vals[] = { 1, 2, 4, 8 }; + +static int sx9310_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (mask) { + case IIO_CHAN_INFO_HARDWAREGAIN: + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(sx9310_gain_vals); + *vals = sx9310_gain_vals; + return IIO_AVAIL_LIST; + } + + return -EINVAL; +} + +static const unsigned int sx9310_pthresh_codes[] = { + 2, 4, 6, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 72, 80, 88, 96, 112, + 128, 144, 160, 192, 224, 256, 320, 384, 512, 640, 768, 1024, 1536 +}; + +static int sx9310_get_thresh_reg(unsigned int channel) +{ + switch (channel) { + case 0: + case 3: + return SX9310_REG_PROX_CTRL8; + case 1: + case 2: + return SX9310_REG_PROX_CTRL9; + } + + return -EINVAL; +} + +static int sx9310_read_thresh(struct sx9310_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int reg; + unsigned int regval; + int ret; + + reg = ret = sx9310_get_thresh_reg(chan->channel); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, reg, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); + if (regval > ARRAY_SIZE(sx9310_pthresh_codes)) + return -EINVAL; + + *val = sx9310_pthresh_codes[regval]; + return IIO_VAL_INT; +} + +static int sx9310_read_hysteresis(struct sx9310_data *data, + const struct iio_chan_spec *chan, int *val) +{ + unsigned int regval, pthresh; + int ret; + + ret = sx9310_read_thresh(data, chan, &pthresh); + if (ret < 0) + return ret; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9310_REG_PROX_CTRL10_HYST_MASK, regval); + if (!regval) + regval = 5; + + /* regval is at most 5 */ + *val = pthresh >> (5 - regval); + + return IIO_VAL_INT; +} + +static int sx9310_read_far_debounce(struct sx9310_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9310_read_close_debounce(struct sx9310_data *data, int *val) +{ + unsigned int regval; + int ret; + + ret = regmap_read(data->regmap, SX9310_REG_PROX_CTRL10, ®val); + if (ret) + return ret; + + regval = FIELD_GET(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, regval); + if (regval) + *val = 1 << regval; + else + *val = 0; + + return IIO_VAL_INT; +} + +static int sx9310_read_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int *val, int *val2) +{ + struct sx9310_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9310_read_thresh(data, chan, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9310_read_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9310_read_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9310_read_hysteresis(data, chan, val); + default: + return -EINVAL; + } +} + +static int sx9310_write_thresh(struct sx9310_data *data, + const struct iio_chan_spec *chan, int val) +{ + unsigned int reg; + unsigned int regval; + int ret, i; + + reg = ret = sx9310_get_thresh_reg(chan->channel); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(sx9310_pthresh_codes); i++) { + if (sx9310_pthresh_codes[i] == val) { + regval = i; + break; + } + } + + if (i == ARRAY_SIZE(sx9310_pthresh_codes)) + return -EINVAL; + + regval = FIELD_PREP(SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, reg, + SX9310_REG_PROX_CTRL8_9_PTHRESH_MASK, regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_write_hysteresis(struct sx9310_data *data, + const struct iio_chan_spec *chan, int _val) +{ + unsigned int hyst, val = _val; + int ret, pthresh; + + ret = sx9310_read_thresh(data, chan, &pthresh); + if (ret < 0) + return ret; + + if (val == 0) + hyst = 0; + else if (val == pthresh >> 2) + hyst = 3; + else if (val == pthresh >> 3) + hyst = 2; + else if (val == pthresh >> 4) + hyst = 1; + else + return -EINVAL; + + hyst = FIELD_PREP(SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_HYST_MASK, hyst); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_write_far_debounce(struct sx9310_data *data, int val) +{ + int ret; + unsigned int regval; + + val = ilog2(val); + regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_FAR_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_write_close_debounce(struct sx9310_data *data, int val) +{ + int ret; + unsigned int regval; + + val = ilog2(val); + regval = FIELD_PREP(SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, val); + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL10, + SX9310_REG_PROX_CTRL10_CLOSE_DEBOUNCE_MASK, + regval); + mutex_unlock(&data->mutex); + + return ret; +} + +static int sx9310_write_event_val(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum iio_event_type type, + enum iio_event_direction dir, + enum iio_event_info info, int val, int val2) +{ + struct sx9310_data *data = iio_priv(indio_dev); + + if (chan->type != IIO_PROXIMITY) + return -EINVAL; + + switch (info) { + case IIO_EV_INFO_VALUE: + return sx9310_write_thresh(data, chan, val); + case IIO_EV_INFO_PERIOD: + switch (dir) { + case IIO_EV_DIR_RISING: + return sx9310_write_far_debounce(data, val); + case IIO_EV_DIR_FALLING: + return sx9310_write_close_debounce(data, val); + default: + return -EINVAL; + } + case IIO_EV_INFO_HYSTERESIS: + return sx9310_write_hysteresis(data, chan, val); + default: + return -EINVAL; + } +} + static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2) { int i, ret; @@ -492,6 +846,37 @@ static int sx9310_set_samp_freq(struct sx9310_data *data, int val, int val2) return ret; } +static int sx9310_write_gain(struct sx9310_data *data, + const struct iio_chan_spec *chan, int val) +{ + unsigned int gain, mask; + int ret; + + gain = ilog2(val); + + switch (chan->channel) { + case 0: + case 3: + mask = SX9310_REG_PROX_CTRL3_GAIN0_MASK; + gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN0_MASK, gain); + break; + case 1: + case 2: + mask = SX9310_REG_PROX_CTRL3_GAIN12_MASK; + gain = FIELD_PREP(SX9310_REG_PROX_CTRL3_GAIN12_MASK, gain); + break; + default: + return -EINVAL; + } + + mutex_lock(&data->mutex); + ret = regmap_update_bits(data->regmap, SX9310_REG_PROX_CTRL3, mask, + gain); + 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) @@ -501,10 +886,14 @@ static int sx9310_write_raw(struct iio_dev *indio_dev, if (chan->type != IIO_PROXIMITY) return -EINVAL; - if (mask != IIO_CHAN_INFO_SAMP_FREQ) - return -EINVAL; + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + return sx9310_set_samp_freq(data, val, val2); + case IIO_CHAN_INFO_HARDWAREGAIN: + return sx9310_write_gain(data, chan, val); + } - return sx9310_set_samp_freq(data, val, val2); + return -EINVAL; } static irqreturn_t sx9310_irq_handler(int irq, void *private) @@ -645,6 +1034,9 @@ static const struct attribute_group sx9310_attribute_group = { static const struct iio_info sx9310_info = { .attrs = &sx9310_attribute_group, .read_raw = sx9310_read_raw, + .read_avail = sx9310_read_avail, + .read_event_value = sx9310_read_event_val, + .write_event_value = sx9310_write_event_val, .write_raw = sx9310_write_raw, .read_event_config = sx9310_read_event_config, .write_event_config = sx9310_write_event_config, @@ -820,9 +1212,113 @@ static int sx9310_init_compensation(struct iio_dev *indio_dev) return ret; } +static const struct sx9310_reg_default * +sx9310_get_default_reg(struct sx9310_data *data, int i, + struct sx9310_reg_default *reg_def) +{ + int ret; + const struct device_node *np = data->client->dev.of_node; + u32 combined[SX9310_NUM_CHANNELS] = { 4, 4, 4, 4 }; + unsigned long comb_mask = 0; + const char *res; + u32 start = 0, raw = 0, pos = 0; + + memcpy(reg_def, &sx9310_default_regs[i], sizeof(*reg_def)); + if (!np) + return reg_def; + + switch (reg_def->reg) { + case SX9310_REG_PROX_CTRL2: + if (of_property_read_bool(np, "semtech,cs0-ground")) { + reg_def->def &= ~SX9310_REG_PROX_CTRL2_SHIELDEN_MASK; + reg_def->def |= SX9310_REG_PROX_CTRL2_SHIELDEN_GROUND; + } + + reg_def->def &= ~SX9310_REG_PROX_CTRL2_COMBMODE_MASK; + of_property_read_u32_array(np, "semtech,combined-sensors", + combined, ARRAY_SIZE(combined)); + for (i = 0; i < ARRAY_SIZE(combined); i++) { + if (combined[i] <= SX9310_NUM_CHANNELS) + comb_mask |= BIT(combined[i]); + } + + comb_mask &= 0xf; + if (comb_mask == (BIT(3) | BIT(2) | BIT(1) | BIT(0))) + reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1_CS2_CS3; + else if (comb_mask == (BIT(1) | BIT(2))) + reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS1_CS2; + else if (comb_mask == (BIT(0) | BIT(1))) + reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS0_CS1; + else if (comb_mask == BIT(3)) + reg_def->def |= SX9310_REG_PROX_CTRL2_COMBMODE_CS3; + + break; + case SX9310_REG_PROX_CTRL4: + ret = of_property_read_string(np, "semtech,resolution", &res); + if (ret) + break; + + reg_def->def &= ~SX9310_REG_PROX_CTRL4_RESOLUTION_MASK; + if (!strcmp(res, "coarsest")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSEST; + else if (!strcmp(res, "very-coarse")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_COARSE; + else if (!strcmp(res, "coarse")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_COARSE; + else if (!strcmp(res, "medium-coarse")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM_COARSE; + else if (!strcmp(res, "medium")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_MEDIUM; + else if (!strcmp(res, "fine")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINE; + else if (!strcmp(res, "very-fine")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_VERY_FINE; + else if (!strcmp(res, "finest")) + reg_def->def |= SX9310_REG_PROX_CTRL4_RESOLUTION_FINEST; + + break; + case SX9310_REG_PROX_CTRL5: + ret = of_property_read_u32(np, "semtech,startup-sensor", &start); + if (ret) { + start = FIELD_GET(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, + reg_def->def); + } + + reg_def->def &= ~SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK; + reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_STARTUPSENS_MASK, + start); + + ret = of_property_read_u32(np, "semtech,proxraw-strength", &raw); + if (ret) { + raw = FIELD_GET(SX9310_REG_PROX_CTRL5_RAWFILT_MASK, + reg_def->def); + } else { + raw = ilog2(raw); + } + + reg_def->def &= ~SX9310_REG_PROX_CTRL5_RAWFILT_MASK; + reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL5_RAWFILT_MASK, + raw); + break; + case SX9310_REG_PROX_CTRL7: + ret = of_property_read_u32(np, "semtech,avg-pos-strength", &pos); + if (ret) + break; + + pos = min(max(ilog2(pos), 3), 10) - 3; + reg_def->def &= ~SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK; + reg_def->def |= FIELD_PREP(SX9310_REG_PROX_CTRL7_AVGPOSFILT_MASK, + pos); + break; + } + + return reg_def; +} + static int sx9310_init_device(struct iio_dev *indio_dev) { struct sx9310_data *data = iio_priv(indio_dev); + struct sx9310_reg_default tmp; const struct sx9310_reg_default *initval; int ret; unsigned int i, val; @@ -840,7 +1336,7 @@ static int sx9310_init_device(struct iio_dev *indio_dev) /* Program some sane defaults. */ for (i = 0; i < ARRAY_SIZE(sx9310_default_regs); i++) { - initval = &sx9310_default_regs[i]; + initval = sx9310_get_default_reg(data, i, &tmp); ret = regmap_write(data->regmap, initval->reg, initval->def); if (ret) return ret; diff --git a/drivers/iio/proximity/vl53l0x-i2c.c b/drivers/iio/proximity/vl53l0x-i2c.c index 235e125aeb3a..cf38144b6f95 100644 --- a/drivers/iio/proximity/vl53l0x-i2c.c +++ b/drivers/iio/proximity/vl53l0x-i2c.c @@ -225,6 +225,12 @@ static int vl53l0x_probe(struct i2c_client *client) return devm_iio_device_register(&client->dev, indio_dev); } +static const struct i2c_device_id vl53l0x_id[] = { + { "vl53l0x", 0}, + { } +}; +MODULE_DEVICE_TABLE(i2c, vl53l0x_id); + static const struct of_device_id st_vl53l0x_dt_match[] = { { .compatible = "st,vl53l0x", }, { } @@ -237,6 +243,7 @@ static struct i2c_driver vl53l0x_driver = { .of_match_table = st_vl53l0x_dt_match, }, .probe_new = vl53l0x_probe, + .id_table = vl53l0x_id, }; module_i2c_driver(vl53l0x_driver); |