12cfc123eSJerome Brunet // SPDX-License-Identifier: (GPL-2.0 OR MIT)
22cfc123eSJerome Brunet //
32cfc123eSJerome Brunet // Copyright (c) 2018 BayLibre, SAS.
42cfc123eSJerome Brunet // Author: Jerome Brunet <jbrunet@baylibre.com>
52cfc123eSJerome Brunet
62cfc123eSJerome Brunet #include <linux/clk.h>
72cfc123eSJerome Brunet #include <linux/module.h>
82cfc123eSJerome Brunet #include <linux/of_irq.h>
92cfc123eSJerome Brunet #include <linux/of_platform.h>
102cfc123eSJerome Brunet #include <linux/regmap.h>
112cfc123eSJerome Brunet #include <sound/soc.h>
122cfc123eSJerome Brunet #include <sound/soc-dai.h>
132cfc123eSJerome Brunet #include <sound/pcm_params.h>
142cfc123eSJerome Brunet
152cfc123eSJerome Brunet #define PDM_CTRL 0x00
162cfc123eSJerome Brunet #define PDM_CTRL_EN BIT(31)
172cfc123eSJerome Brunet #define PDM_CTRL_OUT_MODE BIT(29)
182cfc123eSJerome Brunet #define PDM_CTRL_BYPASS_MODE BIT(28)
192cfc123eSJerome Brunet #define PDM_CTRL_RST_FIFO BIT(16)
202cfc123eSJerome Brunet #define PDM_CTRL_CHAN_RSTN_MASK GENMASK(15, 8)
212cfc123eSJerome Brunet #define PDM_CTRL_CHAN_RSTN(x) ((x) << 8)
222cfc123eSJerome Brunet #define PDM_CTRL_CHAN_EN_MASK GENMASK(7, 0)
232cfc123eSJerome Brunet #define PDM_CTRL_CHAN_EN(x) ((x) << 0)
242cfc123eSJerome Brunet #define PDM_HCIC_CTRL1 0x04
252cfc123eSJerome Brunet #define PDM_FILTER_EN BIT(31)
262cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_GAIN_SFT_MASK GENMASK(29, 24)
272cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_GAIN_SFT(x) ((x) << 24)
282cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_GAIN_MULT_MASK GENMASK(23, 16)
292cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_GAIN_MULT(x) ((x) << 16)
302cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_DSR_MASK GENMASK(8, 4)
312cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_DSR(x) ((x) << 4)
322cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_STAGE_NUM_MASK GENMASK(3, 0)
332cfc123eSJerome Brunet #define PDM_HCIC_CTRL1_STAGE_NUM(x) ((x) << 0)
342cfc123eSJerome Brunet #define PDM_HCIC_CTRL2 0x08
352cfc123eSJerome Brunet #define PDM_F1_CTRL 0x0c
362cfc123eSJerome Brunet #define PDM_LPF_ROUND_MODE_MASK GENMASK(17, 16)
372cfc123eSJerome Brunet #define PDM_LPF_ROUND_MODE(x) ((x) << 16)
382cfc123eSJerome Brunet #define PDM_LPF_DSR_MASK GENMASK(15, 12)
392cfc123eSJerome Brunet #define PDM_LPF_DSR(x) ((x) << 12)
402cfc123eSJerome Brunet #define PDM_LPF_STAGE_NUM_MASK GENMASK(8, 0)
412cfc123eSJerome Brunet #define PDM_LPF_STAGE_NUM(x) ((x) << 0)
422cfc123eSJerome Brunet #define PDM_LPF_MAX_STAGE 336
432cfc123eSJerome Brunet #define PDM_LPF_NUM 3
442cfc123eSJerome Brunet #define PDM_F2_CTRL 0x10
452cfc123eSJerome Brunet #define PDM_F3_CTRL 0x14
462cfc123eSJerome Brunet #define PDM_HPF_CTRL 0x18
472cfc123eSJerome Brunet #define PDM_HPF_SFT_STEPS_MASK GENMASK(20, 16)
482cfc123eSJerome Brunet #define PDM_HPF_SFT_STEPS(x) ((x) << 16)
492cfc123eSJerome Brunet #define PDM_HPF_OUT_FACTOR_MASK GENMASK(15, 0)
502cfc123eSJerome Brunet #define PDM_HPF_OUT_FACTOR(x) ((x) << 0)
512cfc123eSJerome Brunet #define PDM_CHAN_CTRL 0x1c
522cfc123eSJerome Brunet #define PDM_CHAN_CTRL_POINTER_WIDTH 8
532cfc123eSJerome Brunet #define PDM_CHAN_CTRL_POINTER_MAX ((1 << PDM_CHAN_CTRL_POINTER_WIDTH) - 1)
542cfc123eSJerome Brunet #define PDM_CHAN_CTRL_NUM 4
552cfc123eSJerome Brunet #define PDM_CHAN_CTRL1 0x20
562cfc123eSJerome Brunet #define PDM_COEFF_ADDR 0x24
572cfc123eSJerome Brunet #define PDM_COEFF_DATA 0x28
582cfc123eSJerome Brunet #define PDM_CLKG_CTRL 0x2c
592cfc123eSJerome Brunet #define PDM_STS 0x30
602cfc123eSJerome Brunet
612cfc123eSJerome Brunet struct axg_pdm_lpf {
622cfc123eSJerome Brunet unsigned int ds;
632cfc123eSJerome Brunet unsigned int round_mode;
642cfc123eSJerome Brunet const unsigned int *tap;
652cfc123eSJerome Brunet unsigned int tap_num;
662cfc123eSJerome Brunet };
672cfc123eSJerome Brunet
682cfc123eSJerome Brunet struct axg_pdm_hcic {
692cfc123eSJerome Brunet unsigned int shift;
702cfc123eSJerome Brunet unsigned int mult;
712cfc123eSJerome Brunet unsigned int steps;
722cfc123eSJerome Brunet unsigned int ds;
732cfc123eSJerome Brunet };
742cfc123eSJerome Brunet
752cfc123eSJerome Brunet struct axg_pdm_hpf {
762cfc123eSJerome Brunet unsigned int out_factor;
772cfc123eSJerome Brunet unsigned int steps;
782cfc123eSJerome Brunet };
792cfc123eSJerome Brunet
802cfc123eSJerome Brunet struct axg_pdm_filters {
812cfc123eSJerome Brunet struct axg_pdm_hcic hcic;
822cfc123eSJerome Brunet struct axg_pdm_hpf hpf;
832cfc123eSJerome Brunet struct axg_pdm_lpf lpf[PDM_LPF_NUM];
842cfc123eSJerome Brunet };
852cfc123eSJerome Brunet
862cfc123eSJerome Brunet struct axg_pdm_cfg {
872cfc123eSJerome Brunet const struct axg_pdm_filters *filters;
882cfc123eSJerome Brunet unsigned int sys_rate;
892cfc123eSJerome Brunet };
902cfc123eSJerome Brunet
912cfc123eSJerome Brunet struct axg_pdm {
922cfc123eSJerome Brunet const struct axg_pdm_cfg *cfg;
932cfc123eSJerome Brunet struct regmap *map;
942cfc123eSJerome Brunet struct clk *dclk;
952cfc123eSJerome Brunet struct clk *sysclk;
962cfc123eSJerome Brunet struct clk *pclk;
972cfc123eSJerome Brunet };
982cfc123eSJerome Brunet
axg_pdm_enable(struct regmap * map)992cfc123eSJerome Brunet static void axg_pdm_enable(struct regmap *map)
1002cfc123eSJerome Brunet {
1012cfc123eSJerome Brunet /* Reset AFIFO */
1022cfc123eSJerome Brunet regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, PDM_CTRL_RST_FIFO);
1032cfc123eSJerome Brunet regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, 0);
1042cfc123eSJerome Brunet
1052cfc123eSJerome Brunet /* Enable PDM */
1062cfc123eSJerome Brunet regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, PDM_CTRL_EN);
1072cfc123eSJerome Brunet }
1082cfc123eSJerome Brunet
axg_pdm_disable(struct regmap * map)1092cfc123eSJerome Brunet static void axg_pdm_disable(struct regmap *map)
1102cfc123eSJerome Brunet {
1112cfc123eSJerome Brunet regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, 0);
1122cfc123eSJerome Brunet }
1132cfc123eSJerome Brunet
axg_pdm_filters_enable(struct regmap * map,bool enable)1142cfc123eSJerome Brunet static void axg_pdm_filters_enable(struct regmap *map, bool enable)
1152cfc123eSJerome Brunet {
1162cfc123eSJerome Brunet unsigned int val = enable ? PDM_FILTER_EN : 0;
1172cfc123eSJerome Brunet
1182cfc123eSJerome Brunet regmap_update_bits(map, PDM_HCIC_CTRL1, PDM_FILTER_EN, val);
1192cfc123eSJerome Brunet regmap_update_bits(map, PDM_F1_CTRL, PDM_FILTER_EN, val);
1202cfc123eSJerome Brunet regmap_update_bits(map, PDM_F2_CTRL, PDM_FILTER_EN, val);
1212cfc123eSJerome Brunet regmap_update_bits(map, PDM_F3_CTRL, PDM_FILTER_EN, val);
1222cfc123eSJerome Brunet regmap_update_bits(map, PDM_HPF_CTRL, PDM_FILTER_EN, val);
1232cfc123eSJerome Brunet }
1242cfc123eSJerome Brunet
axg_pdm_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)1252cfc123eSJerome Brunet static int axg_pdm_trigger(struct snd_pcm_substream *substream, int cmd,
1262cfc123eSJerome Brunet struct snd_soc_dai *dai)
1272cfc123eSJerome Brunet {
1282cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
1292cfc123eSJerome Brunet
1302cfc123eSJerome Brunet switch (cmd) {
1312cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_START:
1322cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_RESUME:
1332cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
1342cfc123eSJerome Brunet axg_pdm_enable(priv->map);
1352cfc123eSJerome Brunet return 0;
1362cfc123eSJerome Brunet
1372cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_STOP:
1382cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_SUSPEND:
1392cfc123eSJerome Brunet case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
1402cfc123eSJerome Brunet axg_pdm_disable(priv->map);
1412cfc123eSJerome Brunet return 0;
1422cfc123eSJerome Brunet
1432cfc123eSJerome Brunet default:
1442cfc123eSJerome Brunet return -EINVAL;
1452cfc123eSJerome Brunet }
1462cfc123eSJerome Brunet }
1472cfc123eSJerome Brunet
axg_pdm_get_os(struct axg_pdm * priv)1482cfc123eSJerome Brunet static unsigned int axg_pdm_get_os(struct axg_pdm *priv)
1492cfc123eSJerome Brunet {
1502cfc123eSJerome Brunet const struct axg_pdm_filters *filters = priv->cfg->filters;
1512cfc123eSJerome Brunet unsigned int os = filters->hcic.ds;
1522cfc123eSJerome Brunet int i;
1532cfc123eSJerome Brunet
1542cfc123eSJerome Brunet /*
1552cfc123eSJerome Brunet * The global oversampling factor is defined by the down sampling
1562cfc123eSJerome Brunet * factor applied by each filter (HCIC and LPFs)
1572cfc123eSJerome Brunet */
1582cfc123eSJerome Brunet
1592cfc123eSJerome Brunet for (i = 0; i < PDM_LPF_NUM; i++)
1602cfc123eSJerome Brunet os *= filters->lpf[i].ds;
1612cfc123eSJerome Brunet
1622cfc123eSJerome Brunet return os;
1632cfc123eSJerome Brunet }
1642cfc123eSJerome Brunet
axg_pdm_set_sysclk(struct axg_pdm * priv,unsigned int os,unsigned int rate)1652cfc123eSJerome Brunet static int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os,
1662cfc123eSJerome Brunet unsigned int rate)
1672cfc123eSJerome Brunet {
1682cfc123eSJerome Brunet unsigned int sys_rate = os * 2 * rate * PDM_CHAN_CTRL_POINTER_MAX;
1692cfc123eSJerome Brunet
1702cfc123eSJerome Brunet /*
1712cfc123eSJerome Brunet * Set the default system clock rate unless it is too fast for
1724306fc8fSShaomin Deng * the requested sample rate. In this case, the sample pointer
1732cfc123eSJerome Brunet * counter could overflow so set a lower system clock rate
1742cfc123eSJerome Brunet */
1752cfc123eSJerome Brunet if (sys_rate < priv->cfg->sys_rate)
1762cfc123eSJerome Brunet return clk_set_rate(priv->sysclk, sys_rate);
1772cfc123eSJerome Brunet
1782cfc123eSJerome Brunet return clk_set_rate(priv->sysclk, priv->cfg->sys_rate);
1792cfc123eSJerome Brunet }
1802cfc123eSJerome Brunet
axg_pdm_set_sample_pointer(struct axg_pdm * priv)1812cfc123eSJerome Brunet static int axg_pdm_set_sample_pointer(struct axg_pdm *priv)
1822cfc123eSJerome Brunet {
1832cfc123eSJerome Brunet unsigned int spmax, sp, val;
1842cfc123eSJerome Brunet int i;
1852cfc123eSJerome Brunet
1862cfc123eSJerome Brunet /* Max sample counter value per half period of dclk */
1872cfc123eSJerome Brunet spmax = DIV_ROUND_UP_ULL((u64)clk_get_rate(priv->sysclk),
1882cfc123eSJerome Brunet clk_get_rate(priv->dclk) * 2);
1892cfc123eSJerome Brunet
1902cfc123eSJerome Brunet /* Check if sysclk is not too fast - should not happen */
1912cfc123eSJerome Brunet if (WARN_ON(spmax > PDM_CHAN_CTRL_POINTER_MAX))
1922cfc123eSJerome Brunet return -EINVAL;
1932cfc123eSJerome Brunet
1942cfc123eSJerome Brunet /* Capture the data when we are at 75% of the half period */
1952cfc123eSJerome Brunet sp = spmax * 3 / 4;
1962cfc123eSJerome Brunet
1972cfc123eSJerome Brunet for (i = 0, val = 0; i < PDM_CHAN_CTRL_NUM; i++)
1982cfc123eSJerome Brunet val |= sp << (PDM_CHAN_CTRL_POINTER_WIDTH * i);
1992cfc123eSJerome Brunet
2002cfc123eSJerome Brunet regmap_write(priv->map, PDM_CHAN_CTRL, val);
2012cfc123eSJerome Brunet regmap_write(priv->map, PDM_CHAN_CTRL1, val);
2022cfc123eSJerome Brunet
2032cfc123eSJerome Brunet return 0;
2042cfc123eSJerome Brunet }
2052cfc123eSJerome Brunet
axg_pdm_set_channel_mask(struct axg_pdm * priv,unsigned int channels)2062cfc123eSJerome Brunet static void axg_pdm_set_channel_mask(struct axg_pdm *priv,
2072cfc123eSJerome Brunet unsigned int channels)
2082cfc123eSJerome Brunet {
2092cfc123eSJerome Brunet unsigned int mask = GENMASK(channels - 1, 0);
2102cfc123eSJerome Brunet
2112cfc123eSJerome Brunet /* Put all channel in reset */
2122cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_CTRL,
2132cfc123eSJerome Brunet PDM_CTRL_CHAN_RSTN_MASK, 0);
2142cfc123eSJerome Brunet
2152cfc123eSJerome Brunet /* Take the necessary channels out of reset and enable them */
2162cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_CTRL,
2172cfc123eSJerome Brunet PDM_CTRL_CHAN_RSTN_MASK |
2182cfc123eSJerome Brunet PDM_CTRL_CHAN_EN_MASK,
2192cfc123eSJerome Brunet PDM_CTRL_CHAN_RSTN(mask) |
2202cfc123eSJerome Brunet PDM_CTRL_CHAN_EN(mask));
2212cfc123eSJerome Brunet }
2222cfc123eSJerome Brunet
axg_pdm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)2232cfc123eSJerome Brunet static int axg_pdm_hw_params(struct snd_pcm_substream *substream,
2242cfc123eSJerome Brunet struct snd_pcm_hw_params *params,
2252cfc123eSJerome Brunet struct snd_soc_dai *dai)
2262cfc123eSJerome Brunet {
2272cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
2282cfc123eSJerome Brunet unsigned int os = axg_pdm_get_os(priv);
2292cfc123eSJerome Brunet unsigned int rate = params_rate(params);
2302cfc123eSJerome Brunet unsigned int val;
2312cfc123eSJerome Brunet int ret;
2322cfc123eSJerome Brunet
2332cfc123eSJerome Brunet switch (params_width(params)) {
2342cfc123eSJerome Brunet case 24:
2352cfc123eSJerome Brunet val = PDM_CTRL_OUT_MODE;
2362cfc123eSJerome Brunet break;
2372cfc123eSJerome Brunet case 32:
2382cfc123eSJerome Brunet val = 0;
2392cfc123eSJerome Brunet break;
2402cfc123eSJerome Brunet default:
2412cfc123eSJerome Brunet dev_err(dai->dev, "unsupported sample width\n");
2422cfc123eSJerome Brunet return -EINVAL;
2432cfc123eSJerome Brunet }
2442cfc123eSJerome Brunet
2452cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_OUT_MODE, val);
2462cfc123eSJerome Brunet
2472cfc123eSJerome Brunet ret = axg_pdm_set_sysclk(priv, os, rate);
2482cfc123eSJerome Brunet if (ret) {
2492cfc123eSJerome Brunet dev_err(dai->dev, "failed to set system clock\n");
2502cfc123eSJerome Brunet return ret;
2512cfc123eSJerome Brunet }
2522cfc123eSJerome Brunet
2532cfc123eSJerome Brunet ret = clk_set_rate(priv->dclk, rate * os);
2542cfc123eSJerome Brunet if (ret) {
2552cfc123eSJerome Brunet dev_err(dai->dev, "failed to set dclk\n");
2562cfc123eSJerome Brunet return ret;
2572cfc123eSJerome Brunet }
2582cfc123eSJerome Brunet
2592cfc123eSJerome Brunet ret = axg_pdm_set_sample_pointer(priv);
2602cfc123eSJerome Brunet if (ret) {
2612cfc123eSJerome Brunet dev_err(dai->dev, "invalid clock setting\n");
2622cfc123eSJerome Brunet return ret;
2632cfc123eSJerome Brunet }
2642cfc123eSJerome Brunet
2652cfc123eSJerome Brunet axg_pdm_set_channel_mask(priv, params_channels(params));
2662cfc123eSJerome Brunet
2672cfc123eSJerome Brunet return 0;
2682cfc123eSJerome Brunet }
2692cfc123eSJerome Brunet
axg_pdm_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)2702cfc123eSJerome Brunet static int axg_pdm_startup(struct snd_pcm_substream *substream,
2712cfc123eSJerome Brunet struct snd_soc_dai *dai)
2722cfc123eSJerome Brunet {
2732cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
2742cfc123eSJerome Brunet int ret;
2752cfc123eSJerome Brunet
2762cfc123eSJerome Brunet ret = clk_prepare_enable(priv->dclk);
2772cfc123eSJerome Brunet if (ret) {
2782cfc123eSJerome Brunet dev_err(dai->dev, "enabling dclk failed\n");
2792cfc123eSJerome Brunet return ret;
2802cfc123eSJerome Brunet }
2812cfc123eSJerome Brunet
2822cfc123eSJerome Brunet /* Enable the filters */
2832cfc123eSJerome Brunet axg_pdm_filters_enable(priv->map, true);
2842cfc123eSJerome Brunet
2852cfc123eSJerome Brunet return ret;
2862cfc123eSJerome Brunet }
2872cfc123eSJerome Brunet
axg_pdm_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)2882cfc123eSJerome Brunet static void axg_pdm_shutdown(struct snd_pcm_substream *substream,
2892cfc123eSJerome Brunet struct snd_soc_dai *dai)
2902cfc123eSJerome Brunet {
2912cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
2922cfc123eSJerome Brunet
2932cfc123eSJerome Brunet axg_pdm_filters_enable(priv->map, false);
2942cfc123eSJerome Brunet clk_disable_unprepare(priv->dclk);
2952cfc123eSJerome Brunet }
2962cfc123eSJerome Brunet
axg_pdm_set_hcic_ctrl(struct axg_pdm * priv)2972cfc123eSJerome Brunet static void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv)
2982cfc123eSJerome Brunet {
2992cfc123eSJerome Brunet const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic;
3002cfc123eSJerome Brunet unsigned int val;
3012cfc123eSJerome Brunet
3022cfc123eSJerome Brunet val = PDM_HCIC_CTRL1_STAGE_NUM(hcic->steps);
3032cfc123eSJerome Brunet val |= PDM_HCIC_CTRL1_DSR(hcic->ds);
3042cfc123eSJerome Brunet val |= PDM_HCIC_CTRL1_GAIN_MULT(hcic->mult);
3052cfc123eSJerome Brunet val |= PDM_HCIC_CTRL1_GAIN_SFT(hcic->shift);
3062cfc123eSJerome Brunet
3072cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_HCIC_CTRL1,
3082cfc123eSJerome Brunet PDM_HCIC_CTRL1_STAGE_NUM_MASK |
3092cfc123eSJerome Brunet PDM_HCIC_CTRL1_DSR_MASK |
3102cfc123eSJerome Brunet PDM_HCIC_CTRL1_GAIN_MULT_MASK |
3112cfc123eSJerome Brunet PDM_HCIC_CTRL1_GAIN_SFT_MASK,
3122cfc123eSJerome Brunet val);
3132cfc123eSJerome Brunet }
3142cfc123eSJerome Brunet
axg_pdm_set_lpf_ctrl(struct axg_pdm * priv,unsigned int index)3152cfc123eSJerome Brunet static void axg_pdm_set_lpf_ctrl(struct axg_pdm *priv, unsigned int index)
3162cfc123eSJerome Brunet {
3172cfc123eSJerome Brunet const struct axg_pdm_lpf *lpf = &priv->cfg->filters->lpf[index];
3182cfc123eSJerome Brunet unsigned int offset = index * regmap_get_reg_stride(priv->map)
3192cfc123eSJerome Brunet + PDM_F1_CTRL;
3202cfc123eSJerome Brunet unsigned int val;
3212cfc123eSJerome Brunet
3222cfc123eSJerome Brunet val = PDM_LPF_STAGE_NUM(lpf->tap_num);
3232cfc123eSJerome Brunet val |= PDM_LPF_DSR(lpf->ds);
3242cfc123eSJerome Brunet val |= PDM_LPF_ROUND_MODE(lpf->round_mode);
3252cfc123eSJerome Brunet
3262cfc123eSJerome Brunet regmap_update_bits(priv->map, offset,
3272cfc123eSJerome Brunet PDM_LPF_STAGE_NUM_MASK |
3282cfc123eSJerome Brunet PDM_LPF_DSR_MASK |
3292cfc123eSJerome Brunet PDM_LPF_ROUND_MODE_MASK,
3302cfc123eSJerome Brunet val);
3312cfc123eSJerome Brunet }
3322cfc123eSJerome Brunet
axg_pdm_set_hpf_ctrl(struct axg_pdm * priv)3332cfc123eSJerome Brunet static void axg_pdm_set_hpf_ctrl(struct axg_pdm *priv)
3342cfc123eSJerome Brunet {
3352cfc123eSJerome Brunet const struct axg_pdm_hpf *hpf = &priv->cfg->filters->hpf;
3362cfc123eSJerome Brunet unsigned int val;
3372cfc123eSJerome Brunet
3382cfc123eSJerome Brunet val = PDM_HPF_OUT_FACTOR(hpf->out_factor);
3392cfc123eSJerome Brunet val |= PDM_HPF_SFT_STEPS(hpf->steps);
3402cfc123eSJerome Brunet
3412cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_HPF_CTRL,
3422cfc123eSJerome Brunet PDM_HPF_OUT_FACTOR_MASK |
3432cfc123eSJerome Brunet PDM_HPF_SFT_STEPS_MASK,
3442cfc123eSJerome Brunet val);
3452cfc123eSJerome Brunet }
3462cfc123eSJerome Brunet
axg_pdm_set_lpf_filters(struct axg_pdm * priv)3472cfc123eSJerome Brunet static int axg_pdm_set_lpf_filters(struct axg_pdm *priv)
3482cfc123eSJerome Brunet {
3492cfc123eSJerome Brunet const struct axg_pdm_lpf *lpf = priv->cfg->filters->lpf;
3502cfc123eSJerome Brunet unsigned int count = 0;
3512cfc123eSJerome Brunet int i, j;
3522cfc123eSJerome Brunet
3532cfc123eSJerome Brunet for (i = 0; i < PDM_LPF_NUM; i++)
3542cfc123eSJerome Brunet count += lpf[i].tap_num;
3552cfc123eSJerome Brunet
3562cfc123eSJerome Brunet /* Make sure the coeffs fit in the memory */
3572cfc123eSJerome Brunet if (count >= PDM_LPF_MAX_STAGE)
3582cfc123eSJerome Brunet return -EINVAL;
3592cfc123eSJerome Brunet
3602cfc123eSJerome Brunet /* Set the initial APB bus register address */
3612cfc123eSJerome Brunet regmap_write(priv->map, PDM_COEFF_ADDR, 0);
3622cfc123eSJerome Brunet
3632cfc123eSJerome Brunet /* Set the tap filter values of all 3 filters */
3642cfc123eSJerome Brunet for (i = 0; i < PDM_LPF_NUM; i++) {
3652cfc123eSJerome Brunet axg_pdm_set_lpf_ctrl(priv, i);
3662cfc123eSJerome Brunet
3672cfc123eSJerome Brunet for (j = 0; j < lpf[i].tap_num; j++)
3682cfc123eSJerome Brunet regmap_write(priv->map, PDM_COEFF_DATA, lpf[i].tap[j]);
3692cfc123eSJerome Brunet }
3702cfc123eSJerome Brunet
3712cfc123eSJerome Brunet return 0;
3722cfc123eSJerome Brunet }
3732cfc123eSJerome Brunet
axg_pdm_dai_probe(struct snd_soc_dai * dai)3742cfc123eSJerome Brunet static int axg_pdm_dai_probe(struct snd_soc_dai *dai)
3752cfc123eSJerome Brunet {
3762cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
3772cfc123eSJerome Brunet int ret;
3782cfc123eSJerome Brunet
3792cfc123eSJerome Brunet ret = clk_prepare_enable(priv->pclk);
3802cfc123eSJerome Brunet if (ret) {
3812cfc123eSJerome Brunet dev_err(dai->dev, "enabling pclk failed\n");
3822cfc123eSJerome Brunet return ret;
3832cfc123eSJerome Brunet }
3842cfc123eSJerome Brunet
3852cfc123eSJerome Brunet /*
3862cfc123eSJerome Brunet * sysclk must be set and enabled as well to access the pdm registers
3872cfc123eSJerome Brunet * Accessing the register w/o it will give a bus error.
3882cfc123eSJerome Brunet */
3892cfc123eSJerome Brunet ret = clk_set_rate(priv->sysclk, priv->cfg->sys_rate);
3902cfc123eSJerome Brunet if (ret) {
3912cfc123eSJerome Brunet dev_err(dai->dev, "setting sysclk failed\n");
3922cfc123eSJerome Brunet goto err_pclk;
3932cfc123eSJerome Brunet }
3942cfc123eSJerome Brunet
3952cfc123eSJerome Brunet ret = clk_prepare_enable(priv->sysclk);
3962cfc123eSJerome Brunet if (ret) {
3972cfc123eSJerome Brunet dev_err(dai->dev, "enabling sysclk failed\n");
3982cfc123eSJerome Brunet goto err_pclk;
3992cfc123eSJerome Brunet }
4002cfc123eSJerome Brunet
4012cfc123eSJerome Brunet /* Make sure the device is initially disabled */
4022cfc123eSJerome Brunet axg_pdm_disable(priv->map);
4032cfc123eSJerome Brunet
4042cfc123eSJerome Brunet /* Make sure filter bypass is disabled */
4052cfc123eSJerome Brunet regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_BYPASS_MODE, 0);
4062cfc123eSJerome Brunet
4072cfc123eSJerome Brunet /* Load filter settings */
4082cfc123eSJerome Brunet axg_pdm_set_hcic_ctrl(priv);
4092cfc123eSJerome Brunet axg_pdm_set_hpf_ctrl(priv);
4102cfc123eSJerome Brunet
4112cfc123eSJerome Brunet ret = axg_pdm_set_lpf_filters(priv);
4122cfc123eSJerome Brunet if (ret) {
4132cfc123eSJerome Brunet dev_err(dai->dev, "invalid filter configuration\n");
4142cfc123eSJerome Brunet goto err_sysclk;
4152cfc123eSJerome Brunet }
4162cfc123eSJerome Brunet
4172cfc123eSJerome Brunet return 0;
4182cfc123eSJerome Brunet
4192cfc123eSJerome Brunet err_sysclk:
4202cfc123eSJerome Brunet clk_disable_unprepare(priv->sysclk);
4212cfc123eSJerome Brunet err_pclk:
4222cfc123eSJerome Brunet clk_disable_unprepare(priv->pclk);
4232cfc123eSJerome Brunet return ret;
4242cfc123eSJerome Brunet }
4252cfc123eSJerome Brunet
axg_pdm_dai_remove(struct snd_soc_dai * dai)4262cfc123eSJerome Brunet static int axg_pdm_dai_remove(struct snd_soc_dai *dai)
4272cfc123eSJerome Brunet {
4282cfc123eSJerome Brunet struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai);
4292cfc123eSJerome Brunet
4302cfc123eSJerome Brunet clk_disable_unprepare(priv->sysclk);
4312cfc123eSJerome Brunet clk_disable_unprepare(priv->pclk);
4322cfc123eSJerome Brunet
4332cfc123eSJerome Brunet return 0;
4342cfc123eSJerome Brunet }
4352cfc123eSJerome Brunet
436*2d3155a9SKuninori Morimoto static const struct snd_soc_dai_ops axg_pdm_dai_ops = {
437*2d3155a9SKuninori Morimoto .probe = axg_pdm_dai_probe,
438*2d3155a9SKuninori Morimoto .remove = axg_pdm_dai_remove,
439*2d3155a9SKuninori Morimoto .trigger = axg_pdm_trigger,
440*2d3155a9SKuninori Morimoto .hw_params = axg_pdm_hw_params,
441*2d3155a9SKuninori Morimoto .startup = axg_pdm_startup,
442*2d3155a9SKuninori Morimoto .shutdown = axg_pdm_shutdown,
443*2d3155a9SKuninori Morimoto };
444*2d3155a9SKuninori Morimoto
4452cfc123eSJerome Brunet static struct snd_soc_dai_driver axg_pdm_dai_drv = {
4462cfc123eSJerome Brunet .name = "PDM",
4472cfc123eSJerome Brunet .capture = {
4482cfc123eSJerome Brunet .stream_name = "Capture",
4492cfc123eSJerome Brunet .channels_min = 1,
4502cfc123eSJerome Brunet .channels_max = 8,
4512cfc123eSJerome Brunet .rates = SNDRV_PCM_RATE_CONTINUOUS,
4522cfc123eSJerome Brunet .rate_min = 5512,
4532cfc123eSJerome Brunet .rate_max = 48000,
4542cfc123eSJerome Brunet .formats = (SNDRV_PCM_FMTBIT_S24_LE |
4552cfc123eSJerome Brunet SNDRV_PCM_FMTBIT_S32_LE),
4562cfc123eSJerome Brunet },
4572cfc123eSJerome Brunet .ops = &axg_pdm_dai_ops,
4582cfc123eSJerome Brunet };
4592cfc123eSJerome Brunet
460d8572da0SCharles Keepax static const struct snd_soc_component_driver axg_pdm_component_drv = {
461d8572da0SCharles Keepax .legacy_dai_naming = 1,
462d8572da0SCharles Keepax };
4632cfc123eSJerome Brunet
4642cfc123eSJerome Brunet static const struct regmap_config axg_pdm_regmap_cfg = {
4652cfc123eSJerome Brunet .reg_bits = 32,
4662cfc123eSJerome Brunet .val_bits = 32,
4672cfc123eSJerome Brunet .reg_stride = 4,
4682cfc123eSJerome Brunet .max_register = PDM_STS,
4692cfc123eSJerome Brunet };
4702cfc123eSJerome Brunet
4712cfc123eSJerome Brunet static const unsigned int lpf1_default_tap[] = {
4722cfc123eSJerome Brunet 0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45,
4732cfc123eSJerome Brunet 0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21,
4742cfc123eSJerome Brunet 0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212,
4752cfc123eSJerome Brunet 0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa,
4762cfc123eSJerome Brunet 0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef,
4772cfc123eSJerome Brunet 0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077,
4782cfc123eSJerome Brunet 0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690,
4792cfc123eSJerome Brunet 0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3,
4802cfc123eSJerome Brunet 0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686,
4812cfc123eSJerome Brunet 0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812,
4822cfc123eSJerome Brunet 0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60,
4832cfc123eSJerome Brunet 0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000,
4842cfc123eSJerome Brunet 0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e,
4852cfc123eSJerome Brunet 0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c,
4862cfc123eSJerome Brunet 0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece,
4872cfc123eSJerome Brunet 0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645,
4882cfc123eSJerome Brunet 0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9,
4892cfc123eSJerome Brunet 0xffffb2, 0x000014,
4902cfc123eSJerome Brunet };
4912cfc123eSJerome Brunet
4922cfc123eSJerome Brunet static const unsigned int lpf2_default_tap[] = {
4932cfc123eSJerome Brunet 0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818,
4942cfc123eSJerome Brunet 0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41,
4952cfc123eSJerome Brunet 0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0,
4962cfc123eSJerome Brunet 0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000,
4972cfc123eSJerome Brunet 0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93,
4982cfc123eSJerome Brunet 0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12,
4992cfc123eSJerome Brunet 0x0002c1, 0xfff004, 0x00050a,
5002cfc123eSJerome Brunet };
5012cfc123eSJerome Brunet
5022cfc123eSJerome Brunet static const unsigned int lpf3_default_tap[] = {
5032cfc123eSJerome Brunet 0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000,
5042cfc123eSJerome Brunet 0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7,
5052cfc123eSJerome Brunet 0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000,
5062cfc123eSJerome Brunet 0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0,
5072cfc123eSJerome Brunet 0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000,
5082cfc123eSJerome Brunet 0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7,
5092cfc123eSJerome Brunet 0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000,
5102cfc123eSJerome Brunet 0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45,
5112cfc123eSJerome Brunet 0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000,
5122cfc123eSJerome Brunet 0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c,
5132cfc123eSJerome Brunet 0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000,
5142cfc123eSJerome Brunet 0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216,
5152cfc123eSJerome Brunet 0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000,
5162cfc123eSJerome Brunet 0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d,
5172cfc123eSJerome Brunet 0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000,
5182cfc123eSJerome Brunet 0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368,
5192cfc123eSJerome Brunet 0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000,
5202cfc123eSJerome Brunet 0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb,
5212cfc123eSJerome Brunet 0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000,
5222cfc123eSJerome Brunet 0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c,
5232cfc123eSJerome Brunet 0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000,
5242cfc123eSJerome Brunet 0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46,
5252cfc123eSJerome Brunet 0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000,
5262cfc123eSJerome Brunet 0x000081, 0x000000,
5272cfc123eSJerome Brunet };
5282cfc123eSJerome Brunet
5292cfc123eSJerome Brunet /*
5302cfc123eSJerome Brunet * These values are sane defaults for the axg platform:
5312cfc123eSJerome Brunet * - OS = 64
5322cfc123eSJerome Brunet * - Latency = 38700 (?)
5332cfc123eSJerome Brunet *
5342cfc123eSJerome Brunet * TODO: There is a lot of different HCIC, LPFs and HPF configurations possible.
5352cfc123eSJerome Brunet * the configuration may depend on the dmic used by the platform, the
5362cfc123eSJerome Brunet * expected tradeoff between latency and quality, etc ... If/When other
5372cfc123eSJerome Brunet * settings are required, we should add a fw interface to this driver to
5382cfc123eSJerome Brunet * load new filter settings.
5392cfc123eSJerome Brunet */
5402cfc123eSJerome Brunet static const struct axg_pdm_filters axg_default_filters = {
5412cfc123eSJerome Brunet .hcic = {
5422cfc123eSJerome Brunet .shift = 0x15,
5432cfc123eSJerome Brunet .mult = 0x80,
5442cfc123eSJerome Brunet .steps = 7,
5452cfc123eSJerome Brunet .ds = 8,
5462cfc123eSJerome Brunet },
5472cfc123eSJerome Brunet .hpf = {
5482cfc123eSJerome Brunet .out_factor = 0x8000,
5492cfc123eSJerome Brunet .steps = 13,
5502cfc123eSJerome Brunet },
5512cfc123eSJerome Brunet .lpf = {
5522cfc123eSJerome Brunet [0] = {
5532cfc123eSJerome Brunet .ds = 2,
5542cfc123eSJerome Brunet .round_mode = 1,
5552cfc123eSJerome Brunet .tap = lpf1_default_tap,
5562cfc123eSJerome Brunet .tap_num = ARRAY_SIZE(lpf1_default_tap),
5572cfc123eSJerome Brunet },
5582cfc123eSJerome Brunet [1] = {
5592cfc123eSJerome Brunet .ds = 2,
5602cfc123eSJerome Brunet .round_mode = 0,
5612cfc123eSJerome Brunet .tap = lpf2_default_tap,
5622cfc123eSJerome Brunet .tap_num = ARRAY_SIZE(lpf2_default_tap),
5632cfc123eSJerome Brunet },
5642cfc123eSJerome Brunet [2] = {
5652cfc123eSJerome Brunet .ds = 2,
5662cfc123eSJerome Brunet .round_mode = 1,
5672cfc123eSJerome Brunet .tap = lpf3_default_tap,
5682cfc123eSJerome Brunet .tap_num = ARRAY_SIZE(lpf3_default_tap)
5692cfc123eSJerome Brunet },
5702cfc123eSJerome Brunet },
5712cfc123eSJerome Brunet };
5722cfc123eSJerome Brunet
5732cfc123eSJerome Brunet static const struct axg_pdm_cfg axg_pdm_config = {
5742cfc123eSJerome Brunet .filters = &axg_default_filters,
5752cfc123eSJerome Brunet .sys_rate = 250000000,
5762cfc123eSJerome Brunet };
5772cfc123eSJerome Brunet
5782cfc123eSJerome Brunet static const struct of_device_id axg_pdm_of_match[] = {
5792cfc123eSJerome Brunet {
5802cfc123eSJerome Brunet .compatible = "amlogic,axg-pdm",
5812cfc123eSJerome Brunet .data = &axg_pdm_config,
5822cfc123eSJerome Brunet }, {}
5832cfc123eSJerome Brunet };
5842cfc123eSJerome Brunet MODULE_DEVICE_TABLE(of, axg_pdm_of_match);
5852cfc123eSJerome Brunet
axg_pdm_probe(struct platform_device * pdev)5862cfc123eSJerome Brunet static int axg_pdm_probe(struct platform_device *pdev)
5872cfc123eSJerome Brunet {
5882cfc123eSJerome Brunet struct device *dev = &pdev->dev;
5892cfc123eSJerome Brunet struct axg_pdm *priv;
5902cfc123eSJerome Brunet void __iomem *regs;
5912cfc123eSJerome Brunet
5922cfc123eSJerome Brunet priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
5932cfc123eSJerome Brunet if (!priv)
5942cfc123eSJerome Brunet return -ENOMEM;
5952cfc123eSJerome Brunet platform_set_drvdata(pdev, priv);
5962cfc123eSJerome Brunet
5972cfc123eSJerome Brunet priv->cfg = of_device_get_match_data(dev);
5982cfc123eSJerome Brunet if (!priv->cfg) {
5992cfc123eSJerome Brunet dev_err(dev, "failed to match device\n");
6002cfc123eSJerome Brunet return -ENODEV;
6012cfc123eSJerome Brunet }
6022cfc123eSJerome Brunet
6032e73d98fSYueHaibing regs = devm_platform_ioremap_resource(pdev, 0);
6042cfc123eSJerome Brunet if (IS_ERR(regs))
6052cfc123eSJerome Brunet return PTR_ERR(regs);
6062cfc123eSJerome Brunet
6072cfc123eSJerome Brunet priv->map = devm_regmap_init_mmio(dev, regs, &axg_pdm_regmap_cfg);
6082cfc123eSJerome Brunet if (IS_ERR(priv->map)) {
6092cfc123eSJerome Brunet dev_err(dev, "failed to init regmap: %ld\n",
6102cfc123eSJerome Brunet PTR_ERR(priv->map));
6112cfc123eSJerome Brunet return PTR_ERR(priv->map);
6122cfc123eSJerome Brunet }
6132cfc123eSJerome Brunet
6142cfc123eSJerome Brunet priv->pclk = devm_clk_get(dev, "pclk");
6152ff4e003SKuninori Morimoto if (IS_ERR(priv->pclk))
6162ff4e003SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n");
6172cfc123eSJerome Brunet
6182cfc123eSJerome Brunet priv->dclk = devm_clk_get(dev, "dclk");
6192ff4e003SKuninori Morimoto if (IS_ERR(priv->dclk))
6202ff4e003SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(priv->dclk), "failed to get dclk\n");
6212cfc123eSJerome Brunet
6222cfc123eSJerome Brunet priv->sysclk = devm_clk_get(dev, "sysclk");
6232ff4e003SKuninori Morimoto if (IS_ERR(priv->sysclk))
6242ff4e003SKuninori Morimoto return dev_err_probe(dev, PTR_ERR(priv->sysclk), "failed to get dclk\n");
6252cfc123eSJerome Brunet
6262cfc123eSJerome Brunet return devm_snd_soc_register_component(dev, &axg_pdm_component_drv,
6272cfc123eSJerome Brunet &axg_pdm_dai_drv, 1);
6282cfc123eSJerome Brunet }
6292cfc123eSJerome Brunet
6302cfc123eSJerome Brunet static struct platform_driver axg_pdm_pdrv = {
6312cfc123eSJerome Brunet .probe = axg_pdm_probe,
6322cfc123eSJerome Brunet .driver = {
6332cfc123eSJerome Brunet .name = "axg-pdm",
6342cfc123eSJerome Brunet .of_match_table = axg_pdm_of_match,
6352cfc123eSJerome Brunet },
6362cfc123eSJerome Brunet };
6372cfc123eSJerome Brunet module_platform_driver(axg_pdm_pdrv);
6382cfc123eSJerome Brunet
6392cfc123eSJerome Brunet MODULE_DESCRIPTION("Amlogic AXG PDM Input driver");
6402cfc123eSJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
6412cfc123eSJerome Brunet MODULE_LICENSE("GPL v2");
642