18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Copyright (c) 2018 BayLibre, SAS. 48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 98c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 108c2ecf20Sopenharmony_ci#include <linux/regmap.h> 118c2ecf20Sopenharmony_ci#include <sound/soc.h> 128c2ecf20Sopenharmony_ci#include <sound/soc-dai.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define PDM_CTRL 0x00 168c2ecf20Sopenharmony_ci#define PDM_CTRL_EN BIT(31) 178c2ecf20Sopenharmony_ci#define PDM_CTRL_OUT_MODE BIT(29) 188c2ecf20Sopenharmony_ci#define PDM_CTRL_BYPASS_MODE BIT(28) 198c2ecf20Sopenharmony_ci#define PDM_CTRL_RST_FIFO BIT(16) 208c2ecf20Sopenharmony_ci#define PDM_CTRL_CHAN_RSTN_MASK GENMASK(15, 8) 218c2ecf20Sopenharmony_ci#define PDM_CTRL_CHAN_RSTN(x) ((x) << 8) 228c2ecf20Sopenharmony_ci#define PDM_CTRL_CHAN_EN_MASK GENMASK(7, 0) 238c2ecf20Sopenharmony_ci#define PDM_CTRL_CHAN_EN(x) ((x) << 0) 248c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1 0x04 258c2ecf20Sopenharmony_ci#define PDM_FILTER_EN BIT(31) 268c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_GAIN_SFT_MASK GENMASK(29, 24) 278c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_GAIN_SFT(x) ((x) << 24) 288c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_GAIN_MULT_MASK GENMASK(23, 16) 298c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_GAIN_MULT(x) ((x) << 16) 308c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_DSR_MASK GENMASK(8, 4) 318c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_DSR(x) ((x) << 4) 328c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_STAGE_NUM_MASK GENMASK(3, 0) 338c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL1_STAGE_NUM(x) ((x) << 0) 348c2ecf20Sopenharmony_ci#define PDM_HCIC_CTRL2 0x08 358c2ecf20Sopenharmony_ci#define PDM_F1_CTRL 0x0c 368c2ecf20Sopenharmony_ci#define PDM_LPF_ROUND_MODE_MASK GENMASK(17, 16) 378c2ecf20Sopenharmony_ci#define PDM_LPF_ROUND_MODE(x) ((x) << 16) 388c2ecf20Sopenharmony_ci#define PDM_LPF_DSR_MASK GENMASK(15, 12) 398c2ecf20Sopenharmony_ci#define PDM_LPF_DSR(x) ((x) << 12) 408c2ecf20Sopenharmony_ci#define PDM_LPF_STAGE_NUM_MASK GENMASK(8, 0) 418c2ecf20Sopenharmony_ci#define PDM_LPF_STAGE_NUM(x) ((x) << 0) 428c2ecf20Sopenharmony_ci#define PDM_LPF_MAX_STAGE 336 438c2ecf20Sopenharmony_ci#define PDM_LPF_NUM 3 448c2ecf20Sopenharmony_ci#define PDM_F2_CTRL 0x10 458c2ecf20Sopenharmony_ci#define PDM_F3_CTRL 0x14 468c2ecf20Sopenharmony_ci#define PDM_HPF_CTRL 0x18 478c2ecf20Sopenharmony_ci#define PDM_HPF_SFT_STEPS_MASK GENMASK(20, 16) 488c2ecf20Sopenharmony_ci#define PDM_HPF_SFT_STEPS(x) ((x) << 16) 498c2ecf20Sopenharmony_ci#define PDM_HPF_OUT_FACTOR_MASK GENMASK(15, 0) 508c2ecf20Sopenharmony_ci#define PDM_HPF_OUT_FACTOR(x) ((x) << 0) 518c2ecf20Sopenharmony_ci#define PDM_CHAN_CTRL 0x1c 528c2ecf20Sopenharmony_ci#define PDM_CHAN_CTRL_POINTER_WIDTH 8 538c2ecf20Sopenharmony_ci#define PDM_CHAN_CTRL_POINTER_MAX ((1 << PDM_CHAN_CTRL_POINTER_WIDTH) - 1) 548c2ecf20Sopenharmony_ci#define PDM_CHAN_CTRL_NUM 4 558c2ecf20Sopenharmony_ci#define PDM_CHAN_CTRL1 0x20 568c2ecf20Sopenharmony_ci#define PDM_COEFF_ADDR 0x24 578c2ecf20Sopenharmony_ci#define PDM_COEFF_DATA 0x28 588c2ecf20Sopenharmony_ci#define PDM_CLKG_CTRL 0x2c 598c2ecf20Sopenharmony_ci#define PDM_STS 0x30 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistruct axg_pdm_lpf { 628c2ecf20Sopenharmony_ci unsigned int ds; 638c2ecf20Sopenharmony_ci unsigned int round_mode; 648c2ecf20Sopenharmony_ci const unsigned int *tap; 658c2ecf20Sopenharmony_ci unsigned int tap_num; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct axg_pdm_hcic { 698c2ecf20Sopenharmony_ci unsigned int shift; 708c2ecf20Sopenharmony_ci unsigned int mult; 718c2ecf20Sopenharmony_ci unsigned int steps; 728c2ecf20Sopenharmony_ci unsigned int ds; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct axg_pdm_hpf { 768c2ecf20Sopenharmony_ci unsigned int out_factor; 778c2ecf20Sopenharmony_ci unsigned int steps; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct axg_pdm_filters { 818c2ecf20Sopenharmony_ci struct axg_pdm_hcic hcic; 828c2ecf20Sopenharmony_ci struct axg_pdm_hpf hpf; 838c2ecf20Sopenharmony_ci struct axg_pdm_lpf lpf[PDM_LPF_NUM]; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistruct axg_pdm_cfg { 878c2ecf20Sopenharmony_ci const struct axg_pdm_filters *filters; 888c2ecf20Sopenharmony_ci unsigned int sys_rate; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct axg_pdm { 928c2ecf20Sopenharmony_ci const struct axg_pdm_cfg *cfg; 938c2ecf20Sopenharmony_ci struct regmap *map; 948c2ecf20Sopenharmony_ci struct clk *dclk; 958c2ecf20Sopenharmony_ci struct clk *sysclk; 968c2ecf20Sopenharmony_ci struct clk *pclk; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void axg_pdm_enable(struct regmap *map) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci /* Reset AFIFO */ 1028c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, PDM_CTRL_RST_FIFO); 1038c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_CTRL, PDM_CTRL_RST_FIFO, 0); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* Enable PDM */ 1068c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, PDM_CTRL_EN); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void axg_pdm_disable(struct regmap *map) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_CTRL, PDM_CTRL_EN, 0); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic void axg_pdm_filters_enable(struct regmap *map, bool enable) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci unsigned int val = enable ? PDM_FILTER_EN : 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_HCIC_CTRL1, PDM_FILTER_EN, val); 1198c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_F1_CTRL, PDM_FILTER_EN, val); 1208c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_F2_CTRL, PDM_FILTER_EN, val); 1218c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_F3_CTRL, PDM_FILTER_EN, val); 1228c2ecf20Sopenharmony_ci regmap_update_bits(map, PDM_HPF_CTRL, PDM_FILTER_EN, val); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic int axg_pdm_trigger(struct snd_pcm_substream *substream, int cmd, 1268c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci switch (cmd) { 1318c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 1328c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 1338c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 1348c2ecf20Sopenharmony_ci axg_pdm_enable(priv->map); 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 1388c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 1398c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 1408c2ecf20Sopenharmony_ci axg_pdm_disable(priv->map); 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci default: 1448c2ecf20Sopenharmony_ci return -EINVAL; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic unsigned int axg_pdm_get_os(struct axg_pdm *priv) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci const struct axg_pdm_filters *filters = priv->cfg->filters; 1518c2ecf20Sopenharmony_ci unsigned int os = filters->hcic.ds; 1528c2ecf20Sopenharmony_ci int i; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci /* 1558c2ecf20Sopenharmony_ci * The global oversampling factor is defined by the down sampling 1568c2ecf20Sopenharmony_ci * factor applied by each filter (HCIC and LPFs) 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci for (i = 0; i < PDM_LPF_NUM; i++) 1608c2ecf20Sopenharmony_ci os *= filters->lpf[i].ds; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return os; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int axg_pdm_set_sysclk(struct axg_pdm *priv, unsigned int os, 1668c2ecf20Sopenharmony_ci unsigned int rate) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci unsigned int sys_rate = os * 2 * rate * PDM_CHAN_CTRL_POINTER_MAX; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* 1718c2ecf20Sopenharmony_ci * Set the default system clock rate unless it is too fast for 1728c2ecf20Sopenharmony_ci * for the requested sample rate. In this case, the sample pointer 1738c2ecf20Sopenharmony_ci * counter could overflow so set a lower system clock rate 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ci if (sys_rate < priv->cfg->sys_rate) 1768c2ecf20Sopenharmony_ci return clk_set_rate(priv->sysclk, sys_rate); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return clk_set_rate(priv->sysclk, priv->cfg->sys_rate); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int axg_pdm_set_sample_pointer(struct axg_pdm *priv) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci unsigned int spmax, sp, val; 1848c2ecf20Sopenharmony_ci int i; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Max sample counter value per half period of dclk */ 1878c2ecf20Sopenharmony_ci spmax = DIV_ROUND_UP_ULL((u64)clk_get_rate(priv->sysclk), 1888c2ecf20Sopenharmony_ci clk_get_rate(priv->dclk) * 2); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Check if sysclk is not too fast - should not happen */ 1918c2ecf20Sopenharmony_ci if (WARN_ON(spmax > PDM_CHAN_CTRL_POINTER_MAX)) 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Capture the data when we are at 75% of the half period */ 1958c2ecf20Sopenharmony_ci sp = spmax * 3 / 4; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci for (i = 0, val = 0; i < PDM_CHAN_CTRL_NUM; i++) 1988c2ecf20Sopenharmony_ci val |= sp << (PDM_CHAN_CTRL_POINTER_WIDTH * i); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci regmap_write(priv->map, PDM_CHAN_CTRL, val); 2018c2ecf20Sopenharmony_ci regmap_write(priv->map, PDM_CHAN_CTRL1, val); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void axg_pdm_set_channel_mask(struct axg_pdm *priv, 2078c2ecf20Sopenharmony_ci unsigned int channels) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci unsigned int mask = GENMASK(channels - 1, 0); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Put all channel in reset */ 2128c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_CTRL, 2138c2ecf20Sopenharmony_ci PDM_CTRL_CHAN_RSTN_MASK, 0); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* Take the necessary channels out of reset and enable them */ 2168c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_CTRL, 2178c2ecf20Sopenharmony_ci PDM_CTRL_CHAN_RSTN_MASK | 2188c2ecf20Sopenharmony_ci PDM_CTRL_CHAN_EN_MASK, 2198c2ecf20Sopenharmony_ci PDM_CTRL_CHAN_RSTN(mask) | 2208c2ecf20Sopenharmony_ci PDM_CTRL_CHAN_EN(mask)); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int axg_pdm_hw_params(struct snd_pcm_substream *substream, 2248c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 2258c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 2288c2ecf20Sopenharmony_ci unsigned int os = axg_pdm_get_os(priv); 2298c2ecf20Sopenharmony_ci unsigned int rate = params_rate(params); 2308c2ecf20Sopenharmony_ci unsigned int val; 2318c2ecf20Sopenharmony_ci int ret; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci switch (params_width(params)) { 2348c2ecf20Sopenharmony_ci case 24: 2358c2ecf20Sopenharmony_ci val = PDM_CTRL_OUT_MODE; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci case 32: 2388c2ecf20Sopenharmony_ci val = 0; 2398c2ecf20Sopenharmony_ci break; 2408c2ecf20Sopenharmony_ci default: 2418c2ecf20Sopenharmony_ci dev_err(dai->dev, "unsupported sample width\n"); 2428c2ecf20Sopenharmony_ci return -EINVAL; 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_OUT_MODE, val); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci ret = axg_pdm_set_sysclk(priv, os, rate); 2488c2ecf20Sopenharmony_ci if (ret) { 2498c2ecf20Sopenharmony_ci dev_err(dai->dev, "failed to set system clock\n"); 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci ret = clk_set_rate(priv->dclk, rate * os); 2548c2ecf20Sopenharmony_ci if (ret) { 2558c2ecf20Sopenharmony_ci dev_err(dai->dev, "failed to set dclk\n"); 2568c2ecf20Sopenharmony_ci return ret; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci ret = axg_pdm_set_sample_pointer(priv); 2608c2ecf20Sopenharmony_ci if (ret) { 2618c2ecf20Sopenharmony_ci dev_err(dai->dev, "invalid clock setting\n"); 2628c2ecf20Sopenharmony_ci return ret; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci axg_pdm_set_channel_mask(priv, params_channels(params)); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci return 0; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic int axg_pdm_startup(struct snd_pcm_substream *substream, 2718c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 2748c2ecf20Sopenharmony_ci int ret; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->dclk); 2778c2ecf20Sopenharmony_ci if (ret) { 2788c2ecf20Sopenharmony_ci dev_err(dai->dev, "enabling dclk failed\n"); 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci /* Enable the filters */ 2838c2ecf20Sopenharmony_ci axg_pdm_filters_enable(priv->map, true); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void axg_pdm_shutdown(struct snd_pcm_substream *substream, 2898c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci axg_pdm_filters_enable(priv->map, false); 2948c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->dclk); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops axg_pdm_dai_ops = { 2988c2ecf20Sopenharmony_ci .trigger = axg_pdm_trigger, 2998c2ecf20Sopenharmony_ci .hw_params = axg_pdm_hw_params, 3008c2ecf20Sopenharmony_ci .startup = axg_pdm_startup, 3018c2ecf20Sopenharmony_ci .shutdown = axg_pdm_shutdown, 3028c2ecf20Sopenharmony_ci}; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic void axg_pdm_set_hcic_ctrl(struct axg_pdm *priv) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci const struct axg_pdm_hcic *hcic = &priv->cfg->filters->hcic; 3078c2ecf20Sopenharmony_ci unsigned int val; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci val = PDM_HCIC_CTRL1_STAGE_NUM(hcic->steps); 3108c2ecf20Sopenharmony_ci val |= PDM_HCIC_CTRL1_DSR(hcic->ds); 3118c2ecf20Sopenharmony_ci val |= PDM_HCIC_CTRL1_GAIN_MULT(hcic->mult); 3128c2ecf20Sopenharmony_ci val |= PDM_HCIC_CTRL1_GAIN_SFT(hcic->shift); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_HCIC_CTRL1, 3158c2ecf20Sopenharmony_ci PDM_HCIC_CTRL1_STAGE_NUM_MASK | 3168c2ecf20Sopenharmony_ci PDM_HCIC_CTRL1_DSR_MASK | 3178c2ecf20Sopenharmony_ci PDM_HCIC_CTRL1_GAIN_MULT_MASK | 3188c2ecf20Sopenharmony_ci PDM_HCIC_CTRL1_GAIN_SFT_MASK, 3198c2ecf20Sopenharmony_ci val); 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic void axg_pdm_set_lpf_ctrl(struct axg_pdm *priv, unsigned int index) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci const struct axg_pdm_lpf *lpf = &priv->cfg->filters->lpf[index]; 3258c2ecf20Sopenharmony_ci unsigned int offset = index * regmap_get_reg_stride(priv->map) 3268c2ecf20Sopenharmony_ci + PDM_F1_CTRL; 3278c2ecf20Sopenharmony_ci unsigned int val; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci val = PDM_LPF_STAGE_NUM(lpf->tap_num); 3308c2ecf20Sopenharmony_ci val |= PDM_LPF_DSR(lpf->ds); 3318c2ecf20Sopenharmony_ci val |= PDM_LPF_ROUND_MODE(lpf->round_mode); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, offset, 3348c2ecf20Sopenharmony_ci PDM_LPF_STAGE_NUM_MASK | 3358c2ecf20Sopenharmony_ci PDM_LPF_DSR_MASK | 3368c2ecf20Sopenharmony_ci PDM_LPF_ROUND_MODE_MASK, 3378c2ecf20Sopenharmony_ci val); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void axg_pdm_set_hpf_ctrl(struct axg_pdm *priv) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci const struct axg_pdm_hpf *hpf = &priv->cfg->filters->hpf; 3438c2ecf20Sopenharmony_ci unsigned int val; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci val = PDM_HPF_OUT_FACTOR(hpf->out_factor); 3468c2ecf20Sopenharmony_ci val |= PDM_HPF_SFT_STEPS(hpf->steps); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_HPF_CTRL, 3498c2ecf20Sopenharmony_ci PDM_HPF_OUT_FACTOR_MASK | 3508c2ecf20Sopenharmony_ci PDM_HPF_SFT_STEPS_MASK, 3518c2ecf20Sopenharmony_ci val); 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic int axg_pdm_set_lpf_filters(struct axg_pdm *priv) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci const struct axg_pdm_lpf *lpf = priv->cfg->filters->lpf; 3578c2ecf20Sopenharmony_ci unsigned int count = 0; 3588c2ecf20Sopenharmony_ci int i, j; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci for (i = 0; i < PDM_LPF_NUM; i++) 3618c2ecf20Sopenharmony_ci count += lpf[i].tap_num; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Make sure the coeffs fit in the memory */ 3648c2ecf20Sopenharmony_ci if (count >= PDM_LPF_MAX_STAGE) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci /* Set the initial APB bus register address */ 3688c2ecf20Sopenharmony_ci regmap_write(priv->map, PDM_COEFF_ADDR, 0); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci /* Set the tap filter values of all 3 filters */ 3718c2ecf20Sopenharmony_ci for (i = 0; i < PDM_LPF_NUM; i++) { 3728c2ecf20Sopenharmony_ci axg_pdm_set_lpf_ctrl(priv, i); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci for (j = 0; j < lpf[i].tap_num; j++) 3758c2ecf20Sopenharmony_ci regmap_write(priv->map, PDM_COEFF_DATA, lpf[i].tap[j]); 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci return 0; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic int axg_pdm_dai_probe(struct snd_soc_dai *dai) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 3848c2ecf20Sopenharmony_ci int ret; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->pclk); 3878c2ecf20Sopenharmony_ci if (ret) { 3888c2ecf20Sopenharmony_ci dev_err(dai->dev, "enabling pclk failed\n"); 3898c2ecf20Sopenharmony_ci return ret; 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci /* 3938c2ecf20Sopenharmony_ci * sysclk must be set and enabled as well to access the pdm registers 3948c2ecf20Sopenharmony_ci * Accessing the register w/o it will give a bus error. 3958c2ecf20Sopenharmony_ci */ 3968c2ecf20Sopenharmony_ci ret = clk_set_rate(priv->sysclk, priv->cfg->sys_rate); 3978c2ecf20Sopenharmony_ci if (ret) { 3988c2ecf20Sopenharmony_ci dev_err(dai->dev, "setting sysclk failed\n"); 3998c2ecf20Sopenharmony_ci goto err_pclk; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->sysclk); 4038c2ecf20Sopenharmony_ci if (ret) { 4048c2ecf20Sopenharmony_ci dev_err(dai->dev, "enabling sysclk failed\n"); 4058c2ecf20Sopenharmony_ci goto err_pclk; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* Make sure the device is initially disabled */ 4098c2ecf20Sopenharmony_ci axg_pdm_disable(priv->map); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Make sure filter bypass is disabled */ 4128c2ecf20Sopenharmony_ci regmap_update_bits(priv->map, PDM_CTRL, PDM_CTRL_BYPASS_MODE, 0); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci /* Load filter settings */ 4158c2ecf20Sopenharmony_ci axg_pdm_set_hcic_ctrl(priv); 4168c2ecf20Sopenharmony_ci axg_pdm_set_hpf_ctrl(priv); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ret = axg_pdm_set_lpf_filters(priv); 4198c2ecf20Sopenharmony_ci if (ret) { 4208c2ecf20Sopenharmony_ci dev_err(dai->dev, "invalid filter configuration\n"); 4218c2ecf20Sopenharmony_ci goto err_sysclk; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return 0; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cierr_sysclk: 4278c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->sysclk); 4288c2ecf20Sopenharmony_cierr_pclk: 4298c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->pclk); 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int axg_pdm_dai_remove(struct snd_soc_dai *dai) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct axg_pdm *priv = snd_soc_dai_get_drvdata(dai); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->sysclk); 4388c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->pclk); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver axg_pdm_dai_drv = { 4448c2ecf20Sopenharmony_ci .name = "PDM", 4458c2ecf20Sopenharmony_ci .capture = { 4468c2ecf20Sopenharmony_ci .stream_name = "Capture", 4478c2ecf20Sopenharmony_ci .channels_min = 1, 4488c2ecf20Sopenharmony_ci .channels_max = 8, 4498c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 4508c2ecf20Sopenharmony_ci .rate_min = 5512, 4518c2ecf20Sopenharmony_ci .rate_max = 48000, 4528c2ecf20Sopenharmony_ci .formats = (SNDRV_PCM_FMTBIT_S24_LE | 4538c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE), 4548c2ecf20Sopenharmony_ci }, 4558c2ecf20Sopenharmony_ci .ops = &axg_pdm_dai_ops, 4568c2ecf20Sopenharmony_ci .probe = axg_pdm_dai_probe, 4578c2ecf20Sopenharmony_ci .remove = axg_pdm_dai_remove, 4588c2ecf20Sopenharmony_ci}; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver axg_pdm_component_drv = {}; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_cistatic const struct regmap_config axg_pdm_regmap_cfg = { 4638c2ecf20Sopenharmony_ci .reg_bits = 32, 4648c2ecf20Sopenharmony_ci .val_bits = 32, 4658c2ecf20Sopenharmony_ci .reg_stride = 4, 4668c2ecf20Sopenharmony_ci .max_register = PDM_STS, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic const unsigned int lpf1_default_tap[] = { 4708c2ecf20Sopenharmony_ci 0x000014, 0xffffb2, 0xfffed9, 0xfffdce, 0xfffd45, 4718c2ecf20Sopenharmony_ci 0xfffe32, 0x000147, 0x000645, 0x000b86, 0x000e21, 4728c2ecf20Sopenharmony_ci 0x000ae3, 0x000000, 0xffeece, 0xffdca8, 0xffd212, 4738c2ecf20Sopenharmony_ci 0xffd7d1, 0xfff2a7, 0x001f4c, 0x0050c2, 0x0072aa, 4748c2ecf20Sopenharmony_ci 0x006ff1, 0x003c32, 0xffdc4e, 0xff6a18, 0xff0fef, 4758c2ecf20Sopenharmony_ci 0xfefbaf, 0xff4c40, 0x000000, 0x00ebc8, 0x01c077, 4768c2ecf20Sopenharmony_ci 0x02209e, 0x01c1a4, 0x008e60, 0xfebe52, 0xfcd690, 4778c2ecf20Sopenharmony_ci 0xfb8fa5, 0xfba498, 0xfd9812, 0x0181ce, 0x06f5f3, 4788c2ecf20Sopenharmony_ci 0x0d112f, 0x12a958, 0x169686, 0x18000e, 0x169686, 4798c2ecf20Sopenharmony_ci 0x12a958, 0x0d112f, 0x06f5f3, 0x0181ce, 0xfd9812, 4808c2ecf20Sopenharmony_ci 0xfba498, 0xfb8fa5, 0xfcd690, 0xfebe52, 0x008e60, 4818c2ecf20Sopenharmony_ci 0x01c1a4, 0x02209e, 0x01c077, 0x00ebc8, 0x000000, 4828c2ecf20Sopenharmony_ci 0xff4c40, 0xfefbaf, 0xff0fef, 0xff6a18, 0xffdc4e, 4838c2ecf20Sopenharmony_ci 0x003c32, 0x006ff1, 0x0072aa, 0x0050c2, 0x001f4c, 4848c2ecf20Sopenharmony_ci 0xfff2a7, 0xffd7d1, 0xffd212, 0xffdca8, 0xffeece, 4858c2ecf20Sopenharmony_ci 0x000000, 0x000ae3, 0x000e21, 0x000b86, 0x000645, 4868c2ecf20Sopenharmony_ci 0x000147, 0xfffe32, 0xfffd45, 0xfffdce, 0xfffed9, 4878c2ecf20Sopenharmony_ci 0xffffb2, 0x000014, 4888c2ecf20Sopenharmony_ci}; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic const unsigned int lpf2_default_tap[] = { 4918c2ecf20Sopenharmony_ci 0x00050a, 0xfff004, 0x0002c1, 0x003c12, 0xffa818, 4928c2ecf20Sopenharmony_ci 0xffc87d, 0x010aef, 0xff5223, 0xfebd93, 0x028f41, 4938c2ecf20Sopenharmony_ci 0xff5c0e, 0xfc63f8, 0x055f81, 0x000000, 0xf478a0, 4948c2ecf20Sopenharmony_ci 0x11c5e3, 0x2ea74d, 0x11c5e3, 0xf478a0, 0x000000, 4958c2ecf20Sopenharmony_ci 0x055f81, 0xfc63f8, 0xff5c0e, 0x028f41, 0xfebd93, 4968c2ecf20Sopenharmony_ci 0xff5223, 0x010aef, 0xffc87d, 0xffa818, 0x003c12, 4978c2ecf20Sopenharmony_ci 0x0002c1, 0xfff004, 0x00050a, 4988c2ecf20Sopenharmony_ci}; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic const unsigned int lpf3_default_tap[] = { 5018c2ecf20Sopenharmony_ci 0x000000, 0x000081, 0x000000, 0xfffedb, 0x000000, 5028c2ecf20Sopenharmony_ci 0x00022d, 0x000000, 0xfffc46, 0x000000, 0x0005f7, 5038c2ecf20Sopenharmony_ci 0x000000, 0xfff6eb, 0x000000, 0x000d4e, 0x000000, 5048c2ecf20Sopenharmony_ci 0xffed1e, 0x000000, 0x001a1c, 0x000000, 0xffdcb0, 5058c2ecf20Sopenharmony_ci 0x000000, 0x002ede, 0x000000, 0xffc2d1, 0x000000, 5068c2ecf20Sopenharmony_ci 0x004ebe, 0x000000, 0xff9beb, 0x000000, 0x007dd7, 5078c2ecf20Sopenharmony_ci 0x000000, 0xff633a, 0x000000, 0x00c1d2, 0x000000, 5088c2ecf20Sopenharmony_ci 0xff11d5, 0x000000, 0x012368, 0x000000, 0xfe9c45, 5098c2ecf20Sopenharmony_ci 0x000000, 0x01b252, 0x000000, 0xfdebf6, 0x000000, 5108c2ecf20Sopenharmony_ci 0x0290b8, 0x000000, 0xfcca0d, 0x000000, 0x041d7c, 5118c2ecf20Sopenharmony_ci 0x000000, 0xfa8152, 0x000000, 0x07e9c6, 0x000000, 5128c2ecf20Sopenharmony_ci 0xf28fb5, 0x000000, 0x28b216, 0x3fffde, 0x28b216, 5138c2ecf20Sopenharmony_ci 0x000000, 0xf28fb5, 0x000000, 0x07e9c6, 0x000000, 5148c2ecf20Sopenharmony_ci 0xfa8152, 0x000000, 0x041d7c, 0x000000, 0xfcca0d, 5158c2ecf20Sopenharmony_ci 0x000000, 0x0290b8, 0x000000, 0xfdebf6, 0x000000, 5168c2ecf20Sopenharmony_ci 0x01b252, 0x000000, 0xfe9c45, 0x000000, 0x012368, 5178c2ecf20Sopenharmony_ci 0x000000, 0xff11d5, 0x000000, 0x00c1d2, 0x000000, 5188c2ecf20Sopenharmony_ci 0xff633a, 0x000000, 0x007dd7, 0x000000, 0xff9beb, 5198c2ecf20Sopenharmony_ci 0x000000, 0x004ebe, 0x000000, 0xffc2d1, 0x000000, 5208c2ecf20Sopenharmony_ci 0x002ede, 0x000000, 0xffdcb0, 0x000000, 0x001a1c, 5218c2ecf20Sopenharmony_ci 0x000000, 0xffed1e, 0x000000, 0x000d4e, 0x000000, 5228c2ecf20Sopenharmony_ci 0xfff6eb, 0x000000, 0x0005f7, 0x000000, 0xfffc46, 5238c2ecf20Sopenharmony_ci 0x000000, 0x00022d, 0x000000, 0xfffedb, 0x000000, 5248c2ecf20Sopenharmony_ci 0x000081, 0x000000, 5258c2ecf20Sopenharmony_ci}; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci/* 5288c2ecf20Sopenharmony_ci * These values are sane defaults for the axg platform: 5298c2ecf20Sopenharmony_ci * - OS = 64 5308c2ecf20Sopenharmony_ci * - Latency = 38700 (?) 5318c2ecf20Sopenharmony_ci * 5328c2ecf20Sopenharmony_ci * TODO: There is a lot of different HCIC, LPFs and HPF configurations possible. 5338c2ecf20Sopenharmony_ci * the configuration may depend on the dmic used by the platform, the 5348c2ecf20Sopenharmony_ci * expected tradeoff between latency and quality, etc ... If/When other 5358c2ecf20Sopenharmony_ci * settings are required, we should add a fw interface to this driver to 5368c2ecf20Sopenharmony_ci * load new filter settings. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_cistatic const struct axg_pdm_filters axg_default_filters = { 5398c2ecf20Sopenharmony_ci .hcic = { 5408c2ecf20Sopenharmony_ci .shift = 0x15, 5418c2ecf20Sopenharmony_ci .mult = 0x80, 5428c2ecf20Sopenharmony_ci .steps = 7, 5438c2ecf20Sopenharmony_ci .ds = 8, 5448c2ecf20Sopenharmony_ci }, 5458c2ecf20Sopenharmony_ci .hpf = { 5468c2ecf20Sopenharmony_ci .out_factor = 0x8000, 5478c2ecf20Sopenharmony_ci .steps = 13, 5488c2ecf20Sopenharmony_ci }, 5498c2ecf20Sopenharmony_ci .lpf = { 5508c2ecf20Sopenharmony_ci [0] = { 5518c2ecf20Sopenharmony_ci .ds = 2, 5528c2ecf20Sopenharmony_ci .round_mode = 1, 5538c2ecf20Sopenharmony_ci .tap = lpf1_default_tap, 5548c2ecf20Sopenharmony_ci .tap_num = ARRAY_SIZE(lpf1_default_tap), 5558c2ecf20Sopenharmony_ci }, 5568c2ecf20Sopenharmony_ci [1] = { 5578c2ecf20Sopenharmony_ci .ds = 2, 5588c2ecf20Sopenharmony_ci .round_mode = 0, 5598c2ecf20Sopenharmony_ci .tap = lpf2_default_tap, 5608c2ecf20Sopenharmony_ci .tap_num = ARRAY_SIZE(lpf2_default_tap), 5618c2ecf20Sopenharmony_ci }, 5628c2ecf20Sopenharmony_ci [2] = { 5638c2ecf20Sopenharmony_ci .ds = 2, 5648c2ecf20Sopenharmony_ci .round_mode = 1, 5658c2ecf20Sopenharmony_ci .tap = lpf3_default_tap, 5668c2ecf20Sopenharmony_ci .tap_num = ARRAY_SIZE(lpf3_default_tap) 5678c2ecf20Sopenharmony_ci }, 5688c2ecf20Sopenharmony_ci }, 5698c2ecf20Sopenharmony_ci}; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic const struct axg_pdm_cfg axg_pdm_config = { 5728c2ecf20Sopenharmony_ci .filters = &axg_default_filters, 5738c2ecf20Sopenharmony_ci .sys_rate = 250000000, 5748c2ecf20Sopenharmony_ci}; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic const struct of_device_id axg_pdm_of_match[] = { 5778c2ecf20Sopenharmony_ci { 5788c2ecf20Sopenharmony_ci .compatible = "amlogic,axg-pdm", 5798c2ecf20Sopenharmony_ci .data = &axg_pdm_config, 5808c2ecf20Sopenharmony_ci }, {} 5818c2ecf20Sopenharmony_ci}; 5828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, axg_pdm_of_match); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic int axg_pdm_probe(struct platform_device *pdev) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5878c2ecf20Sopenharmony_ci struct axg_pdm *priv; 5888c2ecf20Sopenharmony_ci void __iomem *regs; 5898c2ecf20Sopenharmony_ci int ret; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 5928c2ecf20Sopenharmony_ci if (!priv) 5938c2ecf20Sopenharmony_ci return -ENOMEM; 5948c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci priv->cfg = of_device_get_match_data(dev); 5978c2ecf20Sopenharmony_ci if (!priv->cfg) { 5988c2ecf20Sopenharmony_ci dev_err(dev, "failed to match device\n"); 5998c2ecf20Sopenharmony_ci return -ENODEV; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 6038c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 6048c2ecf20Sopenharmony_ci return PTR_ERR(regs); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci priv->map = devm_regmap_init_mmio(dev, regs, &axg_pdm_regmap_cfg); 6078c2ecf20Sopenharmony_ci if (IS_ERR(priv->map)) { 6088c2ecf20Sopenharmony_ci dev_err(dev, "failed to init regmap: %ld\n", 6098c2ecf20Sopenharmony_ci PTR_ERR(priv->map)); 6108c2ecf20Sopenharmony_ci return PTR_ERR(priv->map); 6118c2ecf20Sopenharmony_ci } 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci priv->pclk = devm_clk_get(dev, "pclk"); 6148c2ecf20Sopenharmony_ci if (IS_ERR(priv->pclk)) { 6158c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->pclk); 6168c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 6178c2ecf20Sopenharmony_ci dev_err(dev, "failed to get pclk: %d\n", ret); 6188c2ecf20Sopenharmony_ci return ret; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci priv->dclk = devm_clk_get(dev, "dclk"); 6228c2ecf20Sopenharmony_ci if (IS_ERR(priv->dclk)) { 6238c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->dclk); 6248c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 6258c2ecf20Sopenharmony_ci dev_err(dev, "failed to get dclk: %d\n", ret); 6268c2ecf20Sopenharmony_ci return ret; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci priv->sysclk = devm_clk_get(dev, "sysclk"); 6308c2ecf20Sopenharmony_ci if (IS_ERR(priv->sysclk)) { 6318c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->sysclk); 6328c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 6338c2ecf20Sopenharmony_ci dev_err(dev, "failed to get dclk: %d\n", ret); 6348c2ecf20Sopenharmony_ci return ret; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci return devm_snd_soc_register_component(dev, &axg_pdm_component_drv, 6388c2ecf20Sopenharmony_ci &axg_pdm_dai_drv, 1); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic struct platform_driver axg_pdm_pdrv = { 6428c2ecf20Sopenharmony_ci .probe = axg_pdm_probe, 6438c2ecf20Sopenharmony_ci .driver = { 6448c2ecf20Sopenharmony_ci .name = "axg-pdm", 6458c2ecf20Sopenharmony_ci .of_match_table = axg_pdm_of_match, 6468c2ecf20Sopenharmony_ci }, 6478c2ecf20Sopenharmony_ci}; 6488c2ecf20Sopenharmony_cimodule_platform_driver(axg_pdm_pdrv); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic AXG PDM Input driver"); 6518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 6528c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 653