stm32-dfsdm-core.c (11453B)
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/pinctrl/consumer.h> 16#include <linux/pm_runtime.h> 17#include <linux/regmap.h> 18#include <linux/slab.h> 19 20#include "stm32-dfsdm.h" 21 22struct stm32_dfsdm_dev_data { 23 unsigned int num_filters; 24 unsigned int num_channels; 25 const struct regmap_config *regmap_cfg; 26}; 27 28#define STM32H7_DFSDM_NUM_FILTERS 4 29#define STM32H7_DFSDM_NUM_CHANNELS 8 30#define STM32MP1_DFSDM_NUM_FILTERS 6 31#define STM32MP1_DFSDM_NUM_CHANNELS 8 32 33static bool stm32_dfsdm_volatile_reg(struct device *dev, unsigned int reg) 34{ 35 if (reg < DFSDM_FILTER_BASE_ADR) 36 return false; 37 38 /* 39 * Mask is done on register to avoid to list registers of all 40 * filter instances. 41 */ 42 switch (reg & DFSDM_FILTER_REG_MASK) { 43 case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: 44 case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: 45 case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: 46 case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: 47 return true; 48 } 49 50 return false; 51} 52 53static const struct regmap_config stm32h7_dfsdm_regmap_cfg = { 54 .reg_bits = 32, 55 .val_bits = 32, 56 .reg_stride = sizeof(u32), 57 .max_register = 0x2B8, 58 .volatile_reg = stm32_dfsdm_volatile_reg, 59 .fast_io = true, 60}; 61 62static const struct stm32_dfsdm_dev_data stm32h7_dfsdm_data = { 63 .num_filters = STM32H7_DFSDM_NUM_FILTERS, 64 .num_channels = STM32H7_DFSDM_NUM_CHANNELS, 65 .regmap_cfg = &stm32h7_dfsdm_regmap_cfg, 66}; 67 68static const struct regmap_config stm32mp1_dfsdm_regmap_cfg = { 69 .reg_bits = 32, 70 .val_bits = 32, 71 .reg_stride = sizeof(u32), 72 .max_register = 0x7fc, 73 .volatile_reg = stm32_dfsdm_volatile_reg, 74 .fast_io = true, 75}; 76 77static const struct stm32_dfsdm_dev_data stm32mp1_dfsdm_data = { 78 .num_filters = STM32MP1_DFSDM_NUM_FILTERS, 79 .num_channels = STM32MP1_DFSDM_NUM_CHANNELS, 80 .regmap_cfg = &stm32mp1_dfsdm_regmap_cfg, 81}; 82 83struct dfsdm_priv { 84 struct platform_device *pdev; /* platform device */ 85 86 struct stm32_dfsdm dfsdm; /* common data exported for all instances */ 87 88 unsigned int spi_clk_out_div; /* SPI clkout divider value */ 89 atomic_t n_active_ch; /* number of current active channels */ 90 91 struct clk *clk; /* DFSDM clock */ 92 struct clk *aclk; /* audio clock */ 93}; 94 95static inline struct dfsdm_priv *to_stm32_dfsdm_priv(struct stm32_dfsdm *dfsdm) 96{ 97 return container_of(dfsdm, struct dfsdm_priv, dfsdm); 98} 99 100static int stm32_dfsdm_clk_prepare_enable(struct stm32_dfsdm *dfsdm) 101{ 102 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 103 int ret; 104 105 ret = clk_prepare_enable(priv->clk); 106 if (ret || !priv->aclk) 107 return ret; 108 109 ret = clk_prepare_enable(priv->aclk); 110 if (ret) 111 clk_disable_unprepare(priv->clk); 112 113 return ret; 114} 115 116static void stm32_dfsdm_clk_disable_unprepare(struct stm32_dfsdm *dfsdm) 117{ 118 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 119 120 clk_disable_unprepare(priv->aclk); 121 clk_disable_unprepare(priv->clk); 122} 123 124/** 125 * stm32_dfsdm_start_dfsdm - start global dfsdm interface. 126 * 127 * Enable interface if n_active_ch is not null. 128 * @dfsdm: Handle used to retrieve dfsdm context. 129 */ 130int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm) 131{ 132 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 133 struct device *dev = &priv->pdev->dev; 134 unsigned int clk_div = priv->spi_clk_out_div, clk_src; 135 int ret; 136 137 if (atomic_inc_return(&priv->n_active_ch) == 1) { 138 ret = pm_runtime_resume_and_get(dev); 139 if (ret < 0) 140 goto error_ret; 141 142 /* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */ 143 clk_src = priv->aclk ? 1 : 0; 144 ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 145 DFSDM_CHCFGR1_CKOUTSRC_MASK, 146 DFSDM_CHCFGR1_CKOUTSRC(clk_src)); 147 if (ret < 0) 148 goto pm_put; 149 150 /* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */ 151 ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 152 DFSDM_CHCFGR1_CKOUTDIV_MASK, 153 DFSDM_CHCFGR1_CKOUTDIV(clk_div)); 154 if (ret < 0) 155 goto pm_put; 156 157 /* Global enable of DFSDM interface */ 158 ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 159 DFSDM_CHCFGR1_DFSDMEN_MASK, 160 DFSDM_CHCFGR1_DFSDMEN(1)); 161 if (ret < 0) 162 goto pm_put; 163 } 164 165 dev_dbg(dev, "%s: n_active_ch %d\n", __func__, 166 atomic_read(&priv->n_active_ch)); 167 168 return 0; 169 170pm_put: 171 pm_runtime_put_sync(dev); 172error_ret: 173 atomic_dec(&priv->n_active_ch); 174 175 return ret; 176} 177EXPORT_SYMBOL_GPL(stm32_dfsdm_start_dfsdm); 178 179/** 180 * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. 181 * 182 * Disable interface if n_active_ch is null 183 * @dfsdm: Handle used to retrieve dfsdm context. 184 */ 185int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm) 186{ 187 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 188 int ret; 189 190 if (atomic_dec_and_test(&priv->n_active_ch)) { 191 /* Global disable of DFSDM interface */ 192 ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 193 DFSDM_CHCFGR1_DFSDMEN_MASK, 194 DFSDM_CHCFGR1_DFSDMEN(0)); 195 if (ret < 0) 196 return ret; 197 198 /* Stop SPI CLKOUT */ 199 ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0), 200 DFSDM_CHCFGR1_CKOUTDIV_MASK, 201 DFSDM_CHCFGR1_CKOUTDIV(0)); 202 if (ret < 0) 203 return ret; 204 205 pm_runtime_put_sync(&priv->pdev->dev); 206 } 207 dev_dbg(&priv->pdev->dev, "%s: n_active_ch %d\n", __func__, 208 atomic_read(&priv->n_active_ch)); 209 210 return 0; 211} 212EXPORT_SYMBOL_GPL(stm32_dfsdm_stop_dfsdm); 213 214static int stm32_dfsdm_parse_of(struct platform_device *pdev, 215 struct dfsdm_priv *priv) 216{ 217 struct device_node *node = pdev->dev.of_node; 218 struct resource *res; 219 unsigned long clk_freq, divider; 220 unsigned int spi_freq, rem; 221 int ret; 222 223 if (!node) 224 return -EINVAL; 225 226 priv->dfsdm.base = devm_platform_get_and_ioremap_resource(pdev, 0, 227 &res); 228 if (IS_ERR(priv->dfsdm.base)) 229 return PTR_ERR(priv->dfsdm.base); 230 231 priv->dfsdm.phys_base = res->start; 232 233 /* 234 * "dfsdm" clock is mandatory for DFSDM peripheral clocking. 235 * "dfsdm" or "audio" clocks can be used as source clock for 236 * the SPI clock out signal and internal processing, depending 237 * on use case. 238 */ 239 priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); 240 if (IS_ERR(priv->clk)) 241 return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), 242 "Failed to get clock\n"); 243 244 priv->aclk = devm_clk_get(&pdev->dev, "audio"); 245 if (IS_ERR(priv->aclk)) 246 priv->aclk = NULL; 247 248 if (priv->aclk) 249 clk_freq = clk_get_rate(priv->aclk); 250 else 251 clk_freq = clk_get_rate(priv->clk); 252 253 /* SPI clock out frequency */ 254 ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", 255 &spi_freq); 256 if (ret < 0) { 257 /* No SPI master mode */ 258 return 0; 259 } 260 261 divider = div_u64_rem(clk_freq, spi_freq, &rem); 262 /* Round up divider when ckout isn't precise, not to exceed spi_freq */ 263 if (rem) 264 divider++; 265 266 /* programmable divider is in range of [2:256] */ 267 if (divider < 2 || divider > 256) { 268 dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); 269 return -EINVAL; 270 } 271 272 /* SPI clock output divider is: divider = CKOUTDIV + 1 */ 273 priv->spi_clk_out_div = divider - 1; 274 priv->dfsdm.spi_master_freq = clk_freq / (priv->spi_clk_out_div + 1); 275 276 if (rem) { 277 dev_warn(&pdev->dev, "SPI clock not accurate\n"); 278 dev_warn(&pdev->dev, "%ld = %d * %d + %d\n", 279 clk_freq, spi_freq, priv->spi_clk_out_div + 1, rem); 280 } 281 282 return 0; 283}; 284 285static const struct of_device_id stm32_dfsdm_of_match[] = { 286 { 287 .compatible = "st,stm32h7-dfsdm", 288 .data = &stm32h7_dfsdm_data, 289 }, 290 { 291 .compatible = "st,stm32mp1-dfsdm", 292 .data = &stm32mp1_dfsdm_data, 293 }, 294 {} 295}; 296MODULE_DEVICE_TABLE(of, stm32_dfsdm_of_match); 297 298static int stm32_dfsdm_probe(struct platform_device *pdev) 299{ 300 struct dfsdm_priv *priv; 301 const struct stm32_dfsdm_dev_data *dev_data; 302 struct stm32_dfsdm *dfsdm; 303 int ret; 304 305 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 306 if (!priv) 307 return -ENOMEM; 308 309 priv->pdev = pdev; 310 311 dev_data = of_device_get_match_data(&pdev->dev); 312 313 dfsdm = &priv->dfsdm; 314 dfsdm->fl_list = devm_kcalloc(&pdev->dev, dev_data->num_filters, 315 sizeof(*dfsdm->fl_list), GFP_KERNEL); 316 if (!dfsdm->fl_list) 317 return -ENOMEM; 318 319 dfsdm->num_fls = dev_data->num_filters; 320 dfsdm->ch_list = devm_kcalloc(&pdev->dev, dev_data->num_channels, 321 sizeof(*dfsdm->ch_list), 322 GFP_KERNEL); 323 if (!dfsdm->ch_list) 324 return -ENOMEM; 325 dfsdm->num_chs = dev_data->num_channels; 326 327 ret = stm32_dfsdm_parse_of(pdev, priv); 328 if (ret < 0) 329 return ret; 330 331 dfsdm->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dfsdm", 332 dfsdm->base, 333 dev_data->regmap_cfg); 334 if (IS_ERR(dfsdm->regmap)) { 335 ret = PTR_ERR(dfsdm->regmap); 336 dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", 337 __func__, ret); 338 return ret; 339 } 340 341 platform_set_drvdata(pdev, dfsdm); 342 343 ret = stm32_dfsdm_clk_prepare_enable(dfsdm); 344 if (ret) { 345 dev_err(&pdev->dev, "Failed to start clock\n"); 346 return ret; 347 } 348 349 pm_runtime_get_noresume(&pdev->dev); 350 pm_runtime_set_active(&pdev->dev); 351 pm_runtime_enable(&pdev->dev); 352 353 ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); 354 if (ret) 355 goto pm_put; 356 357 pm_runtime_put(&pdev->dev); 358 359 return 0; 360 361pm_put: 362 pm_runtime_disable(&pdev->dev); 363 pm_runtime_set_suspended(&pdev->dev); 364 pm_runtime_put_noidle(&pdev->dev); 365 stm32_dfsdm_clk_disable_unprepare(dfsdm); 366 367 return ret; 368} 369 370static int stm32_dfsdm_core_remove(struct platform_device *pdev) 371{ 372 struct stm32_dfsdm *dfsdm = platform_get_drvdata(pdev); 373 374 pm_runtime_get_sync(&pdev->dev); 375 of_platform_depopulate(&pdev->dev); 376 pm_runtime_disable(&pdev->dev); 377 pm_runtime_set_suspended(&pdev->dev); 378 pm_runtime_put_noidle(&pdev->dev); 379 stm32_dfsdm_clk_disable_unprepare(dfsdm); 380 381 return 0; 382} 383 384static int stm32_dfsdm_core_suspend(struct device *dev) 385{ 386 struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 387 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 388 int ret; 389 390 ret = pm_runtime_force_suspend(dev); 391 if (ret) 392 return ret; 393 394 /* Balance devm_regmap_init_mmio_clk() clk_prepare() */ 395 clk_unprepare(priv->clk); 396 397 return pinctrl_pm_select_sleep_state(dev); 398} 399 400static int stm32_dfsdm_core_resume(struct device *dev) 401{ 402 struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 403 struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); 404 int ret; 405 406 ret = pinctrl_pm_select_default_state(dev); 407 if (ret) 408 return ret; 409 410 ret = clk_prepare(priv->clk); 411 if (ret) 412 return ret; 413 414 return pm_runtime_force_resume(dev); 415} 416 417static int stm32_dfsdm_core_runtime_suspend(struct device *dev) 418{ 419 struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 420 421 stm32_dfsdm_clk_disable_unprepare(dfsdm); 422 423 return 0; 424} 425 426static int stm32_dfsdm_core_runtime_resume(struct device *dev) 427{ 428 struct stm32_dfsdm *dfsdm = dev_get_drvdata(dev); 429 430 return stm32_dfsdm_clk_prepare_enable(dfsdm); 431} 432 433static const struct dev_pm_ops stm32_dfsdm_core_pm_ops = { 434 SYSTEM_SLEEP_PM_OPS(stm32_dfsdm_core_suspend, stm32_dfsdm_core_resume) 435 RUNTIME_PM_OPS(stm32_dfsdm_core_runtime_suspend, 436 stm32_dfsdm_core_runtime_resume, 437 NULL) 438}; 439 440static struct platform_driver stm32_dfsdm_driver = { 441 .probe = stm32_dfsdm_probe, 442 .remove = stm32_dfsdm_core_remove, 443 .driver = { 444 .name = "stm32-dfsdm", 445 .of_match_table = stm32_dfsdm_of_match, 446 .pm = pm_ptr(&stm32_dfsdm_core_pm_ops), 447 }, 448}; 449 450module_platform_driver(stm32_dfsdm_driver); 451 452MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 453MODULE_DESCRIPTION("STMicroelectronics STM32 dfsdm driver"); 454MODULE_LICENSE("GPL v2");