From fc843f64f154b843cd7834d6748b409ef1e1487f Mon Sep 17 00:00:00 2001 From: Lionel Vitte 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 #include #include -#include -#include - -static const struct iio_info iio_sd_mod_iio_info; +#include +#include 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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include #include @@ -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 for STMicroelectronics. */ +#include #include #include #include @@ -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