// SPDX-License-Identifier: GPL-2.0 /* * This file is part the core part STM32 DFSDM driver * * Copyright (C) 2017, STMicroelectronics - All Rights Reserved * Author(s): Arnaud Pouliquen <arnaud.pouliquen@st.com> for STMicroelectronics.
*/
/** * struct stm32_dfsdm_dev_data - DFSDM compatible configuration data * @ipid: DFSDM identification number. Used only if hardware provides identification registers * @num_filters: DFSDM number of filters. Unused if identification registers are available * @num_channels: DFSDM number of channels. Unused if identification registers are available * @regmap_cfg: SAI register map configuration pointer
*/ struct stm32_dfsdm_dev_data {
u32 ipid; unsignedint num_filters; unsignedint num_channels; conststruct regmap_config *regmap_cfg;
};
/* * Mask is done on register to avoid to list registers of all * filter instances.
*/ switch (reg & DFSDM_FILTER_REG_MASK) { case DFSDM_CR1(0) & DFSDM_FILTER_REG_MASK: case DFSDM_ISR(0) & DFSDM_FILTER_REG_MASK: case DFSDM_JDATAR(0) & DFSDM_FILTER_REG_MASK: case DFSDM_RDATAR(0) & DFSDM_FILTER_REG_MASK: returntrue;
}
/** * stm32_dfsdm_start_dfsdm - start global dfsdm interface. * * Enable interface if n_active_ch is not null. * @dfsdm: Handle used to retrieve dfsdm context.
*/ int stm32_dfsdm_start_dfsdm(struct stm32_dfsdm *dfsdm)
{ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); struct device *dev = &priv->pdev->dev; unsignedint clk_div = priv->spi_clk_out_div, clk_src; int ret;
if (atomic_inc_return(&priv->n_active_ch) == 1) {
ret = pm_runtime_resume_and_get(dev); if (ret < 0) goto error_ret;
/* select clock source, e.g. 0 for "dfsdm" or 1 for "audio" */
clk_src = priv->aclk ? 1 : 0;
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_CKOUTSRC_MASK,
DFSDM_CHCFGR1_CKOUTSRC(clk_src)); if (ret < 0) goto pm_put;
/* Output the SPI CLKOUT (if clk_div == 0 clock if OFF) */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_CKOUTDIV_MASK,
DFSDM_CHCFGR1_CKOUTDIV(clk_div)); if (ret < 0) goto pm_put;
/* Global enable of DFSDM interface */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_DFSDMEN_MASK,
DFSDM_CHCFGR1_DFSDMEN(1)); if (ret < 0) goto pm_put;
}
/** * stm32_dfsdm_stop_dfsdm - stop global DFSDM interface. * * Disable interface if n_active_ch is null * @dfsdm: Handle used to retrieve dfsdm context.
*/ int stm32_dfsdm_stop_dfsdm(struct stm32_dfsdm *dfsdm)
{ struct dfsdm_priv *priv = to_stm32_dfsdm_priv(dfsdm); int ret;
if (atomic_dec_and_test(&priv->n_active_ch)) { /* Global disable of DFSDM interface */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_DFSDMEN_MASK,
DFSDM_CHCFGR1_DFSDMEN(0)); if (ret < 0) return ret;
/* Stop SPI CLKOUT */
ret = regmap_update_bits(dfsdm->regmap, DFSDM_CHCFGR1(0),
DFSDM_CHCFGR1_CKOUTDIV_MASK,
DFSDM_CHCFGR1_CKOUTDIV(0)); if (ret < 0) return ret;
priv->dfsdm.base = devm_platform_get_and_ioremap_resource(pdev, 0,
&res); if (IS_ERR(priv->dfsdm.base)) return PTR_ERR(priv->dfsdm.base);
priv->dfsdm.phys_base = res->start;
/* * "dfsdm" clock is mandatory for DFSDM peripheral clocking. * "dfsdm" or "audio" clocks can be used as source clock for * the SPI clock out signal and internal processing, depending * on use case.
*/
priv->clk = devm_clk_get(&pdev->dev, "dfsdm"); if (IS_ERR(priv->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk), "Failed to get clock\n");
priv->aclk = devm_clk_get(&pdev->dev, "audio"); if (IS_ERR(priv->aclk))
priv->aclk = NULL;
if (priv->aclk)
clk_freq = clk_get_rate(priv->aclk); else
clk_freq = clk_get_rate(priv->clk);
/* SPI clock out frequency */
ret = of_property_read_u32(pdev->dev.of_node, "spi-max-frequency",
&spi_freq); if (ret < 0) { /* No SPI master mode */ return 0;
}
divider = div_u64_rem(clk_freq, spi_freq, &rem); /* Round up divider when ckout isn't precise, not to exceed spi_freq */ if (rem)
divider++;
/* programmable divider is in range of [2:256] */ if (divider < 2 || divider > 256) {
dev_err(&pdev->dev, "spi-max-frequency not achievable\n"); return -EINVAL;
}
ret = regmap_read(dfsdm->regmap, DFSDM_IPIDR, &id); if (ret) return ret;
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 only child nodes with dfsdm compatible */ if (strstr(compat, "dfsdm"))
count++;
}
ret = regmap_read(dfsdm->regmap, DFSDM_HWCFGR, &val); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.