meta-st-stm32mp/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r...

2146 lines
67 KiB
Diff

From fc843f64f154b843cd7834d6748b409ef1e1487f Mon Sep 17 00:00:00 2001
From: Lionel Vitte <lionel.vitte@st.com>
Date: Thu, 14 Oct 2021 16:51:44 +0200
Subject: [PATCH 08/23] ARM 5.10.61-stm32mp1-r2 I2C-IIO-IRQCHIP
---
drivers/i2c/busses/i2c-stm32f7.c | 285 +++++++++++-------
drivers/iio/adc/sd_adc_modulator.c | 89 +++++-
drivers/iio/adc/stm32-adc-core.c | 21 +-
drivers/iio/adc/stm32-adc-core.h | 8 +
drivers/iio/adc/stm32-adc.c | 445 ++++++++++++++++++++++++-----
drivers/iio/adc/stm32-dfsdm-adc.c | 108 ++++++-
drivers/iio/adc/stm32-dfsdm-core.c | 91 ++++--
drivers/iio/adc/stm32-dfsdm.h | 69 +++--
drivers/irqchip/irq-stm32-exti.c | 89 +++++-
9 files changed, 973 insertions(+), 232 deletions(-)
diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c
index 1e800b65e..0bc9acef2 100644
--- a/drivers/i2c/busses/i2c-stm32f7.c
+++ b/drivers/i2c/busses/i2c-stm32f7.c
@@ -51,6 +51,7 @@
/* STM32F7 I2C control 1 */
#define STM32F7_I2C_CR1_PECEN BIT(23)
+#define STM32F7_I2C_CR1_ALERTEN BIT(22)
#define STM32F7_I2C_CR1_SMBHEN BIT(20)
#define STM32F7_I2C_CR1_WUPEN BIT(18)
#define STM32F7_I2C_CR1_SBC BIT(16)
@@ -125,6 +126,7 @@
(((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17)
#define STM32F7_I2C_ISR_DIR BIT(16)
#define STM32F7_I2C_ISR_BUSY BIT(15)
+#define STM32F7_I2C_ISR_ALERT BIT(13)
#define STM32F7_I2C_ISR_PECERR BIT(11)
#define STM32F7_I2C_ISR_ARLO BIT(9)
#define STM32F7_I2C_ISR_BERR BIT(8)
@@ -138,6 +140,7 @@
#define STM32F7_I2C_ISR_TXE BIT(0)
/* STM32F7 I2C Interrupt Clear */
+#define STM32F7_I2C_ICR_ALERTCF BIT(13)
#define STM32F7_I2C_ICR_PECCF BIT(11)
#define STM32F7_I2C_ICR_ARLOCF BIT(9)
#define STM32F7_I2C_ICR_BERRCF BIT(8)
@@ -161,10 +164,8 @@ enum {
STM32F7_I2C_MAX_SLAVE
};
-#define STM32F7_I2C_DNF_DEFAULT 0
#define STM32F7_I2C_DNF_MAX 15
-#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1
#define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */
#define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */
@@ -223,8 +224,6 @@ struct stm32f7_i2c_spec {
* @clock_src: I2C clock source frequency (Hz)
* @rise_time: Rise time (ns)
* @fall_time: Fall time (ns)
- * @dnf: Digital filter coefficient (0-16)
- * @analog_filter: Analog filter delay (On/Off)
* @fmp_clr_offset: Fast Mode Plus clear register offset from set register
*/
struct stm32f7_i2c_setup {
@@ -232,8 +231,6 @@ struct stm32f7_i2c_setup {
u32 clock_src;
u32 rise_time;
u32 fall_time;
- u8 dnf;
- bool analog_filter;
u32 fmp_clr_offset;
};
@@ -283,6 +280,17 @@ struct stm32f7_i2c_msg {
u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4);
};
+/**
+ * struct stm32f7_i2c_alert - SMBus alert specific data
+ * @setup: platform data for the smbus_alert i2c client
+ * @ara: I2C slave device used to respond to the SMBus Alert with Alert
+ * Response Address
+ */
+struct stm32f7_i2c_alert {
+ struct i2c_smbus_alert_setup setup;
+ struct i2c_client *ara;
+};
+
/**
* struct stm32f7_i2c_dev - private data of the controller
* @adap: I2C adapter for this controller
@@ -312,6 +320,10 @@ struct stm32f7_i2c_msg {
* @wakeup_src: boolean to know if the device is a wakeup source
* @smbus_mode: states that the controller is configured in SMBus mode
* @host_notify_client: SMBus host-notify client
+ * @alert: SMBus alert specific data
+ * @analog_filter: boolean to indicate enabling of the analog filter
+ * @dnf_dt: value of digital filter requested via dt
+ * @dnf: value of digital filter to apply
*/
struct stm32f7_i2c_dev {
struct i2c_adapter adap;
@@ -340,6 +352,10 @@ struct stm32f7_i2c_dev {
bool wakeup_src;
bool smbus_mode;
struct i2c_client *host_notify_client;
+ struct stm32f7_i2c_alert *alert;
+ bool analog_filter;
+ u32 dnf_dt;
+ u32 dnf;
};
/*
@@ -385,15 +401,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = {
static const struct stm32f7_i2c_setup stm32f7_setup = {
.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
- .dnf = STM32F7_I2C_DNF_DEFAULT,
- .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,
};
static const struct stm32f7_i2c_setup stm32mp15_setup = {
.rise_time = STM32F7_I2C_RISE_TIME_DEFAULT,
.fall_time = STM32F7_I2C_FALL_TIME_DEFAULT,
- .dnf = STM32F7_I2C_DNF_DEFAULT,
- .analog_filter = STM32F7_I2C_ANALOG_FILTER_ENABLE,
.fmp_clr_offset = 0x40,
};
@@ -462,27 +474,28 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev,
return -EINVAL;
}
- if (setup->dnf > STM32F7_I2C_DNF_MAX) {
+ i2c_dev->dnf = DIV_ROUND_CLOSEST(i2c_dev->dnf_dt, i2cclk);
+ if (i2c_dev->dnf > STM32F7_I2C_DNF_MAX) {
dev_err(i2c_dev->dev,
"DNF out of bound %d/%d\n",
- setup->dnf, STM32F7_I2C_DNF_MAX);
+ i2c_dev->dnf * i2cclk, STM32F7_I2C_DNF_MAX * i2cclk);
return -EINVAL;
}
/* Analog and Digital Filters */
af_delay_min =
- (setup->analog_filter ?
+ (i2c_dev->analog_filter ?
STM32F7_I2C_ANALOG_FILTER_DELAY_MIN : 0);
af_delay_max =
- (setup->analog_filter ?
+ (i2c_dev->analog_filter ?
STM32F7_I2C_ANALOG_FILTER_DELAY_MAX : 0);
- dnf_delay = setup->dnf * i2cclk;
+ dnf_delay = i2c_dev->dnf * i2cclk;
sdadel_min = specs->hddat_min + setup->fall_time -
- af_delay_min - (setup->dnf + 3) * i2cclk;
+ af_delay_min - (i2c_dev->dnf + 3) * i2cclk;
sdadel_max = specs->vddat_max - setup->rise_time -
- af_delay_max - (setup->dnf + 4) * i2cclk;
+ af_delay_max - (i2c_dev->dnf + 4) * i2cclk;
scldel_min = setup->rise_time + specs->sudat_min;
@@ -648,6 +661,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
setup->speed_freq = t->bus_freq_hz;
i2c_dev->setup.rise_time = t->scl_rise_ns;
i2c_dev->setup.fall_time = t->scl_fall_ns;
+ i2c_dev->dnf_dt = t->digital_filter_width_ns;
setup->clock_src = clk_get_rate(i2c_dev->clk);
if (!setup->clock_src) {
@@ -655,6 +669,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
return -EINVAL;
}
+ if (!of_property_read_bool(i2c_dev->dev->of_node, "i2c-digital-filter"))
+ i2c_dev->dnf_dt = 0;
+
do {
ret = stm32f7_i2c_compute_timing(i2c_dev, setup,
&i2c_dev->timing);
@@ -676,12 +693,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev,
return ret;
}
+ i2c_dev->analog_filter = of_property_read_bool(i2c_dev->dev->of_node,
+ "i2c-analog-filter");
+
dev_dbg(i2c_dev->dev, "I2C Speed(%i), Clk Source(%i)\n",
setup->speed_freq, setup->clock_src);
dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n",
setup->rise_time, setup->fall_time);
dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n",
- (setup->analog_filter ? "On" : "Off"), setup->dnf);
+ (i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf);
i2c_dev->bus_rate = setup->speed_freq;
@@ -720,8 +740,8 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll);
writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR);
- /* Enable I2C */
- if (i2c_dev->setup.analog_filter)
+ /* Configure the Analog Filter */
+ if (i2c_dev->analog_filter)
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_ANFOFF);
else
@@ -732,7 +752,7 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev)
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_DNF_MASK);
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
- STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf));
+ STM32F7_I2C_CR1_DNF(i2c_dev->dnf));
stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1,
STM32F7_I2C_CR1_PE);
@@ -1403,7 +1423,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR);
/* Slave transmitter mode */
- if (status & STM32F7_I2C_ISR_TXIS) {
+ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_TXIS)) {
i2c_slave_event(i2c_dev->slave_running,
I2C_SLAVE_READ_PROCESSED,
&val);
@@ -1413,7 +1433,8 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
}
/* Transfer Complete Reload for Slave receiver mode */
- if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) {
+ if (i2c_dev->slave_running &&
+ (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE)) {
/*
* Read data byte then set NBYTES to receive next byte or NACK
* the current received byte
@@ -1439,7 +1460,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev)
}
/* STOP received */
- if (status & STM32F7_I2C_ISR_STOPF) {
+ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_STOPF)) {
/* Disable interrupts */
stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK);
@@ -1472,6 +1493,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
{
struct stm32f7_i2c_dev *i2c_dev = data;
struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg;
+ struct stm32_i2c_dma *dma = i2c_dev->dma;
void __iomem *base = i2c_dev->base;
u32 status, mask;
int ret = IRQ_HANDLED;
@@ -1497,6 +1519,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n",
__func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR);
+ if (i2c_dev->use_dma) {
+ stm32f7_i2c_disable_dma_req(i2c_dev);
+ dmaengine_terminate_async(dma->chan_using);
+ }
f7_msg->result = -ENXIO;
}
@@ -1512,7 +1538,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
/* Clear STOP flag */
writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR);
- if (i2c_dev->use_dma) {
+ if (i2c_dev->use_dma && !f7_msg->result) {
ret = IRQ_WAKE_THREAD;
} else {
i2c_dev->master_mode = false;
@@ -1525,7 +1551,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data)
if (f7_msg->stop) {
mask = STM32F7_I2C_CR2_STOP;
stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask);
- } else if (i2c_dev->use_dma) {
+ } else if (i2c_dev->use_dma && !f7_msg->result) {
ret = IRQ_WAKE_THREAD;
} else if (f7_msg->smbus) {
stm32f7_i2c_smbus_rep_start(i2c_dev);
@@ -1562,7 +1588,7 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data)
if (!ret) {
dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__);
stm32f7_i2c_disable_dma_req(i2c_dev);
- dmaengine_terminate_all(dma->chan_using);
+ dmaengine_terminate_async(dma->chan_using);
f7_msg->result = -ETIMEDOUT;
}
@@ -1597,7 +1623,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
/* Bus error */
if (status & STM32F7_I2C_ISR_BERR) {
- dev_err(dev, "<%s>: Bus error\n", __func__);
+ dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n",
+ __func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR);
stm32f7_i2c_release_bus(&i2c_dev->adap);
f7_msg->result = -EIO;
@@ -1605,17 +1632,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
/* Arbitration loss */
if (status & STM32F7_I2C_ISR_ARLO) {
- dev_dbg(dev, "<%s>: Arbitration loss\n", __func__);
+ dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n",
+ __func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR);
f7_msg->result = -EAGAIN;
}
if (status & STM32F7_I2C_ISR_PECERR) {
- dev_err(dev, "<%s>: PEC error in reception\n", __func__);
+ dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n",
+ __func__, f7_msg->addr);
writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR);
f7_msg->result = -EINVAL;
}
+ if (status & STM32F7_I2C_ISR_ALERT) {
+ dev_dbg(dev, "<%s>: SMBus alert received\n", __func__);
+ writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR);
+ i2c_handle_smbus_alert(i2c_dev->alert->ara);
+ return IRQ_HANDLED;
+ }
+
if (!i2c_dev->slave_running) {
u32 mask;
/* Disable interrupts */
@@ -1629,7 +1665,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data)
/* Disable dma */
if (i2c_dev->use_dma) {
stm32f7_i2c_disable_dma_req(i2c_dev);
- dmaengine_terminate_all(dma->chan_using);
+ dmaengine_terminate_async(dma->chan_using);
}
i2c_dev->master_mode = false;
@@ -1665,12 +1701,26 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap,
time_left = wait_for_completion_timeout(&i2c_dev->complete,
i2c_dev->adap.timeout);
ret = f7_msg->result;
+ if (ret) {
+ if (i2c_dev->use_dma)
+ dmaengine_synchronize(dma->chan_using);
+
+ /*
+ * It is possible that some unsent data have already been
+ * written into TXDR. To avoid sending old data in a
+ * further transfer, flush TXDR in case of any error
+ */
+ writel_relaxed(STM32F7_I2C_ISR_TXE,
+ i2c_dev->base + STM32F7_I2C_ISR);
+ goto pm_free;
+ }
if (!time_left) {
dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n",
i2c_dev->msg->addr);
if (i2c_dev->use_dma)
- dmaengine_terminate_all(dma->chan_using);
+ dmaengine_terminate_sync(dma->chan_using);
+ stm32f7_i2c_wait_free_bus(i2c_dev);
ret = -ETIMEDOUT;
}
@@ -1713,13 +1763,25 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
timeout = wait_for_completion_timeout(&i2c_dev->complete,
i2c_dev->adap.timeout);
ret = f7_msg->result;
- if (ret)
+ if (ret) {
+ if (i2c_dev->use_dma)
+ dmaengine_synchronize(dma->chan_using);
+
+ /*
+ * It is possible that some unsent data have already been
+ * written into TXDR. To avoid sending old data in a
+ * further transfer, flush TXDR in case of any error
+ */
+ writel_relaxed(STM32F7_I2C_ISR_TXE,
+ i2c_dev->base + STM32F7_I2C_ISR);
goto pm_free;
+ }
if (!timeout) {
dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr);
if (i2c_dev->use_dma)
- dmaengine_terminate_all(dma->chan_using);
+ dmaengine_terminate_sync(dma->chan_using);
+ stm32f7_i2c_wait_free_bus(i2c_dev);
ret = -ETIMEDOUT;
goto pm_free;
}
@@ -1982,6 +2044,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev)
}
}
+static int stm32f7_i2c_enable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_alert *alert;
+ struct i2c_adapter *adap = &i2c_dev->adap;
+ struct device *dev = i2c_dev->dev;
+ void __iomem *base = i2c_dev->base;
+
+ alert = devm_kzalloc(dev, sizeof(*alert), GFP_KERNEL);
+ if (!alert)
+ return -ENOMEM;
+
+ alert->ara = i2c_new_smbus_alert_device(adap, &alert->setup);
+ if (IS_ERR(alert->ara))
+ return PTR_ERR(alert->ara);
+
+ i2c_dev->alert = alert;
+
+ /* Enable SMBus Alert */
+ stm32f7_i2c_set_bits(base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ALERTEN);
+
+ return 0;
+}
+
+static void stm32f7_i2c_disable_smbus_alert(struct stm32f7_i2c_dev *i2c_dev)
+{
+ struct stm32f7_i2c_alert *alert = i2c_dev->alert;
+ void __iomem *base = i2c_dev->base;
+
+ if (alert) {
+ /* Disable SMBus Alert */
+ stm32f7_i2c_clr_bits(base + STM32F7_I2C_CR1,
+ STM32F7_I2C_CR1_ALERTEN);
+ i2c_unregister_device(alert->ara);
+ }
+}
+
static u32 stm32f7_i2c_func(struct i2c_adapter *adap)
{
struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
@@ -2173,6 +2271,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
}
}
+ if (of_property_read_bool(pdev->dev.of_node, "st,smbus-alert")) {
+ ret = stm32f7_i2c_enable_smbus_alert(i2c_dev);
+ if (ret) {
+ dev_err(i2c_dev->dev,
+ "failed to enable SMBus alert protocol (%d)\n",
+ ret);
+ goto i2c_disable_smbus_host;
+ }
+ }
+
dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr);
pm_runtime_mark_last_busy(i2c_dev->dev);
@@ -2180,6 +2288,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev)
return 0;
+i2c_disable_smbus_host:
+ stm32f7_i2c_disable_smbus_host(i2c_dev);
+
i2c_adapter_remove:
i2c_del_adapter(adap);
@@ -2214,6 +2325,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
{
struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
+ stm32f7_i2c_disable_smbus_alert(i2c_dev);
stm32f7_i2c_disable_smbus_host(i2c_dev);
i2c_del_adapter(&i2c_dev->adap);
@@ -2245,64 +2357,25 @@ static int stm32f7_i2c_remove(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
+static void __maybe_unused
+stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
{
- struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
-
- if (!stm32f7_i2c_is_slave_registered(i2c_dev))
- clk_disable_unprepare(i2c_dev->clk);
-
- return 0;
-}
-
-static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
-{
- struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
- int ret;
-
- if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
- ret = clk_prepare_enable(i2c_dev->clk);
- if (ret) {
- dev_err(dev, "failed to prepare_enable clock\n");
- return ret;
- }
- }
-
- return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev)
-{
- int ret;
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
- ret = pm_runtime_resume_and_get(i2c_dev->dev);
- if (ret < 0)
- return ret;
-
backup_regs->cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
backup_regs->cr2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR2);
backup_regs->oar1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR1);
backup_regs->oar2 = readl_relaxed(i2c_dev->base + STM32F7_I2C_OAR2);
backup_regs->tmgr = readl_relaxed(i2c_dev->base + STM32F7_I2C_TIMINGR);
stm32f7_i2c_write_fm_plus_bits(i2c_dev, false);
-
- pm_runtime_put_sync(i2c_dev->dev);
-
- return ret;
}
-static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
+static void __maybe_unused
+stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
{
u32 cr1;
- int ret;
struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs;
- ret = pm_runtime_resume_and_get(i2c_dev->dev);
- if (ret < 0)
- return ret;
-
cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1);
if (cr1 & STM32F7_I2C_CR1_PE)
stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1,
@@ -2318,54 +2391,68 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev)
writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1);
writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2);
stm32f7_i2c_write_fm_plus_bits(i2c_dev, true);
+}
- pm_runtime_put_sync(i2c_dev->dev);
+static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
- return ret;
+ stm32f7_i2c_regs_backup(i2c_dev);
+
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev))
+ clk_disable_unprepare(i2c_dev->clk);
+
+ return 0;
}
-static int stm32f7_i2c_suspend(struct device *dev)
+static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev)
{
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
- i2c_mark_adapter_suspended(&i2c_dev->adap);
-
- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) {
- ret = stm32f7_i2c_regs_backup(i2c_dev);
- if (ret < 0) {
- i2c_mark_adapter_resumed(&i2c_dev->adap);
+ if (!stm32f7_i2c_is_slave_registered(i2c_dev)) {
+ ret = clk_prepare_enable(i2c_dev->clk);
+ if (ret) {
+ dev_err(dev, "failed to prepare_enable clock\n");
return ret;
}
+ }
+ stm32f7_i2c_regs_restore(i2c_dev);
+
+ return 0;
+}
+
+static int __maybe_unused stm32f7_i2c_suspend(struct device *dev)
+{
+ struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
+
+ i2c_mark_adapter_suspended(&i2c_dev->adap);
+
+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev))
pinctrl_pm_select_sleep_state(dev);
- pm_runtime_force_suspend(dev);
- }
+
+ pm_runtime_force_suspend(dev);
return 0;
}
-static int stm32f7_i2c_resume(struct device *dev)
+static int __maybe_unused stm32f7_i2c_resume(struct device *dev)
{
struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev);
int ret;
- if (!device_may_wakeup(dev) && !dev->power.wakeup_path) {
- ret = pm_runtime_force_resume(dev);
- if (ret < 0)
- return ret;
- pinctrl_pm_select_default_state(dev);
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
- ret = stm32f7_i2c_regs_restore(i2c_dev);
- if (ret < 0)
- return ret;
- }
+ if (!device_may_wakeup(dev) && !device_wakeup_path(dev))
+ pinctrl_pm_select_default_state(dev);
i2c_mark_adapter_resumed(&i2c_dev->adap);
return 0;
}
-#endif
static const struct dev_pm_ops stm32f7_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend,
diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c
index 327cc2097..ceb150296 100644
--- a/drivers/iio/adc/sd_adc_modulator.c
+++ b/drivers/iio/adc/sd_adc_modulator.c
@@ -9,10 +9,8 @@
#include <linux/iio/iio.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/platform_device.h>
-
-static const struct iio_info iio_sd_mod_iio_info;
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
static const struct iio_chan_spec iio_sd_mod_ch = {
.type = IIO_VOLTAGE,
@@ -22,34 +20,99 @@ static const struct iio_chan_spec iio_sd_mod_ch = {
.realbits = 1,
.shift = 0,
},
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+};
+
+static const struct iio_chan_spec iio_sd_mod_ch_ads = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 1,
+ .shift = 0,
+ },
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+ .differential = 1,
+};
+
+struct iio_sd_mod_priv {
+ int vref_mv;
+};
+
+static const struct of_device_id sd_adc_of_match[] = {
+ { .compatible = "sd-modulator", .data = &iio_sd_mod_ch },
+ { .compatible = "ads1201", .data = &iio_sd_mod_ch_ads },
+ { }
+};
+
+static int iio_sd_mod_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct iio_sd_mod_priv *priv = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *val = priv->vref_mv;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_INT;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_info iio_sd_mod_iio_info = {
+ .read_raw = iio_sd_mod_read_raw,
};
static int iio_sd_mod_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct iio_sd_mod_priv *priv;
+ struct regulator *vref;
struct iio_dev *iio;
+ int ret;
- iio = devm_iio_device_alloc(dev, 0);
+ iio = devm_iio_device_alloc(dev, sizeof(*priv));
if (!iio)
return -ENOMEM;
+ iio->channels = (const struct iio_chan_spec *)
+ of_match_device(sd_adc_of_match, &pdev->dev)->data;
+
+ priv = iio_priv(iio);
+
+ iio->dev.parent = dev;
+ iio->dev.of_node = dev->of_node;
iio->name = dev_name(dev);
iio->info = &iio_sd_mod_iio_info;
iio->modes = INDIO_BUFFER_HARDWARE;
-
iio->num_channels = 1;
- iio->channels = &iio_sd_mod_ch;
- platform_set_drvdata(pdev, iio);
+ vref = devm_regulator_get_optional(dev, "vref");
+ if (IS_ERR(vref)) {
+ ret = PTR_ERR(vref);
+ if (ret != -ENODEV) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "vref get failed, %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!IS_ERR(vref)) {
+ ret = regulator_get_voltage(vref);
+ if (ret < 0) {
+ dev_err(dev, "vref get failed, %d\n", ret);
+ return ret;
+ }
+
+ priv->vref_mv = ret / 1000;
+ dev_dbg(dev, "vref+=%dmV\n", priv->vref_mv);
+ }
return devm_iio_device_register(&pdev->dev, iio);
}
-static const struct of_device_id sd_adc_of_match[] = {
- { .compatible = "sd-modulator" },
- { .compatible = "ads1201" },
- { }
-};
MODULE_DEVICE_TABLE(of, sd_adc_of_match);
static struct platform_driver iio_sd_mod_adc = {
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index a83199b21..9d1ad6e38 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -200,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
{
u32 ckmode, presc, val;
unsigned long rate;
- int i, div;
+ int i, div, duty;
/* stm32h7 bus clock is common for all ADC instances (mandatory) */
if (!priv->bclk) {
@@ -224,6 +224,11 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
return -EINVAL;
}
+ /* If duty is an error, kindly use at least /2 divider */
+ duty = clk_get_scaled_duty_cycle(priv->aclk, 100);
+ if (duty < 0)
+ dev_warn(&pdev->dev, "adc clock duty: %d\n", duty);
+
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
@@ -232,6 +237,13 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (ckmode)
continue;
+ /*
+ * For proper operation, clock duty cycle range is 49%
+ * to 51%. Apply at least /2 prescaler otherwise.
+ */
+ if (div == 1 && (duty < 49 || duty > 51))
+ continue;
+
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
@@ -244,6 +256,10 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
return -EINVAL;
}
+ duty = clk_get_scaled_duty_cycle(priv->bclk, 100);
+ if (duty < 0)
+ dev_warn(&pdev->dev, "bus clock duty: %d\n", duty);
+
for (i = 0; i < ARRAY_SIZE(stm32h7_adc_ckmodes_spec); i++) {
ckmode = stm32h7_adc_ckmodes_spec[i].ckmode;
presc = stm32h7_adc_ckmodes_spec[i].presc;
@@ -252,6 +268,9 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev,
if (!ckmode)
continue;
+ if (div == 1 && (duty < 49 || duty > 51))
+ continue;
+
if ((rate / div) <= priv->max_clk_rate)
goto out;
}
diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
index 2322809bf..7c924f463 100644
--- a/drivers/iio/adc/stm32-adc-core.h
+++ b/drivers/iio/adc/stm32-adc-core.h
@@ -102,6 +102,9 @@
#define STM32H7_ADC_CALFACT 0xC4
#define STM32H7_ADC_CALFACT2 0xC8
+/* STM32MP1 - ADC2 instance option register */
+#define STM32MP1_ADC2_OR 0xD0
+
/* STM32H7 - common registers for all ADC instances */
#define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00)
#define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08)
@@ -168,11 +171,16 @@ enum stm32h7_adc_dmngt {
#define STM32H7_EOC_MST BIT(2)
/* STM32H7_ADC_CCR - bit fields */
+#define STM32H7_VBATEN BIT(24)
+#define STM32H7_VREFEN BIT(22)
#define STM32H7_PRESC_SHIFT 18
#define STM32H7_PRESC_MASK GENMASK(21, 18)
#define STM32H7_CKMODE_SHIFT 16
#define STM32H7_CKMODE_MASK GENMASK(17, 16)
+/* STM32MP1_ADC2_OR - bit fields */
+#define STM32MP1_VDDCOREEN BIT(0)
+
/**
* struct stm32_adc_common - stm32 ADC driver common data (for all instances)
* @base: control registers base cpu addr
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index 16c02c30d..6e9744944 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -21,6 +21,7 @@
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
+#include <linux/nvmem-consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/of.h>
@@ -35,12 +36,14 @@
#define STM32H7_BOOST_CLKRATE 20000000UL
#define STM32_ADC_CH_MAX 20 /* max number of channels */
-#define STM32_ADC_CH_SZ 10 /* max channel name size */
+#define STM32_ADC_CH_SZ 16 /* max channel name size */
#define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */
#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_ADC_CHAN_NONE -1
+#define STM32_ADC_VREFINT_VOLTAGE 3300
#define STM32_DMA_BUFFER_SIZE PAGE_SIZE
@@ -77,6 +80,30 @@ enum stm32_adc_extsel {
STM32_EXT20,
};
+enum stm32_adc_int_ch {
+ STM32_ADC_INT_CH_NONE = -1,
+ STM32_ADC_INT_CH_VDDCORE,
+ STM32_ADC_INT_CH_VREFINT,
+ STM32_ADC_INT_CH_VBAT,
+ STM32_ADC_INT_CH_NB,
+};
+
+/**
+ * struct stm32_adc_ic - ADC internal channels
+ * @name: name of the internal channel
+ * @idx: internal channel enum index
+ */
+struct stm32_adc_ic {
+ const char *name;
+ u32 idx;
+};
+
+static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = {
+ { "vddcore", STM32_ADC_INT_CH_VDDCORE },
+ { "vrefint", STM32_ADC_INT_CH_VREFINT },
+ { "vbat", STM32_ADC_INT_CH_VBAT },
+};
+
/**
* struct stm32_adc_trig_info - ADC trigger info
* @name: name of the trigger, corresponding to its source
@@ -113,6 +140,16 @@ struct stm32_adc_regs {
int shift;
};
+/**
+ * struct stm32_adc_vrefint - stm32 ADC internal reference voltage data
+ * @vrefint_cal: vrefint calibration value from nvmem
+ * @vrefint_data: vrefint actual value
+ */
+struct stm32_adc_vrefint {
+ u32 vrefint_cal;
+ u32 vrefint_data;
+};
+
/**
* struct stm32_adc_regspec - stm32 registers definition
* @dr: data register offset
@@ -126,6 +163,9 @@ struct stm32_adc_regs {
* @res: resolution selection register & bitfield
* @smpr: smpr1 & smpr2 registers offset array
* @smp_bits: smpr1 & smpr2 index and bitfields
+ * @or_vdd: option register & vddcore bitfield
+ * @ccr_vbat: common register & vbat bitfield
+ * @ccr_vref: common register & vrefint bitfield
*/
struct stm32_adc_regspec {
const u32 dr;
@@ -139,6 +179,9 @@ struct stm32_adc_regspec {
const struct stm32_adc_regs res;
const u32 smpr[2];
const struct stm32_adc_regs *smp_bits;
+ const struct stm32_adc_regs or_vdd;
+ const struct stm32_adc_regs ccr_vbat;
+ const struct stm32_adc_regs ccr_vref;
};
struct stm32_adc;
@@ -156,6 +199,7 @@ struct stm32_adc;
* @unprepare: optional unprepare routine (disable, power-down)
* @irq_clear: routine to clear irqs
* @smp_cycles: programmable sampling time (ADC clock cycles)
+ * @ts_vrefint_ns: vrefint minimum sampling time in ns
*/
struct stm32_adc_cfg {
const struct stm32_adc_regspec *regs;
@@ -169,6 +213,7 @@ struct stm32_adc_cfg {
void (*unprepare)(struct iio_dev *);
void (*irq_clear)(struct iio_dev *indio_dev, u32 msk);
const unsigned int *smp_cycles;
+ const unsigned int ts_vrefint_ns;
};
/**
@@ -193,7 +238,10 @@ struct stm32_adc_cfg {
* @pcsel: bitmask to preselect channels on some devices
* @smpr_val: sampling time settings (e.g. smpr1 / smpr2)
* @cal: optional calibration data on some devices
+ * @vrefint: internal reference voltage data
* @chan_name: channel name array
+ * @num_diff: number of differential channels
+ * @int_ch: internal channel indexes array
*/
struct stm32_adc {
struct stm32_adc_common *common;
@@ -216,7 +264,10 @@ struct stm32_adc {
u32 pcsel;
u32 smpr_val[2];
struct stm32_adc_calib cal;
+ struct stm32_adc_vrefint vrefint;
char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ];
+ u32 num_diff;
+ int int_ch[STM32_ADC_INT_CH_NB];
};
struct stm32_adc_diff_channel {
@@ -449,6 +500,24 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = {
.smp_bits = stm32h7_smp_bits,
};
+static const struct stm32_adc_regspec stm32mp1_adc_regspec = {
+ .dr = STM32H7_ADC_DR,
+ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE },
+ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE },
+ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC },
+ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR },
+ .sqr = stm32h7_sq,
+ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT },
+ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK,
+ STM32H7_EXTSEL_SHIFT },
+ .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT },
+ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 },
+ .smp_bits = stm32h7_smp_bits,
+ .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN },
+ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN },
+ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN },
+};
+
/**
* STM32 ADC registers access routines
* @adc: stm32 adc instance
@@ -581,6 +650,61 @@ static int stm32_adc_hw_start(struct device *dev)
return ret;
}
+static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u32 i, val, bits = 0, offset = 0;
+
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
+ if (adc->int_ch[i] == STM32_ADC_CHAN_NONE)
+ continue;
+
+ switch (i) {
+ case STM32_ADC_INT_CH_VDDCORE:
+ dev_dbg(&indio_dev->dev, "Enable VDDCore\n");
+ stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg,
+ adc->cfg->regs->or_vdd.mask);
+ break;
+ case STM32_ADC_INT_CH_VREFINT:
+ dev_dbg(&indio_dev->dev, "Enable VREFInt\n");
+ offset = adc->cfg->regs->ccr_vref.reg;
+ bits |= adc->cfg->regs->ccr_vref.mask;
+ break;
+ case STM32_ADC_INT_CH_VBAT:
+ dev_dbg(&indio_dev->dev, "Enable VBAT\n");
+ offset = adc->cfg->regs->ccr_vbat.reg;
+ bits |= adc->cfg->regs->ccr_vbat.mask;
+ break;
+ }
+ }
+
+ if (bits) {
+ val = readl_relaxed(adc->common->base + offset);
+ val |= bits;
+ writel_relaxed(val, adc->common->base + offset);
+ }
+}
+
+static void stm32_adc_int_ch_disable(struct stm32_adc *adc)
+{
+ u32 val, bits, offset, i;
+
+ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg,
+ adc->cfg->regs->or_vdd.mask);
+
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
+ if (adc->int_ch[i] != STM32_ADC_CHAN_NONE) {
+ offset = adc->cfg->regs->ccr_vref.reg;
+ bits = adc->cfg->regs->ccr_vref.mask |
+ adc->cfg->regs->ccr_vbat.mask;
+ val = readl_relaxed(adc->common->base + offset);
+ val &= ~bits;
+ writel_relaxed(bits, adc->common->base + offset);
+ break;
+ }
+ }
+}
+
/**
* stm32f4_adc_start_conv() - Start conversions for regular channels.
* @indio_dev: IIO device instance
@@ -949,11 +1073,13 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
goto pwr_dwn;
calib = ret;
+ stm32_adc_int_ch_enable(indio_dev);
+
stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel);
ret = stm32h7_adc_enable(indio_dev);
if (ret)
- goto pwr_dwn;
+ goto ch_disable;
/* Either restore or read calibration result for future reference */
if (calib)
@@ -969,6 +1095,8 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev)
disable:
stm32h7_adc_disable(indio_dev);
+ch_disable:
+ stm32_adc_int_ch_disable(adc);
pwr_dwn:
stm32h7_adc_enter_pwr_down(adc);
@@ -979,7 +1107,9 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
+ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0);
stm32h7_adc_disable(indio_dev);
+ stm32_adc_int_ch_disable(adc);
stm32h7_adc_enter_pwr_down(adc);
}
@@ -1225,15 +1355,35 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
ret = stm32_adc_single_conv(indio_dev, chan, val);
else
ret = -EINVAL;
+
+ /* If channel mask corresponds to vrefint, store data */
+ if (adc->int_ch[STM32_ADC_INT_CH_VREFINT] == chan->channel)
+ adc->vrefint.vrefint_data = *val;
+
iio_device_release_direct_mode(indio_dev);
return ret;
case IIO_CHAN_INFO_SCALE:
if (chan->differential) {
- *val = adc->common->vref_mv * 2;
+ if (adc->vrefint.vrefint_data &&
+ adc->vrefint.vrefint_cal) {
+ *val = STM32_ADC_VREFINT_VOLTAGE * 2 *
+ adc->vrefint.vrefint_cal /
+ adc->vrefint.vrefint_data;
+ } else {
+ *val = adc->common->vref_mv * 2;
+ }
*val2 = chan->scan_type.realbits;
} else {
- *val = adc->common->vref_mv;
+ /* Use vrefint data if available */
+ if (adc->vrefint.vrefint_data &&
+ adc->vrefint.vrefint_cal) {
+ *val = STM32_ADC_VREFINT_VOLTAGE *
+ adc->vrefint.vrefint_cal /
+ adc->vrefint.vrefint_data;
+ } else {
+ *val = adc->common->vref_mv;
+ }
*val2 = chan->scan_type.realbits;
}
return IIO_VAL_FRACTIONAL_LOG2;
@@ -1353,7 +1503,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val)
* dma cyclic transfers are used, buffer is split into two periods.
* There should be :
* - always one buffer (period) dma is working on
- * - one buffer (period) driver can push with iio_trigger_poll().
+ * - one buffer (period) driver can push data.
*/
watermark = min(watermark, val * (unsigned)(sizeof(u16)));
adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv);
@@ -1616,31 +1766,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p)
dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi);
- if (!adc->dma_chan) {
- /* reset buffer index */
- adc->bufi = 0;
- iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
- pf->timestamp);
- } else {
- int residue = stm32_adc_dma_residue(adc);
-
- while (residue >= indio_dev->scan_bytes) {
- u16 *buffer = (u16 *)&adc->rx_buf[adc->bufi];
-
- iio_push_to_buffers_with_timestamp(indio_dev, buffer,
- pf->timestamp);
- residue -= indio_dev->scan_bytes;
- adc->bufi += indio_dev->scan_bytes;
- if (adc->bufi >= adc->rx_buf_sz)
- adc->bufi = 0;
- }
- }
-
+ /* reset buffer index */
+ adc->bufi = 0;
+ iio_push_to_buffers_with_timestamp(indio_dev, adc->buffer,
+ pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
/* re-enable eoc irq */
- if (!adc->dma_chan)
- stm32_adc_conv_irq_enable(adc);
+ stm32_adc_conv_irq_enable(adc);
return IRQ_HANDLED;
}
@@ -1686,6 +1819,14 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns)
u32 period_ns, shift = smpr->shift, mask = smpr->mask;
unsigned int smp, r = smpr->reg;
+ /*
+ * For vrefint channel, ensure that the sampling time cannot
+ * be lower than the one specified in the datasheet
+ */
+ if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT] &&
+ smp_ns < adc->cfg->ts_vrefint_ns)
+ smp_ns = adc->cfg->ts_vrefint_ns;
+
/* Determine sampling time (ADC clock cycles) */
period_ns = NSEC_PER_SEC / adc->common->rate;
for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++)
@@ -1735,17 +1876,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev,
}
}
-static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
+static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc)
{
struct device_node *node = indio_dev->dev.of_node;
- struct stm32_adc *adc = iio_priv(indio_dev);
const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
- struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
- struct property *prop;
- const __be32 *cur;
- struct iio_chan_spec *channels;
- int scan_index = 0, num_channels = 0, num_diff = 0, ret, i;
- u32 val, smp = 0;
+ int num_channels = 0, ret;
ret = of_property_count_u32_elems(node, "st,adc-channels");
if (ret > adc_info->max_channels) {
@@ -1756,23 +1891,17 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
}
ret = of_property_count_elems_of_size(node, "st,adc-diff-channels",
- sizeof(*diff));
+ sizeof(struct stm32_adc_diff_channel));
if (ret > adc_info->max_channels) {
dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n");
return -EINVAL;
} else if (ret > 0) {
- int size = ret * sizeof(*diff) / sizeof(u32);
-
- num_diff = ret;
+ adc->num_diff = ret;
num_channels += ret;
- ret = of_property_read_u32_array(node, "st,adc-diff-channels",
- (u32 *)diff, size);
- if (ret)
- return ret;
}
if (!num_channels) {
- dev_err(&indio_dev->dev, "No channels configured\n");
+ dev_err(indio_dev->dev.parent, "No channel found\n");
return -ENODATA;
}
@@ -1783,10 +1912,45 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
return -EINVAL;
}
- channels = devm_kcalloc(&indio_dev->dev, num_channels,
- sizeof(struct iio_chan_spec), GFP_KERNEL);
- if (!channels)
- return -ENOMEM;
+ return num_channels;
+}
+
+static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev,
+ struct stm32_adc *adc,
+ struct iio_chan_spec *channels)
+{
+ struct device_node *node = indio_dev->dev.of_node;
+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
+ struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX];
+ u32 num_diff = adc->num_diff;
+ int size = num_diff * sizeof(*diff) / sizeof(u32);
+ int scan_index = 0, val, ret, i;
+ struct property *prop;
+ const __be32 *cur;
+ u32 smp = 0;
+
+ if (num_diff) {
+ ret = of_property_read_u32_array(node, "st,adc-diff-channels",
+ (u32 *)diff, size);
+ if (ret) {
+ dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < num_diff; i++) {
+ if (diff[i].vinp >= adc_info->max_channels ||
+ diff[i].vinn >= adc_info->max_channels) {
+ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
+ diff[i].vinp, diff[i].vinn);
+ return -EINVAL;
+ }
+
+ stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
+ diff[i].vinp, diff[i].vinn,
+ scan_index, true);
+ scan_index++;
+ }
+ }
of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) {
if (val >= adc_info->max_channels) {
@@ -1797,8 +1961,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
/* Channel can't be configured both as single-ended & diff */
for (i = 0; i < num_diff; i++) {
if (val == diff[i].vinp) {
- dev_err(&indio_dev->dev,
- "channel %d miss-configured\n", val);
+ dev_err(&indio_dev->dev, "channel %d misconfigured\n", val);
return -EINVAL;
}
}
@@ -1807,19 +1970,6 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
scan_index++;
}
- for (i = 0; i < num_diff; i++) {
- if (diff[i].vinp >= adc_info->max_channels ||
- diff[i].vinn >= adc_info->max_channels) {
- dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
- diff[i].vinp, diff[i].vinn);
- return -EINVAL;
- }
- stm32_adc_chan_init_one(indio_dev, &channels[scan_index],
- diff[i].vinp, diff[i].vinn, scan_index,
- true);
- scan_index++;
- }
-
for (i = 0; i < scan_index; i++) {
/*
* Using of_property_read_u32_index(), smp value will only be
@@ -1827,13 +1977,173 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
* get either no value, 1 shared value for all indexes, or one
* value per channel.
*/
- of_property_read_u32_index(node, "st,min-sample-time-nsecs",
- i, &smp);
+ of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp);
+
/* Prepare sampling time settings */
stm32_adc_smpr_init(adc, channels[i].channel, smp);
}
- indio_dev->num_channels = scan_index;
+ return scan_index;
+}
+
+static int stm32_adc_get_int_ch(struct iio_dev *indio_dev, const char *ch_name,
+ int chan)
+{
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ u16 vrefint;
+ int i, ret;
+
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) {
+ if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) {
+ adc->int_ch[i] = chan;
+ /* If channel is vrefint get calibration data. */
+ if (stm32_adc_ic[i].idx == STM32_ADC_INT_CH_VREFINT) {
+ ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint);
+ if (ret && ret != -ENOENT && ret != -EOPNOTSUPP) {
+ dev_err(&indio_dev->dev, "nvmem access error %d\n", ret);
+ return ret;
+ }
+ if (ret == -ENOENT)
+ dev_dbg(&indio_dev->dev,
+ "vrefint calibration not found\n");
+ else
+ adc->vrefint.vrefint_cal = vrefint;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev,
+ struct stm32_adc *adc,
+ struct iio_chan_spec *channels)
+{
+ struct device_node *node = indio_dev->dev.of_node;
+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
+ struct device_node *child;
+ const char *name;
+ int val, scan_index = 0, ret, i;
+ bool differential;
+ u32 vin[2];
+
+ for (i = 0; i < STM32_ADC_INT_CH_NB; i++)
+ adc->int_ch[i] = STM32_ADC_CHAN_NONE;
+
+ for_each_available_child_of_node(node, child) {
+ ret = of_property_read_u32(child, "reg", &val);
+ if (ret) {
+ dev_err(&indio_dev->dev, "Missing channel index %d\n", ret);
+ goto err;
+ }
+
+ ret = of_property_read_string(child, "label", &name);
+ /* label is optional */
+ if (!ret) {
+ if (strlen(name) >= STM32_ADC_CH_SZ) {
+ dev_err(&indio_dev->dev, "Label %s exceeds %d characters\n",
+ name, STM32_ADC_CH_SZ);
+ return -EINVAL;
+ }
+ strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ);
+ ret = stm32_adc_get_int_ch(indio_dev, name, val);
+ if (ret)
+ goto err;
+ } else if (ret != -EINVAL) {
+ dev_err(&indio_dev->dev, "Invalid label %d\n", ret);
+ goto err;
+ }
+
+ if (val >= adc_info->max_channels) {
+ dev_err(&indio_dev->dev, "Invalid channel %d\n", val);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ differential = false;
+ ret = of_property_read_u32_array(child, "diff-channels", vin, 2);
+ /* diff-channels is optional */
+ if (!ret) {
+ differential = true;
+ if (vin[0] != val || vin[1] >= adc_info->max_channels) {
+ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n",
+ vin[0], vin[1]);
+ goto err;
+ }
+ } else if (ret != -EINVAL) {
+ dev_err(&indio_dev->dev, "Invalid diff-channels property %d\n", ret);
+ goto err;
+ }
+
+ stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val,
+ vin[1], scan_index, differential);
+
+ ret = of_property_read_u32(child, "st,min-sample-time-nsecs", &val);
+ /* st,min-sample-time-nsecs is optional */
+ if (!ret) {
+ stm32_adc_smpr_init(adc, channels[scan_index].channel, val);
+ if (differential)
+ stm32_adc_smpr_init(adc, vin[1], val);
+ } else if (ret != -EINVAL) {
+ dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs property %d\n",
+ ret);
+ goto err;
+ }
+
+ scan_index++;
+ }
+
+ return scan_index;
+
+err:
+ of_node_put(child);
+
+ return ret;
+}
+
+static int stm32_adc_chan_of_init(struct iio_dev *indio_dev)
+{
+ struct device_node *node = indio_dev->dev.of_node;
+ struct stm32_adc *adc = iio_priv(indio_dev);
+ const struct stm32_adc_info *adc_info = adc->cfg->adc_info;
+ struct iio_chan_spec *channels;
+ int num_channels = 0, ret;
+ bool legacy = false;
+
+ num_channels = of_get_available_child_count(node);
+ /*
+ * If no channels have been found, fallback to channels legacy properties.
+ * Legacy channel properties will be ignored, if some channels are
+ * already defined using the standard binding.
+ */
+ if (!num_channels) {
+ ret = stm32_adc_get_legacy_chan_count(indio_dev, adc);
+ if (ret < 0)
+ return ret;
+
+ legacy = true;
+ num_channels = ret;
+ }
+
+ if (num_channels > adc_info->max_channels) {
+ dev_err(&indio_dev->dev, "Channel number [%d] exceeds %d\n",
+ num_channels, adc_info->max_channels);
+ return -EINVAL;
+ }
+
+ channels = devm_kcalloc(&indio_dev->dev, num_channels,
+ sizeof(struct iio_chan_spec), GFP_KERNEL);
+ if (!channels)
+ return -ENOMEM;
+
+ if (legacy)
+ ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels);
+ else
+ ret = stm32_adc_generic_chan_init(indio_dev, adc, channels);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->num_channels = ret;
indio_dev->channels = channels;
return 0;
@@ -2105,7 +2415,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = {
};
static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
- .regs = &stm32h7_adc_regspec,
+ .regs = &stm32mp1_adc_regspec,
.adc_info = &stm32h7_adc_info,
.trigs = stm32h7_adc_trigs,
.has_vregready = true,
@@ -2115,6 +2425,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = {
.unprepare = stm32h7_adc_unprepare,
.smp_cycles = stm32h7_adc_smp_cycles,
.irq_clear = stm32h7_adc_irq_clear,
+ .ts_vrefint_ns = 4300,
};
static const struct of_device_id stm32_adc_of_match[] = {
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index 9234f1416..10e5a48cd 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -10,6 +10,7 @@
#include <linux/dma-mapping.h>
#include <linux/iio/adc/stm32-dfsdm-adc.h>
#include <linux/iio/buffer.h>
+#include <linux/iio/consumer.h>
#include <linux/iio/hw-consumer.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/timer/stm32-lptim-trigger.h>
@@ -67,6 +68,13 @@ struct stm32_dfsdm_dev_data {
const struct regmap_config *regmap_cfg;
};
+struct stm32_dfsdm_sd_chan_info {
+ int scale_val;
+ int scale_val2;
+ int offset;
+ unsigned int differential;
+};
+
struct stm32_dfsdm_adc {
struct stm32_dfsdm *dfsdm;
const struct stm32_dfsdm_dev_data *dev_data;
@@ -79,6 +87,7 @@ struct stm32_dfsdm_adc {
struct iio_hw_consumer *hwc;
struct completion completion;
u32 *buffer;
+ struct stm32_dfsdm_sd_chan_info *sd_chan;
/* Audio specific */
unsigned int spi_freq; /* SPI bus clock frequency */
@@ -1224,7 +1233,13 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
int *val2, long mask)
{
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
- int ret;
+ struct stm32_dfsdm_filter *fl = &adc->dfsdm->fl_list[adc->fl_id];
+ struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast];
+ u32 max = flo->max << (flo->lshift - chan->scan_type.shift);
+ int ret, idx = chan->scan_index;
+
+ if (flo->lshift < chan->scan_type.shift)
+ max = flo->max >> (chan->scan_type.shift - flo->lshift);
switch (mask) {
case IIO_CHAN_INFO_RAW:
@@ -1260,6 +1275,39 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev,
*val = adc->sample_freq;
return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ /*
+ * Scale is expressed in mV.
+ * When fast mode is disabled, actual resolution may be lower
+ * than 2^n, where n=realbits-1.
+ * This leads to underestimating input voltage. To
+ * compensate this deviation, the voltage reference can be
+ * corrected with a factor = realbits resolution / actual max
+ */
+ *val = div_u64((u64)adc->sd_chan[idx].scale_val *
+ (u64)BIT(DFSDM_DATA_RES - 1), max);
+ *val2 = chan->scan_type.realbits;
+ if (adc->sd_chan[idx].differential)
+ *val *= 2;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_OFFSET:
+ /*
+ * DFSDM output data are in the range [-2^n,2^n-1],
+ * with n=realbits-1.
+ * - Differential modulator:
+ * Offset correspond to SD modulator offset.
+ * - Single ended modulator:
+ * Input is in [0V,Vref] range, where 0V corresponds to -2^n.
+ * Add 2^n to offset. (i.e. middle of input range)
+ * offset = offset(sd) * vref / res(sd) * max / vref.
+ */
+ *val = div_u64((u64)max * adc->sd_chan[idx].offset,
+ BIT(adc->sd_chan[idx].scale_val2 - 1));
+ if (!adc->sd_chan[idx].differential)
+ *val += max;
+ return IIO_VAL_INT;
}
return -EINVAL;
@@ -1384,7 +1432,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
* IIO_CHAN_INFO_RAW: used to compute regular conversion
* IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling
*/
- ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ ch->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET);
ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
BIT(IIO_CHAN_INFO_SAMP_FREQ);
@@ -1394,7 +1444,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev,
ch->scan_type.shift = 8;
}
ch->scan_type.sign = 's';
- ch->scan_type.realbits = 24;
+ ch->scan_type.realbits = DFSDM_DATA_RES;
ch->scan_type.storagebits = 32;
return stm32_dfsdm_chan_configure(adc->dfsdm,
@@ -1435,8 +1485,10 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
{
struct iio_chan_spec *ch;
struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
+ struct iio_channel *channels, *chan;
+ struct stm32_dfsdm_sd_chan_info *sd_chan;
int num_ch;
- int ret, chan_idx;
+ int ret, chan_idx, val2;
adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING;
ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp);
@@ -1460,6 +1512,21 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
if (!ch)
return -ENOMEM;
+ /* Get SD modulator channels */
+ channels = iio_channel_get_all(&indio_dev->dev);
+ if (IS_ERR(channels)) {
+ dev_err(&indio_dev->dev, "Failed to get channel %ld\n",
+ PTR_ERR(channels));
+ return PTR_ERR(channels);
+ }
+ chan = &channels[0];
+
+ adc->sd_chan = devm_kzalloc(&indio_dev->dev,
+ sizeof(*adc->sd_chan) * num_ch, GFP_KERNEL);
+ if (!adc->sd_chan)
+ return -ENOMEM;
+ sd_chan = adc->sd_chan;
+
for (chan_idx = 0; chan_idx < num_ch; chan_idx++) {
ch[chan_idx].scan_index = chan_idx;
ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]);
@@ -1467,6 +1534,38 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev)
dev_err(&indio_dev->dev, "Channels init failed\n");
return ret;
}
+
+ if (!chan->indio_dev)
+ return -EINVAL;
+
+ ret = iio_read_channel_scale(chan, &sd_chan->scale_val,
+ &sd_chan->scale_val2);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev,
+ "Failed to get channel %d scale\n", chan_idx);
+ return ret;
+ }
+
+ if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_OFFSET)) {
+ ret = iio_read_channel_offset(chan, &sd_chan->offset,
+ &val2);
+ if (ret < 0) {
+ dev_err(&indio_dev->dev,
+ "Failed to get channel %d offset\n",
+ chan_idx);
+ return ret;
+ }
+ }
+
+ sd_chan->differential = chan->channel->differential;
+
+ dev_dbg(&indio_dev->dev, "Channel %d %s scale ref=%d offset=%d",
+ chan_idx, chan->channel->differential ?
+ "differential" : "single-ended",
+ sd_chan->scale_val, sd_chan->offset);
+
+ chan++;
+ sd_chan++;
}
indio_dev->num_channels = num_ch;
@@ -1521,6 +1620,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = {
},
{}
};
+MODULE_DEVICE_TABLE(of, stm32_dfsdm_adc_match);
static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
{
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index 42a737770..627557d8e 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -6,6 +6,7 @@
* Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
@@ -20,6 +21,7 @@
#include "stm32-dfsdm.h"
struct stm32_dfsdm_dev_data {
+ u32 ipid;
unsigned int num_filters;
unsigned int num_channels;
const struct regmap_config *regmap_cfg;
@@ -27,8 +29,6 @@ struct stm32_dfsdm_dev_data {
#define STM32H7_DFSDM_NUM_FILTERS 4
#define STM32H7_DFSDM_NUM_CHANNELS 8
-#define STM32MP1_DFSDM_NUM_FILTERS 6
-#define STM32MP1_DFSDM_NUM_CHANNELS 8
static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg)
{
@@ -75,8 +75,7 @@ static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = {
};
static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = {
- .num_filters = STM32MP1_DFSDM_NUM_FILTERS,
- .num_channels = STM32MP1_DFSDM_NUM_CHANNELS,
+ .ipid = STM32MP15_IPIDR_NUMBER,
.regmap_cfg = &stm32mp1_dfsdm_regmap_cfg,
};
@@ -298,6 +297,64 @@ static const struct of_device_id stm32_dfsdm_of_match[] = {
};
MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match);
+static int stm32_dfsdm_config_check(struct platform_device *pdev,
+ struct dfsdm_priv *priv,
+ const struct stm32_dfsdm_dev_data *dev_data)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ struct stm32_dfsdm *dfsdm = &priv->dfsdm;
+ const char *compat;
+ int ret, count = 0;
+ u32 id, val;
+
+ if (!dev_data->ipid) {
+ dfsdm->num_fls = dev_data->num_filters;
+ dfsdm->num_chs = dev_data->num_channels;
+ return 0;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &val);
+ if (ret)
+ return ret;
+
+ id = FIELD_GET(DFSDM_IPIDR_MASK, val);
+ if (id != dev_data->ipid) {
+ dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id);
+ return -EINVAL;
+ }
+
+ for_each_child_of_node(np, child) {
+ ret = of_property_read_string(child, "compatible", &compat);
+ if (ret)
+ continue;
+ count++;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val);
+ if (ret)
+ return ret;
+
+ dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val);
+ dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val);
+
+ if (count > dfsdm->num_fls) {
+ dev_err(&pdev->dev, "Unexpected child number: %d", count);
+ return -EINVAL;
+ }
+
+ ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n",
+ FIELD_GET(DFSDM_VERR_MAJREV_MASK, val),
+ FIELD_GET(DFSDM_VERR_MINREV_MASK, val),
+ dfsdm->num_chs, dfsdm->num_fls);
+
+ return 0;
+}
+
static int stm32_dfsdm_probe(struct platform_device *pdev)
{
struct dfsdm_priv *priv;
@@ -314,18 +371,6 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
dev_data = of_device_get_match_data(&pdev->dev);
dfsdm = &priv->dfsdm;
- dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters,
- sizeof(*dfsdm->fl_list), GFP_KERNEL);
- if (!dfsdm->fl_list)
- return -ENOMEM;
-
- dfsdm->num_fls = dev_data->num_filters;
- dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels,
- sizeof(*dfsdm->ch_list),
- GFP_KERNEL);
- if (!dfsdm->ch_list)
- return -ENOMEM;
- dfsdm->num_chs = dev_data->num_channels;
ret = stm32_dfsdm_parse_of(pdev, priv);
if (ret < 0)
@@ -341,6 +386,20 @@ static int stm32_dfsdm_probe(struct platform_device *pdev)
return ret;
}
+ ret = stm32_dfsdm_config_check(pdev, priv, dev_data);
+ if (ret < 0)
+ return ret;
+
+ dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls,
+ sizeof(*dfsdm->fl_list), GFP_KERNEL);
+ if (!dfsdm->fl_list)
+ return -ENOMEM;
+
+ dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs,
+ sizeof(*dfsdm->ch_list), GFP_KERNEL);
+ if (!dfsdm->ch_list)
+ return -ENOMEM;
+
platform_set_drvdata(pdev, dfsdm);
ret = stm32_dfsdm_clk_prepare_enable(dfsdm);
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h
index 4afc1f528..4f230e2a7 100644
--- a/drivers/iio/adc/stm32-dfsdm.h
+++ b/drivers/iio/adc/stm32-dfsdm.h
@@ -13,25 +13,28 @@
/*
* STM32 DFSDM - global register map
- * ________________________________________________________
- * | Offset | Registers block |
- * --------------------------------------------------------
- * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
- * --------------------------------------------------------
- * | 0x020 | CHANNEL 1 |
- * --------------------------------------------------------
- * | ... | ..... |
- * --------------------------------------------------------
- * | 0x0E0 | CHANNEL 7 |
- * --------------------------------------------------------
- * | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
- * --------------------------------------------------------
- * | 0x200 | FILTER 1 |
- * --------------------------------------------------------
- * | 0x300 | FILTER 2 |
- * --------------------------------------------------------
- * | 0x400 | FILTER 3 |
- * --------------------------------------------------------
+ * __________________________________________________________
+ * | Offset | Registers block |
+ * ----------------------------------------------------------
+ * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS |
+ * ----------------------------------------------------------
+ * | 0x020 | CHANNEL 1 |
+ * ----------------------------------------------------------
+ * | ... | ..... |
+ * ----------------------------------------------------------
+ * | 0x20 x n | CHANNEL n |
+ * ----------------------------------------------------------
+ * | 0x100 | FILTER 0 + COMMON FILTER FIELDs |
+ * ----------------------------------------------------------
+ * | 0x200 | FILTER 1 |
+ * ----------------------------------------------------------
+ * | | ..... |
+ * ----------------------------------------------------------
+ * | 0x100 x m| FILTER m |
+ * ----------------------------------------------------------
+ * ----------------------------------------------------------
+ * | 0x7F0-7FC| Identification registers |
+ * ----------------------------------------------------------
*/
/*
@@ -231,6 +234,34 @@
#define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8)
#define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v)
+/*
+ * Identification register definitions
+ */
+#define DFSDM_HWCFGR 0x7F0
+#define DFSDM_VERR 0x7F4
+#define DFSDM_IPIDR 0x7F8
+#define DFSDM_SIDR 0x7FC
+
+/* HWCFGR: Hardware configuration register */
+#define DFSDM_HWCFGR_NBT_SHIFT 0
+#define DFSDM_HWCFGR_NBT_MASK GENMASK(7, 0)
+#define DFSDM_HWCFGR_NBF_SHIFT 8
+#define DFSDM_HWCFGR_NBF_MASK GENMASK(15, 8)
+
+/* VERR: Version register */
+#define DFSDM_VERR_MINREV_SHIFT 0
+#define DFSDM_VERR_MINREV_MASK GENMASK(3, 0)
+#define DFSDM_VERR_MAJREV_SHIFT 4
+#define DFSDM_VERR_MAJREV_MASK GENMASK(7, 4)
+
+/* IPDR: Identification register */
+#define DFSDM_IPIDR_MASK GENMASK(31, 0)
+
+/* SIDR: Size identification register */
+#define DFSDM_SIDR_MASK GENMASK(31, 0)
+
+#define STM32MP15_IPIDR_NUMBER 0x00110031
+
/* DFSDM filter order */
enum stm32_dfsdm_sinc_order {
DFSDM_FASTSINC_ORDER, /* FastSinc filter type */
diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c
index 8662d7b7b..d38896125 100644
--- a/drivers/irqchip/irq-stm32-exti.c
+++ b/drivers/irqchip/irq-stm32-exti.c
@@ -132,7 +132,6 @@ static const struct stm32_exti_drv_data stm32h7xx_drv_data = {
static const struct stm32_exti_bank stm32mp1_exti_b1 = {
.imr_ofst = 0x80,
- .emr_ofst = 0x84,
.rtsr_ofst = 0x00,
.ftsr_ofst = 0x04,
.swier_ofst = 0x08,
@@ -142,7 +141,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b1 = {
static const struct stm32_exti_bank stm32mp1_exti_b2 = {
.imr_ofst = 0x90,
- .emr_ofst = 0x94,
.rtsr_ofst = 0x20,
.ftsr_ofst = 0x24,
.swier_ofst = 0x28,
@@ -152,7 +150,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b2 = {
static const struct stm32_exti_bank stm32mp1_exti_b3 = {
.imr_ofst = 0xA0,
- .emr_ofst = 0xA4,
.rtsr_ofst = 0x40,
.ftsr_ofst = 0x44,
.swier_ofst = 0x48,
@@ -193,7 +190,16 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = {
{ .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct },
{ .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct },
{ .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 26, .irq_parent = 37, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 27, .irq_parent = 38, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 28, .irq_parent = 39, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 29, .irq_parent = 71, .chip = &stm32_exti_h_chip_direct },
{ .exti = 30, .irq_parent = 52, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct },
+ { .exti = 44, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct },
{ .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct },
{ .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct },
{ .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct },
@@ -534,6 +540,9 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type)
unlock:
raw_spin_unlock(&chip_data->rlock);
+ if (d->parent_data->chip)
+ irq_chip_set_type_parent(d, type);
+
return err;
}
@@ -551,6 +560,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on)
raw_spin_unlock(&chip_data->rlock);
+ if (d->parent_data->chip)
+ irq_chip_set_wake_parent(d, on);
+
return 0;
}
@@ -560,7 +572,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d,
if (d->parent_data->chip)
return irq_chip_set_affinity_parent(d, dest, force);
- return -EINVAL;
+ return IRQ_SET_MASK_OK_DONE;
+}
+
+static void stm32_exti_h_ack(struct irq_data *d)
+{
+ if (d->parent_data->chip)
+ irq_chip_ack_parent(d);
}
static int __maybe_unused stm32_exti_h_suspend(void)
@@ -624,6 +642,7 @@ static int stm32_exti_h_retrigger(struct irq_data *d)
static struct irq_chip stm32_exti_h_chip = {
.name = "stm32-exti-h",
.irq_eoi = stm32_exti_h_eoi,
+ .irq_ack = stm32_exti_h_ack,
.irq_mask = stm32_exti_h_mask,
.irq_unmask = stm32_exti_h_unmask,
.irq_retrigger = stm32_exti_h_retrigger,
@@ -637,8 +656,8 @@ static struct irq_chip stm32_exti_h_chip_direct = {
.name = "stm32-exti-h-direct",
.irq_eoi = irq_chip_eoi_parent,
.irq_ack = irq_chip_ack_parent,
- .irq_mask = irq_chip_mask_parent,
- .irq_unmask = irq_chip_unmask_parent,
+ .irq_mask = stm32_exti_h_mask,
+ .irq_unmask = stm32_exti_h_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_type = irq_chip_set_type_parent,
.irq_set_wake = stm32_exti_h_set_wake,
@@ -669,14 +688,28 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm,
irq_domain_set_hwirq_and_chip(dm, virq, hwirq, desc->chip,
chip_data);
- if (desc->irq_parent) {
+ /*
+ * EXTI 55 to 60 are mapped to PWR interrupt controller.
+ * The hwirq translation is done diferently than for GIC.
+ */
+ if (hwirq >= 55 && hwirq <= 60) {
p_fwspec.fwnode = dm->parent->fwnode;
- p_fwspec.param_count = 3;
- p_fwspec.param[0] = GIC_SPI;
- p_fwspec.param[1] = desc->irq_parent;
- p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+ p_fwspec.param_count = 2;
+ p_fwspec.param[0] = hwirq - 55;
+ p_fwspec.param[1] = fwspec->param[1];
return irq_domain_alloc_irqs_parent(dm, virq, 1, &p_fwspec);
+ } else {
+ if (desc->irq_parent) {
+ p_fwspec.fwnode = dm->parent->fwnode;
+ p_fwspec.param_count = 3;
+ p_fwspec.param[0] = GIC_SPI;
+ p_fwspec.param[1] = desc->irq_parent;
+ p_fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+
+ return irq_domain_alloc_irqs_parent(dm, virq, 1,
+ &p_fwspec);
+ }
}
return 0;
@@ -738,7 +771,8 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
* clear registers to avoid residue
*/
writel_relaxed(0, base + stm32_bank->imr_ofst);
- writel_relaxed(0, base + stm32_bank->emr_ofst);
+ if (stm32_bank->emr_ofst)
+ writel_relaxed(0, base + stm32_bank->emr_ofst);
pr_info("%pOF: bank%d\n", node, bank_idx);
@@ -841,11 +875,12 @@ static int stm32_exti_probe(struct platform_device *pdev)
{
int ret, i;
struct device *dev = &pdev->dev;
- struct device_node *np = dev->of_node;
+ struct device_node *child, *np = dev->of_node;
struct irq_domain *parent_domain, *domain;
struct stm32_exti_host_data *host_data;
const struct stm32_exti_drv_data *drv_data;
struct resource *res;
+ u32 nirqs;
host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL);
if (!host_data)
@@ -913,6 +948,34 @@ static int stm32_exti_probe(struct platform_device *pdev)
if (ret)
return ret;
+ for_each_child_of_node(np, child) {
+ parent_domain = irq_find_host(of_irq_find_parent(child));
+ if (!parent_domain) {
+ dev_err(dev, "child interrupt-parent not found\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(child, "st,irq-number", &nirqs);
+ if (ret || !nirqs) {
+ dev_err(dev, "Missing or bad irq-number property\n");
+ return -EINVAL;
+ }
+
+ domain = irq_domain_add_hierarchy(parent_domain, 0, nirqs,
+ child,
+ &stm32_exti_h_domain_ops,
+ host_data);
+ if (!domain) {
+ dev_err(dev, "Could not register exti domain\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_add_action_or_reset(dev, stm32_exti_remove_irq,
+ domain);
+ if (ret)
+ return ret;
+ }
+
stm32_exti_h_syscore_init(host_data);
return 0;
--
2.17.1