diff options
| author | Arnaud Pouliquen <arnaud.pouliquen@st.com> | 2018-01-10 05:13:10 -0500 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2018-01-10 05:30:11 -0500 |
| commit | bed73904e76fc08d0ec3a7ba3eb2ddbb2e38862c (patch) | |
| tree | 99193706b1e4dc8d0a1906f827af83428dbcbc6f | |
| parent | 6c82f947fc9784b774cad0b90c20a5d703f9b763 (diff) | |
IIO: ADC: add stm32 DFSDM core support
Add driver for stm32 DFSDM pheripheral. Its converts a sigma delta
stream in n bit samples through a low pass filter and an integrator.
stm32-dfsdm-core driver is the core part supporting the filter
instances dedicated to sigma-delta ADC or audio PDM microphone purpose.
Signed-off-by: Arnaud Pouliquen <arnaud.pouliquen@st.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
| -rw-r--r-- | drivers/iio/adc/Kconfig | 12 | ||||
| -rw-r--r-- | drivers/iio/adc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/iio/adc/stm32-dfsdm-core.c | 309 | ||||
| -rw-r--r-- | drivers/iio/adc/stm32-dfsdm.h | 310 |
4 files changed, 632 insertions, 0 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 5f9d04a8ba53..776192e68ad5 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig | |||
| @@ -668,6 +668,18 @@ config STM32_ADC | |||
| 668 | This driver can also be built as a module. If so, the module | 668 | This driver can also be built as a module. If so, the module |
| 669 | will be called stm32-adc. | 669 | will be called stm32-adc. |
| 670 | 670 | ||
| 671 | config STM32_DFSDM_CORE | ||
| 672 | tristate "STMicroelectronics STM32 DFSDM core" | ||
| 673 | depends on (ARCH_STM32 && OF) || COMPILE_TEST | ||
| 674 | select REGMAP | ||
| 675 | select REGMAP_MMIO | ||
| 676 | help | ||
| 677 | Select this option to enable the driver for STMicroelectronics | ||
| 678 | STM32 digital filter for sigma delta converter. | ||
| 679 | |||
| 680 | This driver can also be built as a module. If so, the module | ||
| 681 | will be called stm32-dfsdm-core. | ||
| 682 | |||
| 671 | config STX104 | 683 | config STX104 |
| 672 | tristate "Apex Embedded Systems STX104 driver" | 684 | tristate "Apex Embedded Systems STX104 driver" |
| 673 | depends on PC104 && X86 && ISA_BUS_API | 685 | depends on PC104 && X86 && ISA_BUS_API |
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index fa5e7949f642..8dda348f1920 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile | |||
| @@ -64,6 +64,7 @@ obj-$(CONFIG_STX104) += stx104.o | |||
| 64 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o | 64 | obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o |
| 65 | obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o | 65 | obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o |
| 66 | obj-$(CONFIG_STM32_ADC) += stm32-adc.o | 66 | obj-$(CONFIG_STM32_ADC) += stm32-adc.o |
| 67 | obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o | ||
| 67 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o | 68 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o |
| 68 | obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o | 69 | obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o |
| 69 | obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o | 70 | obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o |
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c new file mode 100644 index 000000000000..72427414db7f --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm-core.c | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * This file is part the core part STM32 DFSDM driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
| 6 | * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/clk.h> | ||
| 10 | #include <linux/iio/iio.h> | ||
| 11 | #include <linux/iio/sysfs.h> | ||
| 12 | #include <linux/interrupt.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/of_device.h> | ||
| 15 | #include <linux/regmap.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | |||
| 18 | #include "stm32-dfsdm.h" | ||
| 19 | |||
| 20 | struct stm32_dfsdm_dev_data { | ||
| 21 | unsigned int num_filters; | ||
| 22 | unsigned int num_channels; | ||
| 23 | const struct regmap_config *regmap_cfg; | ||
| 24 | }; | ||
| 25 | |||
| 26 | #define STM32H7_DFSDM_NUM_FILTERS 4 | ||
| 27 | #define STM32H7_DFSDM_NUM_CHANNELS 8 | ||
| 28 | |||
| 29 | static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) | ||
| 30 | { | ||
| 31 | if (reg < DFSDM_FILTER_BASE_ADR) | ||
| 32 | return false; | ||
| 33 | |||
| 34 | /* | ||
| 35 | * Mask is done on register to avoid to list registers of all | ||
| 36 | * filter instances. | ||
| 37 | */ | ||
| 38 | switch (reg & DFSDM_FILTER_REG_MASK) { | ||
| 39 | case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: | ||
| 40 | case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: | ||
| 41 | case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: | ||
| 42 | case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | return false; | ||
| 47 | } | ||
| 48 | |||
| 49 | static const struct regmap_config stm32h7_dfsdm_regmap_cfg = { | ||
| 50 | .reg_bits = 32, | ||
| 51 | .val_bits = 32, | ||
| 52 | .reg_stride = sizeof(u32), | ||
| 53 | .max_register = 0x2B8, | ||
| 54 | .volatile_reg = stm32_dfsdm_volatile_reg, | ||
| 55 | .fast_io = true, | ||
| 56 | }; | ||
| 57 | |||
| 58 | static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { | ||
| 59 | .num_filters = STM32H7_DFSDM_NUM_FILTERS, | ||
| 60 | .num_channels = STM32H7_DFSDM_NUM_CHANNELS, | ||
| 61 | .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct dfsdm_priv { | ||
| 65 | struct platform_device *pdev; /* platform device */ | ||
| 66 | |||
| 67 | struct stm32_dfsdm dfsdm; /* common data exported for all instances */ | ||
| 68 | |||
| 69 | unsigned int spi_clk_out_div; /* SPI clkout divider value */ | ||
| 70 | atomic_t n_active_ch; /* number of current active channels */ | ||
| 71 | |||
| 72 | struct clk *clk; /* DFSDM clock */ | ||
| 73 | struct clk *aclk; /* audio clock */ | ||
| 74 | }; | ||
| 75 | |||
| 76 | /** | ||
| 77 | * stm32_dfsdm_start_dfsdm - start global dfsdm interface. | ||
| 78 | * | ||
| 79 | * Enable interface if n_active_ch is not null. | ||
| 80 | * @dfsdm: Handle used to retrieve dfsdm context. | ||
| 81 | */ | ||
| 82 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) | ||
| 83 | { | ||
| 84 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | ||
| 85 | struct device *dev = &priv->pdev->dev; | ||
| 86 | unsigned int clk_div = priv->spi_clk_out_div; | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | if (atomic_inc_return(&priv->n_active_ch) == 1) { | ||
| 90 | ret = clk_prepare_enable(priv->clk); | ||
| 91 | if (ret < 0) { | ||
| 92 | dev_err(dev, "Failed to start clock\n"); | ||
| 93 | goto error_ret; | ||
| 94 | } | ||
| 95 | if (priv->aclk) { | ||
| 96 | ret = clk_prepare_enable(priv->aclk); | ||
| 97 | if (ret < 0) { | ||
| 98 | dev_err(dev, "Failed to start audio clock\n"); | ||
| 99 | goto disable_clk; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ | ||
| 104 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
| 105 | DFSDM_CHCFGR1_CKOUTDIV_MASK, | ||
| 106 | DFSDM_CHCFGR1_CKOUTDIV(clk_div)); | ||
| 107 | if (ret < 0) | ||
| 108 | goto disable_aclk; | ||
| 109 | |||
| 110 | /* Global enable of DFSDM interface */ | ||
| 111 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
| 112 | DFSDM_CHCFGR1_DFSDMEN_MASK, | ||
| 113 | DFSDM_CHCFGR1_DFSDMEN(1)); | ||
| 114 | if (ret < 0) | ||
| 115 | goto disable_aclk; | ||
| 116 | } | ||
| 117 | |||
| 118 | dev_dbg(dev, "%s: n_active_ch %d\n", __func__, | ||
| 119 | atomic_read(&priv->n_active_ch)); | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | |||
| 123 | disable_aclk: | ||
| 124 | clk_disable_unprepare(priv->aclk); | ||
| 125 | disable_clk: | ||
| 126 | clk_disable_unprepare(priv->clk); | ||
| 127 | |||
| 128 | error_ret: | ||
| 129 | atomic_dec(&priv->n_active_ch); | ||
| 130 | |||
| 131 | return ret; | ||
| 132 | } | ||
| 133 | EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); | ||
| 134 | |||
| 135 | /** | ||
| 136 | * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. | ||
| 137 | * | ||
| 138 | * Disable interface if n_active_ch is null | ||
| 139 | * @dfsdm: Handle used to retrieve dfsdm context. | ||
| 140 | */ | ||
| 141 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) | ||
| 142 | { | ||
| 143 | struct dfsdm_priv *priv = container_of(dfsdm, struct dfsdm_priv, dfsdm); | ||
| 144 | int ret; | ||
| 145 | |||
| 146 | if (atomic_dec_and_test(&priv->n_active_ch)) { | ||
| 147 | /* Global disable of DFSDM interface */ | ||
| 148 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
| 149 | DFSDM_CHCFGR1_DFSDMEN_MASK, | ||
| 150 | DFSDM_CHCFGR1_DFSDMEN(0)); | ||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | |||
| 154 | /* Stop SPI CLKOUT */ | ||
| 155 | ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), | ||
| 156 | DFSDM_CHCFGR1_CKOUTDIV_MASK, | ||
| 157 | DFSDM_CHCFGR1_CKOUTDIV(0)); | ||
| 158 | if (ret < 0) | ||
| 159 | return ret; | ||
| 160 | |||
| 161 | clk_disable_unprepare(priv->clk); | ||
| 162 | if (priv->aclk) | ||
| 163 | clk_disable_unprepare(priv->aclk); | ||
| 164 | } | ||
| 165 | dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, | ||
| 166 | atomic_read(&priv->n_active_ch)); | ||
| 167 | |||
| 168 | return 0; | ||
| 169 | } | ||
| 170 | EXPORT_SYMBOL_GPL(stm32_dfsdm_stop_dfsdm); | ||
| 171 | |||
| 172 | static int stm32_dfsdm_parse_of(struct platform_device *pdev, | ||
| 173 | struct dfsdm_priv *priv) | ||
| 174 | { | ||
| 175 | struct device_node *node = pdev->dev.of_node; | ||
| 176 | struct resource *res; | ||
| 177 | unsigned long clk_freq; | ||
| 178 | unsigned int spi_freq, rem; | ||
| 179 | int ret; | ||
| 180 | |||
| 181 | if (!node) | ||
| 182 | return -EINVAL; | ||
| 183 | |||
| 184 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 185 | if (!res) { | ||
| 186 | dev_err(&pdev->dev, "Failed to get memory resource\n"); | ||
| 187 | return -ENODEV; | ||
| 188 | } | ||
| 189 | priv->dfsdm.phys_base = res->start; | ||
| 190 | priv->dfsdm.base = devm_ioremap_resource(&pdev->dev, res); | ||
| 191 | |||
| 192 | /* | ||
| 193 | * "dfsdm" clock is mandatory for DFSDM peripheral clocking. | ||
| 194 | * "dfsdm" or "audio" clocks can be used as source clock for | ||
| 195 | * the SPI clock out signal and internal processing, depending | ||
| 196 | * on use case. | ||
| 197 | */ | ||
| 198 | priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); | ||
| 199 | if (IS_ERR(priv->clk)) { | ||
| 200 | dev_err(&pdev->dev, "No stm32_dfsdm_clk clock found\n"); | ||
| 201 | return -EINVAL; | ||
| 202 | } | ||
| 203 | |||
| 204 | priv->aclk = devm_clk_get(&pdev->dev, "audio"); | ||
| 205 | if (IS_ERR(priv->aclk)) | ||
| 206 | priv->aclk = NULL; | ||
| 207 | |||
| 208 | if (priv->aclk) | ||
| 209 | clk_freq = clk_get_rate(priv->aclk); | ||
| 210 | else | ||
| 211 | clk_freq = clk_get_rate(priv->clk); | ||
| 212 | |||
| 213 | /* SPI clock out frequency */ | ||
| 214 | ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", | ||
| 215 | &spi_freq); | ||
| 216 | if (ret < 0) { | ||
| 217 | /* No SPI master mode */ | ||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | priv->spi_clk_out_div = div_u64_rem(clk_freq, spi_freq, &rem) - 1; | ||
| 222 | priv->dfsdm.spi_master_freq = spi_freq; | ||
| 223 | |||
| 224 | if (rem) { | ||
| 225 | dev_warn(&pdev->dev, "SPI clock not accurate\n"); | ||
| 226 | dev_warn(&pdev->dev, "%ld = %d * %d + %d\n", | ||
| 227 | clk_freq, spi_freq, priv->spi_clk_out_div + 1, rem); | ||
| 228 | } | ||
| 229 | |||
| 230 | return 0; | ||
| 231 | }; | ||
| 232 | |||
| 233 | static const struct of_device_id stm32_dfsdm_of_match[] = { | ||
| 234 | { | ||
| 235 | .compatible = "st,stm32h7-dfsdm", | ||
| 236 | .data = &stm32h7_dfsdm_data, | ||
| 237 | }, | ||
| 238 | {} | ||
| 239 | }; | ||
| 240 | MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); | ||
| 241 | |||
| 242 | static int stm32_dfsdm_probe(struct platform_device *pdev) | ||
| 243 | { | ||
| 244 | struct dfsdm_priv *priv; | ||
| 245 | struct device_node *pnode = pdev->dev.of_node; | ||
| 246 | const struct of_device_id *of_id; | ||
| 247 | const struct stm32_dfsdm_dev_data *dev_data; | ||
| 248 | struct stm32_dfsdm *dfsdm; | ||
| 249 | int ret; | ||
| 250 | |||
| 251 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
| 252 | if (!priv) | ||
| 253 | return -ENOMEM; | ||
| 254 | |||
| 255 | priv->pdev = pdev; | ||
| 256 | |||
| 257 | of_id = of_match_node(stm32_dfsdm_of_match, pnode); | ||
| 258 | if (!of_id->data) { | ||
| 259 | dev_err(&pdev->dev, "Data associated to device is missing\n"); | ||
| 260 | return -EINVAL; | ||
| 261 | } | ||
| 262 | |||
| 263 | dev_data = (const struct stm32_dfsdm_dev_data *)of_id->data; | ||
| 264 | dfsdm = &priv->dfsdm; | ||
| 265 | dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, | ||
| 266 | sizeof(*dfsdm->fl_list), GFP_KERNEL); | ||
| 267 | if (!dfsdm->fl_list) | ||
| 268 | return -ENOMEM; | ||
| 269 | |||
| 270 | dfsdm->num_fls = dev_data->num_filters; | ||
| 271 | dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, | ||
| 272 | sizeof(*dfsdm->ch_list), | ||
| 273 | GFP_KERNEL); | ||
| 274 | if (!dfsdm->ch_list) | ||
| 275 | return -ENOMEM; | ||
| 276 | dfsdm->num_chs = dev_data->num_channels; | ||
| 277 | |||
| 278 | ret = stm32_dfsdm_parse_of(pdev, priv); | ||
| 279 | if (ret < 0) | ||
| 280 | return ret; | ||
| 281 | |||
| 282 | dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", | ||
| 283 | dfsdm->base, | ||
| 284 | &stm32h7_dfsdm_regmap_cfg); | ||
| 285 | if (IS_ERR(dfsdm->regmap)) { | ||
| 286 | ret = PTR_ERR(dfsdm->regmap); | ||
| 287 | dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", | ||
| 288 | __func__, ret); | ||
| 289 | return ret; | ||
| 290 | } | ||
| 291 | |||
| 292 | platform_set_drvdata(pdev, dfsdm); | ||
| 293 | |||
| 294 | return devm_of_platform_populate(&pdev->dev); | ||
| 295 | } | ||
| 296 | |||
| 297 | static struct platform_driver stm32_dfsdm_driver = { | ||
| 298 | .probe = stm32_dfsdm_probe, | ||
| 299 | .driver = { | ||
| 300 | .name = "stm32-dfsdm", | ||
| 301 | .of_match_table = stm32_dfsdm_of_match, | ||
| 302 | }, | ||
| 303 | }; | ||
| 304 | |||
| 305 | module_platform_driver(stm32_dfsdm_driver); | ||
| 306 | |||
| 307 | MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); | ||
| 308 | MODULE_DESCRIPTION("STMicroelectronics STM32 dfsdm driver"); | ||
| 309 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h new file mode 100644 index 000000000000..8708394b0725 --- /dev/null +++ b/drivers/iio/adc/stm32-dfsdm.h | |||
| @@ -0,0 +1,310 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * This file is part of STM32 DFSDM driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017, STMicroelectronics - All Rights Reserved | ||
| 6 | * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com>. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef MDF_STM32_DFSDM__H | ||
| 10 | #define MDF_STM32_DFSDM__H | ||
| 11 | |||
| 12 | #include <linux/bitfield.h> | ||
| 13 | |||
| 14 | /* | ||
| 15 | * STM32 DFSDM - global register map | ||
| 16 | * ________________________________________________________ | ||
| 17 | * | Offset | Registers block | | ||
| 18 | * -------------------------------------------------------- | ||
| 19 | * | 0x000 | CHANNEL 0 + COMMON CHANNEL FIELDS | | ||
| 20 | * -------------------------------------------------------- | ||
| 21 | * | 0x020 | CHANNEL 1 | | ||
| 22 | * -------------------------------------------------------- | ||
| 23 | * | ... | ..... | | ||
| 24 | * -------------------------------------------------------- | ||
| 25 | * | 0x0E0 | CHANNEL 7 | | ||
| 26 | * -------------------------------------------------------- | ||
| 27 | * | 0x100 | FILTER 0 + COMMON FILTER FIELDs | | ||
| 28 | * -------------------------------------------------------- | ||
| 29 | * | 0x200 | FILTER 1 | | ||
| 30 | * -------------------------------------------------------- | ||
| 31 | * | 0x300 | FILTER 2 | | ||
| 32 | * -------------------------------------------------------- | ||
| 33 | * | 0x400 | FILTER 3 | | ||
| 34 | * -------------------------------------------------------- | ||
| 35 | */ | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Channels register definitions | ||
| 39 | */ | ||
| 40 | #define DFSDM_CHCFGR1(y) ((y) * 0x20 + 0x00) | ||
| 41 | #define DFSDM_CHCFGR2(y) ((y) * 0x20 + 0x04) | ||
| 42 | #define DFSDM_AWSCDR(y) ((y) * 0x20 + 0x08) | ||
| 43 | #define DFSDM_CHWDATR(y) ((y) * 0x20 + 0x0C) | ||
| 44 | #define DFSDM_CHDATINR(y) ((y) * 0x20 + 0x10) | ||
| 45 | |||
| 46 | /* CHCFGR1: Channel configuration register 1 */ | ||
| 47 | #define DFSDM_CHCFGR1_SITP_MASK GENMASK(1, 0) | ||
| 48 | #define DFSDM_CHCFGR1_SITP(v) FIELD_PREP(DFSDM_CHCFGR1_SITP_MASK, v) | ||
| 49 | #define DFSDM_CHCFGR1_SPICKSEL_MASK GENMASK(3, 2) | ||
| 50 | #define DFSDM_CHCFGR1_SPICKSEL(v) FIELD_PREP(DFSDM_CHCFGR1_SPICKSEL_MASK, v) | ||
| 51 | #define DFSDM_CHCFGR1_SCDEN_MASK BIT(5) | ||
| 52 | #define DFSDM_CHCFGR1_SCDEN(v) FIELD_PREP(DFSDM_CHCFGR1_SCDEN_MASK, v) | ||
| 53 | #define DFSDM_CHCFGR1_CKABEN_MASK BIT(6) | ||
| 54 | #define DFSDM_CHCFGR1_CKABEN(v) FIELD_PREP(DFSDM_CHCFGR1_CKABEN_MASK, v) | ||
| 55 | #define DFSDM_CHCFGR1_CHEN_MASK BIT(7) | ||
| 56 | #define DFSDM_CHCFGR1_CHEN(v) FIELD_PREP(DFSDM_CHCFGR1_CHEN_MASK, v) | ||
| 57 | #define DFSDM_CHCFGR1_CHINSEL_MASK BIT(8) | ||
| 58 | #define DFSDM_CHCFGR1_CHINSEL(v) FIELD_PREP(DFSDM_CHCFGR1_CHINSEL_MASK, v) | ||
| 59 | #define DFSDM_CHCFGR1_DATMPX_MASK GENMASK(13, 12) | ||
| 60 | #define DFSDM_CHCFGR1_DATMPX(v) FIELD_PREP(DFSDM_CHCFGR1_DATMPX_MASK, v) | ||
| 61 | #define DFSDM_CHCFGR1_DATPACK_MASK GENMASK(15, 14) | ||
| 62 | #define DFSDM_CHCFGR1_DATPACK(v) FIELD_PREP(DFSDM_CHCFGR1_DATPACK_MASK, v) | ||
| 63 | #define DFSDM_CHCFGR1_CKOUTDIV_MASK GENMASK(23, 16) | ||
| 64 | #define DFSDM_CHCFGR1_CKOUTDIV(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTDIV_MASK, v) | ||
| 65 | #define DFSDM_CHCFGR1_CKOUTSRC_MASK BIT(30) | ||
| 66 | #define DFSDM_CHCFGR1_CKOUTSRC(v) FIELD_PREP(DFSDM_CHCFGR1_CKOUTSRC_MASK, v) | ||
| 67 | #define DFSDM_CHCFGR1_DFSDMEN_MASK BIT(31) | ||
| 68 | #define DFSDM_CHCFGR1_DFSDMEN(v) FIELD_PREP(DFSDM_CHCFGR1_DFSDMEN_MASK, v) | ||
| 69 | |||
| 70 | /* CHCFGR2: Channel configuration register 2 */ | ||
| 71 | #define DFSDM_CHCFGR2_DTRBS_MASK GENMASK(7, 3) | ||
| 72 | #define DFSDM_CHCFGR2_DTRBS(v) FIELD_PREP(DFSDM_CHCFGR2_DTRBS_MASK, v) | ||
| 73 | #define DFSDM_CHCFGR2_OFFSET_MASK GENMASK(31, 8) | ||
| 74 | #define DFSDM_CHCFGR2_OFFSET(v) FIELD_PREP(DFSDM_CHCFGR2_OFFSET_MASK, v) | ||
| 75 | |||
| 76 | /* AWSCDR: Channel analog watchdog and short circuit detector */ | ||
| 77 | #define DFSDM_AWSCDR_SCDT_MASK GENMASK(7, 0) | ||
| 78 | #define DFSDM_AWSCDR_SCDT(v) FIELD_PREP(DFSDM_AWSCDR_SCDT_MASK, v) | ||
| 79 | #define DFSDM_AWSCDR_BKSCD_MASK GENMASK(15, 12) | ||
| 80 | #define DFSDM_AWSCDR_BKSCD(v) FIELD_PREP(DFSDM_AWSCDR_BKSCD_MASK, v) | ||
| 81 | #define DFSDM_AWSCDR_AWFOSR_MASK GENMASK(20, 16) | ||
| 82 | #define DFSDM_AWSCDR_AWFOSR(v) FIELD_PREP(DFSDM_AWSCDR_AWFOSR_MASK, v) | ||
| 83 | #define DFSDM_AWSCDR_AWFORD_MASK GENMASK(23, 22) | ||
| 84 | #define DFSDM_AWSCDR_AWFORD(v) FIELD_PREP(DFSDM_AWSCDR_AWFORD_MASK, v) | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Filters register definitions | ||
| 88 | */ | ||
| 89 | #define DFSDM_FILTER_BASE_ADR 0x100 | ||
| 90 | #define DFSDM_FILTER_REG_MASK 0x7F | ||
| 91 | #define DFSDM_FILTER_X_BASE_ADR(x) ((x) * 0x80 + DFSDM_FILTER_BASE_ADR) | ||
| 92 | |||
| 93 | #define DFSDM_CR1(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x00) | ||
| 94 | #define DFSDM_CR2(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x04) | ||
| 95 | #define DFSDM_ISR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x08) | ||
| 96 | #define DFSDM_ICR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x0C) | ||
| 97 | #define DFSDM_JCHGR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x10) | ||
| 98 | #define DFSDM_FCR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x14) | ||
| 99 | #define DFSDM_JDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x18) | ||
| 100 | #define DFSDM_RDATAR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x1C) | ||
| 101 | #define DFSDM_AWHTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x20) | ||
| 102 | #define DFSDM_AWLTR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x24) | ||
| 103 | #define DFSDM_AWSR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x28) | ||
| 104 | #define DFSDM_AWCFR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x2C) | ||
| 105 | #define DFSDM_EXMAX(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x30) | ||
| 106 | #define DFSDM_EXMIN(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x34) | ||
| 107 | #define DFSDM_CNVTIMR(x) (DFSDM_FILTER_X_BASE_ADR(x) + 0x38) | ||
| 108 | |||
| 109 | /* CR1 Control register 1 */ | ||
| 110 | #define DFSDM_CR1_DFEN_MASK BIT(0) | ||
| 111 | #define DFSDM_CR1_DFEN(v) FIELD_PREP(DFSDM_CR1_DFEN_MASK, v) | ||
| 112 | #define DFSDM_CR1_JSWSTART_MASK BIT(1) | ||
| 113 | #define DFSDM_CR1_JSWSTART(v) FIELD_PREP(DFSDM_CR1_JSWSTART_MASK, v) | ||
| 114 | #define DFSDM_CR1_JSYNC_MASK BIT(3) | ||
| 115 | #define DFSDM_CR1_JSYNC(v) FIELD_PREP(DFSDM_CR1_JSYNC_MASK, v) | ||
| 116 | #define DFSDM_CR1_JSCAN_MASK BIT(4) | ||
| 117 | #define DFSDM_CR1_JSCAN(v) FIELD_PREP(DFSDM_CR1_JSCAN_MASK, v) | ||
| 118 | #define DFSDM_CR1_JDMAEN_MASK BIT(5) | ||
| 119 | #define DFSDM_CR1_JDMAEN(v) FIELD_PREP(DFSDM_CR1_JDMAEN_MASK, v) | ||
| 120 | #define DFSDM_CR1_JEXTSEL_MASK GENMASK(12, 8) | ||
| 121 | #define DFSDM_CR1_JEXTSEL(v) FIELD_PREP(DFSDM_CR1_JEXTSEL_MASK, v) | ||
| 122 | #define DFSDM_CR1_JEXTEN_MASK GENMASK(14, 13) | ||
| 123 | #define DFSDM_CR1_JEXTEN(v) FIELD_PREP(DFSDM_CR1_JEXTEN_MASK, v) | ||
| 124 | #define DFSDM_CR1_RSWSTART_MASK BIT(17) | ||
| 125 | #define DFSDM_CR1_RSWSTART(v) FIELD_PREP(DFSDM_CR1_RSWSTART_MASK, v) | ||
| 126 | #define DFSDM_CR1_RCONT_MASK BIT(18) | ||
| 127 | #define DFSDM_CR1_RCONT(v) FIELD_PREP(DFSDM_CR1_RCONT_MASK, v) | ||
| 128 | #define DFSDM_CR1_RSYNC_MASK BIT(19) | ||
| 129 | #define DFSDM_CR1_RSYNC(v) FIELD_PREP(DFSDM_CR1_RSYNC_MASK, v) | ||
| 130 | #define DFSDM_CR1_RDMAEN_MASK BIT(21) | ||
| 131 | #define DFSDM_CR1_RDMAEN(v) FIELD_PREP(DFSDM_CR1_RDMAEN_MASK, v) | ||
| 132 | #define DFSDM_CR1_RCH_MASK GENMASK(26, 24) | ||
| 133 | #define DFSDM_CR1_RCH(v) FIELD_PREP(DFSDM_CR1_RCH_MASK, v) | ||
| 134 | #define DFSDM_CR1_FAST_MASK BIT(29) | ||
| 135 | #define DFSDM_CR1_FAST(v) FIELD_PREP(DFSDM_CR1_FAST_MASK, v) | ||
| 136 | #define DFSDM_CR1_AWFSEL_MASK BIT(30) | ||
| 137 | #define DFSDM_CR1_AWFSEL(v) FIELD_PREP(DFSDM_CR1_AWFSEL_MASK, v) | ||
| 138 | |||
| 139 | /* CR2: Control register 2 */ | ||
| 140 | #define DFSDM_CR2_IE_MASK GENMASK(6, 0) | ||
| 141 | #define DFSDM_CR2_IE(v) FIELD_PREP(DFSDM_CR2_IE_MASK, v) | ||
| 142 | #define DFSDM_CR2_JEOCIE_MASK BIT(0) | ||
| 143 | #define DFSDM_CR2_JEOCIE(v) FIELD_PREP(DFSDM_CR2_JEOCIE_MASK, v) | ||
| 144 | #define DFSDM_CR2_REOCIE_MASK BIT(1) | ||
| 145 | #define DFSDM_CR2_REOCIE(v) FIELD_PREP(DFSDM_CR2_REOCIE_MASK, v) | ||
| 146 | #define DFSDM_CR2_JOVRIE_MASK BIT(2) | ||
| 147 | #define DFSDM_CR2_JOVRIE(v) FIELD_PREP(DFSDM_CR2_JOVRIE_MASK, v) | ||
| 148 | #define DFSDM_CR2_ROVRIE_MASK BIT(3) | ||
| 149 | #define DFSDM_CR2_ROVRIE(v) FIELD_PREP(DFSDM_CR2_ROVRIE_MASK, v) | ||
| 150 | #define DFSDM_CR2_AWDIE_MASK BIT(4) | ||
| 151 | #define DFSDM_CR2_AWDIE(v) FIELD_PREP(DFSDM_CR2_AWDIE_MASK, v) | ||
| 152 | #define DFSDM_CR2_SCDIE_MASK BIT(5) | ||
| 153 | #define DFSDM_CR2_SCDIE(v) FIELD_PREP(DFSDM_CR2_SCDIE_MASK, v) | ||
| 154 | #define DFSDM_CR2_CKABIE_MASK BIT(6) | ||
| 155 | #define DFSDM_CR2_CKABIE(v) FIELD_PREP(DFSDM_CR2_CKABIE_MASK, v) | ||
| 156 | #define DFSDM_CR2_EXCH_MASK GENMASK(15, 8) | ||
| 157 | #define DFSDM_CR2_EXCH(v) FIELD_PREP(DFSDM_CR2_EXCH_MASK, v) | ||
| 158 | #define DFSDM_CR2_AWDCH_MASK GENMASK(23, 16) | ||
| 159 | #define DFSDM_CR2_AWDCH(v) FIELD_PREP(DFSDM_CR2_AWDCH_MASK, v) | ||
| 160 | |||
| 161 | /* ISR: Interrupt status register */ | ||
| 162 | #define DFSDM_ISR_JEOCF_MASK BIT(0) | ||
| 163 | #define DFSDM_ISR_JEOCF(v) FIELD_PREP(DFSDM_ISR_JEOCF_MASK, v) | ||
| 164 | #define DFSDM_ISR_REOCF_MASK BIT(1) | ||
| 165 | #define DFSDM_ISR_REOCF(v) FIELD_PREP(DFSDM_ISR_REOCF_MASK, v) | ||
| 166 | #define DFSDM_ISR_JOVRF_MASK BIT(2) | ||
| 167 | #define DFSDM_ISR_JOVRF(v) FIELD_PREP(DFSDM_ISR_JOVRF_MASK, v) | ||
| 168 | #define DFSDM_ISR_ROVRF_MASK BIT(3) | ||
| 169 | #define DFSDM_ISR_ROVRF(v) FIELD_PREP(DFSDM_ISR_ROVRF_MASK, v) | ||
| 170 | #define DFSDM_ISR_AWDF_MASK BIT(4) | ||
| 171 | #define DFSDM_ISR_AWDF(v) FIELD_PREP(DFSDM_ISR_AWDF_MASK, v) | ||
| 172 | #define DFSDM_ISR_JCIP_MASK BIT(13) | ||
| 173 | #define DFSDM_ISR_JCIP(v) FIELD_PREP(DFSDM_ISR_JCIP_MASK, v) | ||
| 174 | #define DFSDM_ISR_RCIP_MASK BIT(14) | ||
| 175 | #define DFSDM_ISR_RCIP(v) FIELD_PREP(DFSDM_ISR_RCIP, v) | ||
| 176 | #define DFSDM_ISR_CKABF_MASK GENMASK(23, 16) | ||
| 177 | #define DFSDM_ISR_CKABF(v) FIELD_PREP(DFSDM_ISR_CKABF_MASK, v) | ||
| 178 | #define DFSDM_ISR_SCDF_MASK GENMASK(31, 24) | ||
| 179 | #define DFSDM_ISR_SCDF(v) FIELD_PREP(DFSDM_ISR_SCDF_MASK, v) | ||
| 180 | |||
| 181 | /* ICR: Interrupt flag clear register */ | ||
| 182 | #define DFSDM_ICR_CLRJOVRF_MASK BIT(2) | ||
| 183 | #define DFSDM_ICR_CLRJOVRF(v) FIELD_PREP(DFSDM_ICR_CLRJOVRF_MASK, v) | ||
| 184 | #define DFSDM_ICR_CLRROVRF_MASK BIT(3) | ||
| 185 | #define DFSDM_ICR_CLRROVRF(v) FIELD_PREP(DFSDM_ICR_CLRROVRF_MASK, v) | ||
| 186 | #define DFSDM_ICR_CLRCKABF_MASK GENMASK(23, 16) | ||
| 187 | #define DFSDM_ICR_CLRCKABF(v) FIELD_PREP(DFSDM_ICR_CLRCKABF_MASK, v) | ||
| 188 | #define DFSDM_ICR_CLRCKABF_CH_MASK(y) BIT(16 + (y)) | ||
| 189 | #define DFSDM_ICR_CLRCKABF_CH(v, y) \ | ||
| 190 | (((v) << (16 + (y))) & DFSDM_ICR_CLRCKABF_CH_MASK(y)) | ||
| 191 | #define DFSDM_ICR_CLRSCDF_MASK GENMASK(31, 24) | ||
| 192 | #define DFSDM_ICR_CLRSCDF(v) FIELD_PREP(DFSDM_ICR_CLRSCDF_MASK, v) | ||
| 193 | #define DFSDM_ICR_CLRSCDF_CH_MASK(y) BIT(24 + (y)) | ||
| 194 | #define DFSDM_ICR_CLRSCDF_CH(v, y) \ | ||
| 195 | (((v) << (24 + (y))) & DFSDM_ICR_CLRSCDF_MASK(y)) | ||
| 196 | |||
| 197 | /* FCR: Filter control register */ | ||
| 198 | #define DFSDM_FCR_IOSR_MASK GENMASK(7, 0) | ||
| 199 | #define DFSDM_FCR_IOSR(v) FIELD_PREP(DFSDM_FCR_IOSR_MASK, v) | ||
| 200 | #define DFSDM_FCR_FOSR_MASK GENMASK(25, 16) | ||
| 201 | #define DFSDM_FCR_FOSR(v) FIELD_PREP(DFSDM_FCR_FOSR_MASK, v) | ||
| 202 | #define DFSDM_FCR_FORD_MASK GENMASK(31, 29) | ||
| 203 | #define DFSDM_FCR_FORD(v) FIELD_PREP(DFSDM_FCR_FORD_MASK, v) | ||
| 204 | |||
| 205 | /* RDATAR: Filter data register for regular channel */ | ||
| 206 | #define DFSDM_DATAR_CH_MASK GENMASK(2, 0) | ||
| 207 | #define DFSDM_DATAR_DATA_OFFSET 8 | ||
| 208 | #define DFSDM_DATAR_DATA_MASK GENMASK(31, DFSDM_DATAR_DATA_OFFSET) | ||
| 209 | |||
| 210 | /* AWLTR: Filter analog watchdog low threshold register */ | ||
| 211 | #define DFSDM_AWLTR_BKAWL_MASK GENMASK(3, 0) | ||
| 212 | #define DFSDM_AWLTR_BKAWL(v) FIELD_PREP(DFSDM_AWLTR_BKAWL_MASK, v) | ||
| 213 | #define DFSDM_AWLTR_AWLT_MASK GENMASK(31, 8) | ||
| 214 | #define DFSDM_AWLTR_AWLT(v) FIELD_PREP(DFSDM_AWLTR_AWLT_MASK, v) | ||
| 215 | |||
| 216 | /* AWHTR: Filter analog watchdog low threshold register */ | ||
| 217 | #define DFSDM_AWHTR_BKAWH_MASK GENMASK(3, 0) | ||
| 218 | #define DFSDM_AWHTR_BKAWH(v) FIELD_PREP(DFSDM_AWHTR_BKAWH_MASK, v) | ||
| 219 | #define DFSDM_AWHTR_AWHT_MASK GENMASK(31, 8) | ||
| 220 | #define DFSDM_AWHTR_AWHT(v) FIELD_PREP(DFSDM_AWHTR_AWHT_MASK, v) | ||
| 221 | |||
| 222 | /* AWSR: Filter watchdog status register */ | ||
| 223 | #define DFSDM_AWSR_AWLTF_MASK GENMASK(7, 0) | ||
| 224 | #define DFSDM_AWSR_AWLTF(v) FIELD_PREP(DFSDM_AWSR_AWLTF_MASK, v) | ||
| 225 | #define DFSDM_AWSR_AWHTF_MASK GENMASK(15, 8) | ||
| 226 | #define DFSDM_AWSR_AWHTF(v) FIELD_PREP(DFSDM_AWSR_AWHTF_MASK, v) | ||
| 227 | |||
| 228 | /* AWCFR: Filter watchdog status register */ | ||
| 229 | #define DFSDM_AWCFR_AWLTF_MASK GENMASK(7, 0) | ||
| 230 | #define DFSDM_AWCFR_AWLTF(v) FIELD_PREP(DFSDM_AWCFR_AWLTF_MASK, v) | ||
| 231 | #define DFSDM_AWCFR_AWHTF_MASK GENMASK(15, 8) | ||
| 232 | #define DFSDM_AWCFR_AWHTF(v) FIELD_PREP(DFSDM_AWCFR_AWHTF_MASK, v) | ||
| 233 | |||
| 234 | /* DFSDM filter order */ | ||
| 235 | enum stm32_dfsdm_sinc_order { | ||
| 236 | DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ | ||
| 237 | DFSDM_SINC1_ORDER, /* Sinc 1 filter type */ | ||
| 238 | DFSDM_SINC2_ORDER, /* Sinc 2 filter type */ | ||
| 239 | DFSDM_SINC3_ORDER, /* Sinc 3 filter type */ | ||
| 240 | DFSDM_SINC4_ORDER, /* Sinc 4 filter type (N.A. for watchdog) */ | ||
| 241 | DFSDM_SINC5_ORDER, /* Sinc 5 filter type (N.A. for watchdog) */ | ||
| 242 | DFSDM_NB_SINC_ORDER, | ||
| 243 | }; | ||
| 244 | |||
| 245 | /** | ||
| 246 | * struct stm32_dfsdm_filter - structure relative to stm32 FDSDM filter | ||
| 247 | * @iosr: integrator oversampling | ||
| 248 | * @fosr: filter oversampling | ||
| 249 | * @ford: filter order | ||
| 250 | * @res: output sample resolution | ||
| 251 | * @sync_mode: filter synchronized with filter 0 | ||
| 252 | * @fast: filter fast mode | ||
| 253 | */ | ||
| 254 | struct stm32_dfsdm_filter { | ||
| 255 | unsigned int iosr; | ||
| 256 | unsigned int fosr; | ||
| 257 | enum stm32_dfsdm_sinc_order ford; | ||
| 258 | u64 res; | ||
| 259 | unsigned int sync_mode; | ||
| 260 | unsigned int fast; | ||
| 261 | }; | ||
| 262 | |||
| 263 | /** | ||
| 264 | * struct stm32_dfsdm_channel - structure relative to stm32 FDSDM channel | ||
| 265 | * @id: id of the channel | ||
| 266 | * @type: interface type linked to stm32_dfsdm_chan_type | ||
| 267 | * @src: interface type linked to stm32_dfsdm_chan_src | ||
| 268 | * @alt_si: alternative serial input interface | ||
| 269 | */ | ||
| 270 | struct stm32_dfsdm_channel { | ||
| 271 | unsigned int id; | ||
| 272 | unsigned int type; | ||
| 273 | unsigned int src; | ||
| 274 | unsigned int alt_si; | ||
| 275 | }; | ||
| 276 | |||
| 277 | /** | ||
| 278 | * struct stm32_dfsdm - stm32 FDSDM driver common data (for all instances) | ||
| 279 | * @base: control registers base cpu addr | ||
| 280 | * @phys_base: DFSDM IP register physical address | ||
| 281 | * @regmap: regmap for register read/write | ||
| 282 | * @fl_list: filter resources list | ||
| 283 | * @num_fls: number of filter resources available | ||
| 284 | * @ch_list: channel resources list | ||
| 285 | * @num_chs: number of channel resources available | ||
| 286 | * @spi_master_freq: SPI clock out frequency | ||
| 287 | */ | ||
| 288 | struct stm32_dfsdm { | ||
| 289 | void __iomem *base; | ||
| 290 | phys_addr_t phys_base; | ||
| 291 | struct regmap *regmap; | ||
| 292 | struct stm32_dfsdm_filter *fl_list; | ||
| 293 | unsigned int num_fls; | ||
| 294 | struct stm32_dfsdm_channel *ch_list; | ||
| 295 | unsigned int num_chs; | ||
| 296 | unsigned int spi_master_freq; | ||
| 297 | }; | ||
| 298 | |||
| 299 | /* DFSDM channel serial spi clock source */ | ||
| 300 | enum stm32_dfsdm_spi_clk_src { | ||
| 301 | DFSDM_CHANNEL_SPI_CLOCK_EXTERNAL, | ||
| 302 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL, | ||
| 303 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_FALLING, | ||
| 304 | DFSDM_CHANNEL_SPI_CLOCK_INTERNAL_DIV2_RISING | ||
| 305 | }; | ||
| 306 | |||
| 307 | int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm); | ||
| 308 | int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm); | ||
| 309 | |||
| 310 | #endif | ||
