Commit d58c67d1 authored by Fabrice Gasnier's avatar Fabrice Gasnier Committed by Jonathan Cameron

iio: adc: stm32-adc: add support for STM32MP1

Add support for STM32MP1 ADC. It's quite similar to STM32H7 ADC.
Introduce new compatible to handle variants of this hardware such as
vregready flag, trigger list, interrupts, clock rate.
Signed-off-by: default avatarFabrice Gasnier <fabrice.gasnier@st.com>
Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 92a37376
...@@ -34,9 +34,6 @@ ...@@ -34,9 +34,6 @@
#define STM32F4_ADC_ADCPRE_SHIFT 16 #define STM32F4_ADC_ADCPRE_SHIFT 16
#define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16) #define STM32F4_ADC_ADCPRE_MASK GENMASK(17, 16)
/* STM32 F4 maximum analog clock rate (from datasheet) */
#define STM32F4_ADC_MAX_CLK_RATE 36000000
/* STM32H7 - common registers for all ADC instances */ /* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) #define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
...@@ -51,9 +48,6 @@ ...@@ -51,9 +48,6 @@
#define STM32H7_CKMODE_SHIFT 16 #define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16) #define STM32H7_CKMODE_MASK GENMASK(17, 16)
/* STM32 H7 maximum analog clock rate (from datasheet) */
#define STM32H7_ADC_MAX_CLK_RATE 36000000
/** /**
* stm32_adc_common_regs - stm32 common registers, compatible dependent data * stm32_adc_common_regs - stm32 common registers, compatible dependent data
* @csr: common status register offset * @csr: common status register offset
...@@ -74,15 +68,17 @@ struct stm32_adc_priv; ...@@ -74,15 +68,17 @@ struct stm32_adc_priv;
* stm32_adc_priv_cfg - stm32 core compatible configuration data * stm32_adc_priv_cfg - stm32 core compatible configuration data
* @regs: common registers for all instances * @regs: common registers for all instances
* @clk_sel: clock selection routine * @clk_sel: clock selection routine
* @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
*/ */
struct stm32_adc_priv_cfg { struct stm32_adc_priv_cfg {
const struct stm32_adc_common_regs *regs; const struct stm32_adc_common_regs *regs;
int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *); int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
u32 max_clk_rate_hz;
}; };
/** /**
* struct stm32_adc_priv - stm32 ADC core private data * struct stm32_adc_priv - stm32 ADC core private data
* @irq: irq for ADC block * @irq: irq(s) for ADC block
* @domain: irq domain reference * @domain: irq domain reference
* @aclk: clock reference for the analog circuitry * @aclk: clock reference for the analog circuitry
* @bclk: bus clock common for all ADCs, depends on part used * @bclk: bus clock common for all ADCs, depends on part used
...@@ -91,7 +87,7 @@ struct stm32_adc_priv_cfg { ...@@ -91,7 +87,7 @@ struct stm32_adc_priv_cfg {
* @common: common data for all ADC instances * @common: common data for all ADC instances
*/ */
struct stm32_adc_priv { struct stm32_adc_priv {
int irq; int irq[STM32_ADC_MAX_ADCS];
struct irq_domain *domain; struct irq_domain *domain;
struct clk *aclk; struct clk *aclk;
struct clk *bclk; struct clk *bclk;
...@@ -133,7 +129,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev, ...@@ -133,7 +129,7 @@ static int stm32f4_adc_clk_sel(struct platform_device *pdev,
} }
for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) { for (i = 0; i < ARRAY_SIZE(stm32f4_pclk_div); i++) {
if ((rate / stm32f4_pclk_div[i]) <= STM32F4_ADC_MAX_CLK_RATE) if ((rate / stm32f4_pclk_div[i]) <= priv->cfg->max_clk_rate_hz)
break; break;
} }
if (i >= ARRAY_SIZE(stm32f4_pclk_div)) { if (i >= ARRAY_SIZE(stm32f4_pclk_div)) {
...@@ -222,7 +218,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, ...@@ -222,7 +218,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode) if (ckmode)
continue; continue;
if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) if ((rate / div) <= priv->cfg->max_clk_rate_hz)
goto out; goto out;
} }
} }
...@@ -242,7 +238,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, ...@@ -242,7 +238,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode) if (!ckmode)
continue; continue;
if ((rate / div) <= STM32H7_ADC_MAX_CLK_RATE) if ((rate / div) <= priv->cfg->max_clk_rate_hz)
goto out; goto out;
} }
...@@ -328,11 +324,24 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, ...@@ -328,11 +324,24 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
struct stm32_adc_priv *priv) struct stm32_adc_priv *priv)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
unsigned int i;
for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
priv->irq[i] = platform_get_irq(pdev, i);
if (priv->irq[i] < 0) {
/*
* At least one interrupt must be provided, make others
* optional:
* - stm32f4/h7 shares a common interrupt.
* - stm32mp1, has one line per ADC (either for ADC1,
* ADC2 or both).
*/
if (i && priv->irq[i] == -ENXIO)
continue;
dev_err(&pdev->dev, "failed to get irq\n");
priv->irq = platform_get_irq(pdev, 0); return priv->irq[i];
if (priv->irq < 0) { }
dev_err(&pdev->dev, "failed to get irq\n");
return priv->irq;
} }
priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0, priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
...@@ -343,8 +352,12 @@ static int stm32_adc_irq_probe(struct platform_device *pdev, ...@@ -343,8 +352,12 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
return -ENOMEM; return -ENOMEM;
} }
irq_set_chained_handler(priv->irq, stm32_adc_irq_handler); for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
irq_set_handler_data(priv->irq, priv); if (priv->irq[i] < 0)
continue;
irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler);
irq_set_handler_data(priv->irq[i], priv);
}
return 0; return 0;
} }
...@@ -353,11 +366,17 @@ static void stm32_adc_irq_remove(struct platform_device *pdev, ...@@ -353,11 +366,17 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
struct stm32_adc_priv *priv) struct stm32_adc_priv *priv)
{ {
int hwirq; int hwirq;
unsigned int i;
for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++) for (hwirq = 0; hwirq < STM32_ADC_MAX_ADCS; hwirq++)
irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq)); irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
irq_domain_remove(priv->domain); irq_domain_remove(priv->domain);
irq_set_chained_handler(priv->irq, NULL);
for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
if (priv->irq[i] < 0)
continue;
irq_set_chained_handler(priv->irq[i], NULL);
}
} }
static int stm32_adc_probe(struct platform_device *pdev) static int stm32_adc_probe(struct platform_device *pdev)
...@@ -497,11 +516,19 @@ static int stm32_adc_remove(struct platform_device *pdev) ...@@ -497,11 +516,19 @@ static int stm32_adc_remove(struct platform_device *pdev)
static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = { static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
.regs = &stm32f4_adc_common_regs, .regs = &stm32f4_adc_common_regs,
.clk_sel = stm32f4_adc_clk_sel, .clk_sel = stm32f4_adc_clk_sel,
.max_clk_rate_hz = 36000000,
}; };
static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = { static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs, .regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel, .clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 36000000,
};
static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
.regs = &stm32h7_adc_common_regs,
.clk_sel = stm32h7_adc_clk_sel,
.max_clk_rate_hz = 40000000,
}; };
static const struct of_device_id stm32_adc_of_match[] = { static const struct of_device_id stm32_adc_of_match[] = {
...@@ -511,6 +538,9 @@ static const struct of_device_id stm32_adc_of_match[] = { ...@@ -511,6 +538,9 @@ static const struct of_device_id stm32_adc_of_match[] = {
}, { }, {
.compatible = "st,stm32h7-adc-core", .compatible = "st,stm32h7-adc-core",
.data = (void *)&stm32h7_adc_priv_cfg .data = (void *)&stm32h7_adc_priv_cfg
}, {
.compatible = "st,stm32mp1-adc-core",
.data = (void *)&stm32mp1_adc_priv_cfg
}, { }, {
}, },
}; };
......
...@@ -84,6 +84,7 @@ ...@@ -84,6 +84,7 @@
#define STM32H7_ADC_CALFACT2 0xC8 #define STM32H7_ADC_CALFACT2 0xC8
/* STM32H7_ADC_ISR - bit fields */ /* STM32H7_ADC_ISR - bit fields */
#define STM32MP1_VREGREADY BIT(12)
#define STM32H7_EOC BIT(2) #define STM32H7_EOC BIT(2)
#define STM32H7_ADRDY BIT(0) #define STM32H7_ADRDY BIT(0)
...@@ -249,6 +250,7 @@ struct stm32_adc; ...@@ -249,6 +250,7 @@ struct stm32_adc;
* @adc_info: per instance input channels definitions * @adc_info: per instance input channels definitions
* @trigs: external trigger sources * @trigs: external trigger sources
* @clk_required: clock is required * @clk_required: clock is required
* @has_vregready: vregready status flag presence
* @selfcalib: optional routine for self-calibration * @selfcalib: optional routine for self-calibration
* @prepare: optional prepare routine (power-up, enable) * @prepare: optional prepare routine (power-up, enable)
* @start_conv: routine to start conversions * @start_conv: routine to start conversions
...@@ -261,6 +263,7 @@ struct stm32_adc_cfg { ...@@ -261,6 +263,7 @@ struct stm32_adc_cfg {
const struct stm32_adc_info *adc_info; const struct stm32_adc_info *adc_info;
struct stm32_adc_trig_info *trigs; struct stm32_adc_trig_info *trigs;
bool clk_required; bool clk_required;
bool has_vregready;
int (*selfcalib)(struct stm32_adc *); int (*selfcalib)(struct stm32_adc *);
int (*prepare)(struct stm32_adc *); int (*prepare)(struct stm32_adc *);
void (*start_conv)(struct stm32_adc *, bool dma); void (*start_conv)(struct stm32_adc *, bool dma);
...@@ -695,8 +698,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc) ...@@ -695,8 +698,12 @@ static void stm32h7_adc_stop_conv(struct stm32_adc *adc)
stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK); stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR, STM32H7_DMNGT_MASK);
} }
static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) static int stm32h7_adc_exit_pwr_down(struct stm32_adc *adc)
{ {
struct iio_dev *indio_dev = iio_priv_to_dev(adc);
int ret;
u32 val;
/* Exit deep power down, then enable ADC voltage regulator */ /* Exit deep power down, then enable ADC voltage regulator */
stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD); stm32_adc_clr_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN); stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADVREGEN);
...@@ -705,7 +712,20 @@ static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc) ...@@ -705,7 +712,20 @@ static void stm32h7_adc_exit_pwr_down(struct stm32_adc *adc)
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST); stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_BOOST);
/* Wait for startup time */ /* Wait for startup time */
usleep_range(10, 20); if (!adc->cfg->has_vregready) {
usleep_range(10, 20);
return 0;
}
ret = stm32_adc_readl_poll_timeout(STM32H7_ADC_ISR, val,
val & STM32MP1_VREGREADY, 100,
STM32_ADC_TIMEOUT_US);
if (ret) {
stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_DEEPPWD);
dev_err(&indio_dev->dev, "Failed to exit power down\n");
}
return ret;
} }
static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc) static void stm32h7_adc_enter_pwr_down(struct stm32_adc *adc)
...@@ -888,7 +908,9 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc) ...@@ -888,7 +908,9 @@ static int stm32h7_adc_selfcalib(struct stm32_adc *adc)
int ret; int ret;
u32 val; u32 val;
stm32h7_adc_exit_pwr_down(adc); ret = stm32h7_adc_exit_pwr_down(adc);
if (ret)
return ret;
/* /*
* Select calibration mode: * Select calibration mode:
...@@ -952,7 +974,10 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc) ...@@ -952,7 +974,10 @@ static int stm32h7_adc_prepare(struct stm32_adc *adc)
{ {
int ret; int ret;
stm32h7_adc_exit_pwr_down(adc); ret = stm32h7_adc_exit_pwr_down(adc);
if (ret)
return ret;
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(adc); ret = stm32h7_adc_enable(adc);
...@@ -1944,9 +1969,23 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { ...@@ -1944,9 +1969,23 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
.smp_cycles = stm32h7_adc_smp_cycles, .smp_cycles = stm32h7_adc_smp_cycles,
}; };
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.regs = &stm32h7_adc_regspec,
.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,
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
};
static const struct of_device_id stm32_adc_of_match[] = { static const struct of_device_id stm32_adc_of_match[] = {
{ .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg }, { .compatible = "st,stm32f4-adc", .data = (void *)&stm32f4_adc_cfg },
{ .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg }, { .compatible = "st,stm32h7-adc", .data = (void *)&stm32h7_adc_cfg },
{ .compatible = "st,stm32mp1-adc", .data = (void *)&stm32mp1_adc_cfg },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, stm32_adc_of_match); MODULE_DEVICE_TABLE(of, stm32_adc_of_match);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment