File Index
Files and directories
Sign in
FILE

stm32-dfsdm-core.c

File preview with syntax highlighting.

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