diff options
author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-12-13 15:37:24 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-12-13 15:37:24 +0300 |
commit | c6cbcdea7ab94120b676a4865e9782ed3c06dc80 (patch) | |
tree | 52942f6c443bae19327c286ed159ef1ddec1aa5f | |
parent | e894075934a44ef66413fd1046808542011d8552 (diff) | |
parent | db23d88756abd38e0995ea8449d0025b3de4b26b (diff) | |
download | linux-c6cbcdea7ab94120b676a4865e9782ed3c06dc80.tar.xz |
Merge tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next
Jonathan writes:
Second set of IIO new device support, features and cleanups for the 4.21 cycle.
Staging graduation
* ad2s90
- Driver for this resolver to digital chip.
New drivers and device support.
* ad5686
- Add support for ad5310r DAC and associated fix in value read back.
* exynos-adc
- Support for S5PV210 which is slightly different from other parts.
* mcp41010
- Driver supporting MCP41010, MCP41050, MCP41100, MCP42010, MCP42050 and
MCP42100 microchip potentiometers.
New ACPI ids.
* ak8975
- AKM9911 ACPI HID.
* kxcjk-1013
- KXJ2109 ACPI HID.
- KIOX010A ACPI HID.
New features
* ad5933
- Explicit DT binding.
* ad2s90
- Explicit DT binding including dropping spi setup that is done via dt
in favour of verifying the settings form DT.
* adt7316
- Explicit DT binding and support for gpio, irq_flags etc.
* stm32-adc
- Runtime power management.
Minor fixes and cleanups
* core
- Protect against missing info structure.
* ad2s90
- SPDX
- Add documentation fo the mutex.
* ad7280a
- Check allocation failure.
- Fix an accidental replacement of an error return.
* adt7316
- Switch some variables to be local and rename for consistency with other
drivers.
- Revert a false handling of 0 as an error introduced earlier this cycle.
* bmi160
- Use devm functions throughout probe() to avoid need for remove().
* hid-sensor-hub
- White space cleanup.
* hts221
- MAINTAINERS entry.
* lis302
- Use generic name in the DT binding doc.
* Messon-saradc
- Check for allocation error.
- Fix some presented clock names that break clk debugfs.
* qcom-spmi-adc
- A fix for initialization of the prescale property. Came late in the
cycle, so merge window is probably the best route for this.
* st_lsm6dsx
- Allow for variable read length to support wider range of slave devices.
* tag 'iio-for-4.21b' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (37 commits)
iio: adc: qcom-spmi-adc5: Initialize prescale properly
dt-bindings: iio: adc: exynos-adc: Add S5PV210 variant
iio: adc: Allow selection of Exynos ADC on S5PV210
iio: adc: exynos-adc: Add S5PV210 variant
iio: bmi160: use all devm functions in probe
iio: dac: ad5686: fix bit shift read register
iio:dac:ad5686: Add AD5310R support
Revert "Staging: iio: adt7316: Add an extra check for 'ret' equals to 0"
dt-bindings: iio: accel: use a generic node name for lis302
iio: core: check 'info' value before registering the device
staging: iio: adc: ad7280a: fix overwrite of the returned value
staging: iio: adc: ad7280a: check for devm_kasprint() failure
iio: humidity: hts221: add entry in MAINTAINERS file
iio: magnetometer: ak8975: Add the "AKM9911" ACPI HID
staging:iio:ad2s90: Move out of staging
staging:iio:ad2s90: Add comment to device state mutex
staging:iio:ad2s90: Replace license text w/ SPDX identifier
dt-bindings:iio:resolver: Add docs for ad2s90
staging:iio:ad2s90: Add max frequency check at probe
staging:iio:ad2s90: Remove spi setup that should be done via dt
...
37 files changed, 852 insertions, 298 deletions
diff --git a/Documentation/devicetree/bindings/iio/accel/lis302.txt b/Documentation/devicetree/bindings/iio/accel/lis302.txt index dfdce67826ba..764e28ec1a0a 100644 --- a/Documentation/devicetree/bindings/iio/accel/lis302.txt +++ b/Documentation/devicetree/bindings/iio/accel/lis302.txt @@ -64,7 +64,7 @@ Optional properties for all bus drivers: Example for a SPI device node: - lis302@0 { + accelerometer@0 { compatible = "st,lis302dl-spi"; reg = <0>; spi-max-frequency = <1000000>; @@ -89,7 +89,7 @@ Example for a SPI device node: Example for a I2C device node: - lis331dlh: lis331dlh@18 { + lis331dlh: accelerometer@18 { compatible = "st,lis331dlh", "st,lis3lv02d"; reg = <0x18>; Vdd-supply = <&lis3_reg>; diff --git a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt index 6c49db7f8ad2..a10c1f89037d 100644 --- a/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/samsung,exynos-adc.txt @@ -11,7 +11,7 @@ New driver handles the following Required properties: - compatible: Must be "samsung,exynos-adc-v1" - for exynos4412/5250 and s5pv210 controllers. + for exynos4412/5250 controllers. Must be "samsung,exynos-adc-v2" for future controllers. Must be "samsung,exynos3250-adc" for @@ -28,6 +28,8 @@ Required properties: the ADC in s3c2443 and compatibles Must be "samsung,s3c6410-adc" for the ADC in s3c6410 and compatibles + Must be "samsung,s5pv210-adc" for + the ADC in s5pv210 and compatibles - reg: List of ADC register address range - The base address and range of ADC register - The base address and range of ADC_PHY register (every diff --git a/Documentation/devicetree/bindings/iio/potentiometer/mcp41010.txt b/Documentation/devicetree/bindings/iio/potentiometer/mcp41010.txt new file mode 100644 index 000000000000..566711b9950c --- /dev/null +++ b/Documentation/devicetree/bindings/iio/potentiometer/mcp41010.txt @@ -0,0 +1,28 @@ +* Microchip MCP41010/41050/41100/42010/42050/42100 Digital Potentiometer + +Datasheet publicly available at: +http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf + +The node for this driver must be a child node of a SPI controller, hence +all mandatory properties described in + + Documentation/devicetree/bindings/spi/spi-bus.txt + +must be specified. + +Required properties: + - compatible: Must be one of the following, depending on the + model: + "microchip,mcp41010" + "microchip,mcp41050" + "microchip,mcp41100" + "microchip,mcp42010" + "microchip,mcp42050" + "microchip,mcp42100" + +Example: +potentiometer@0 { + compatible = "microchip,mcp41010"; + reg = <0>; + spi-max-frequency = <500000>; +}; diff --git a/Documentation/devicetree/bindings/iio/resolver/ad2s90.txt b/Documentation/devicetree/bindings/iio/resolver/ad2s90.txt new file mode 100644 index 000000000000..477d41fa6467 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/resolver/ad2s90.txt @@ -0,0 +1,31 @@ +Analog Devices AD2S90 Resolver-to-Digital Converter + +https://www.analog.com/en/products/ad2s90.html + +Required properties: + - compatible: should be "adi,ad2s90" + - reg: SPI chip select number for the device + - spi-max-frequency: set maximum clock frequency, must be 830000 + - spi-cpol and spi-cpha: + Either SPI mode (0,0) or (1,1) must be used, so specify none or both of + spi-cpha, spi-cpol. + +See for more details: + Documentation/devicetree/bindings/spi/spi-bus.txt + +Note about max frequency: + Chip's max frequency, as specified in its datasheet, is 2Mhz. But a 600ns + delay is expected between the application of a logic LO to CS and the + application of SCLK, as also specified. And since the delay is not + implemented in the spi code, to satisfy it, SCLK's period should be at most + 2 * 600ns, so the max frequency should be 1 / (2 * 6e-7), which gives + roughly 830000Hz. + +Example: +resolver@0 { + compatible = "adi,ad2s90"; + reg = <0>; + spi-max-frequency = <830000>; + spi-cpol; + spi-cpha; +}; diff --git a/MAINTAINERS b/MAINTAINERS index 771a87260c81..db9fcf23e7a2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6866,6 +6866,14 @@ L: linux-input@vger.kernel.org S: Maintained F: drivers/input/touchscreen/htcpen.c +HTS221 TEMPERATURE-HUMIDITY IIO DRIVER +M: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> +L: linux-iio@vger.kernel.org +W: http://www.st.com/ +S: Maintained +F: drivers/iio/humidity/hts221* +F: Documentation/devicetree/bindings/iio/humidity/hts221.txt + HUAWEI ETHERNET DRIVER M: Aviad Krawczyk <aviad.krawczyk@huawei.com> L: netdev@vger.kernel.org diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index 8600e4be88ad..7096e577b23f 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c @@ -1491,7 +1491,9 @@ static const struct acpi_device_id kx_acpi_match[] = { {"KXCJ9000", KXCJ91008}, {"KIOX0009", KXTJ21009}, {"KIOX000A", KXCJ91008}, + {"KIOX010A", KXCJ91008}, /* KXCJ91008 inside the display of a 2-in-1 */ {"KXTJ1009", KXTJ21009}, + {"KXJ2109", KXTJ21009}, {"SMO8500", KXCJ91008}, { }, }; diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index da9644b50846..7a3ca4ec0cb7 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -295,7 +295,7 @@ config EP93XX_ADC config EXYNOS_ADC tristate "Exynos ADC driver support" - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) + depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || (OF && COMPILE_TEST) depends on HAS_IOMEM help Core support for the ADC block found in the Samsung EXYNOS series diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c index f10443f92e4c..fa2d2b5767f3 100644 --- a/drivers/iio/adc/exynos_adc.c +++ b/drivers/iio/adc/exynos_adc.c @@ -115,6 +115,7 @@ #define MAX_ADC_V2_CHANNELS 10 #define MAX_ADC_V1_CHANNELS 8 #define MAX_EXYNOS3250_ADC_CHANNELS 2 +#define MAX_S5PV210_ADC_CHANNELS 10 /* Bit definitions common for ADC_V1 and ADC_V2 */ #define ADC_CON_EN_START (1u << 0) @@ -282,6 +283,16 @@ static const struct exynos_adc_data exynos_adc_v1_data = { .start_conv = exynos_adc_v1_start_conv, }; +static const struct exynos_adc_data exynos_adc_s5pv210_data = { + .num_channels = MAX_S5PV210_ADC_CHANNELS, + .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */ + + .init_hw = exynos_adc_v1_init_hw, + .exit_hw = exynos_adc_v1_exit_hw, + .clear_irq = exynos_adc_v1_clear_irq, + .start_conv = exynos_adc_v1_start_conv, +}; + static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info, unsigned long addr) { @@ -479,6 +490,9 @@ static const struct of_device_id exynos_adc_match[] = { .compatible = "samsung,s3c6410-adc", .data = &exynos_adc_s3c64xx_data, }, { + .compatible = "samsung,s5pv210-adc", + .data = &exynos_adc_s5pv210_data, + }, { .compatible = "samsung,exynos-adc-v1", .data = &exynos_adc_v1_data, }, { diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c index 26011254ffbc..729becb2d3d9 100644 --- a/drivers/iio/adc/meson_saradc.c +++ b/drivers/iio/adc/meson_saradc.c @@ -656,8 +656,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, struct clk_init_data init; const char *clk_parents[1]; - init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div", - indio_dev->dev.of_node); + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div", + dev_name(indio_dev->dev.parent)); + if (!init.name) + return -ENOMEM; + init.flags = 0; init.ops = &clk_divider_ops; clk_parents[0] = __clk_get_name(priv->clkin); @@ -675,8 +678,11 @@ static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, if (WARN_ON(IS_ERR(priv->adc_div_clk))) return PTR_ERR(priv->adc_div_clk); - init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en", - indio_dev->dev.of_node); + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en", + dev_name(indio_dev->dev.parent)); + if (!init.name) + return -ENOMEM; + init.flags = CLK_SET_RATE_PARENT; init.ops = &clk_gate_ops; clk_parents[0] = __clk_get_name(priv->adc_div_clk); diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index f9af6b082916..6a866cc187f7 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -423,6 +423,7 @@ struct adc5_channels { enum vadc_scale_fn_type scale_fn_type; }; +/* In these definitions, _pre refers to an index into adc5_prescale_ratios. */ #define ADC5_CHAN(_dname, _type, _mask, _pre, _scale) \ { \ .datasheet_name = _dname, \ @@ -443,63 +444,63 @@ struct adc5_channels { _pre, _scale) \ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = { - [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1, + [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0, SCALE_HW_CALIB_DEFAULT) - [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1, + [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0, SCALE_HW_CALIB_DEFAULT) - [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3, + [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3, + [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1, + [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0, SCALE_HW_CALIB_PMIC_THERM) - [ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 1, + [ADC5_USB_IN_I] = ADC5_CHAN_VOLT("usb_in_i_uv", 0, SCALE_HW_CALIB_DEFAULT) - [ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 16, + [ADC5_USB_IN_V_16] = ADC5_CHAN_VOLT("usb_in_v_div_16", 8, SCALE_HW_CALIB_DEFAULT) - [ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 1, + [ADC5_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0, SCALE_HW_CALIB_PM5_CHG_TEMP) /* Charger prescales SBUx and MID_CHG to fit within 1.8V upper unit */ - [ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 3, + [ADC5_SBUx] = ADC5_CHAN_VOLT("chg_sbux", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 6, + [ADC5_MID_CHG_DIV6] = ADC5_CHAN_VOLT("chg_mid_chg", 3, SCALE_HW_CALIB_DEFAULT) - [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 1, + [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm", 0, SCALE_HW_CALIB_XOTHERM) - [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1, + [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1, + [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1, + [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 1, + [ADC5_AMUX_THM2] = ADC5_CHAN_TEMP("amux_thm2", 0, SCALE_HW_CALIB_PM5_SMB_TEMP) }; static const struct adc5_channels adc5_chans_rev2[ADC5_MAX_CHANNEL] = { - [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 1, + [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0, SCALE_HW_CALIB_DEFAULT) - [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 1, + [ADC5_1P25VREF] = ADC5_CHAN_VOLT("vref_1p25", 0, SCALE_HW_CALIB_DEFAULT) - [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 3, + [ADC5_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 3, + [ADC5_VBAT_SNS] = ADC5_CHAN_VOLT("vbat_sns", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 3, + [ADC5_VCOIN] = ADC5_CHAN_VOLT("vcoin", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 1, + [ADC5_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0, SCALE_HW_CALIB_PMIC_THERM) - [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 1, + [ADC5_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 1, + [ADC5_AMUX_THM2_100K_PU] = ADC5_CHAN_TEMP("amux_thm2_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 1, + [ADC5_AMUX_THM3_100K_PU] = ADC5_CHAN_TEMP("amux_thm3_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 1, + [ADC5_AMUX_THM4_100K_PU] = ADC5_CHAN_TEMP("amux_thm4_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 1, + [ADC5_AMUX_THM5_100K_PU] = ADC5_CHAN_TEMP("amux_thm5_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 1, + [ADC5_XO_THERM_100K_PU] = ADC5_CHAN_TEMP("xo_therm_100k_pu", 0, SCALE_HW_CALIB_THERM_100K_PULLUP) }; @@ -558,6 +559,9 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, return ret; } prop->prescale = ret; + } else { + prop->prescale = + adc->data->adc_chans[prop->channel].prescale_index; } ret = of_property_read_u32(node, "qcom,hw-settle-time", &value); diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index ca432e7b6ff1..2327ec18b40c 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -16,6 +16,7 @@ #include <linux/irqdomain.h> #include <linux/module.h> #include <linux/of_device.h> +#include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> @@ -48,15 +49,19 @@ #define STM32H7_CKMODE_SHIFT 16 #define STM32H7_CKMODE_MASK GENMASK(17, 16) +#define STM32_ADC_CORE_SLEEP_DELAY_MS 2000 + /** * stm32_adc_common_regs - stm32 common registers, compatible dependent data * @csr: common status register offset + * @ccr: common control register offset * @eoc1: adc1 end of conversion flag in @csr * @eoc2: adc2 end of conversion flag in @csr * @eoc3: adc3 end of conversion flag in @csr */ struct stm32_adc_common_regs { u32 csr; + u32 ccr; u32 eoc1_msk; u32 eoc2_msk; u32 eoc3_msk; @@ -85,6 +90,7 @@ struct stm32_adc_priv_cfg { * @vref: regulator reference * @cfg: compatible configuration data * @common: common data for all ADC instances + * @ccr_bak: backup CCR in low power mode */ struct stm32_adc_priv { int irq[STM32_ADC_MAX_ADCS]; @@ -94,6 +100,7 @@ struct stm32_adc_priv { struct regulator *vref; const struct stm32_adc_priv_cfg *cfg; struct stm32_adc_common common; + u32 ccr_bak; }; static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) @@ -265,6 +272,7 @@ out: /* STM32F4 common registers definitions */ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { .csr = STM32F4_ADC_CSR, + .ccr = STM32F4_ADC_CCR, .eoc1_msk = STM32F4_EOC1, .eoc2_msk = STM32F4_EOC2, .eoc3_msk = STM32F4_EOC3, @@ -273,6 +281,7 @@ static const struct stm32_adc_common_regs stm32f4_adc_common_regs = { /* STM32H7 common registers definitions */ static const struct stm32_adc_common_regs stm32h7_adc_common_regs = { .csr = STM32H7_ADC_CSR, + .ccr = STM32H7_ADC_CCR, .eoc1_msk = STM32H7_EOC_MST, .eoc2_msk = STM32H7_EOC_SLV, }; @@ -379,6 +388,61 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, } } +static int stm32_adc_core_hw_start(struct device *dev) +{ + struct stm32_adc_common *common = dev_get_drvdata(dev); + struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + int ret; + + ret = regulator_enable(priv->vref); + if (ret < 0) { + dev_err(dev, "vref enable failed\n"); + return ret; + } + + if (priv->bclk) { + ret = clk_prepare_enable(priv->bclk); + if (ret < 0) { + dev_err(dev, "bus clk enable failed\n"); + goto err_regulator_disable; + } + } + + if (priv->aclk) { + ret = clk_prepare_enable(priv->aclk); + if (ret < 0) { + dev_err(dev, "adc clk enable failed\n"); + goto err_bclk_disable; + } + } + + writel_relaxed(priv->ccr_bak, priv->common.base + priv->cfg->regs->ccr); + + return 0; + +err_bclk_disable: + if (priv->bclk) + clk_disable_unprepare(priv->bclk); +err_regulator_disable: + regulator_disable(priv->vref); + + return ret; +} + +static void stm32_adc_core_hw_stop(struct device *dev) +{ + struct stm32_adc_common *common = dev_get_drvdata(dev); + struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + + /* Backup CCR that may be lost (depends on power state to achieve) */ + priv->ccr_bak = readl_relaxed(priv->common.base + priv->cfg->regs->ccr); + if (priv->aclk) + clk_disable_unprepare(priv->aclk); + if (priv->bclk) + clk_disable_unprepare(priv->bclk); + regulator_disable(priv->vref); +} + static int stm32_adc_probe(struct platform_device *pdev) { struct stm32_adc_priv *priv; @@ -393,6 +457,7 @@ static int stm32_adc_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + platform_set_drvdata(pdev, &priv->common); priv->cfg = (const struct stm32_adc_priv_cfg *) of_match_device(dev->driver->of_match_table, dev)->data; @@ -410,67 +475,51 @@ static int stm32_adc_probe(struct platform_device *pdev) return ret; } - ret = regulator_enable(priv->vref); - if (ret < 0) { - dev_err(&pdev->dev, "vref enable failed\n"); - return ret; - } - - ret = regulator_get_voltage(priv->vref); - if (ret < 0) { - dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret); - goto err_regulator_disable; - } - priv->common.vref_mv = ret / 1000; - dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); - priv->aclk = devm_clk_get(&pdev->dev, "adc"); if (IS_ERR(priv->aclk)) { ret = PTR_ERR(priv->aclk); - if (ret == -ENOENT) { - priv->aclk = NULL; - } else { + if (ret != -ENOENT) { dev_err(&pdev->dev, "Can't get 'adc' clock\n"); - goto err_regulator_disable; - } - } - - if (priv->aclk) { - ret = clk_prepare_enable(priv->aclk); - if (ret < 0) { - dev_err(&pdev->dev, "adc clk enable failed\n"); - goto err_regulator_disable; + return ret; } + priv->aclk = NULL; } priv->bclk = devm_clk_get(&pdev->dev, "bus"); if (IS_ERR(priv->bclk)) { ret = PTR_ERR(priv->bclk); - if (ret == -ENOENT) { - priv->bclk = NULL; - } else { + if (ret != -ENOENT) { dev_err(&pdev->dev, "Can't get 'bus' clock\n"); - goto err_aclk_disable; + return ret; } + priv->bclk = NULL; } - if (priv->bclk) { - ret = clk_prepare_enable(priv->bclk); - if (ret < 0) { - dev_err(&pdev->dev, "adc clk enable failed\n"); - goto err_aclk_disable; - } + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, STM32_ADC_CORE_SLEEP_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + ret = stm32_adc_core_hw_start(dev); + if (ret) + goto err_pm_stop; + + ret = regulator_get_voltage(priv->vref); + if (ret < 0) { + dev_err(&pdev->dev, "vref get voltage failed, %d\n", ret); + goto err_hw_stop; } + priv->common.vref_mv = ret / 1000; + dev_dbg(&pdev->dev, "vref+=%dmV\n", priv->common.vref_mv); ret = priv->cfg->clk_sel(pdev, priv); if (ret < 0) - goto err_bclk_disable; + goto err_hw_stop; ret = stm32_adc_irq_probe(pdev, priv); if (ret < 0) - goto err_bclk_disable; - - platform_set_drvdata(pdev, &priv->common); + goto err_hw_stop; ret = of_platform_populate(np, NULL, NULL, &pdev->dev); if (ret < 0) { @@ -478,21 +527,19 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_irq_remove; } + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; err_irq_remove: stm32_adc_irq_remove(pdev, priv); - -err_bclk_disable: - if (priv->bclk) - clk_disable_unprepare(priv->bclk); - -err_aclk_disable: - if (priv->aclk) - clk_disable_unprepare(priv->aclk); - -err_regulator_disable: - regulator_disable(priv->vref); +err_hw_stop: + stm32_adc_core_hw_stop(dev); +err_pm_stop: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); return ret; } @@ -502,17 +549,39 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc_common *common = platform_get_drvdata(pdev); struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + pm_runtime_get_sync(&pdev->dev); of_platform_depopulate(&pdev->dev); stm32_adc_irq_remove(pdev, priv); - if (priv->bclk) - clk_disable_unprepare(priv->bclk); - if (priv->aclk) - clk_disable_unprepare(priv->aclk); - regulator_disable(priv->vref); + stm32_adc_core_hw_stop(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); return 0; } +#if defined(CONFIG_PM) +static int stm32_adc_core_runtime_suspend(struct device *dev) +{ + stm32_adc_core_hw_stop(dev); + + return 0; +} + +static int stm32_adc_core_runtime_resume(struct device *dev) +{ + return stm32_adc_core_hw_start(dev); +} +#endif + +static const struct dev_pm_ops stm32_adc_core_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(stm32_adc_core_runtime_suspend, + stm32_adc_core_runtime_resume, + NULL) +}; + static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { .regs = &stm32f4_adc_common_regs, .clk_sel = stm32f4_adc_clk_sel, @@ -552,6 +621,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc-core", .of_match_table = stm32_adc_of_match, + .pm = &stm32_adc_core_pm_ops, }, }; module_platform_driver(stm32_adc_driver); diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 378411853d75..205e1699f954 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -22,6 +22,7 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> @@ -148,6 +149,7 @@ enum stm32h7_adc_dmngt { #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ #define STM32_ADC_TIMEOUT_US 100000 #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) +#define STM32_ADC_HW_STOP_DELAY_MS 100 #define STM32_DMA_BUFFER_SIZE PAGE_SIZE @@ -199,11 +201,13 @@ struct stm32_adc_trig_info { * @calfact_s: Calibration offset for single ended channels * @calfact_d: Calibration offset in differential * @lincalfact: Linearity calibration factor + * @calibrated: Indicates calibration status */ struct stm32_adc_calib { u32 calfact_s; u32 calfact_d; u32 lincalfact[STM32H7_LINCALFACT_NUM]; + bool calibrated; }; /** @@ -251,7 +255,6 @@ struct stm32_adc; * @trigs: external trigger sources * @clk_required: clock is required * @has_vregready: vregready status flag presence - * @selfcalib: optional routine for self-calibration * @prepare: optional prepare routine (power-up, enable) * @start_conv: routine to start conversions * @stop_conv: routine to stop conversions @@ -264,7 +267,6 @@ struct stm32_adc_cfg { struct stm32_adc_trig_info *trigs; bool clk_required; bool has_vregready; - int (*selfcalib)(struct stm32_adc *); int (*prepare)(struct stm32_adc *); void (*start_conv)(struct stm32_adc *, bool dma); void (*stop_conv)(struct stm32_adc *); @@ -623,6 +625,47 @@ static void stm32_adc_set_res(struct stm32_adc *adc) stm32_adc_writel(adc, res->reg, val); } +static int stm32_adc_hw_stop(struct device *dev) +{ + struct stm32_adc *adc = dev_get_drvdata(dev); + + if (adc->cfg->unprepare) + adc->cfg->unprepare(adc); + + if (adc->clk) + clk_disable_unprepare(adc->clk); + + return 0; +} + +static int stm32_adc_hw_start(struct device *dev) +{ + struct stm32_adc *adc = dev_get_drvdata(dev); + int ret; + + if (adc->clk) { + ret = clk_prepare_enable(adc->clk); + if (ret) + return ret; + } + + stm32_adc_set_res(adc); + + if (adc->cfg->prepare) { + ret = adc->cfg->prepare(adc); + if (ret) + goto err_clk_dis; + } + + return 0; + +err_clk_dis: + if (adc->clk) + clk_disable_unprepare(adc->clk); + + return ret; +} + /** * stm32f4_adc_start_conv() - Start conversions for regular channels. * @adc: stm32 adc instance @@ -777,6 +820,7 @@ static void stm32h7_adc_disable(struct stm32_adc *adc) /** * stm32h7_adc_read_selfcalib() - read calibration shadow regs, save result * @adc: stm32 adc instance + * Note: Must be called once ADC is enabled, so LINCALRDYW[1..6] are writable */ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) { @@ -784,11 +828,6 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) int i, ret; u32 lincalrdyw_mask, val; - /* Enable adc so LINCALRDYW1..6 bits are writable */ - ret = stm32h7_adc_enable(adc); - if (ret) - return ret; - /* Read linearity calibration */ lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { @@ -801,7 +840,7 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) 100, STM32_ADC_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "Failed to read calfact\n"); - goto disable; + return ret; } val = stm32_adc_readl(adc, STM32H7_ADC_CALFACT2); @@ -817,11 +856,9 @@ static int stm32h7_adc_read_selfcalib(struct stm32_adc *adc) adc->cal.calfact_s >>= STM32H7_CALFACT_S_SHIFT; adc->cal.calfact_d = (val & STM32H7_CALFACT_D_MASK); adc->cal.calfact_d >>= STM32H7_CALFACT_D_SHIFT; + adc->cal.calibrated = true; -disable: - stm32h7_adc_disable(adc); - - return ret; + return 0; } /** @@ -898,9 +935,9 @@ static int stm32h7_adc_restore_selfcalib(struct stm32_adc *adc) #define STM32H7_ADC_CALIB_TIMEOUT_US 100000 /** - * stm32h7_adc_selfcalib() - Procedure to calibrate ADC (from power down) + * stm32h7_adc_selfcalib() - Procedure to calibrate ADC * @adc: stm32 adc instance - * Exit from power down, calibrate ADC, then return to power down. + * Note: Must be called once ADC is out of power down. */ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) { @@ -908,9 +945,8 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) int ret; u32 val; - ret = stm32h7_adc_exit_pwr_down(adc); - if (ret) - return ret; + if (adc->cal.calibrated) + return true; /* * Select calibration mode: @@ -927,7 +963,7 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "calibration failed\n"); - goto pwr_dwn; + goto out; } /* @@ -944,18 +980,13 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { dev_err(&indio_dev->dev, "calibration failed\n"); - goto pwr_dwn; + goto out; } +out: stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_ADCALDIF | STM32H7_ADCALLIN); - /* Read calibration result for future reference */ - ret = stm32h7_adc_read_selfcalib(adc); - -pwr_dwn: - stm32h7_adc_enter_pwr_down(adc); - return ret; } @@ -972,19 +1003,28 @@ pwr_dwn: */ static int stm32h7_adc_prepare(struct stm32_adc *adc) { - int ret; + int calib, ret; ret = stm32h7_adc_exit_pwr_down(adc); if (ret) return ret; + ret = stm32h7_adc_selfcalib(adc); + if (ret < 0) + goto pwr_dwn; + calib = ret; + stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); ret = stm32h7_adc_enable(adc); if (ret) goto pwr_dwn; - ret = stm32h7_adc_restore_selfcalib(adc); + /* Either restore or read calibration result for future reference */ + if (calib) + ret = stm32h7_adc_restore_selfcalib(adc); + else + ret = stm32h7_adc_read_selfcalib(adc); if (ret) goto disable; @@ -1174,6 +1214,7 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, int *res) { struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; const struct stm32_adc_regspec *regs = adc->cfg->regs; long timeout; u32 val; @@ -1183,10 +1224,10 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, adc->bufi = 0; - if (adc->cfg->prepare) { - ret = adc->cfg->prepare(adc); - if (ret) - return ret; + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; } /* Apply sampling time settings */ @@ -1224,8 +1265,8 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev, stm32_adc_conv_irq_disable(adc); - if (adc->cfg->unprepare) - adc->cfg->unprepare(adc); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return ret; } @@ -1333,15 +1374,22 @@ static int stm32_adc_update_scan_mode(struct iio_dev *indio_dev, const unsigned long *scan_mask) { struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; int ret; + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + adc->num_conv = bitmap_weight(scan_mask, indio_dev->masklength); ret = stm32_adc_conf_scan_seq(indio_dev, scan_mask); - if (ret) - return ret; + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); - return 0; + return ret; } static int stm32_adc_of_xlate(struct iio_dev *indio_dev, @@ -1371,12 +1419,23 @@ static int stm32_adc_debugfs_reg_access(struct iio_dev *indio_dev, unsigned *readval) { struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + int ret; + + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } if (!readval) stm32_adc_writel(adc, reg, writeval); else *readval = stm32_adc_readl(adc, reg); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; } @@ -1459,21 +1518,22 @@ static int stm32_adc_dma_start(struct iio_dev *indio_dev) return 0; } -static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) +static int __stm32_adc_buffer_postenable(struct iio_dev *indio_dev) { struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; int ret; - if (adc->cfg->prepare) { - ret = adc->cfg->prepare(adc); - if (ret) - return ret; + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; } ret = stm32_adc_set_trig(indio_dev, indio_dev->trig); if (ret) { dev_err(&indio_dev->dev, "Can't set trigger\n"); - goto err_unprepare; + goto err_pm_put; } ret = stm32_adc_dma_start(indio_dev); @@ -1482,10 +1542,6 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) goto err_clr_trig; } - ret = iio_triggered_buffer_postenable(indio_dev); - if (ret < 0) - goto err_stop_dma; - /* Reset adc buffer index */ adc->bufi = 0; @@ -1496,39 +1552,58 @@ static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) return 0; -err_stop_dma: - if (adc->dma_chan) - dmaengine_terminate_all(adc->dma_chan); err_clr_trig: stm32_adc_set_trig(indio_dev, NULL); -err_unprepare: - if (adc->cfg->unprepare) - adc->cfg->unprepare(adc); +err_pm_put: + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return ret; } -static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +static int stm32_adc_buffer_postenable(struct iio_dev *indio_dev) { - struct stm32_adc *adc = iio_priv(indio_dev); int ret; + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret < 0) + return ret; + + ret = __stm32_adc_buffer_postenable(indio_dev); + if (ret < 0) + iio_triggered_buffer_predisable(indio_dev); + + return ret; +} + +static void __stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct device *dev = indio_dev->dev.parent; + adc->cfg->stop_conv(adc); if (!adc->dma_chan) stm32_adc_conv_irq_disable(adc); - ret = iio_triggered_buffer_predisable(indio_dev); - if (ret < 0) - dev_err(&indio_dev->dev, "predisable failed\n"); - if (adc->dma_chan) dmaengine_terminate_all(adc->dma_chan); if (stm32_adc_set_trig(indio_dev, NULL)) dev_err(&indio_dev->dev, "Can't clear trigger\n"); - if (adc->cfg->unprepare) - adc->cfg->unprepare(adc); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); +} + +static int stm32_adc_buffer_predisable(struct iio_dev *indio_dev) +{ + int ret; + + __stm32_adc_buffer_predisable(indio_dev); + + ret = iio_triggered_buffer_predisable(indio_dev); + if (ret < 0) + dev_err(&indio_dev->dev, "predisable failed\n"); return ret; } @@ -1867,32 +1942,17 @@ static int stm32_adc_probe(struct platform_device *pdev) } } - if (adc->clk) { - ret = clk_prepare_enable(adc->clk); - if (ret < 0) { - dev_err(&pdev->dev, "clk enable failed\n"); - return ret; - } - } - ret = stm32_adc_of_get_resolution(indio_dev); if (ret < 0) - goto err_clk_disable; - stm32_adc_set_res(adc); - - if (adc->cfg->selfcalib) { - ret = adc->cfg->selfcalib(adc); - if (ret) - goto err_clk_disable; - } + return ret; ret = stm32_adc_chan_of_init(indio_dev); if (ret < 0) - goto err_clk_disable; + return ret; ret = stm32_adc_dma_request(indio_dev); if (ret < 0) - goto err_clk_disable; + return ret; ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, @@ -1903,15 +1963,35 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_dma_disable; } + /* Get stm32-adc-core PM online */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); + + ret = stm32_adc_hw_start(dev); + if (ret) + goto err_buffer_cleanup; + ret = iio_device_register(indio_dev); if (ret) { dev_err(&pdev->dev, "iio dev register failed\n"); - goto err_buffer_cleanup; + goto err_hw_stop; } + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + return 0; +err_hw_stop: + stm32_adc_hw_stop(dev); + err_buffer_cleanup: + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); + pm_runtime_put_noidle(dev); iio_triggered_buffer_cleanup(indio_dev); err_dma_disable: @@ -1921,9 +2001,6 @@ err_dma_disable: adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } -err_clk_disable: - if (adc->clk) - clk_disable_unprepare(adc->clk); return ret; } @@ -1933,7 +2010,12 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc *adc = platform_get_drvdata(pdev); struct iio_dev *indio_dev = iio_priv_to_dev(adc); + pm_runtime_get_sync(&pdev->dev); iio_device_unregister(indio_dev); + stm32_adc_hw_stop(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); iio_triggered_buffer_cleanup(indio_dev); if (adc->dma_chan) { dma_free_coherent(adc->dma_chan->device->dev, @@ -1941,12 +2023,62 @@ static int stm32_adc_remove(struct platform_device *pdev) adc->rx_buf, adc->rx_dma_buf); dma_release_channel(adc->dma_chan); } - if (adc->clk) - clk_disable_unprepare(adc->clk); return 0; } +#if defined(CONFIG_PM_SLEEP) +static int stm32_adc_suspend(struct device *dev) +{ + struct stm32_adc *adc = dev_get_drvdata(dev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + + if (iio_buffer_enabled(indio_dev)) + __stm32_adc_buffer_predisable(indio_dev); + + return pm_runtime_force_suspend(dev); +} + +static int stm32_adc_resume(struct device *dev) +{ + struct stm32_adc *adc = dev_get_drvdata(dev); + struct iio_dev *indio_dev = iio_priv_to_dev(adc); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret < 0) + return ret; + + if (!iio_buffer_enabled(indio_dev)) + return 0; + + ret = stm32_adc_update_scan_mode(indio_dev, + indio_dev->active_scan_mask); + if (ret < 0) + return ret; + + return __stm32_adc_buffer_postenable(indio_dev); +} +#endif + +#if defined(CONFIG_PM) +static int stm32_adc_runtime_suspend(struct device *dev) +{ + return stm32_adc_hw_stop(dev); +} + +static int stm32_adc_runtime_resume(struct device *dev) +{ + return stm32_adc_hw_start(dev); +} +#endif + +static const struct dev_pm_ops stm32_adc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_adc_suspend, stm32_adc_resume) + SET_RUNTIME_PM_OPS(stm32_adc_runtime_suspend, stm32_adc_runtime_resume, + NULL) +}; + static const struct stm32_adc_cfg stm32f4_adc_cfg = { .regs = &stm32f4_adc_regspec, .adc_info = &stm32f4_adc_info, @@ -1961,7 +2093,6 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { .regs = &stm32h7_adc_regspec, .adc_info = &stm32h7_adc_info, .trigs = stm32h7_adc_trigs, - .selfcalib = stm32h7_adc_selfcalib, .start_conv = stm32h7_adc_start_conv, .stop_conv = stm32h7_adc_stop_conv, .prepare = stm32h7_adc_prepare, @@ -1974,7 +2105,6 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { .adc_info = &stm32h7_adc_info, .trigs = stm32h7_adc_trigs, .has_vregready = true, - .selfcalib = stm32h7_adc_selfcalib, .start_conv = stm32h7_adc_start_conv, .stop_conv = stm32h7_adc_stop_conv, .prepare = stm32h7_adc_prepare, @@ -1996,6 +2126,7 @@ static struct platform_driver stm32_adc_driver = { .driver = { .name = "stm32-adc", .of_match_table = stm32_adc_of_match, + .pm = &stm32_adc_pm_ops, }, }; module_platform_driver(stm32_adc_driver); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c index ed3849d6fc6a..b2143d7b4ccb 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -336,7 +336,7 @@ static void adjust_exponent_nano(int *val0, int *val1, int scale0, scale1 = scale1 % pow_10(8 - i); } *val0 += res; - *val1 = scale1 * pow_10(exp); + *val1 = scale1 * pow_10(exp); } else if (exp < 0) { exp = abs(exp); if (exp > 9) { diff --git a/drivers/iio/dac/ad5686-spi.c b/drivers/iio/dac/ad5686-spi.c index 1df9143f55e9..665fa6bd9ced 100644 --- a/drivers/iio/dac/ad5686-spi.c +++ b/drivers/iio/dac/ad5686-spi.c @@ -19,6 +19,12 @@ static int ad5686_spi_write(struct ad5686_state *st, u8 tx_len, *buf; switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) | + val); + buf = &st->data[0].d8[0]; + tx_len = 2; + break; case AD5683_REGMAP: st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5683_DATA(val)); @@ -56,10 +62,18 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr) u8 cmd = 0; int ret; - if (st->chip_info->regmap_type == AD5686_REGMAP) - cmd = AD5686_CMD_READBACK_ENABLE; - else if (st->chip_info->regmap_type == AD5683_REGMAP) + switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + return -ENOTSUPP; + case AD5683_REGMAP: cmd = AD5686_CMD_READBACK_ENABLE_V2; + break; + case AD5686_REGMAP: + cmd = AD5686_CMD_READBACK_ENABLE; + break; + default: + return -EINVAL; + } st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr)); @@ -86,6 +100,7 @@ static int ad5686_spi_remove(struct spi_device *spi) } static const struct spi_device_id ad5686_spi_id[] = { + {"ad5310r", ID_AD5310R}, {"ad5672r", ID_AD5672R}, {"ad5676", ID_AD5676}, {"ad5676r", ID_AD5676R}, diff --git a/drivers/iio/dac/ad5686.c b/drivers/iio/dac/ad5686.c index 0e134b13967a..a332b93ca2c4 100644 --- a/drivers/iio/dac/ad5686.c +++ b/drivers/iio/dac/ad5686.c @@ -83,6 +83,10 @@ static ssize_t ad5686_write_dac_powerdown(struct iio_dev *indio_dev, st->pwr_down_mask &= ~(0x3 << (chan->channel * 2)); switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + shift = 9; + ref_bit_msk = AD5310_REF_BIT_MSK; + break; case AD5683_REGMAP: shift = 13; ref_bit_msk = AD5683_REF_BIT_MSK; @@ -124,7 +128,8 @@ static int ad5686_read_raw(struct iio_dev *indio_dev, mutex_unlock(&indio_dev->mlock); if (ret < 0) return ret; - *val = ret; + *val = (ret >> chan->scan_type.shift) & + GENMASK(chan->scan_type.realbits - 1, 0); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: *val = st->vref_mv; @@ -221,6 +226,7 @@ static struct iio_chan_spec name[] = { \ AD5868_CHANNEL(7, 7, bits, _shift), \ } +DECLARE_AD5693_CHANNELS(ad5310r_channels, 10, 2); DECLARE_AD5693_CHANNELS(ad5311r_channels, 10, 6); DECLARE_AD5676_CHANNELS(ad5672_channels, 12, 4); DECLARE_AD5676_CHANNELS(ad5676_channels, 16, 0); @@ -232,6 +238,12 @@ DECLARE_AD5693_CHANNELS(ad5692r_channels, 14, 2); DECLARE_AD5693_CHANNELS(ad5691r_channels, 12, 4); static const struct ad5686_chip_info ad5686_chip_info_tbl[] = { + [ID_AD5310R] = { + .channels = ad5310r_channels, + .int_vref_mv = 2500, + .num_channels = 1, + .regmap_type = AD5310_REGMAP, + }, [ID_AD5311R] = { .channels = ad5311r_channels, .int_vref_mv = 2500, @@ -419,6 +431,11 @@ int ad5686_probe(struct device *dev, indio_dev->num_channels = st->chip_info->num_channels; switch (st->chip_info->regmap_type) { + case AD5310_REGMAP: + cmd = AD5686_CMD_CONTROL_REG; + ref_bit_msk = AD5310_REF_BIT_MSK; + st->use_internal_vref = !voltage_uv; + break; case AD5683_REGMAP: cmd = AD5686_CMD_CONTROL_REG; ref_bit_msk = AD5683_REF_BIT_MSK; diff --git a/drivers/iio/dac/ad5686.h b/drivers/iio/dac/ad5686.h index 57b3c61bfb91..19f6917d4738 100644 --- a/drivers/iio/dac/ad5686.h +++ b/drivers/iio/dac/ad5686.h @@ -13,7 +13,10 @@ #include <linux/mutex.h> #include <linux/kernel.h> +#define AD5310_CMD(x) ((x) << 12) + #define AD5683_DATA(x) ((x) << 4) + #define AD5686_ADDR(x) ((x) << 16) #define AD5686_CMD(x) ((x) << 20) @@ -38,6 +41,8 @@ #define AD5686_CMD_CONTROL_REG 0x4 #define AD5686_CMD_READBACK_ENABLE_V2 0x5 + +#define AD5310_REF_BIT_MSK BIT(8) #define AD5683_REF_BIT_MSK BIT(12) #define AD5693_REF_BIT_MSK BIT(12) @@ -45,6 +50,7 @@ * ad5686_supported_device_ids: */ enum ad5686_supported_device_ids { + ID_AD5310R, ID_AD5311R, ID_AD5671R, ID_AD5672R, @@ -72,6 +78,7 @@ enum ad5686_supported_device_ids { }; enum ad5686_regmap_type { + AD5310_REGMAP, AD5683_REGMAP, AD5686_REGMAP, AD5693_REGMAP diff --git a/drivers/iio/imu/bmi160/bmi160.h b/drivers/iio/imu/bmi160/bmi160.h index e7b11e74fd1d..2351049d930b 100644 --- a/drivers/iio/imu/bmi160/bmi160.h +++ b/drivers/iio/imu/bmi160/bmi160.h @@ -6,6 +6,5 @@ extern const struct regmap_config bmi160_regmap_config; int bmi160_core_probe(struct device *dev, struct regmap *regmap, const char *name, bool use_spi); -void bmi160_core_remove(struct device *dev); #endif /* BMI160_H_ */ diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index c85659ca9507..b10330b0f93f 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -542,10 +542,12 @@ static int bmi160_chip_init(struct bmi160_data *data, bool use_spi) return 0; } -static void bmi160_chip_uninit(struct bmi160_data *data) +static void bmi160_chip_uninit(void *data) { - bmi160_set_mode(data, BMI160_GYRO, false); - bmi160_set_mode(data, BMI160_ACCEL, false); + struct bmi160_data *bmi_data = data; + + bmi160_set_mode(bmi_data, BMI160_GYRO, false); + bmi160_set_mode(bmi_data, BMI160_ACCEL, false); } int bmi160_core_probe(struct device *dev, struct regmap *regmap, @@ -567,6 +569,10 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, if (ret < 0) return ret; + ret = devm_add_action_or_reset(dev, bmi160_chip_uninit, data); + if (ret < 0) + return ret; + if (!name && ACPI_HANDLE(dev)) name = bmi160_match_acpi_device(dev); @@ -577,35 +583,19 @@ int bmi160_core_probe(struct device *dev, struct regmap *regmap, indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &bmi160_info; - ret = iio_triggered_buffer_setup(indio_dev, NULL, - bmi160_trigger_handler, NULL); + ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, + bmi160_trigger_handler, NULL); if (ret < 0) - goto uninit; + return ret; - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret < 0) - goto buffer_cleanup; + return ret; return 0; -buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); -uninit: - bmi160_chip_uninit(data); - return ret; } EXPORT_SYMBOL_GPL(bmi160_core_probe); -void bmi160_core_remove(struct device *dev) -{ - struct iio_dev *indio_dev = dev_get_drvdata(dev); - struct bmi160_data *data = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - iio_triggered_buffer_cleanup(indio_dev); - bmi160_chip_uninit(data); -} -EXPORT_SYMBOL_GPL(bmi160_core_remove); - MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com"); MODULE_DESCRIPTION("Bosch BMI160 driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/imu/bmi160/bmi160_i2c.c b/drivers/iio/imu/bmi160/bmi160_i2c.c index 155a31f72445..5b1f7e6af651 100644 --- a/drivers/iio/imu/bmi160/bmi160_i2c.c +++ b/drivers/iio/imu/bmi160/bmi160_i2c.c @@ -38,13 +38,6 @@ static int bmi160_i2c_probe(struct i2c_client *client, return bmi160_core_probe(&client->dev, regmap, name, false); } -static int bmi160_i2c_remove(struct i2c_client *client) -{ - bmi160_core_remove(&client->dev); - - return 0; -} - static const struct i2c_device_id bmi160_i2c_id[] = { {"bmi160", 0}, {} @@ -72,7 +65,6 @@ static struct i2c_driver bmi160_i2c_driver = { .of_match_table = of_match_ptr(bmi160_of_match), }, .probe = bmi160_i2c_probe, - .remove = bmi160_i2c_remove, .id_table = bmi160_i2c_id, }; module_i2c_driver(bmi160_i2c_driver); diff --git a/drivers/iio/imu/bmi160/bmi160_spi.c b/drivers/iio/imu/bmi160/bmi160_spi.c index d34dfdfd1a7d..e521ad14eeac 100644 --- a/drivers/iio/imu/bmi160/bmi160_spi.c +++ b/drivers/iio/imu/bmi160/bmi160_spi.c @@ -29,13 +29,6 @@ static int bmi160_spi_probe(struct spi_device *spi) return bmi160_core_probe(&spi->dev, regmap, id->name, true); } -static int bmi160_spi_remove(struct spi_device *spi) -{ - bmi160_core_remove(&spi->dev); - - return 0; -} - static const struct spi_device_id bmi160_spi_id[] = { {"bmi160", 0}, {} @@ -58,7 +51,6 @@ MODULE_DEVICE_TABLE(of, bmi160_of_match); static struct spi_driver bmi160_spi_driver = { .probe = bmi160_spi_probe, - .remove = bmi160_spi_remove, .id_table = bmi160_spi_id, .driver = { .acpi_match_table = ACPI_PTR(bmi160_acpi_match), diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c index ee59b0cac84f..8e47dccdd40f 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_shub.c @@ -432,8 +432,8 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor, struct iio_chan_spec const *ch, int *val) { - int err, delay, len = ch->scan_type.realbits >> 3; - __le16 data; + int err, delay, len; + u8 data[4]; err = st_lsm6dsx_shub_set_enable(sensor, true); if (err < 0) @@ -442,15 +442,17 @@ st_lsm6dsx_shub_read_oneshot(struct st_lsm6dsx_sensor *sensor, delay = 1000000 / sensor->odr; usleep_range(delay, 2 * delay); - err = st_lsm6dsx_shub_read(sensor, ch->address, (u8 *)&data, len); - if (err < 0) - return err; + len = min_t(int, sizeof(data), ch->scan_type.realbits >> 3); + err = st_lsm6dsx_shub_read(sensor, ch->address, data, len); st_lsm6dsx_shub_set_enable(sensor, false); + if (err < 0) + return err; + switch (len) { case 2: - *val = (s16)le16_to_cpu(data); + *val = (s16)le16_to_cpu(*((__le16 *)data)); break; default: return -EINVAL; diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index a062cfddc5af..4f5cd9f60870 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1671,6 +1671,9 @@ int __iio_device_register(struct iio_dev *indio_dev, struct module *this_mod) if (ret < 0) return ret; + if (!indio_dev->info) + return -EINVAL; + /* configure elements for the chrdev */ indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index 42a827a66512..d430b80808ef 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -790,6 +790,7 @@ static const struct acpi_device_id ak_acpi_match[] = { {"INVN6500", AK8963}, {"AK009911", AK09911}, {"AK09911", AK09911}, + {"AKM9911", AK09911}, {"AK09912", AK09912}, { }, }; diff --git a/drivers/iio/potentiometer/Kconfig b/drivers/iio/potentiometer/Kconfig index 79ec2eba4969..6303cbe79903 100644 --- a/drivers/iio/potentiometer/Kconfig +++ b/drivers/iio/potentiometer/Kconfig @@ -90,6 +90,18 @@ config MCP4531 To compile this driver as a module, choose M here: the module will be called mcp4531. +config MCP41010 + tristate "Microchip MCP41xxx/MCP42xxx Digital Potentiometer driver" + depends on SPI + help + Say yes here to build support for the Microchip + MCP41010, MCP41050, MCP41100, + MCP42010, MCP42050, MCP42100 + digital potentiometer chips. + + To compile this driver as a module, choose M here: the + module will be called mcp41010. + config TPL0102 tristate "Texas Instruments digital potentiometer driver" depends on I2C diff --git a/drivers/iio/potentiometer/Makefile b/drivers/iio/potentiometer/Makefile index 4af657883c3f..8ff55138cf12 100644 --- a/drivers/iio/potentiometer/Makefile +++ b/drivers/iio/potentiometer/Makefile @@ -11,4 +11,5 @@ obj-$(CONFIG_MAX5487) += max5487.o obj-$(CONFIG_MCP4018) += mcp4018.o obj-$(CONFIG_MCP4131) += mcp4131.o obj-$(CONFIG_MCP4531) += mcp4531.o +obj-$(CONFIG_MCP41010) += mcp41010.o obj-$(CONFIG_TPL0102) += tpl0102.o diff --git a/drivers/iio/potentiometer/mcp41010.c b/drivers/iio/potentiometer/mcp41010.c new file mode 100644 index 000000000000..2368b39debf5 --- /dev/null +++ b/drivers/iio/potentiometer/mcp41010.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Industrial I/O driver for Microchip digital potentiometers + * + * Copyright (c) 2018 Chris Coffey <cmc@babblebit.net> + * Based on: Slawomir Stepien's code from mcp4131.c + * + * Datasheet: http://ww1.microchip.com/downloads/en/devicedoc/11195c.pdf + * + * DEVID #Wipers #Positions Resistance (kOhm) + * mcp41010 1 256 10 + * mcp41050 1 256 50 + * mcp41100 1 256 100 + * mcp42010 2 256 10 + * mcp42050 2 256 50 + * mcp42100 2 256 100 + */ + +#include <linux/cache.h> +#include <linux/err.h> +#include <linux/iio/iio.h> +#include <linux/iio/types.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/spi/spi.h> + +#define MCP41010_MAX_WIPERS 2 +#define MCP41010_WRITE BIT(4) +#define MCP41010_WIPER_MAX 255 +#define MCP41010_WIPER_CHANNEL BIT(0) + +struct mcp41010_cfg { + char name[16]; + int wipers; + int kohms; +}; + +enum mcp41010_type { + MCP41010, + MCP41050, + MCP41100, + MCP42010, + MCP42050, + MCP42100, +}; + +static const struct mcp41010_cfg mcp41010_cfg[] = { + [MCP41010] = { .name = "mcp41010", .wipers = 1, .kohms = 10, }, + [MCP41050] = { .name = "mcp41050", .wipers = 1, .kohms = 50, }, + [MCP41100] = { .name = "mcp41100", .wipers = 1, .kohms = 100, }, + [MCP42010] = { .name = "mcp42010", .wipers = 2, .kohms = 10, }, + [MCP42050] = { .name = "mcp42050", .wipers = 2, .kohms = 50, }, + [MCP42100] = { .name = "mcp42100", .wipers = 2, .kohms = 100, }, +}; + +struct mcp41010_data { + struct spi_device *spi; + const struct mcp41010_cfg *cfg; + struct mutex lock; /* Protect write sequences */ + unsigned int value[MCP41010_MAX_WIPERS]; /* Cache wiper values */ + u8 buf[2] ____cacheline_aligned; +}; + +#define MCP41010_CHANNEL(ch) { \ + .type = IIO_RESISTANCE, \ + .indexed = 1, \ + .output = 1, \ + .channel = (ch), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ +} + +static const struct iio_chan_spec mcp41010_channels[] = { + MCP41010_CHANNEL(0), + MCP41010_CHANNEL(1), +}; + +static int mcp41010_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct mcp41010_data *data = iio_priv(indio_dev); + int channel = chan->channel; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + *val = data->value[channel]; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_SCALE: + *val = 1000 * data->cfg->kohms; + *val2 = MCP41010_WIPER_MAX; + return IIO_VAL_FRACTIONAL; + } + + return -EINVAL; +} + +static int mcp41010_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + int err; + struct mcp41010_data *data = iio_priv(indio_dev); + int channel = chan->channel; + + if (mask != IIO_CHAN_INFO_RAW) + return -EINVAL; + + if (val > MCP41010_WIPER_MAX || val < 0) + return -EINVAL; + + mutex_lock(&data->lock); + + data->buf[0] = MCP41010_WIPER_CHANNEL << channel; + data->buf[0] |= MCP41010_WRITE; + data->buf[1] = val & 0xff; + + err = spi_write(data->spi, data->buf, sizeof(data->buf)); + if (!err) + data->value[channel] = val; + + mutex_unlock(&data->lock); + + return err; +} + +static const struct iio_info mcp41010_info = { + .read_raw = mcp41010_read_raw, + .write_raw = mcp41010_write_raw, +}; + +static int mcp41010_probe(struct spi_device *spi) +{ + int err; + struct device *dev = &spi->dev; + struct mcp41010_data *data; + struct iio_dev *indio_dev; + + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); + if (!indio_dev) + return -ENOMEM; + + data = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + data->spi = spi; + data->cfg = of_device_get_match_data(&spi->dev); + if (!data->cfg) + data->cfg = &mcp41010_cfg[spi_get_device_id(spi)->driver_data]; + + mutex_init(&data->lock); + + indio_dev->dev.parent = dev; + indio_dev->info = &mcp41010_info; + indio_dev->channels = mcp41010_channels; + indio_dev->num_channels = data->cfg->wipers; + indio_dev->name = data->cfg->name; + + err = devm_iio_device_register(dev, indio_dev); + if (err) + dev_info(&spi->dev, "Unable to register %s\n", indio_dev->name); + + return err; +} + +static const struct of_device_id mcp41010_match[] = { + { .compatible = "microchip,mcp41010", .data = &mcp41010_cfg[MCP41010] }, + { .compatible = "microchip,mcp41050", .data = &mcp41010_cfg[MCP41050] }, + { .compatible = "microchip,mcp41100", .data = &mcp41010_cfg[MCP41100] }, + { .compatible = "microchip,mcp42010", .data = &mcp41010_cfg[MCP42010] }, + { .compatible = "microchip,mcp42050", .data = &mcp41010_cfg[MCP42050] }, + { .compatible = "microchip,mcp42100", .data = &mcp41010_cfg[MCP42100] }, + {} +}; +MODULE_DEVICE_TABLE(of, mcp41010_match); + +static const struct spi_device_id mcp41010_id[] = { + { "mcp41010", MCP41010 }, + { "mcp41050", MCP41050 }, + { "mcp41100", MCP41100 }, + { "mcp42010", MCP42010 }, + { "mcp42050", MCP42050 }, + { "mcp42100", MCP42100 }, + {} +}; +MODULE_DEVICE_TABLE(spi, mcp41010_id); + +static struct spi_driver mcp41010_driver = { + .driver = { + .name = "mcp41010", + .of_match_table = mcp41010_match, + }, + .probe = mcp41010_probe, + .id_table = mcp41010_id, +}; + +module_spi_driver(mcp41010_driver); + +MODULE_AUTHOR("Chris Coffey <cmc@babblebit.net>"); +MODULE_DESCRIPTION("MCP41010 digital potentiometer"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/resolver/Kconfig b/drivers/iio/resolver/Kconfig index 2ced9f22aa70..786801be54f6 100644 --- a/drivers/iio/resolver/Kconfig +++ b/drivers/iio/resolver/Kconfig @@ -3,6 +3,16 @@ # menu "Resolver to digital converters" +config AD2S90 + tristate "Analog Devices ad2s90 driver" + depends on SPI + help + Say yes here to build support for Analog Devices spi resolver + to digital converters, ad2s90, provides direct access via sysfs. + + To compile this driver as a module, choose M here: the + module will be called ad2s90. + config AD2S1200 tristate "Analog Devices ad2s1200/ad2s1205 driver" depends on SPI diff --git a/drivers/iio/resolver/Makefile b/drivers/iio/resolver/Makefile index 4e1dccae07e7..398d82d50028 100644 --- a/drivers/iio/resolver/Makefile +++ b/drivers/iio/resolver/Makefile @@ -2,4 +2,5 @@ # Makefile for Resolver/Synchro drivers # +obj-$(CONFIG_AD2S90) += ad2s90.o obj-$(CONFIG_AD2S1200) += ad2s1200.o diff --git a/drivers/staging/iio/resolver/ad2s90.c b/drivers/iio/resolver/ad2s90.c index 3e257ac46f7a..a41f5cb10da5 100644 --- a/drivers/staging/iio/resolver/ad2s90.c +++ b/drivers/iio/resolver/ad2s90.c @@ -1,12 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ad2s90.c simple support for the ADI Resolver to Digital Converters: AD2S90 * * Copyright (c) 2010-2010 Analog Devices Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * */ #include <linux/types.h> #include <linux/mutex.h> @@ -19,8 +15,14 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +/* + * Although chip's max frequency is 2Mhz, it needs 600ns between CS and the + * first falling edge of SCLK, so frequency should be at most 1 / (2 * 6e-7) + */ +#define AD2S90_MAX_SPI_FREQ_HZ 830000 + struct ad2s90_state { - struct mutex lock; + struct mutex lock; /* lock to protect rx buffer */ struct spi_device *sdev; u8 rx[2] ____cacheline_aligned; }; @@ -77,7 +79,12 @@ static int ad2s90_probe(struct spi_device *spi) { struct iio_dev *indio_dev; struct ad2s90_state *st; - int ret; + + if (spi->max_speed_hz > AD2S90_MAX_SPI_FREQ_HZ) { + dev_err(&spi->dev, "SPI CLK, %d Hz exceeds %d Hz\n", + spi->max_speed_hz, AD2S90_MAX_SPI_FREQ_HZ); + return -EINVAL; + } indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st)); if (!indio_dev) @@ -94,19 +101,15 @@ static int ad2s90_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->name = spi_get_device_id(spi)->name; - /* need 600ns between CS and the first falling edge of SCLK */ - spi->max_speed_hz = 830000; - spi->mode = SPI_MODE_3; - ret = spi_setup(spi); - - if (ret < 0) { - dev_err(&spi->dev, "spi_setup failed!\n"); - return ret; - } - return devm_iio_device_register(indio_dev->dev.parent, indio_dev); } +static const struct of_device_id ad2s90_of_match[] = { + { .compatible = "adi,ad2s90", }, + {} +}; +MODULE_DEVICE_TABLE(of, ad2s90_of_match); + static const struct spi_device_id ad2s90_id[] = { { "ad2s90" }, {} @@ -116,6 +119,7 @@ MODULE_DEVICE_TABLE(spi, ad2s90_id); static struct spi_driver ad2s90_driver = { .driver = { .name = "ad2s90", + .of_match_table = ad2s90_of_match, }, .probe = ad2s90_probe, .id_table = ad2s90_id, diff --git a/drivers/staging/iio/adc/ad7280a.c b/drivers/staging/iio/adc/ad7280a.c index 0bb9ab174f2a..14f6a3ced060 100644 --- a/drivers/staging/iio/adc/ad7280a.c +++ b/drivers/staging/iio/adc/ad7280a.c @@ -561,6 +561,7 @@ static int ad7280_attr_init(struct ad7280_state *st) { int dev, ch, cnt; unsigned int index; + struct iio_dev_attr *iio_attr; st->iio_attr = devm_kcalloc(&st->spi->dev, 2, sizeof(*st->iio_attr) * (st->slave_num + 1) * AD7280A_CELLS_PER_DEV, @@ -571,37 +572,35 @@ static int ad7280_attr_init(struct ad7280_state *st) for (dev = 0, cnt = 0; dev <= st->slave_num; dev++) for (ch = AD7280A_CELL_VOLTAGE_1; ch <= AD7280A_CELL_VOLTAGE_6; ch++, cnt++) { + iio_attr = &st->iio_attr[cnt]; index = dev * AD7280A_CELLS_PER_DEV + ch; - st->iio_attr[cnt].address = - ad7280a_devaddr(dev) << 8 | ch; - st->iio_attr[cnt].dev_attr.attr.mode = - 0644; - st->iio_attr[cnt].dev_attr.show = - ad7280_show_balance_sw; - st->iio_attr[cnt].dev_attr.store = - ad7280_store_balance_sw; - st->iio_attr[cnt].dev_attr.attr.name = + iio_attr->address = ad7280a_devaddr(dev) << 8 | ch; + iio_attr->dev_attr.attr.mode = 0644; + iio_attr->dev_attr.show = ad7280_show_balance_sw; + iio_attr->dev_attr.store = ad7280_store_balance_sw; + iio_attr->dev_attr.attr.name = devm_kasprintf(&st->spi->dev, GFP_KERNEL, "in%d-in%d_balance_switch_en", index, index + 1); - ad7280_attributes[cnt] = - &st->iio_attr[cnt].dev_attr.attr; + if (!iio_attr->dev_attr.attr.name) + return -ENOMEM; + + ad7280_attributes[cnt] = &iio_attr->dev_attr.attr; cnt++; - st->iio_attr[cnt].address = - ad7280a_devaddr(dev) << 8 | + iio_attr = &st->iio_attr[cnt]; + iio_attr->address = ad7280a_devaddr(dev) << 8 | (AD7280A_CB1_TIMER + ch); - st->iio_attr[cnt].dev_attr.attr.mode = - 0644; - st->iio_attr[cnt].dev_attr.show = - ad7280_show_balance_timer; - st->iio_attr[cnt].dev_attr.store = - ad7280_store_balance_timer; - st->iio_attr[cnt].dev_attr.attr.name = + iio_attr->dev_attr.attr.mode = 0644; + iio_attr->dev_attr.show = ad7280_show_balance_timer; + iio_attr->dev_attr.store = ad7280_store_balance_timer; + iio_attr->dev_attr.attr.name = devm_kasprintf(&st->spi->dev, GFP_KERNEL, "in%d-in%d_balance_timer", index, index + 1); - ad7280_attributes[cnt] = - &st->iio_attr[cnt].dev_attr.attr; + if (!iio_attr->dev_attr.attr.name) + return -ENOMEM; + + ad7280_attributes[cnt] = &iio_attr->dev_attr.attr; } ad7280_attributes[cnt] = NULL; @@ -880,15 +879,15 @@ static int ad7280_probe(struct spi_device *spi) if (ret < 0) return ret; - ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st); - if (ret) - return ret; - st->slave_num = ret; st->scan_cnt = (st->slave_num + 1) * AD7280A_NUM_CH; st->cell_threshhigh = 0xFF; st->aux_threshhigh = 0xFF; + ret = devm_add_action_or_reset(&spi->dev, ad7280_sw_power_down, st); + if (ret) + return ret; + /* * Total Conversion Time = ((tACQ + tCONV) * * (Number of Conversions per Part)) − diff --git a/drivers/staging/iio/addac/adt7316-i2c.c b/drivers/staging/iio/addac/adt7316-i2c.c index 473e5e34ec00..2d51bd425662 100644 --- a/drivers/staging/iio/addac/adt7316-i2c.c +++ b/drivers/staging/iio/addac/adt7316-i2c.c @@ -30,10 +30,6 @@ static int adt7316_i2c_read(void *client, u8 reg, u8 *data) } ret = i2c_smbus_read_byte(client); - - if (!ret) - return -EIO; - if (ret < 0) { dev_err(&cl->dev, "I2C read error\n"); return ret; @@ -104,7 +100,6 @@ static int adt7316_i2c_probe(struct i2c_client *client, struct adt7316_bus bus = { .client = client, .irq = client->irq, - .irq_flags = IRQF_TRIGGER_LOW, .read = adt7316_i2c_read, .write = adt7316_i2c_write, .multi_read = adt7316_i2c_multi_read, @@ -126,9 +121,22 @@ static const struct i2c_device_id adt7316_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id); +static const struct of_device_id adt7316_of_match[] = { + { .compatible = "adi,adt7316" }, + { .compatible = "adi,adt7317" }, + { .compatible = "adi,adt7318" }, + { .compatible = "adi,adt7516" }, + { .compatible = "adi,adt7517" }, + { .compatible = "adi,adt7519" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adt7316_of_match); + static struct i2c_driver adt7316_driver = { .driver = { .name = "adt7316", + .of_match_table = adt7316_of_match, .pm = ADT7316_PM_OPS, }, .probe = adt7316_i2c_probe, diff --git a/drivers/staging/iio/addac/adt7316-spi.c b/drivers/staging/iio/addac/adt7316-spi.c index 5cd22743e140..e75827e326a6 100644 --- a/drivers/staging/iio/addac/adt7316-spi.c +++ b/drivers/staging/iio/addac/adt7316-spi.c @@ -94,7 +94,6 @@ static int adt7316_spi_probe(struct spi_device *spi_dev) struct adt7316_bus bus = { .client = spi_dev, .irq = spi_dev->irq, - .irq_flags = IRQF_TRIGGER_LOW, .read = adt7316_spi_read, .write = adt7316_spi_write, .multi_read = adt7316_spi_multi_read, diff --git a/drivers/staging/iio/addac/adt7316.c b/drivers/staging/iio/addac/adt7316.c index 2f8a122f475d..dc93e85808e0 100644 --- a/drivers/staging/iio/addac/adt7316.c +++ b/drivers/staging/iio/addac/adt7316.c @@ -177,7 +177,7 @@ struct adt7316_chip_info { struct adt7316_bus bus; - u16 ldac_pin; + struct gpio_desc *ldac_pin; u16 int_mask; /* 0x2f */ u8 config1; u8 config2; @@ -950,8 +950,8 @@ static ssize_t adt7316_store_update_DAC(struct device *dev, if (ret) return -EIO; } else { - gpio_set_value(chip->ldac_pin, 0); - gpio_set_value(chip->ldac_pin, 1); + gpiod_set_value(chip->ldac_pin, 0); + gpiod_set_value(chip->ldac_pin, 1); } return len; @@ -2104,6 +2104,7 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, struct adt7316_chip_info *chip; struct iio_dev *indio_dev; unsigned short *adt7316_platform_data = dev->platform_data; + int irq_type = IRQF_TRIGGER_LOW; int ret = 0; indio_dev = devm_iio_device_alloc(dev, sizeof(*chip)); @@ -2122,7 +2123,13 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, else return -ENODEV; - chip->ldac_pin = adt7316_platform_data[1]; + chip->ldac_pin = devm_gpiod_get_optional(dev, "adi,ldac", GPIOD_OUT_LOW); + if (IS_ERR(chip->ldac_pin)) { + ret = PTR_ERR(chip->ldac_pin); + dev_err(dev, "Failed to request ldac GPIO: %d\n", ret); + return ret; + } + if (chip->ldac_pin) { chip->config3 |= ADT7316_DA_EN_VIA_DAC_LDCA; if ((chip->id & ID_FAMILY_MASK) == ID_ADT75XX) @@ -2142,19 +2149,18 @@ int adt7316_probe(struct device *dev, struct adt7316_bus *bus, if (chip->bus.irq > 0) { if (adt7316_platform_data[0]) - chip->bus.irq_flags = adt7316_platform_data[0]; + irq_type = adt7316_platform_data[0]; ret = devm_request_threaded_irq(dev, chip->bus.irq, NULL, adt7316_event_handler, - chip->bus.irq_flags | - IRQF_ONESHOT, + irq_type | IRQF_ONESHOT, indio_dev->name, indio_dev); if (ret) return ret; - if (chip->bus.irq_flags & IRQF_TRIGGER_HIGH) + if (irq_type & IRQF_TRIGGER_HIGH) chip->config1 |= ADT7316_INT_POLARITY; } diff --git a/drivers/staging/iio/addac/adt7316.h b/drivers/staging/iio/addac/adt7316.h index b954dcbc92db..84ca4f6c88f5 100644 --- a/drivers/staging/iio/addac/adt7316.h +++ b/drivers/staging/iio/addac/adt7316.h @@ -17,7 +17,6 @@ struct adt7316_bus { void *client; int irq; - int irq_flags; int (*read)(void *client, u8 reg, u8 *data); int (*write)(void *client, u8 reg, u8 val); int (*multi_read)(void *client, u8 first_reg, u8 count, u8 *data); diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index f9bcb8310e21..9e52384f5370 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -786,9 +786,18 @@ static const struct i2c_device_id ad5933_id[] = { MODULE_DEVICE_TABLE(i2c, ad5933_id); +static const struct of_device_id ad5933_of_match[] = { + { .compatible = "adi,ad5933" }, + { .compatible = "adi,ad5934" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, ad5933_of_match); + static struct i2c_driver ad5933_driver = { .driver = { .name = "ad5933", + .of_match_table = ad5933_of_match, }, .probe = ad5933_probe, .remove = ad5933_remove, diff --git a/drivers/staging/iio/resolver/Kconfig b/drivers/staging/iio/resolver/Kconfig index 6a469ee6101f..4a727c17bb8f 100644 --- a/drivers/staging/iio/resolver/Kconfig +++ b/drivers/staging/iio/resolver/Kconfig @@ -3,16 +3,6 @@ # menu "Resolver to digital converters" -config AD2S90 - tristate "Analog Devices ad2s90 driver" - depends on SPI - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s90, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s90. - config AD2S1210 tristate "Analog Devices ad2s1210 driver" depends on SPI diff --git a/drivers/staging/iio/resolver/Makefile b/drivers/staging/iio/resolver/Makefile index 8d901dc7500b..b2049f2ce36e 100644 --- a/drivers/staging/iio/resolver/Makefile +++ b/drivers/staging/iio/resolver/Makefile @@ -2,5 +2,4 @@ # Makefile for Resolver/Synchro drivers # -obj-$(CONFIG_AD2S90) += ad2s90.o obj-$(CONFIG_AD2S1210) += ad2s1210.o |