From 00871994a616f0bf5f2956db65069ccdf53f7e98 Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Sat, 2 Nov 2024 22:55:19 +0800 Subject: [PATCH 1/5] ASoC: codecs: rk_dsm: add support iomux switching for anti-pop automatically The LP/LN and RP/RN differential pairs of rkdsm should keep in the same direction as much as possible when working and shutting down, otherwise the common mode output is likely to cause pop sound. Therefore, we can introduce the ioc register address as REG resource in dts, and switch the dsm pin to function and io state respectively when dsm starts and stops. Change-Id: I4a3e6f5e45f030fdbab74ee7d9a769fc8d77f86d Signed-off-by: Xing Zheng --- sound/soc/codecs/rk_dsm.c | 268 +++++++++++++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rk_dsm.c b/sound/soc/codecs/rk_dsm.c index 15cb7f89e1e9..d198d0ed9316 100644 --- a/sound/soc/codecs/rk_dsm.c +++ b/sound/soc/codecs/rk_dsm.c @@ -23,15 +23,72 @@ #include #include "rk_dsm.h" +#define RK3506_DSM_AUDM0_EN BIT(0) +#define RK3506_DSM_AUDM1_EN BIT(1) +#define RK3506_IOC1_REG_BASE (0xff660000) +#define RK3506_GPIO1_IOC_GPIO1C_IOMUX_SEL_0 (0x0030) /* DSM_AUD_RP_M0 / DSM_AUD_RN_M0 */ +#define RK3506_GPIO1_IOC_GPIO1C2_SEL_MASK GENMASK(11, 8) +#define RK3506_GPIO1_IOC_DSM_AUD_RP_M0 (4 << 8) +#define RK3506_GPIO1_IOC_GPIO2C2 (0 << 8) +#define RK3506_GPIO1_IOC_GPIO1C1_SEL_MASK GENMASK(7, 4) +#define RK3506_GPIO1_IOC_DSM_AUD_RN_M0 (4 << 4) +#define RK3506_GPIO1_IOC_GPIO2C1 (0 << 4) +#define RK3506_GPIO1_IOC_GPIO1D_IOMUX_SEL_0 (0x0038) /* DSM_AUD_LP_M0 / DSM_AUD_LN_M0 */ +#define RK3506_GPIO1_IOC_GPIO1D1_SEL_MASK GENMASK(7, 4) +#define RK3506_GPIO1_IOC_DSM_AUD_LP_M0 (4 << 4) +#define RK3506_GPIO1_IOC_GPIO2D1 (0 << 4) +#define RK3506_GPIO1_IOC_GPIO1D0_SEL_MASK GENMASK(3, 0) +#define RK3506_GPIO1_IOC_DSM_AUD_LN_M0 (4 << 0) +#define RK3506_GPIO1_IOC_GPIO2D0 (0 << 0) +#define RK3506_IOC2_REG_BASE (0xff4d8000) +#define RK3506_GPIO2_IOC_GPIO2B_IOMUX_SEL_1 (0x004c) /* DSM_AUD_LP_M1 / DSM_AUD_LN_M1 / DSM_AUD_RP_M1 / DSM_AUD_RN_M1 */ +#define RK3506_GPIO2_IOC_GPIO2B7_SEL_MASK GENMASK(15, 12) +#define RK3506_GPIO2_IOC_DSM_AUD_LP_M1 (2 << 12) +#define RK3506_GPIO2_IOC_GPIO2B7 (0 << 12) +#define RK3506_GPIO2_IOC_GPIO2B6_SEL_MASK GENMASK(11, 8) +#define RK3506_GPIO2_IOC_DSM_AUD_LN_M1 (2 << 8) +#define RK3506_GPIO2_IOC_GPIO2B6 (0 << 8) +#define RK3506_GPIO2_IOC_GPIO2B5_SEL_MASK GENMASK(7, 4) +#define RK3506_GPIO2_IOC_DSM_AUD_RP_M1 (2 << 4) +#define RK3506_GPIO2_IOC_GPIO2B5 (0 << 4) +#define RK3506_GPIO2_IOC_GPIO2B4_SEL_MASK GENMASK(3, 0) +#define RK3506_GPIO2_IOC_DSM_AUD_RN_M1 (2 << 0) +#define RK3506_GPIO2_IOC_GPIO2B4 (0 << 0) + #define RK3506_GRF_SOC_CON0 (0x0) #define RK3506_DSM_SEL (9) #define RK3562_GRF_PERI_AUDIO_CON (0x0070) #define RK3576_SYS_GRF_SOC_CON2 (0x0008) #define RK3576_DSM_SEL (0x0) +#define RKDSM_VOL_VAL_MAX (0xff) + +enum { + RKDSM_ON_GPIO = 0, + RKDSM_ON_FUNC, +}; + struct rk_dsm_soc_data { int (*init)(struct device *dev); void (*deinit)(struct device *dev); + int (*iomux_switch)(struct device *dev, int type); +}; + +struct rk_dsm_vols { + int vol_l; + int vol_r; + int polarity; +}; + +struct rk_dsm_iomux_res { + phys_addr_t regbase; + unsigned long size; +}; + +struct rk_dsm_iomux { + void __iomem **ioc; + unsigned int audm_en; + int res_num; }; struct rk_dsm_priv { @@ -43,6 +100,12 @@ struct rk_dsm_priv { struct gpio_desc *pa_ctl; struct reset_control *rc; const struct rk_dsm_soc_data *data; + struct device *dev; + struct rk_dsm_vols vols; + struct rk_dsm_iomux iomuxes; + struct pinctrl *pinctrl; + struct pinctrl_state *pin_state; + struct pinctrl_state *io_state; }; /* DAC digital gain */ @@ -92,6 +155,8 @@ static int rk_dsm_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(component); unsigned int reg = mc->reg; unsigned int rreg = mc->rreg; unsigned int shift = mc->shift; @@ -116,6 +181,9 @@ static int rk_dsm_dac_vol_put(struct snd_kcontrol *kcontrol, snd_soc_component_update_bits(component, reg, val_mask, val); snd_soc_component_update_bits(component, rreg, val_mask, val); snd_soc_component_write(component, DACVOGP, sign); + rd->vols.vol_l = val; + rd->vols.vol_r = val; + rd->vols.polarity = sign; return 0; } @@ -355,9 +423,7 @@ static int rk_dsm_hw_params(struct snd_pcm_substream *substream, DSM_DACDSM_CTRL_DSM_EN_MASK, DSM_DACDSM_CTRL_DSM_MODE_CKE_EN | DSM_DACDSM_CTRL_DSM_EN); - } - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { regmap_update_bits(rd->regmap, I2S_XFER, DSM_I2S_XFER_RXS_MASK, DSM_I2S_XFER_RXS_START); @@ -366,6 +432,9 @@ static int rk_dsm_hw_params(struct snd_pcm_substream *substream, DSM_DACDIGEN_DACEN_L0R1_MASK, DSM_DACDIGEN_DAC_GLBEN_EN | DSM_DACDIGEN_DACEN_L0R1_EN); + + if (rd->data && rd->data->iomux_switch) + rd->data->iomux_switch(rd->dev, RKDSM_ON_FUNC); } return 0; @@ -377,6 +446,11 @@ static int rk_dsm_pcm_startup(struct snd_pcm_substream *substream, struct rk_dsm_priv *rd = snd_soc_component_get_drvdata(dai->component); + /* Recover DAC Volumes */ + regmap_write(rd->regmap, DACVOLL0, rd->vols.vol_l); + regmap_write(rd->regmap, DACVOLR0, rd->vols.vol_r); + regmap_write(rd->regmap, DACVOGP, rd->vols.polarity); + gpiod_set_value(rd->pa_ctl, 1); if (rd->pa_ctl_delay_ms) msleep(rd->pa_ctl_delay_ms); @@ -425,11 +499,44 @@ static void rk_dsm_pcm_shutdown(struct snd_pcm_substream *substream, rk_dsm_reset(rd); } +static int rk_dsm_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct rk_dsm_priv *rd = + snd_soc_component_get_drvdata(dai->component); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + /** + * After receiving the stop action, adjust the volume to the + * minimum as soon as possible and switch the differential pair + * of DSM to IO state, so that the same direction change of P/N + * level can reduce the pop sound to the minimum. + */ + regmap_write(rd->regmap, DACVOLL0, RKDSM_VOL_VAL_MAX); + regmap_write(rd->regmap, DACVOLR0, RKDSM_VOL_VAL_MAX); + regmap_write(rd->regmap, DACVOGP, DSM_DACVOGP_VOLGPL0_NEG | DSM_DACVOGP_VOLGPR0_NEG); + regcache_cache_only(rd->regmap, false); + regcache_mark_dirty(rd->regmap); + regcache_sync(rd->regmap); + if (rd->data && rd->data->iomux_switch) + rd->data->iomux_switch(rd->dev, RKDSM_ON_GPIO); + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_dai_ops rd_dai_ops = { .hw_params = rk_dsm_hw_params, .set_fmt = rk_dsm_set_dai_fmt, .startup = rk_dsm_pcm_startup, .shutdown = rk_dsm_pcm_shutdown, + .trigger = rk_dsm_pcm_trigger, }; static struct snd_soc_dai_driver rd_dai[] = { @@ -473,7 +580,71 @@ static const struct regmap_config rd_regmap_config = { static int rk3506_soc_init(struct device *dev) { struct rk_dsm_priv *rd = dev_get_drvdata(dev); + struct rk_dsm_iomux_res res[] = { + { .regbase = RK3506_IOC1_REG_BASE, .size = 0x100, }, + { .regbase = RK3506_IOC2_REG_BASE, .size = 0x100, }, + }; + int c; + rd->iomuxes.res_num = ARRAY_SIZE(res); + rd->iomuxes.ioc = devm_kcalloc(dev, rd->iomuxes.res_num, sizeof(void __iomem *), GFP_KERNEL); + if (!rd->iomuxes.ioc) + return -ENOMEM; + + for (c = 0; c < rd->iomuxes.res_num; c++) { + rd->iomuxes.ioc[c] = ioremap(res[c].regbase, res[c].size); + if (!rd->iomuxes.ioc[c]) { + int n; + + /* iounmap previous mapped address */ + for (n = 0; n < rd->iomuxes.res_num; n++) { + if (rd->iomuxes.ioc[n]) { + iounmap(rd->iomuxes.ioc[n]); + rd->iomuxes.ioc[n] = NULL; + } + } + dev_err(dev, "ioremap res[%d] start: 0x%lx failed\n", + c, (unsigned long)res[c].regbase); + return -ENOMEM; + } + dev_info(dev, "ioremap ioc res[%d] start: 0x%lx success\n", c, (unsigned long)res[c].regbase); + } + + rd->pinctrl = devm_pinctrl_get(dev); + if (!IS_ERR_OR_NULL(rd->pinctrl)) { + const char *io_name; + const char *pin_name; + + if (rd->iomuxes.audm_en == (RK3506_DSM_AUDM0_EN | RK3506_DSM_AUDM1_EN)) { + io_name = "audm0m1-iodown"; + pin_name = "audm0m1-pins"; + } else if (rd->iomuxes.audm_en == RK3506_DSM_AUDM1_EN) { + io_name = "audm1-iodown"; + pin_name = "audm1-pins"; + } else { + /* default case */ + io_name = "audm0-iodown"; + pin_name = "audm0-pins"; + rd->iomuxes.audm_en = RK3506_DSM_AUDM0_EN; + } + + rd->io_state = pinctrl_lookup_state(rd->pinctrl, io_name); + if (IS_ERR(rd->io_state)) { + rd->io_state = NULL; + dev_err(dev, "Have no dsm pinctrl io state by: %s\n", io_name); + } + + rd->pin_state = pinctrl_lookup_state(rd->pinctrl, pin_name); + if (IS_ERR(rd->pin_state)) { + rd->pin_state = NULL; + dev_err(dev, "Have no dsm pinctrl pin state, by: %s\n", pin_name); + } + } + + if (rd->data && rd->data->iomux_switch) + rd->data->iomux_switch(rd->dev, RKDSM_ON_GPIO); + + dev_info(dev, "iomuxes audm_en: 0x%x\n", rd->iomuxes.audm_en); /* enable internal codec to sai3 */ return regmap_write(rd->grf, RK3506_GRF_SOC_CON0, BIT(RK3506_DSM_SEL) << 16 | BIT(RK3506_DSM_SEL)); @@ -482,13 +653,102 @@ static int rk3506_soc_init(struct device *dev) static void rk3506_soc_deinit(struct device *dev) { struct rk_dsm_priv *rd = dev_get_drvdata(dev); + int c; regmap_write(rd->grf, RK3506_GRF_SOC_CON0, BIT(RK3506_DSM_SEL) << 16); + for (c = 0; c < rd->iomuxes.res_num; c++) { + if (rd->iomuxes.ioc[c]) { + iounmap(rd->iomuxes.ioc[c]); + rd->iomuxes.ioc[c] = NULL; + } + } +} + +static int rk3506_soc_iomux_switch(struct device *dev, int type) +{ + struct rk_dsm_priv *rd = dev_get_drvdata(dev); + struct rk_dsm_iomux *iomuxes = &rd->iomuxes; + unsigned long flags; + + local_irq_save(flags); + if (iomuxes->audm_en & RK3506_DSM_AUDM0_EN) { + /** + * DSM_AUD_RN_M0 - GPIO1_C1 + * DSM_AUD_RP_M0 - GPIO1_C2 + * DSM_AUD_LN_M0 - GPIO1_D0 + * DSM_AUD_LP_M0 - GPIO1_D1 + */ + if (type == RKDSM_ON_FUNC) { + writel(((RK3506_GPIO1_IOC_GPIO1C2_SEL_MASK | + RK3506_GPIO1_IOC_GPIO1C1_SEL_MASK) << 16) | + (RK3506_GPIO1_IOC_DSM_AUD_RP_M0 | + RK3506_GPIO1_IOC_DSM_AUD_RN_M0), + iomuxes->ioc[0] + RK3506_GPIO1_IOC_GPIO1C_IOMUX_SEL_0); + writel(((RK3506_GPIO1_IOC_GPIO1D1_SEL_MASK | + RK3506_GPIO1_IOC_GPIO1D0_SEL_MASK) << 16) | + (RK3506_GPIO1_IOC_DSM_AUD_LP_M0 | + RK3506_GPIO1_IOC_DSM_AUD_LN_M0), + iomuxes->ioc[0] + RK3506_GPIO1_IOC_GPIO1D_IOMUX_SEL_0); + } else { + /* RKDSM_ON_GPIO */ + writel(((RK3506_GPIO1_IOC_GPIO1C2_SEL_MASK | + RK3506_GPIO1_IOC_GPIO1C1_SEL_MASK) << 16) | + (RK3506_GPIO1_IOC_GPIO2C2 | + RK3506_GPIO1_IOC_GPIO2C1), + iomuxes->ioc[0] + RK3506_GPIO1_IOC_GPIO1C_IOMUX_SEL_0); + writel(((RK3506_GPIO1_IOC_GPIO1D1_SEL_MASK | + RK3506_GPIO1_IOC_GPIO1D0_SEL_MASK) << 16) | + (RK3506_GPIO1_IOC_GPIO2D1 | + RK3506_GPIO1_IOC_GPIO2D0), + iomuxes->ioc[0] + RK3506_GPIO1_IOC_GPIO1D_IOMUX_SEL_0); + } + } + + if (iomuxes->audm_en & RK3506_DSM_AUDM1_EN) { + /** + * DSM_AUD_RN_M1 - GPIO2_B4 + * DSM_AUD_RP_M1 - GPIO2_B5 + * DSM_AUD_LN_M1 - GPIO2_B6 + * DSM_AUD_LP_M1 - GPIO2_B7 + */ + if (type == RKDSM_ON_FUNC) { + writel(((RK3506_GPIO2_IOC_GPIO2B7_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B6_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B5_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B4_SEL_MASK) << 16) | + (RK3506_GPIO2_IOC_DSM_AUD_LP_M1 | + RK3506_GPIO2_IOC_DSM_AUD_LN_M1 | + RK3506_GPIO2_IOC_DSM_AUD_RP_M1 | + RK3506_GPIO2_IOC_DSM_AUD_RN_M1), + iomuxes->ioc[1] + RK3506_GPIO2_IOC_GPIO2B_IOMUX_SEL_1); + } else { + /* RKDSM_ON_GPIO */ + writel(((RK3506_GPIO2_IOC_GPIO2B7_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B6_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B5_SEL_MASK | + RK3506_GPIO2_IOC_GPIO2B4_SEL_MASK) << 16) | + (RK3506_GPIO2_IOC_GPIO2B7 | + RK3506_GPIO2_IOC_GPIO2B6 | + RK3506_GPIO2_IOC_GPIO2B5 | + RK3506_GPIO2_IOC_GPIO2B4), + iomuxes->ioc[1] + RK3506_GPIO2_IOC_GPIO2B_IOMUX_SEL_1); + } + } + local_irq_restore(flags); + + /* Keeping sync with pinctrl framework */ + if (type == RKDSM_ON_FUNC) + pinctrl_select_state(rd->pinctrl, rd->pin_state); + else + pinctrl_select_state(rd->pinctrl, rd->io_state); + + return 0; } static const struct rk_dsm_soc_data rk3506_data = { .init = rk3506_soc_init, .deinit = rk3506_soc_deinit, + .iomux_switch = rk3506_soc_iomux_switch, }; static int rk3562_soc_init(struct device *dev) @@ -601,6 +861,9 @@ static int rk_dsm_platform_probe(struct platform_device *pdev) &rd->pa_ctl_delay_ms)) rd->pa_ctl_delay_ms = 0; + if (device_property_read_u32(&pdev->dev, "rockchip,dsm-audm-en", &rd->iomuxes.audm_en)) + rd->iomuxes.audm_en = 0; + rd->rc = devm_reset_control_get(&pdev->dev, "reset"); rd->clk_dac = devm_clk_get(&pdev->dev, "dac"); @@ -620,6 +883,7 @@ static int rk_dsm_platform_probe(struct platform_device *pdev) if (IS_ERR(rd->regmap)) return PTR_ERR(rd->regmap); + rd->dev = &pdev->dev; platform_set_drvdata(pdev, rd); rd->data = device_get_match_data(&pdev->dev); From 1d4a4669a58b3bd1654b8b03984b658bed68604a Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 5 Nov 2024 12:18:34 +0800 Subject: [PATCH 2/5] ARM: dts: rockchip: rk3502 & rk3506-pinctrl: add more descriptions and references of rkdsm pins And update naming 'dsm_audmX_pins' by generating file and using ioc1 base for dsm-audm0 iomux switching only by default. Change-Id: I4791a464513bc36ff277abecf98ea4b1ee65a2fa Signed-off-by: Xing Zheng --- arch/arm/boot/dts/rk3502.dtsi | 22 ++++++++--- arch/arm/boot/dts/rk3506-pinctrl.dtsi | 54 +++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/rk3502.dtsi b/arch/arm/boot/dts/rk3502.dtsi index d61679411fb0..e8a87238cfaa 100644 --- a/arch/arm/boot/dts/rk3502.dtsi +++ b/arch/arm/boot/dts/rk3502.dtsi @@ -1009,11 +1009,23 @@ resets = <&cru SRST_M_DSM>; reset-names = "reset" ; rockchip,grf = <&grf>; - pinctrl-names = "default"; - pinctrl-0 = <&dsm_audm0_ln_pins - &dsm_audm0_lp_pins - &dsm_audm0_rn_pins - &dsm_audm0_rp_pins>; + /** + * this is bitmap + * 0x1: (1 << 0) - audm0 enabled + * 0x2: (1 << 1) - audm1 enabled + * 0x3: - audm0 + audm1 enabled + * others - invalid + */ + rockchip,dsm-audm-en = <0x1>; + pinctrl-names = "audm0-iodown", "audm0-pins", + "audm1-iodown", "audm1-pins", + "audm0m1-iodown", "audm0m1-pins"; + pinctrl-0 = <&dsm_audm0_iodown_pins>; + pinctrl-1 = <&dsm_audm0_pins>; + pinctrl-2 = <&dsm_audm1_iodown_pins>; + pinctrl-3 = <&dsm_audm1_pins>; + pinctrl-4 = <&dsm_audm0_iodown_pins>, <&dsm_audm1_iodown_pins>; + pinctrl-5 = <&dsm_audm0_pins>, <&dsm_audm1_pins>; #sound-dai-cells = <0>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/rk3506-pinctrl.dtsi b/arch/arm/boot/dts/rk3506-pinctrl.dtsi index a6ef7f76e875..fcf918370ea6 100644 --- a/arch/arm/boot/dts/rk3506-pinctrl.dtsi +++ b/arch/arm/boot/dts/rk3506-pinctrl.dtsi @@ -1307,6 +1307,60 @@ * This part is edited handly. */ &pinctrl { + dsm_aud { + /omit-if-no-ref/ + dsm_audm0_pins: dsm-audm0-pins { + rockchip,pins = + /* dsm_aud_ln_m0 */ + <1 RK_PD0 4 &pcfg_pull_none>, + /* dsm_aud_lp_m0 */ + <1 RK_PD1 4 &pcfg_pull_none>, + /* dsm_aud_rn_m0 */ + <1 RK_PC1 4 &pcfg_pull_none>, + /* dsm_aud_rp_m0 */ + <1 RK_PC2 4 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm1_pins: dsm-audm1-pins { + rockchip,pins = + /* dsm_aud_ln_m1 */ + <2 RK_PB6 2 &pcfg_pull_none>, + /* dsm_aud_lp_m1 */ + <2 RK_PB7 2 &pcfg_pull_none>, + /* dsm_aud_rn_m1 */ + <2 RK_PB4 2 &pcfg_pull_none>, + /* dsm_aud_rp_m1 */ + <2 RK_PB5 2 &pcfg_pull_none>; + }; + + /omit-if-no-ref/ + dsm_audm0_iodown_pins: dsm-audm0-iodown-pins { + rockchip,pins = + /* dsm_aud_ln_m0 */ + <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_lp_m0 */ + <1 RK_PD1 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_rn_m0 */ + <1 RK_PC1 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_rp_m0 */ + <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>; + }; + + /omit-if-no-ref/ + dsm_audm1_iodown_pins: dsm-audm1-iodown-pins { + rockchip,pins = + /* dsm_aud_ln_m1 */ + <2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_lp_m1 */ + <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_rn_m1 */ + <2 RK_PB4 RK_FUNC_GPIO &pcfg_pull_down>, + /* dsm_aud_rp_m1 */ + <2 RK_PB5 RK_FUNC_GPIO &pcfg_pull_down>; + }; + }; + dsmc { /omit-if-no-ref/ dsmc_csn_pull_pins: dsmc-csn-pull-pins { From 54b79326d66baaae4c760b063058193d34840520 Mon Sep 17 00:00:00 2001 From: XiaoDong Huang Date: Mon, 12 Aug 2024 17:35:19 +0800 Subject: [PATCH 3/5] soc: rockchip: pm_config: support sip sleep_io_config Signed-off-by: XiaoDong Huang Change-Id: I95f2313e1e296a77fbffdde1afa3203cc921bede --- drivers/soc/rockchip/rockchip_pm_config.c | 9 ++++++++- include/linux/rockchip/rockchip_sip.h | 7 +++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/soc/rockchip/rockchip_pm_config.c b/drivers/soc/rockchip/rockchip_pm_config.c index 49050b026571..42fa7afa8e76 100644 --- a/drivers/soc/rockchip/rockchip_pm_config.c +++ b/drivers/soc/rockchip/rockchip_pm_config.c @@ -434,7 +434,7 @@ out: static int parse_io_config(struct device *dev) { - int ret = 0, cnt; + int ret = 0, cnt, i; struct device_node *node = dev->of_node; struct rk_sleep_config *config = &sleep_config[RK_PM_MEM]; @@ -456,6 +456,13 @@ static int parse_io_config(struct device *dev) } config->sleep_io_config_cnt = cnt; + + sip_smc_set_suspend_mode(SLEEP_IO_CONFIG, RK_PM_SLEEP_IO_CFG_CNT, cnt); + + for (i = 0; i < cnt; i++) + sip_smc_set_suspend_mode(SLEEP_IO_CONFIG, + RK_PM_SLEEP_IO_CFG_VAL, + config->sleep_io_config[i]); } else { dev_dbg(dev, "not set sleep-pin-config\n"); } diff --git a/include/linux/rockchip/rockchip_sip.h b/include/linux/rockchip/rockchip_sip.h index b05a0a624209..20dbece78cf9 100644 --- a/include/linux/rockchip/rockchip_sip.h +++ b/include/linux/rockchip/rockchip_sip.h @@ -111,6 +111,13 @@ #define LINUX_PM_STATE 0x09 #define SUSPEND_IO_RET_CONFIG 0x0a #define SLEEP_PIN_CONFIG 0x0b +#define SLEEP_IO_CONFIG 0x0c + +enum { + RK_PM_SLEEP_IO_CFG_CNT = 0, + RK_PM_SLEEP_IO_CFG_VAL = 1, + RK_PM_SLEEP_IO_CFG_MAX, +}; /* SIP_REMOTECTL_CFG call types */ #define REMOTECTL_SET_IRQ 0xf0 From 89521ea57b2a008c9ded9d3bebc6ff844f841eb9 Mon Sep 17 00:00:00 2001 From: Joseph Chen Date: Fri, 8 Nov 2024 14:31:19 +0800 Subject: [PATCH 4/5] ARM: dts: rockchip: rk3502-evb1-v10: Add suspend io config Set these gpios to right state for system low power. Signed-off-by: Joseph Chen Change-Id: I8e030a872209f9955834aab008b8059f4fb2d507 --- arch/arm/boot/dts/rk3502-evb1-v10.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/boot/dts/rk3502-evb1-v10.dtsi b/arch/arm/boot/dts/rk3502-evb1-v10.dtsi index 8f4e57790602..54979e626dce 100644 --- a/arch/arm/boot/dts/rk3502-evb1-v10.dtsi +++ b/arch/arm/boot/dts/rk3502-evb1-v10.dtsi @@ -410,6 +410,17 @@ | RKPM_PWREN_SLEEP_GPIO0A0 | RKPM_PWREN_SLEEP_ACT_LOW ) >; + +#define GPIO0_IOC_GPIO0A_PULL_REG 0xff950200 +#define GPIO0_IOC_GPIO0C_PULL_REG 0xff950208 +#define GPIO0A3_PULL_DOWN 0x00c00080 +#define GPIO0C5_PULL_DOWN 0x0c000800 + + /* Note: support max 16 pairs */ + rockchip,sleep-io-config = < + GPIO0_IOC_GPIO0C_PULL_REG GPIO0C5_PULL_DOWN /* PWM0_CH0_CPU */ + GPIO0_IOC_GPIO0A_PULL_REG GPIO0A3_PULL_DOWN /* PWM0_CH2_LCD_BL */ + >; }; &sai1 { From 10f8a9f06a7b94601400512f0f2b1b8d0612042f Mon Sep 17 00:00:00 2001 From: Luo Wei Date: Mon, 11 Nov 2024 17:10:53 +0800 Subject: [PATCH 5/5] mfd: display-serdes: if route enable then no need init serdes pinctrl and i2c address to reduce booting time Signed-off-by: Luo Wei Change-Id: I3d6e3598418a7b9a07a624f38e823b023109b50d --- .../mfd/display-serdes/serdes-bridge-split.c | 6 ++++++ drivers/mfd/display-serdes/serdes-i2c.c | 19 ++++++++++++++----- drivers/mfd/display-serdes/serdes-pinctrl.c | 3 ++- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/display-serdes/serdes-bridge-split.c b/drivers/mfd/display-serdes/serdes-bridge-split.c index f76201ad7665..74db054d1de0 100644 --- a/drivers/mfd/display-serdes/serdes-bridge-split.c +++ b/drivers/mfd/display-serdes/serdes-bridge-split.c @@ -188,10 +188,16 @@ serdes_bridge_split_detect(struct drm_bridge *bridge) struct serdes_bridge_split *serdes_bridge_split = to_serdes_bridge_split(bridge); struct serdes *serdes = serdes_bridge_split->parent; enum drm_connector_status status = connector_status_connected; + enum drm_connector_status last_status = serdes->serdes_bridge_split->status; if (serdes->chip_data->bridge_ops->detect) status = serdes->chip_data->bridge_ops->detect(serdes); + if (status != last_status) + dev_info(serdes->dev, "%s: %s, %s\n", __func__, serdes->chip_data->name, + (status == connector_status_connected) ? "connected" : "disconnect"); + + serdes->serdes_bridge_split->status = status; return status; } diff --git a/drivers/mfd/display-serdes/serdes-i2c.c b/drivers/mfd/display-serdes/serdes-i2c.c index 249210873ceb..04c4073c126d 100644 --- a/drivers/mfd/display-serdes/serdes-i2c.c +++ b/drivers/mfd/display-serdes/serdes-i2c.c @@ -61,6 +61,7 @@ static int serdes_set_i2c_address(struct serdes *serdes, u32 reg_hw, u32 reg_use int ret = 0; struct i2c_client *client_split; struct serdes *serdes_split = serdes->g_serdes_bridge_split; + unsigned int def = 0; if (!serdes_split) { dev_info(serdes->dev, "%s serdes_split is null\n", __func__); @@ -72,7 +73,12 @@ static int serdes_set_i2c_address(struct serdes *serdes, u32 reg_hw, u32 reg_use __func__, dev_name(serdes_split->dev), client_split->name, client_split->addr, serdes->reg_hw, serdes->reg_use, serdes_split); - client_split->addr = serdes->reg_hw; + client_split->addr = serdes->reg_use; + ret = serdes_reg_read(serdes, serdes->serdes_init_seq->reg_sequence[0].reg, &def); + if (ret) { + client_split->addr = serdes->reg_hw; + dev_info(serdes->dev, "%s try to use addr 0x%x\n", __func__, serdes->reg_hw); + } if (serdes_split && serdes_split->chip_data->split_ops && serdes_split->chip_data->split_ops->select) @@ -410,10 +416,13 @@ static int serdes_i2c_probe(struct i2c_client *client, if (serdes->reg_hw) { SERDES_DBG_MFD("%s: %s start change i2c address from 0x%x to 0x%x\n", __func__, dev->of_node->name, serdes->reg_hw, serdes->reg_use); - ret = serdes_set_i2c_address(serdes, serdes->reg_hw, - serdes->reg_use, serdes->link_use); - if (ret) - dev_err(dev, "%s failed to set i2c address\n", serdes->chip_data->name); + + if (!serdes->route_enable) { + ret = serdes_set_i2c_address(serdes, serdes->reg_hw, + serdes->reg_use, serdes->link_use); + if (ret) + dev_err(dev, "%s failed to set addr\n", serdes->chip_data->name); + } } serdes->use_delay_work = of_property_read_bool(dev->of_node, "use-delay-work"); diff --git a/drivers/mfd/display-serdes/serdes-pinctrl.c b/drivers/mfd/display-serdes/serdes-pinctrl.c index 72d3518e8d6d..2cdc2890ef1d 100644 --- a/drivers/mfd/display-serdes/serdes-pinctrl.c +++ b/drivers/mfd/display-serdes/serdes-pinctrl.c @@ -335,7 +335,8 @@ static int serdes_pinctrl_probe(struct platform_device *pdev) } } - ret = pinctrl_enable(serdes_pinctrl->pctl); + if (!serdes->route_enable) + ret = pinctrl_enable(serdes_pinctrl->pctl); ret = serdes_pinctrl_gpio_init(serdes);