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 { 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 { 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); 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 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);