diff --git a/sound/soc/rockchip/rockchip_pdm_v2.c b/sound/soc/rockchip/rockchip_pdm_v2.c index 8f35e7c695bc..e3e9f7a46dc0 100644 --- a/sound/soc/rockchip/rockchip_pdm_v2.c +++ b/sound/soc/rockchip/rockchip_pdm_v2.c @@ -29,11 +29,13 @@ #define PDM_V2_START_DELAY_MS_MIN (0) #define PDM_V2_START_DELAY_MS_MAX (1000) #define PDM_V2_REF_CLK_MAX 61440000 +#define PDM_V2_CHANNEL_MAX 8 #define QUIRK_ALWAYS_ON BIT(0) #define RK3506_PDM 0x2311 #define RK3576_PDM 0x2302 +#define RV1126B_PDM 0x2411 struct rk_pdm_v2_clkref { unsigned int sr; @@ -73,6 +75,7 @@ struct rk_pdm_v2_dev { unsigned int clk_ref_frq; unsigned int quirks; unsigned int version; + unsigned int data_shift[PDM_V2_CHANNEL_MAX]; }; static int get_pdm_v2_clkref(struct rk_pdm_v2_dev *pdm, unsigned int sr) @@ -121,6 +124,12 @@ static void rockchip_pdm_v2_rxctrl(struct rk_pdm_v2_dev *pdm, int on) regmap_update_bits(pdm->regmap, PDM_V2_SYSCONFIG, PDM_V2_RX_MSK | PDM_V2_RX_CLR_MSK | PDM_V2_NUM_MSK, PDM_V2_RX_STOP | PDM_V2_RX_CLR_WR | PDM_V2_NUM_STOP); + if (pdm->version == RV1126B_PDM) { + regmap_update_bits(pdm->regmap, PDM_V2_DATA_SHIFT0, + 0xffffffff, 0x0); + regmap_update_bits(pdm->regmap, PDM_V2_DATA_SHIFT1, + 0xffffffff, 0x0); + } } } @@ -209,7 +218,7 @@ static int rockchip_pdm_v2_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rk_pdm_v2_dev *pdm = to_info(dai); - unsigned int val = 0; + unsigned int i, n = 0, val = 0; regmap_update_bits(pdm->regmap, PDM_V2_CTRL, PDM_V2_SJM_SEL_MSK, PDM_V2_SJM_SEL_L); @@ -223,9 +232,42 @@ static int rockchip_pdm_v2_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(pdm->regmap, PDM_V2_FILTER_CTRL, PDM_V2_HPF_R_MSK | PDM_V2_HPF_L_MSK | PDM_V2_HPF_FREQ_MSK, PDM_V2_HPF_R_EN | PDM_V2_HPF_L_EN | PDM_V2_HPF_FREQ_60); + } else if (pdm->version == RV1126B_PDM) { + /* Move the hpf after cic filter */ + regmap_update_bits(pdm->regmap, PDM_V2_FILTER_CTRL1, + PDM_V2_FILT1_HPF_V2_R_MSK | PDM_V2_FILT1_HPF_V2_L_MSK | + PDM_V2_FILT1_HPF_V2_FREQ_MSK, + PDM_V2_FILT1_HPF_V2_R_EN | PDM_V2_FILT1_HPF_V2_L_EN | + PDM_V2_FILT1_HPF_V2_FREQ_60); + } + + if (pdm->version == RV1126B_PDM) { + /* PDM data shift */ + n = params_channels(params); + + if (n > PDM_V2_CHANNEL_MAX / 2) { + for (i = 0; i < PDM_V2_CHANNEL_MAX / 2; i++) + val += pdm->data_shift[i] << (i * 8); + + regmap_update_bits(pdm->regmap, PDM_V2_DATA_SHIFT0, + 0xffffffff, val); + val = 0; + for (i = 0; i < (n - PDM_V2_CHANNEL_MAX / 2); i++) + val += pdm->data_shift[i + PDM_V2_CHANNEL_MAX / 2] << (i * 8); + + regmap_update_bits(pdm->regmap, PDM_V2_DATA_SHIFT1, + 0xffffffff, val); + } else { + for (i = 0; i < n; i++) + val += pdm->data_shift[i] << (i * 8); + + regmap_update_bits(pdm->regmap, PDM_V2_DATA_SHIFT0, + 0xffffffff, val); + } } rockchip_pdm_v2_set_samplerate(pdm, params_rate(params)); + val = 0; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: val |= PDM_V2_VDW(16); @@ -336,6 +378,7 @@ static int rockchip_pdm_v2_prepare(struct snd_pcm_substream *substream, static const struct snd_kcontrol_new rk3506_controls[]; static const struct snd_kcontrol_new rk3576_controls[]; +static const struct snd_kcontrol_new rv1126b_controls[]; static int rockchip_pdm_v2_dai_probe(struct snd_soc_dai *dai) { @@ -347,6 +390,8 @@ static int rockchip_pdm_v2_dai_probe(struct snd_soc_dai *dai) snd_soc_add_component_controls(dai->component, rk3506_controls, 1); else if (pdm->version == RK3576_PDM) snd_soc_add_component_controls(dai->component, rk3576_controls, 1); + else if (pdm->version == RV1126B_PDM) + snd_soc_add_component_controls(dai->component, rv1126b_controls, 1); return 0; } @@ -446,6 +491,8 @@ static SOC_ENUM_SINGLE_DECL(hpf_cutoff_enum, PDM_V2_FILTER_CTRL, 19, hpf_cutoff_text); static SOC_ENUM_SINGLE_DECL(hpf_v2_cutoff_enum, PDM_V2_FILTER_CTRL, 21, hpf_v2_cutoff_text); +static SOC_ENUM_SINGLE_DECL(hpf1_v2_cutoff_enum, PDM_V2_FILTER_CTRL1, + 2, hpf_v2_cutoff_text); static const DECLARE_TLV_DB_SCALE(pdm_v2_digtal_gain_tlv, -6563, 75, 0); static const struct snd_kcontrol_new rockchip_pdm_v2_controls[] = { @@ -487,6 +534,36 @@ static const struct snd_kcontrol_new rk3576_controls[] = { SOC_SINGLE("HPFR Switch", PDM_V2_FILTER_CTRL, 21, 1, 0), }; +static const struct snd_kcontrol_new rv1126b_controls[] = { + SOC_SINGLE_RANGE_TLV("Gain Volume 0", + PDM_V2_GAIN_CTRL, + 1, + PDM_V2_GAIN_CTRL_MIN, + PDM_V2_GAIN_CTRL_MAX, + 0, pdm_v2_digtal_gain_tlv), + SOC_SINGLE_RANGE_TLV("Gain Volume 1", + PDM_V2_GAIN_CTRL, + 9, + PDM_V2_GAIN_CTRL_MIN, + PDM_V2_GAIN_CTRL_MAX, + 0, pdm_v2_digtal_gain_tlv), + SOC_SINGLE_RANGE_TLV("Gain Volume 2", + PDM_V2_GAIN_CTRL, + 17, + PDM_V2_GAIN_CTRL_MIN, + PDM_V2_GAIN_CTRL_MAX, + 0, pdm_v2_digtal_gain_tlv), + SOC_SINGLE_RANGE_TLV("Gain Volume 3", + PDM_V2_GAIN_CTRL, + 25, + PDM_V2_GAIN_CTRL_MIN, + PDM_V2_GAIN_CTRL_MAX, + 0, pdm_v2_digtal_gain_tlv), + SOC_ENUM("HPF Cutoff", hpf1_v2_cutoff_enum), + SOC_SINGLE("HPFL Switch", PDM_V2_FILTER_CTRL1, 1, 1, 0), + SOC_SINGLE("HPFR Switch", PDM_V2_FILTER_CTRL1, 0, 1, 0), +}; + static const struct snd_soc_component_driver rockchip_pdm_v2_component = { .name = "rockchip-pdm-v2", .controls = rockchip_pdm_v2_controls, @@ -584,6 +661,9 @@ static bool rockchip_pdm_v2_wr_reg(struct device *dev, unsigned int reg) case PDM_V2_RXFIFO_DATA: case PDM_V2_DATA_VALID: case PDM_V2_GAIN_CTRL: + case PDM_V2_DATA_SHIFT0: + case PDM_V2_DATA_SHIFT1: + case PDM_V2_FILTER_CTRL1: return true; default: return false; @@ -601,6 +681,9 @@ static bool rockchip_pdm_v2_rd_reg(struct device *dev, unsigned int reg) case PDM_V2_RXFIFO_DATA: case PDM_V2_VERSION: case PDM_V2_GAIN_CTRL: + case PDM_V2_DATA_SHIFT0: + case PDM_V2_DATA_SHIFT1: + case PDM_V2_FILTER_CTRL1: return true; default: return false; @@ -639,7 +722,7 @@ static const struct regmap_config rockchip_pdm_v2_regmap_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, - .max_register = PDM_V2_GAIN_CTRL, + .max_register = PDM_V2_FILTER_CTRL1, .reg_defaults = rockchip_pdm_v2_reg_defaults, .num_reg_defaults = ARRAY_SIZE(rockchip_pdm_v2_reg_defaults), .writeable_reg = rockchip_pdm_v2_wr_reg, @@ -652,6 +735,7 @@ static const struct regmap_config rockchip_pdm_v2_regmap_config = { static const struct of_device_id rockchip_pdm_v2_match[] __maybe_unused = { { .compatible = "rockchip,rk3506-pdm", }, { .compatible = "rockchip,rk3576-pdm", }, + { .compatible = "rockchip,rv1126b-pdm", }, {}, }; MODULE_DEVICE_TABLE(of, rockchip_pdm_v2_match); @@ -754,6 +838,49 @@ static int rockchip_pdm_v2_register_platform(struct device *dev) return ret; } +static int rockchip_pdm_v2_data_shift(struct rk_pdm_v2_dev *pdm, + struct device_node *np) +{ + char *pdm_data_shift_prop = "rockchip,pdm-data-shift"; + int num, ret = 0; + + num = of_count_phandle_with_args(np, pdm_data_shift_prop, NULL); + if (num < 0) { + if (num != -ENOENT) { + dev_err(pdm->dev, + "Failed to read '%s' num: %d\n", + pdm_data_shift_prop, num); + ret = num; + } + + return ret; + } else if (num != PDM_V2_CHANNEL_MAX) { + dev_err(pdm->dev, + "The num: %d should be: %d\n", num, PDM_V2_CHANNEL_MAX); + + return -EINVAL; + } + + ret = of_property_read_u32_array(np, pdm_data_shift_prop, + pdm->data_shift, num); + if (ret < 0) { + dev_err(pdm->dev, "Failed to read '%s': %d\n", pdm_data_shift_prop, ret); + + return ret; + } + + for (num = 0; num < PDM_V2_CHANNEL_MAX; num++) { + if (pdm->data_shift[num] > 0xff) { + dev_err(pdm->dev, + "The data_shift: %d exceed 0xff\n", num); + + return -EINVAL; + } + } + + return ret; +} + static int rockchip_pdm_v2_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -827,6 +954,16 @@ static int rockchip_pdm_v2_probe(struct platform_device *pdev) } else if (pdm->version == RK3576_PDM) { regmap_update_bits(pdm->regmap, PDM_V2_FILTER_CTRL, PDM_V2_GAIN_MSK, PDM_V2_GAIN_0DB); + } else if (pdm->version == RV1126B_PDM) { + regmap_update_bits(pdm->regmap, PDM_V2_GAIN_CTRL, + PDM_V2_GAIN_CTRL_MSK | + PDM_V2_GAIN_CTRL_MSK << 8 | + PDM_V2_GAIN_CTRL_MSK << 16 | + PDM_V2_GAIN_CTRL_MSK << 24, + PDM_V2_GAIN_CTRL_0DB | + PDM_V2_GAIN_CTRL_0DB << 8 | + PDM_V2_GAIN_CTRL_0DB << 16 | + PDM_V2_GAIN_CTRL_0DB << 24); } ret = rockchip_pdm_v2_path_parse(pdm, node); @@ -836,6 +973,12 @@ static int rockchip_pdm_v2_probe(struct platform_device *pdev) ret = rockchip_pdm_v2_parse_quirks(pdm); if (ret) goto err_hclk; + + if (pdm->version == RV1126B_PDM) { + ret = rockchip_pdm_v2_data_shift(pdm, node); + if (ret) + goto err_hclk; + } /* * MUST: after pm_runtime_enable step, any register R/W * should be wrapped with pm_runtime_get_sync/put. diff --git a/sound/soc/rockchip/rockchip_pdm_v2.h b/sound/soc/rockchip/rockchip_pdm_v2.h index ed2144d5dbc7..d44c043f549e 100644 --- a/sound/soc/rockchip/rockchip_pdm_v2.h +++ b/sound/soc/rockchip/rockchip_pdm_v2.h @@ -24,6 +24,9 @@ #define PDM_V2_DATA3L 0x0034 #define PDM_V2_VERSION 0x0038 #define PDM_V2_GAIN_CTRL 0x003c +#define PDM_V2_DATA_SHIFT0 0x0040 +#define PDM_V2_DATA_SHIFT1 0x0044 +#define PDM_V2_FILTER_CTRL1 0x0048 #define PDM_V2_INCR_RXDR 0x0400 /* PDM_V2_SYSCONFIG */ @@ -152,4 +155,27 @@ #define PDM_V2_GAIN_CTRL_MAX 0x7f #define PDM_V2_GAIN_CTRL_0DB (175 << 0) +/* PDM_V2_FILTER_CTRL1 */ +#define PDM_V2_FILT1_HPF_V2_R_MSK (0x1 << 0) +#define PDM_V2_FILT1_HPF_V2_R_EN (0x1 << 0) +#define PDM_V2_FILT1_HPF_V2_R_DIS (0x0 << 0) +#define PDM_V2_FILT1_HPF_V2_L_MSK (0x1 << 1) +#define PDM_V2_FILT1_HPF_V2_L_EN (0x1 << 1) +#define PDM_V2_FILT1_HPF_V2_L_DIS (0x0 << 1) +#define PDM_V2_FILT1_HPF_V2_FREQ_MSK (0xf << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_0_234 (0x0 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_0_468 (0x1 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_0_937 (0x2 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_1_875 (0x3 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_3_75 (0x4 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_7_5 (0x5 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_15 (0x6 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_30 (0x7 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_60 (0x8 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_122 (0x9 << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_251 (0xa << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_528 (0xb << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_1183 (0xc << 2) +#define PDM_V2_FILT1_HPF_V2_FREQ_3152 (0xd << 2) + #endif