From 72179a889501ef339df094abe108846b19e7a06c Mon Sep 17 00:00:00 2001 From: Christophe Priouzeau Date: Mon, 26 Nov 2018 14:46:26 +0100 Subject: [PATCH 29/52] ARM-stm32mp1-r0-rc2-HWSPINLOCK-IIO-I2C --- .../devicetree/bindings/iio/adc/st,stm32-adc.txt | 34 +++ arch/arm/Kconfig.debug | 27 ++ drivers/hwspinlock/Kconfig | 9 + drivers/hwspinlock/Makefile | 1 + drivers/hwspinlock/stm32_hwspinlock.c | 157 +++++++++++ drivers/i2c/busses/i2c-stm32f7.c | 6 +- drivers/iio/adc/stm32-adc-core.c | 296 ++++++++++++++++++++- drivers/iio/adc/stm32-adc.c | 4 +- 8 files changed, 529 insertions(+), 5 deletions(-) create mode 100644 drivers/hwspinlock/stm32_hwspinlock.c diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt index c46598c..a6aa796 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.txt @@ -49,6 +49,40 @@ Optional properties: - st,max-clk-rate-hz: Allow to specify desired max clock rate used by analog circuitry. +- vdda-supply: Phandle to the vdda input voltage. It can be used to supply ADC + analog inputs switches on stm32mp1 and stm32h7. + +- vdd-supply: Phandle to the vdd input voltage. It can be used to supply ADC + analog inputs switches on stm32mp1. + +- st,syscfg-vbooster: Voltage booster control for analog switches supply. + This is available on stm32mp1 and stm32h7 (requires vdda-supply property). + It must be composed of 3 cells: + 1st cell: phandle to syscfg + 2nd cell: register offset within SYSCFG + 3rd cell: bitmask for BOOSTE on stm32h7, EN_BOOSTER set bit on stm32mp1 + +- st,syscfg-vbooster-clr: Voltage booster clear for analog switches supply. + This is available on stm32mp1 (requires st,syscfg-vbooster and vdda-supply). + 1st cell: phandle to syscfg + 2nd cell: clear register offset within SYSCFG + 3rd cell: bitmask for EN_BOOSTER clear bit on stm32mp1 + +- st,syscfg-anaswvdd: VDDA / VDD selection for analog switches supply. + This is available on stm32mp1 (requires vdda-supply and vdd-supply). + It must be composed of 3 cells: + 1st cell: phandle to syscfg + 2nd cell: register offset within SYSCFG + 3rd cell: bitmask for ANASWVDD set bit + +- st,syscfg-anaswvdd-clr: VDDA / VDD selection clear for analog switches supply. + This is available on stm32mp1 (requires st,syscfg-anaswvdd, vdda-supply and + vdd-supply). + It must be composed of 3 cells: + 1st cell: phandle to syscfg + 2nd cell: clear register offset within SYSCFG + 3rd cell: bitmask for ANASWVDD clear bit + Contents of a stm32 adc child node: ----------------------------------- An ADC block node should contain at least one subnode, representing an diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index f6fcb8a..d5ec6c3 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -1184,6 +1184,28 @@ choice If unsure, say N. + config STM32F4_DEBUG_UART + bool "Use STM32F4 UART for low-level debug" + depends on ARCH_STM32 + select DEBUG_STM32_UART + help + Say Y here if you want kernel low-level debugging support + on STM32F4 based platforms, which default UART is wired on + USART1. + + If unsure, say N. + + config STM32F7_DEBUG_UART + bool "Use STM32F7 UART for low-level debug" + depends on ARCH_STM32 + select DEBUG_STM32_UART + help + Say Y here if you want kernel low-level debugging support + on STM32F7 based platforms, which default UART is wired on + USART1. + + If unsure, say N. + config TEGRA_DEBUG_UART_AUTO_ODMDATA bool "Kernel low-level debugging messages via Tegra UART via ODMDATA" depends on ARCH_TEGRA @@ -1468,6 +1490,10 @@ config DEBUG_STI_UART bool depends on ARCH_STI +config DEBUG_STM32_UART + bool + depends on ARCH_STM32 + config DEBUG_SIRFSOC_UART bool depends on ARCH_SIRF @@ -1517,6 +1543,7 @@ config DEBUG_LL_INCLUDE default "debug/s5pv210.S" if DEBUG_S5PV210_UART default "debug/sirf.S" if DEBUG_SIRFSOC_UART default "debug/sti.S" if DEBUG_STI_UART + default "debug/stm32.S" if DEBUG_STM32_UART default "debug/tegra.S" if DEBUG_TEGRA_UART default "debug/ux500.S" if DEBUG_UX500_UART default "debug/vexpress.S" if DEBUG_VEXPRESS_UART0_DETECT diff --git a/drivers/hwspinlock/Kconfig b/drivers/hwspinlock/Kconfig index e895d29..7869c67 100644 --- a/drivers/hwspinlock/Kconfig +++ b/drivers/hwspinlock/Kconfig @@ -49,6 +49,15 @@ config HWSPINLOCK_SPRD If unsure, say N. +config HWSPINLOCK_STM32 + tristate "STM32 Hardware Spinlock device" + depends on MACH_STM32MP157 + depends on HWSPINLOCK + help + Say y here to support the STM32 Hardware Spinlock device. + + If unsure, say N. + config HSEM_U8500 tristate "STE Hardware Semaphore functionality" depends on HWSPINLOCK diff --git a/drivers/hwspinlock/Makefile b/drivers/hwspinlock/Makefile index b87c01a..ed053e3 100644 --- a/drivers/hwspinlock/Makefile +++ b/drivers/hwspinlock/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_SIRF) += sirf_hwspinlock.o obj-$(CONFIG_HWSPINLOCK_SPRD) += sprd_hwspinlock.o +obj-$(CONFIG_HWSPINLOCK_STM32) += stm32_hwspinlock.o obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c new file mode 100644 index 0000000..3242b72 --- /dev/null +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics SA 2018 + * Author: Benjamin Gaignard for STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hwspinlock_internal.h" + +#define STM32_MUTEX_COREID BIT(8) +#define STM32_MUTEX_LOCK_BIT BIT(31) +#define STM32_MUTEX_NUM_LOCKS 32 + +struct stm32_hwspinlock { + struct clk *clk; + struct hwspinlock_device bank; +}; + +static int stm32_hwspinlock_trylock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + u32 status; + + writel(STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID, lock_addr); + status = readl(lock_addr); + + return status == (STM32_MUTEX_LOCK_BIT | STM32_MUTEX_COREID); +} + +static void stm32_hwspinlock_unlock(struct hwspinlock *lock) +{ + void __iomem *lock_addr = lock->priv; + + writel(STM32_MUTEX_COREID, lock_addr); +} + +static const struct hwspinlock_ops stm32_hwspinlock_ops = { + .trylock = stm32_hwspinlock_trylock, + .unlock = stm32_hwspinlock_unlock, +}; + +static int stm32_hwspinlock_probe(struct platform_device *pdev) +{ + struct stm32_hwspinlock *hw; + void __iomem *io_base; + struct resource *res; + size_t array_size; + int i, ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(&pdev->dev, res); + if (!io_base) + return -ENOMEM; + + array_size = STM32_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock); + hw = devm_kzalloc(&pdev->dev, sizeof(*hw) + array_size, GFP_KERNEL); + if (!hw) + return -ENOMEM; + + hw->clk = devm_clk_get(&pdev->dev, "hsem"); + if (IS_ERR(hw->clk)) + return PTR_ERR(hw->clk); + + for (i = 0; i < STM32_MUTEX_NUM_LOCKS; i++) + hw->bank.lock[i].priv = io_base + i * sizeof(u32); + + platform_set_drvdata(pdev, hw); + pm_runtime_enable(&pdev->dev); + + ret = hwspin_lock_register(&hw->bank, &pdev->dev, &stm32_hwspinlock_ops, + 0, STM32_MUTEX_NUM_LOCKS); + + if (ret) + pm_runtime_disable(&pdev->dev); + + return ret; +} + +static int stm32_hwspinlock_remove(struct platform_device *pdev) +{ + struct stm32_hwspinlock *hw = platform_get_drvdata(pdev); + int ret; + + ret = hwspin_lock_unregister(&hw->bank); + if (ret) + dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret); + + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int __maybe_unused stm32_hwspinlock_runtime_suspend(struct device *dev) +{ + struct stm32_hwspinlock *hw = dev_get_drvdata(dev); + + clk_disable_unprepare(hw->clk); + + return 0; +} + +static int __maybe_unused stm32_hwspinlock_runtime_resume(struct device *dev) +{ + struct stm32_hwspinlock *hw = dev_get_drvdata(dev); + + clk_prepare_enable(hw->clk); + + return 0; +} + +static const struct dev_pm_ops stm32_hwspinlock_pm_ops = { + SET_RUNTIME_PM_OPS(stm32_hwspinlock_runtime_suspend, + stm32_hwspinlock_runtime_resume, + NULL) +}; + +static const struct of_device_id stm32_hwpinlock_ids[] = { + { .compatible = "st,stm32-hwspinlock", }, + {}, +}; +MODULE_DEVICE_TABLE(of, stm32_hwpinlock_ids); + +static struct platform_driver stm32_hwspinlock_driver = { + .probe = stm32_hwspinlock_probe, + .remove = stm32_hwspinlock_remove, + .driver = { + .name = "stm32_hwspinlock", + .of_match_table = stm32_hwpinlock_ids, + .pm = &stm32_hwspinlock_pm_ops, + }, +}; + +static int __init stm32_hwspinlock_init(void) +{ + return platform_driver_register(&stm32_hwspinlock_driver); +} + +/* board init code might need to reserve hwspinlocks for predefined purposes */ +postcore_initcall(stm32_hwspinlock_init); + +static void __exit stm32_hwspinlock_exit(void) +{ + platform_driver_unregister(&stm32_hwspinlock_driver); +} +module_exit(stm32_hwspinlock_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Hardware spinlock driver for STM32 SoCs"); +MODULE_AUTHOR("Benjamin Gaignard "); diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index c1cbf93..ac30aea 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -457,7 +457,7 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0); dnf_delay = setup->dnf * i2cclk; - sdadel_min = setup->fall_time - i2c_specs[setup->speed].hddat_min - + sdadel_min = i2c_specs[setup->speed].hddat_min + setup->fall_time - af_delay_min - (setup->dnf + 3) * i2cclk; sdadel_max = i2c_specs[setup->speed].vddat_max - setup->rise_time - @@ -501,8 +501,12 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, list_add_tail(&v->node, &solutions); + break; } } + + if (p_prev == p) + break; } } diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c index a32e826..6234456 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -16,10 +16,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -88,6 +90,8 @@ #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 @@ -117,16 +121,30 @@ struct stm32_adc_priv; * @regs: common registers for all instances * @clk_sel: clock selection routine * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet) + * @has_syscfg_clr: analog switch control use set and clear registers * @exti_trigs EXTI triggers info */ struct stm32_adc_priv_cfg { const struct stm32_adc_common_regs *regs; int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); u32 max_clk_rate_hz; + int has_syscfg_clr; struct stm32_adc_trig_info *exti_trigs; }; /** + * stm32_adc_syscfg - stm32 ADC SYSCFG data + * @regmap: reference to syscon + * @reg: register offset within SYSCFG + * @mask: bitmask within SYSCFG register + */ +struct stm32_adc_syscfg { + struct regmap *regmap; + u32 reg; + u32 mask; +}; + +/** * struct stm32_adc_priv - stm32 ADC core private data * @irq: irq(s) for ADC block * @domain: irq domain reference @@ -137,6 +155,10 @@ struct stm32_adc_priv_cfg { * @cfg: compatible configuration data * @common: common data for all ADC instances * @ccr_bak: backup'ed CCR in low power mode + * @vbooster: BOOSTE syscfg / EN_BOOSTER syscfg set + * @vbooster_clr: EN_BOOSTER syscfg clear + * @anaswvdd: ANASWVDD syscfg set + * @anaswvdd_clr: ANASWVDD syscfg clear */ struct stm32_adc_priv { int irq[STM32_ADC_MAX_ADCS]; @@ -144,10 +166,16 @@ struct stm32_adc_priv { struct clk *aclk; struct clk *bclk; u32 max_clk_rate; + struct regulator *vdd; + struct regulator *vdda; struct regulator *vref; const struct stm32_adc_priv_cfg *cfg; struct stm32_adc_common common; u32 ccr_bak; + struct stm32_adc_syscfg vbooster; + struct stm32_adc_syscfg vbooster_clr; + struct stm32_adc_syscfg anaswvdd; + struct stm32_adc_syscfg anaswvdd_clr; }; static struct stm32_adc_priv *to_stm32_adc_priv(struct stm32_adc_common *com) @@ -567,16 +595,187 @@ static int stm32_adc_triggers_probe(struct platform_device *pdev, return 0; } +static int stm32_adc_switches_supply_en(struct device *dev) +{ + struct stm32_adc_common *common = dev_get_drvdata(dev); + struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + int ret, vdda, vdd = 0; + u32 anaswvdd, en_booster; + + /* + * On STM32H7 and STM32MP1, the ADC inputs are multiplexed with analog + * switches (e.g. PCSEL) which have reduced performances when their + * supply is below 2.7V (vdda by default): + * - Voltage booster can be used, to get full ADC performances + * (increases power consumption). + * - Vdd can be used if above 2.7V (STM32MP1 only). + * + * Make all this optional, since this is a trade-off between analog + * performance and power consumption. + */ + if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap)) { + dev_dbg(dev, "%s: nothing to do\n", __func__); + return 0; + } + + ret = regulator_enable(priv->vdda); + if (ret < 0) { + dev_err(dev, "vdda enable failed %d\n", ret); + return ret; + } + + ret = regulator_get_voltage(priv->vdda); + if (ret < 0) { + dev_err(dev, "vdda get voltage failed %d\n", ret); + goto vdda_dis; + } + vdda = ret; + + if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) { + ret = regulator_enable(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd enable failed %d\n", ret); + goto vdda_dis; + } + + ret = regulator_get_voltage(priv->vdd); + if (ret < 0) { + dev_err(dev, "vdd get voltage failed %d\n", ret); + goto vdd_dis; + } + vdd = ret; + } + + /* + * Recommended settings for ANASWVDD and EN_BOOSTER: + * - vdda > 2.7V: ANASWVDD = 0, EN_BOOSTER = 0 + * - vdda < 2.7V and vdd < 2.7V: ANASWVDD = 0, EN_BOOSTER = 1 + * - vdda < 2.7V but vdd > 2.7V: ANASWVDD = 1, EN_BOOSTER = 0 (stm32mp1) + */ + if (vdda > 2700000) { + /* analog switches supplied by vdda (default) */ + anaswvdd = 0; + en_booster = 0; + } else { + if (vdd < 2700000) { + /* Voltage booster enabled */ + anaswvdd = 0; + en_booster = priv->vbooster.mask; + } else { + /* analog switches supplied by vdd */ + anaswvdd = priv->anaswvdd.mask; + en_booster = 0; + } + } + + dev_dbg(dev, "vdda=%d, vdd=%d, setting: en_booster=%x, anaswvdd=%x\n", + vdda, vdd, en_booster, anaswvdd); + + /* direct write en_booster value (or use clear register) */ + if (en_booster || IS_ERR(priv->vbooster_clr.regmap)) + ret = regmap_update_bits(priv->vbooster.regmap, + priv->vbooster.reg, + priv->vbooster.mask, en_booster); + else + ret = regmap_update_bits(priv->vbooster_clr.regmap, + priv->vbooster_clr.reg, + priv->vbooster_clr.mask, + priv->vbooster_clr.mask); + if (ret) { + dev_err(dev, "can't access voltage booster, %d\n", ret); + goto vdd_dis; + } + + /* Booster voltage can take up to 50 μs to stabilize */ + if (en_booster) + usleep_range(50, 100); + + if (!IS_ERR(priv->anaswvdd.regmap)) { + /* direct write anaswvdd value (or use clear register) */ + if (anaswvdd || IS_ERR(priv->anaswvdd_clr.regmap)) + ret = regmap_update_bits(priv->anaswvdd.regmap, + priv->anaswvdd.reg, + priv->anaswvdd.mask, anaswvdd); + else + ret = regmap_update_bits(priv->anaswvdd_clr.regmap, + priv->anaswvdd_clr.reg, + priv->anaswvdd_clr.mask, + priv->anaswvdd_clr.mask); + if (ret) { + dev_err(dev, "can't access anaswvdd, %d\n", ret); + goto booster_dis; + } + } + + return ret; + +booster_dis: + if (IS_ERR(priv->vbooster_clr.regmap)) + regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg, + priv->vbooster.mask, 0); + else + regmap_update_bits(priv->vbooster_clr.regmap, + priv->vbooster_clr.reg, + priv->vbooster_clr.mask, + priv->vbooster_clr.mask); +vdd_dis: + if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) + regulator_disable(priv->vdd); +vdda_dis: + regulator_disable(priv->vdda); + + return ret; +} + +static void stm32_adc_switches_supply_dis(struct device *dev) +{ + struct stm32_adc_common *common = dev_get_drvdata(dev); + struct stm32_adc_priv *priv = to_stm32_adc_priv(common); + + if (IS_ERR(priv->vdda) || IS_ERR(priv->vbooster.regmap)) + return; + + if (!IS_ERR(priv->anaswvdd.regmap)) { + if (IS_ERR(priv->anaswvdd_clr.regmap)) + regmap_update_bits(priv->anaswvdd.regmap, + priv->anaswvdd.reg, + priv->anaswvdd.mask, 0); + else + regmap_update_bits(priv->anaswvdd_clr.regmap, + priv->anaswvdd_clr.reg, + priv->anaswvdd_clr.mask, + priv->anaswvdd_clr.mask); + } + + if (IS_ERR(priv->vbooster_clr.regmap)) + regmap_update_bits(priv->vbooster.regmap, priv->vbooster.reg, + priv->vbooster.mask, 0); + else + regmap_update_bits(priv->vbooster_clr.regmap, + priv->vbooster_clr.reg, + priv->vbooster_clr.mask, + priv->vbooster_clr.mask); + + if (!IS_ERR(priv->vdd) && !IS_ERR(priv->anaswvdd.regmap)) + regulator_disable(priv->vdd); + + regulator_disable(priv->vdda); +} + 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 = stm32_adc_switches_supply_en(dev); + if (ret < 0) + return ret; + ret = regulator_enable(priv->vref); if (ret < 0) { dev_err(dev, "vref enable failed\n"); - return ret; + goto err_switches_disable; } if (priv->bclk) { @@ -604,6 +803,8 @@ static int stm32_adc_core_hw_start(struct device *dev) clk_disable_unprepare(priv->bclk); err_regulator_disable: regulator_disable(priv->vref); +err_switches_disable: + stm32_adc_switches_supply_dis(dev); return ret; } @@ -620,6 +821,68 @@ static void stm32_adc_core_hw_stop(struct device *dev) if (priv->bclk) clk_disable_unprepare(priv->bclk); regulator_disable(priv->vref); + stm32_adc_switches_supply_dis(dev); +} + +static int stm32_adc_get_syscfg_cell(struct device_node *np, + struct stm32_adc_syscfg *syscfg, + const char * prop) +{ + int ret; + + syscfg->regmap = syscon_regmap_lookup_by_phandle(np, prop); + if (IS_ERR(syscfg->regmap)) { + pr_debug("FGA: %s %ld\n", prop, PTR_ERR(syscfg->regmap)); + /* Optional */ + if (PTR_ERR(syscfg->regmap) == -ENODEV) + return 0; + else + return PTR_ERR(syscfg->regmap); + } + + ret = of_property_read_u32_index(np, prop, 1, &syscfg->reg); + if (ret) + return ret; + + return of_property_read_u32_index(np, prop, 2, &syscfg->mask); +} + +static int stm32_adc_syscfg_probe(struct platform_device *pdev, + struct stm32_adc_priv *priv) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + /* Start to lookup BOOSTE/EN_BOOSTER first, for stm32h7/stm32mp1 */ + ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster, + "st,syscfg-vbooster"); + if (ret) + return ret; + + /* Continue with stm32mp1 EN_BOOSTER/ANASWVDD set and clear bits*/ + ret = stm32_adc_get_syscfg_cell(np, &priv->vbooster_clr, + "st,syscfg-vbooster-clr"); + if (ret) + return ret; + + ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd, + "st,syscfg-anaswvdd"); + if (ret) + return ret; + + ret = stm32_adc_get_syscfg_cell(np, &priv->anaswvdd_clr, + "st,syscfg-anaswvdd-clr"); + if (ret) + return ret; + + /* Sanity, check syscfg set/clear pairs are filled in */ + if (priv->cfg->has_syscfg_clr && ((!IS_ERR(priv->vbooster.regmap) && + IS_ERR(priv->vbooster_clr.regmap)) || + (!IS_ERR(priv->anaswvdd.regmap) && + IS_ERR(priv->anaswvdd_clr.regmap)))) + return -EINVAL; + + return ret; } static int stm32_adc_probe(struct platform_device *pdev) @@ -657,6 +920,24 @@ static int stm32_adc_probe(struct platform_device *pdev) return ret; } + priv->vdda = devm_regulator_get_optional(&pdev->dev, "vdda"); + if (IS_ERR(priv->vdda)) { + ret = PTR_ERR(priv->vdda); + if (ret != -ENODEV) { + dev_err(&pdev->dev, "vdda get failed, %d\n", ret); + return ret; + } + } + + priv->vdd = devm_regulator_get_optional(&pdev->dev, "vdd"); + if (IS_ERR(priv->vdd)) { + ret = PTR_ERR(priv->vdd); + if (ret != -ENODEV) { + dev_err(&pdev->dev, "vdd get failed, %d\n", ret); + return ret; + } + } + priv->aclk = devm_clk_get(&pdev->dev, "adc"); if (IS_ERR(priv->aclk)) { ret = PTR_ERR(priv->aclk); @@ -677,8 +958,17 @@ static int stm32_adc_probe(struct platform_device *pdev) priv->bclk = NULL; } + ret = stm32_adc_syscfg_probe(pdev, priv); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Can't probe syscfg: %d\n", ret); + return ret; + } + 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); @@ -718,7 +1008,8 @@ static int stm32_adc_probe(struct platform_device *pdev) goto err_irq_remove; } - pm_runtime_put(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); return 0; @@ -789,6 +1080,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = { .regs = &stm32h7_adc_common_regs, .clk_sel = stm32h7_adc_clk_sel, + .has_syscfg_clr = true, .max_clk_rate_hz = 40000000, .exti_trigs = stm32h7_adc_exti_trigs, }; diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 980355e..13d2e3c 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -201,7 +201,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_AUTO_SUSPEND_DELAY_MS 2000 +#define STM32_ADC_HW_STOP_DELAY_MS 100 #define STM32_DMA_BUFFER_SIZE PAGE_SIZE @@ -2783,7 +2783,7 @@ static int stm32_adc_probe(struct platform_device *pdev) /* Get stm32-adc-core PM online */ pm_runtime_get_noresume(dev); pm_runtime_set_active(dev); - pm_runtime_set_autosuspend_delay(dev, STM32_ADC_AUTO_SUSPEND_DELAY_MS); + pm_runtime_set_autosuspend_delay(dev, STM32_ADC_HW_STOP_DELAY_MS); pm_runtime_use_autosuspend(dev); pm_runtime_enable(dev); -- 2.7.4