162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file is part the core part STM32 DFSDM driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 662306a36Sopenharmony_ci * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bitfield.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/iio/iio.h> 1262306a36Sopenharmony_ci#include <linux/iio/sysfs.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/of_platform.h> 1762306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/regmap.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "stm32-dfsdm.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/** 2662306a36Sopenharmony_ci * struct stm32_dfsdm_dev_data - DFSDM compatible configuration data 2762306a36Sopenharmony_ci * @ipid: DFSDM identification number. Used only if hardware provides identification registers 2862306a36Sopenharmony_ci * @num_filters: DFSDM number of filters. Unused if identification registers are available 2962306a36Sopenharmony_ci * @num_channels: DFSDM number of channels. Unused if identification registers are available 3062306a36Sopenharmony_ci * @regmap_cfg: SAI register map configuration pointer 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistruct stm32_dfsdm_dev_data { 3362306a36Sopenharmony_ci u32 ipid; 3462306a36Sopenharmony_ci unsigned int num_filters; 3562306a36Sopenharmony_ci unsigned int num_channels; 3662306a36Sopenharmony_ci const struct regmap_config *regmap_cfg; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define STM32H7_DFSDM_NUM_FILTERS 4 4062306a36Sopenharmony_ci#define STM32H7_DFSDM_NUM_CHANNELS 8 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci if (reg < DFSDM_FILTER_BASE_ADR) 4562306a36Sopenharmony_ci return false; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * Mask is done on register to avoid to list registers of all 4962306a36Sopenharmony_ci * filter instances. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci switch (reg & DFSDM_FILTER_REG_MASK) { 5262306a36Sopenharmony_ci case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: 5362306a36Sopenharmony_ci case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: 5462306a36Sopenharmony_ci case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: 5562306a36Sopenharmony_ci case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: 5662306a36Sopenharmony_ci return true; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return false; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const struct regmap_config stm32h7_dfsdm_regmap_cfg = { 6362306a36Sopenharmony_ci .reg_bits = 32, 6462306a36Sopenharmony_ci .val_bits = 32, 6562306a36Sopenharmony_ci .reg_stride = sizeof(u32), 6662306a36Sopenharmony_ci .max_register = 0x2B8, 6762306a36Sopenharmony_ci .volatile_reg = stm32_dfsdm_volatile_reg, 6862306a36Sopenharmony_ci .fast_io = true, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { 7262306a36Sopenharmony_ci .num_filters = STM32H7_DFSDM_NUM_FILTERS, 7362306a36Sopenharmony_ci .num_channels = STM32H7_DFSDM_NUM_CHANNELS, 7462306a36Sopenharmony_ci .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct regmap_config stm32mp1_dfsdm_regmap_cfg = { 7862306a36Sopenharmony_ci .reg_bits = 32, 7962306a36Sopenharmony_ci .val_bits = 32, 8062306a36Sopenharmony_ci .reg_stride = sizeof(u32), 8162306a36Sopenharmony_ci .max_register = 0x7fc, 8262306a36Sopenharmony_ci .volatile_reg = stm32_dfsdm_volatile_reg, 8362306a36Sopenharmony_ci .fast_io = true, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = { 8762306a36Sopenharmony_ci .ipid = STM32MP15_IPIDR_NUMBER, 8862306a36Sopenharmony_ci .regmap_cfg = &stm32mp1_dfsdm_regmap_cfg, 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistruct dfsdm_priv { 9262306a36Sopenharmony_ci struct platform_device *pdev; /* platform device */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci struct stm32_dfsdm dfsdm; /* common data exported for all instances */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci unsigned int spi_clk_out_div; /* SPI clkout divider value */ 9762306a36Sopenharmony_ci atomic_t n_active_ch; /* number of current active channels */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci struct clk *clk; /* DFSDM clock */ 10062306a36Sopenharmony_ci struct clk *aclk; /* audio clock */ 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci return container_of(dfsdm, struct dfsdm_priv, dfsdm); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 11162306a36Sopenharmony_ci int ret; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 11462306a36Sopenharmony_ci if (ret || !priv->aclk) 11562306a36Sopenharmony_ci return ret; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ret = clk_prepare_enable(priv->aclk); 11862306a36Sopenharmony_ci if (ret) 11962306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return ret; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci clk_disable_unprepare(priv->aclk); 12962306a36Sopenharmony_ci clk_disable_unprepare(priv->clk); 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * stm32_dfsdm_start_dfsdm - start global dfsdm interface. 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * Enable interface if n_active_ch is not null. 13662306a36Sopenharmony_ci * @dfsdm: Handle used to retrieve dfsdm context. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ciint stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 14162306a36Sopenharmony_ci struct device *dev = &priv->pdev->dev; 14262306a36Sopenharmony_ci unsigned int clk_div = priv->spi_clk_out_div, clk_src; 14362306a36Sopenharmony_ci int ret; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (atomic_inc_return(&priv->n_active_ch) == 1) { 14662306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 14762306a36Sopenharmony_ci if (ret < 0) 14862306a36Sopenharmony_ci goto error_ret; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ 15162306a36Sopenharmony_ci clk_src = priv->aclk ? 1 : 0; 15262306a36Sopenharmony_ci ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 15362306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTSRC_MASK, 15462306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTSRC(clk_src)); 15562306a36Sopenharmony_ci if (ret < 0) 15662306a36Sopenharmony_ci goto pm_put; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ 15962306a36Sopenharmony_ci ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 16062306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTDIV_MASK, 16162306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTDIV(clk_div)); 16262306a36Sopenharmony_ci if (ret < 0) 16362306a36Sopenharmony_ci goto pm_put; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci /* Global enable of DFSDM interface */ 16662306a36Sopenharmony_ci ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 16762306a36Sopenharmony_ci DFSDM_CHCFGR1_DFSDMEN_MASK, 16862306a36Sopenharmony_ci DFSDM_CHCFGR1_DFSDMEN(1)); 16962306a36Sopenharmony_ci if (ret < 0) 17062306a36Sopenharmony_ci goto pm_put; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dev_dbg(dev, "%s: n_active_ch %d\n", __func__, 17462306a36Sopenharmony_ci atomic_read(&priv->n_active_ch)); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci return 0; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cipm_put: 17962306a36Sopenharmony_ci pm_runtime_put_sync(dev); 18062306a36Sopenharmony_cierror_ret: 18162306a36Sopenharmony_ci atomic_dec(&priv->n_active_ch); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return ret; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/** 18862306a36Sopenharmony_ci * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Disable interface if n_active_ch is null 19162306a36Sopenharmony_ci * @dfsdm: Handle used to retrieve dfsdm context. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_ciint stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 19662306a36Sopenharmony_ci int ret; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (atomic_dec_and_test(&priv->n_active_ch)) { 19962306a36Sopenharmony_ci /* Global disable of DFSDM interface */ 20062306a36Sopenharmony_ci ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 20162306a36Sopenharmony_ci DFSDM_CHCFGR1_DFSDMEN_MASK, 20262306a36Sopenharmony_ci DFSDM_CHCFGR1_DFSDMEN(0)); 20362306a36Sopenharmony_ci if (ret < 0) 20462306a36Sopenharmony_ci return ret; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Stop SPI CLKOUT */ 20762306a36Sopenharmony_ci ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 20862306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTDIV_MASK, 20962306a36Sopenharmony_ci DFSDM_CHCFGR1_CKOUTDIV(0)); 21062306a36Sopenharmony_ci if (ret < 0) 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci pm_runtime_put_sync(&priv->pdev->dev); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, 21662306a36Sopenharmony_ci atomic_read(&priv->n_active_ch)); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(stm32_dfsdm_stop_dfsdm); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int stm32_dfsdm_parse_of(struct platform_device *pdev, 22362306a36Sopenharmony_ci struct dfsdm_priv *priv) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 22662306a36Sopenharmony_ci struct resource *res; 22762306a36Sopenharmony_ci unsigned long clk_freq, divider; 22862306a36Sopenharmony_ci unsigned int spi_freq, rem; 22962306a36Sopenharmony_ci int ret; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!node) 23262306a36Sopenharmony_ci return -EINVAL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci priv->dfsdm.base = devm_platform_get_and_ioremap_resource(pdev, 0, 23562306a36Sopenharmony_ci &res); 23662306a36Sopenharmony_ci if (IS_ERR(priv->dfsdm.base)) 23762306a36Sopenharmony_ci return PTR_ERR(priv->dfsdm.base); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci priv->dfsdm.phys_base = res->start; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * "dfsdm" clock is mandatory for DFSDM peripheral clocking. 24362306a36Sopenharmony_ci * "dfsdm" or "audio" clocks can be used as source clock for 24462306a36Sopenharmony_ci * the SPI clock out signal and internal processing, depending 24562306a36Sopenharmony_ci * on use case. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_ci priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); 24862306a36Sopenharmony_ci if (IS_ERR(priv->clk)) 24962306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), 25062306a36Sopenharmony_ci "Failed to get clock\n"); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci priv->aclk = devm_clk_get(&pdev->dev, "audio"); 25362306a36Sopenharmony_ci if (IS_ERR(priv->aclk)) 25462306a36Sopenharmony_ci priv->aclk = NULL; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (priv->aclk) 25762306a36Sopenharmony_ci clk_freq = clk_get_rate(priv->aclk); 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci clk_freq = clk_get_rate(priv->clk); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* SPI clock out frequency */ 26262306a36Sopenharmony_ci ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", 26362306a36Sopenharmony_ci &spi_freq); 26462306a36Sopenharmony_ci if (ret < 0) { 26562306a36Sopenharmony_ci /* No SPI master mode */ 26662306a36Sopenharmony_ci return 0; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci divider = div_u64_rem(clk_freq, spi_freq, &rem); 27062306a36Sopenharmony_ci /* Round up divider when ckout isn't precise, not to exceed spi_freq */ 27162306a36Sopenharmony_ci if (rem) 27262306a36Sopenharmony_ci divider++; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci /* programmable divider is in range of [2:256] */ 27562306a36Sopenharmony_ci if (divider < 2 || divider > 256) { 27662306a36Sopenharmony_ci dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); 27762306a36Sopenharmony_ci return -EINVAL; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* SPI clock output divider is: divider = CKOUTDIV + 1 */ 28162306a36Sopenharmony_ci priv->spi_clk_out_div = divider - 1; 28262306a36Sopenharmony_ci priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (rem) { 28562306a36Sopenharmony_ci dev_warn(&pdev->dev, "SPI clock not accurate\n"); 28662306a36Sopenharmony_ci dev_warn(&pdev->dev, "%ld = %d * %d + %d\n", 28762306a36Sopenharmony_ci clk_freq, spi_freq, priv->spi_clk_out_div + 1, rem); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic const struct of_device_id stm32_dfsdm_of_match[] = { 29462306a36Sopenharmony_ci { 29562306a36Sopenharmony_ci .compatible = "st,stm32h7-dfsdm", 29662306a36Sopenharmony_ci .data = &stm32h7_dfsdm_data, 29762306a36Sopenharmony_ci }, 29862306a36Sopenharmony_ci { 29962306a36Sopenharmony_ci .compatible = "st,stm32mp1-dfsdm", 30062306a36Sopenharmony_ci .data = &stm32mp1_dfsdm_data, 30162306a36Sopenharmony_ci }, 30262306a36Sopenharmony_ci {} 30362306a36Sopenharmony_ci}; 30462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int stm32_dfsdm_probe_identification(struct platform_device *pdev, 30762306a36Sopenharmony_ci struct dfsdm_priv *priv, 30862306a36Sopenharmony_ci const struct stm32_dfsdm_dev_data *dev_data) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 31162306a36Sopenharmony_ci struct device_node *child; 31262306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = &priv->dfsdm; 31362306a36Sopenharmony_ci const char *compat; 31462306a36Sopenharmony_ci int ret, count = 0; 31562306a36Sopenharmony_ci u32 id, val; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (!dev_data->ipid) { 31862306a36Sopenharmony_ci dfsdm->num_fls = dev_data->num_filters; 31962306a36Sopenharmony_ci dfsdm->num_chs = dev_data->num_channels; 32062306a36Sopenharmony_ci return 0; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &id); 32462306a36Sopenharmony_ci if (ret) 32562306a36Sopenharmony_ci return ret; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (id != dev_data->ipid) { 32862306a36Sopenharmony_ci dev_err(&pdev->dev, "Unexpected IP version: 0x%x", id); 32962306a36Sopenharmony_ci return -EINVAL; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci for_each_child_of_node(np, child) { 33362306a36Sopenharmony_ci ret = of_property_read_string(child, "compatible", &compat); 33462306a36Sopenharmony_ci if (ret) 33562306a36Sopenharmony_ci continue; 33662306a36Sopenharmony_ci /* Count only child nodes with dfsdm compatible */ 33762306a36Sopenharmony_ci if (strstr(compat, "dfsdm")) 33862306a36Sopenharmony_ci count++; 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val); 34262306a36Sopenharmony_ci if (ret) 34362306a36Sopenharmony_ci return ret; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci dfsdm->num_fls = FIELD_GET(DFSDM_HWCFGR_NBF_MASK, val); 34662306a36Sopenharmony_ci dfsdm->num_chs = FIELD_GET(DFSDM_HWCFGR_NBT_MASK, val); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (count > dfsdm->num_fls) { 34962306a36Sopenharmony_ci dev_err(&pdev->dev, "Unexpected child number: %d", count); 35062306a36Sopenharmony_ci return -EINVAL; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ret = regmap_read(dfsdm->regmap, DFSDM_VERR, &val); 35462306a36Sopenharmony_ci if (ret) 35562306a36Sopenharmony_ci return ret; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dev_dbg(&pdev->dev, "DFSDM version: %lu.%lu. %d channels/%d filters\n", 35862306a36Sopenharmony_ci FIELD_GET(DFSDM_VERR_MAJREV_MASK, val), 35962306a36Sopenharmony_ci FIELD_GET(DFSDM_VERR_MINREV_MASK, val), 36062306a36Sopenharmony_ci dfsdm->num_chs, dfsdm->num_fls); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int stm32_dfsdm_probe(struct platform_device *pdev) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct dfsdm_priv *priv; 36862306a36Sopenharmony_ci const struct stm32_dfsdm_dev_data *dev_data; 36962306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm; 37062306a36Sopenharmony_ci int ret; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 37362306a36Sopenharmony_ci if (!priv) 37462306a36Sopenharmony_ci return -ENOMEM; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci priv->pdev = pdev; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci dev_data = of_device_get_match_data(&pdev->dev); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci dfsdm = &priv->dfsdm; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ret = stm32_dfsdm_parse_of(pdev, priv); 38362306a36Sopenharmony_ci if (ret < 0) 38462306a36Sopenharmony_ci return ret; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", 38762306a36Sopenharmony_ci dfsdm->base, 38862306a36Sopenharmony_ci dev_data->regmap_cfg); 38962306a36Sopenharmony_ci if (IS_ERR(dfsdm->regmap)) { 39062306a36Sopenharmony_ci ret = PTR_ERR(dfsdm->regmap); 39162306a36Sopenharmony_ci dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", 39262306a36Sopenharmony_ci __func__, ret); 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ret = stm32_dfsdm_probe_identification(pdev, priv, dev_data); 39762306a36Sopenharmony_ci if (ret < 0) 39862306a36Sopenharmony_ci return ret; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci dfsdm->fl_list = devm_kcalloc(&pdev->dev, dfsdm->num_fls, 40162306a36Sopenharmony_ci sizeof(*dfsdm->fl_list), GFP_KERNEL); 40262306a36Sopenharmony_ci if (!dfsdm->fl_list) 40362306a36Sopenharmony_ci return -ENOMEM; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci dfsdm->ch_list = devm_kcalloc(&pdev->dev, dfsdm->num_chs, 40662306a36Sopenharmony_ci sizeof(*dfsdm->ch_list), GFP_KERNEL); 40762306a36Sopenharmony_ci if (!dfsdm->ch_list) 40862306a36Sopenharmony_ci return -ENOMEM; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci platform_set_drvdata(pdev, dfsdm); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci ret = stm32_dfsdm_clk_prepare_enable(dfsdm); 41362306a36Sopenharmony_ci if (ret) { 41462306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to start clock\n"); 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci pm_runtime_get_noresume(&pdev->dev); 41962306a36Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 42062306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 42362306a36Sopenharmony_ci if (ret) 42462306a36Sopenharmony_ci goto pm_put; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cipm_put: 43162306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 43262306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 43362306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 43462306a36Sopenharmony_ci stm32_dfsdm_clk_disable_unprepare(dfsdm); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return ret; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int stm32_dfsdm_core_remove(struct platform_device *pdev) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 44462306a36Sopenharmony_ci of_platform_depopulate(&pdev->dev); 44562306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 44662306a36Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 44762306a36Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 44862306a36Sopenharmony_ci stm32_dfsdm_clk_disable_unprepare(dfsdm); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci return 0; 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int stm32_dfsdm_core_suspend(struct device *dev) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 45662306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 45762306a36Sopenharmony_ci int ret; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 46062306a36Sopenharmony_ci if (ret) 46162306a36Sopenharmony_ci return ret; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Balance devm_regmap_init_mmio_clk() clk_prepare() */ 46462306a36Sopenharmony_ci clk_unprepare(priv->clk); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return pinctrl_pm_select_sleep_state(dev); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int stm32_dfsdm_core_resume(struct device *dev) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 47262306a36Sopenharmony_ci struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 47362306a36Sopenharmony_ci int ret; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ret = pinctrl_pm_select_default_state(dev); 47662306a36Sopenharmony_ci if (ret) 47762306a36Sopenharmony_ci return ret; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ret = clk_prepare(priv->clk); 48062306a36Sopenharmony_ci if (ret) 48162306a36Sopenharmony_ci return ret; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci return pm_runtime_force_resume(dev); 48462306a36Sopenharmony_ci} 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic int stm32_dfsdm_core_runtime_suspend(struct device *dev) 48762306a36Sopenharmony_ci{ 48862306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci stm32_dfsdm_clk_disable_unprepare(dfsdm); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci return 0; 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic int stm32_dfsdm_core_runtime_resume(struct device *dev) 49662306a36Sopenharmony_ci{ 49762306a36Sopenharmony_ci struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci return stm32_dfsdm_clk_prepare_enable(dfsdm); 50062306a36Sopenharmony_ci} 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { 50362306a36Sopenharmony_ci SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, stm32_dfsdm_core_resume) 50462306a36Sopenharmony_ci RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, 50562306a36Sopenharmony_ci stm32_dfsdm_core_runtime_resume, 50662306a36Sopenharmony_ci NULL) 50762306a36Sopenharmony_ci}; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic struct platform_driver stm32_dfsdm_driver = { 51062306a36Sopenharmony_ci .probe = stm32_dfsdm_probe, 51162306a36Sopenharmony_ci .remove = stm32_dfsdm_core_remove, 51262306a36Sopenharmony_ci .driver = { 51362306a36Sopenharmony_ci .name = "stm32-dfsdm", 51462306a36Sopenharmony_ci .of_match_table = stm32_dfsdm_of_match, 51562306a36Sopenharmony_ci .pm = pm_ptr(&stm32_dfsdm_core_pm_ops), 51662306a36Sopenharmony_ci }, 51762306a36Sopenharmony_ci}; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cimodule_platform_driver(stm32_dfsdm_driver); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ciMODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 52262306a36Sopenharmony_ciMODULE_DESCRIPTION("STMicroelectronics STM32 dfsdm driver"); 52362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 524