Hi Prabhakar, Thanks for the feedback. > -----Original Message----- > From: Prabhakar <prabhakar.csengg@xxxxxxxxx> > Sent: Wednesday, June 5, 2024 8:50 AM > Subject: [RFC PATCH 4/4] mmc: renesas_sdhi: Add support for RZ/V2H(P) SoC > > From: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> > > The SDHI/eMMC IPs found in the RZ/V2H(P) (a.k.a. r9a09g057) are very similar to those found in R- > Car Gen3. However, they are not identical, necessitating an SoC-specific compatible string for > fine-tuning driver support. > > Key features of the RZ/V2H(P) SDHI/eMMC IPs include: > - Voltage level control via the IOVS bit. > - PWEN pin support via SD_STATUS register. > - Lack of HS400 support. > - Fixed address mode operation. > > sd_iovs and sd_pwen quirks are introduced for SoCs supporting this bit to handle voltage level > control and power enable via SD_STATUS register. > > regulator support is added to control the volatage levels of SD pins via sd_iovs bit in SD_STATUS > register. > > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@xxxxxxxxxxxxxx> > --- > drivers/mmc/host/renesas_sdhi.h | 7 ++ > drivers/mmc/host/renesas_sdhi_core.c | 67 +++++++++++++++++-- > drivers/mmc/host/renesas_sdhi_internal_dmac.c | 45 +++++++++++++ > drivers/mmc/host/tmio_mmc.h | 4 ++ > 4 files changed, 118 insertions(+), 5 deletions(-) > > diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h index > 586f94d4dbfd..9ef4fdf44280 100644 > --- a/drivers/mmc/host/renesas_sdhi.h > +++ b/drivers/mmc/host/renesas_sdhi.h > @@ -11,6 +11,8 @@ > > #include <linux/dmaengine.h> > #include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/regulator/driver.h> > #include "tmio_mmc.h" > > struct renesas_sdhi_scc { > @@ -49,6 +51,11 @@ struct renesas_sdhi_quirks { > bool manual_tap_correction; > bool old_info1_layout; > u32 hs400_bad_taps; > + bool sd_iovs; > + bool sd_pwen; > + struct regulator_desc *rdesc; > + const struct regmap_config *rdesc_regmap_config; > + unsigned int rdesc_offset; > const u8 (*hs400_calib_table)[SDHI_CALIB_TABLE_MAX]; > }; > > diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c > index 12f4faaaf4ee..2eeea9513a23 100644 > --- a/drivers/mmc/host/renesas_sdhi_core.c > +++ b/drivers/mmc/host/renesas_sdhi_core.c > @@ -248,6 +248,19 @@ static int renesas_sdhi_card_busy(struct mmc_host *mmc) > TMIO_STAT_DAT0); > } > > +static void renesas_sdhi_sd_status_pwen(struct tmio_mmc_host *host, > +bool on) { > + u32 sd_status; > + > + sd_ctrl_read32_rep(host, CTL_SD_STATUS, &sd_status, 1); > + if (on) > + sd_status |= SD_STATUS_PWEN; > + else > + sd_status &= ~SD_STATUS_PWEN; > + > + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); } > + May be use regulator_set_voltage() to set this?? > static int renesas_sdhi_start_signal_voltage_switch(struct mmc_host *mmc, > struct mmc_ios *ios) > { > @@ -587,6 +600,9 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve) > false, priv->rstc); > /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */ > sd_ctrl_write16(host, CTL_RESET_SD, 0x0001); > + if (sdhi_has_quirk(priv, sd_pwen)) > + renesas_sdhi_sd_status_pwen(host, true); > + > priv->needs_adjust_hs400 = false; > renesas_sdhi_set_clock(host, host->clk_cache); > > @@ -904,6 +920,34 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable) > renesas_sdhi_sdbuf_width(host, enable ? width : 16); } > > +static int renesas_sdhi_internal_dmac_register_regulator(struct platform_device *pdev, > + const struct renesas_sdhi_quirks *quirks) { > + struct tmio_mmc_host *host = platform_get_drvdata(pdev); > + struct renesas_sdhi *priv = host_to_priv(host); > + struct regulator_config rcfg = { > + .dev = &pdev->dev, > + .driver_data = priv, > + }; > + struct regulator_dev *rdev; > + const char *devname; > + > + devname = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s-vqmmc-regulator", > + dev_name(&pdev->dev)); > + if (!devname) > + return -ENOMEM; > + > + quirks->rdesc->name = devname; > + rcfg.regmap = devm_regmap_init_mmio(&pdev->dev, host->ctl + quirks->rdesc_offset, This is (CTL_SD_STATUS << 2) , so the variable can be dropped from quirks. Cheers, Biju > + quirks->rdesc_regmap_config); > + if (IS_ERR(rcfg.regmap)) > + return PTR_ERR(rcfg.regmap); > + > + rdev = devm_regulator_register(&pdev->dev, quirks->rdesc, &rcfg); > + > + return PTR_ERR_OR_ZERO(rdev); > +} > + > int renesas_sdhi_probe(struct platform_device *pdev, > const struct tmio_mmc_dma_ops *dma_ops, > const struct renesas_sdhi_of_data *of_data, @@ -1051,6 +1095,15 @@ int > renesas_sdhi_probe(struct platform_device *pdev, > if (ret) > goto efree; > > + if (sdhi_has_quirk(priv, sd_iovs)) { > + ret = renesas_sdhi_internal_dmac_register_regulator(pdev, quirks); > + if (ret) > + goto efree; > + } > + > + if (sdhi_has_quirk(priv, sd_pwen)) > + renesas_sdhi_sd_status_pwen(host, true); > + > ver = sd_ctrl_read16(host, CTL_VERSION); > /* GEN2_SDR104 is first known SDHI to use 32bit block count */ > if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX) @@ -1110,26 +1163,26 @@ > int renesas_sdhi_probe(struct platform_device *pdev, > num_irqs = platform_irq_count(pdev); > if (num_irqs < 0) { > ret = num_irqs; > - goto eirq; > + goto epwen; > } > > /* There must be at least one IRQ source */ > if (!num_irqs) { > ret = -ENXIO; > - goto eirq; > + goto epwen; > } > > for (i = 0; i < num_irqs; i++) { > irq = platform_get_irq(pdev, i); > if (irq < 0) { > ret = irq; > - goto eirq; > + goto epwen; > } > > ret = devm_request_irq(&pdev->dev, irq, tmio_mmc_irq, 0, > dev_name(&pdev->dev), host); > if (ret) > - goto eirq; > + goto epwen; > } > > ret = tmio_mmc_host_probe(host); > @@ -1141,7 +1194,9 @@ int renesas_sdhi_probe(struct platform_device *pdev, > > return ret; > > -eirq: > +epwen: > + if (sdhi_has_quirk(priv, sd_pwen)) > + renesas_sdhi_sd_status_pwen(host, false); > tmio_mmc_host_remove(host); > edisclk: > renesas_sdhi_clk_disable(host); > @@ -1157,6 +1212,8 @@ void renesas_sdhi_remove(struct platform_device *pdev) > struct tmio_mmc_host *host = platform_get_drvdata(pdev); > > tmio_mmc_host_remove(host); > + if (sdhi_has_quirk(host_to_priv(host), sd_pwen)) > + renesas_sdhi_sd_status_pwen(host, false); > renesas_sdhi_clk_disable(host); > tmio_mmc_host_free(host); > } > diff --git a/drivers/mmc/host/renesas_sdhi_internal_dmac.c > b/drivers/mmc/host/renesas_sdhi_internal_dmac.c > index 422fa63a2e99..f824d167bb09 100644 > --- a/drivers/mmc/host/renesas_sdhi_internal_dmac.c > +++ b/drivers/mmc/host/renesas_sdhi_internal_dmac.c > @@ -215,6 +215,45 @@ static const struct renesas_sdhi_quirks sdhi_quirks_rzg2l = { > .hs400_disabled = true, > }; > > +static const unsigned int r9a09g057_vqmmc_voltages[] = { > + 3300000, 1800000, > +}; > + > +static const struct regulator_ops r9a09g057_regulator_voltage_ops = { > + .list_voltage = regulator_list_voltage_table, > + .map_voltage = regulator_map_voltage_descend, > + .get_voltage_sel = regulator_get_voltage_sel_regmap, > + .set_voltage_sel = regulator_set_voltage_sel_regmap, }; > + > +static struct regulator_desc r9a09g057_vqmmc_regulator = { > + .of_match = of_match_ptr("vqmmc-r9a09g057-regulator"), > + .owner = THIS_MODULE, > + .type = REGULATOR_VOLTAGE, > + .ops = &r9a09g057_regulator_voltage_ops, > + .volt_table = r9a09g057_vqmmc_voltages, > + .n_voltages = ARRAY_SIZE(r9a09g057_vqmmc_voltages), > + .vsel_mask = 0x10000, > + .vsel_reg = 0, > +}; > + > +static const struct regmap_config r9a09g057_vqmmc_regmap_config = { > + .reg_bits = 32, > + .val_bits = 32, > + .reg_stride = 4, > + .max_register = 1, > +}; > + > +static const struct renesas_sdhi_quirks sdhi_quirks_r9a09g057 = { > + .fixed_addr_mode = true, > + .hs400_disabled = true, > + .sd_iovs = true, > + .sd_pwen = true, > + .rdesc = &r9a09g057_vqmmc_regulator, > + .rdesc_regmap_config = &r9a09g057_vqmmc_regmap_config, > + .rdesc_offset = 0x3C8, > +}; > + > /* > * Note for r8a7796 / r8a774a1: we can't distinguish ES1.1 and 1.2 as of now. > * So, we want to treat them equally and only have a match for ES1.2 to enforce @@ -260,6 +299,11 > @@ static const struct renesas_sdhi_of_data_with_quirks of_rzg2l_compatible = { > .quirks = &sdhi_quirks_rzg2l, > }; > > +static const struct renesas_sdhi_of_data_with_quirks of_r9a09g057_compatible = { > + .of_data = &of_data_rcar_gen3, > + .quirks = &sdhi_quirks_r9a09g057, > +}; > + > static const struct renesas_sdhi_of_data_with_quirks of_rcar_gen3_compatible = { > .of_data = &of_data_rcar_gen3, > }; > @@ -284,6 +328,7 @@ static const struct of_device_id renesas_sdhi_internal_dmac_of_match[] = { > { .compatible = "renesas,sdhi-r8a77990", .data = &of_r8a77990_compatible, }, > { .compatible = "renesas,sdhi-r8a77995", .data = &of_rcar_gen3_nohs400_compatible, }, > { .compatible = "renesas,sdhi-r9a09g011", .data = &of_rzg2l_compatible, }, > + { .compatible = "renesas,sdhi-r9a09g057", .data = > +&of_r9a09g057_compatible, }, > { .compatible = "renesas,rzg2l-sdhi", .data = &of_rzg2l_compatible, }, > { .compatible = "renesas,rcar-gen3-sdhi", .data = &of_rcar_gen3_compatible, }, > { .compatible = "renesas,rcar-gen4-sdhi", .data = &of_rcar_gen3_compatible, }, diff --git > a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h index de56e6534aea..d03aedf61aa3 100644 > --- a/drivers/mmc/host/tmio_mmc.h > +++ b/drivers/mmc/host/tmio_mmc.h > @@ -43,6 +43,7 @@ > #define CTL_RESET_SD 0xe0 > #define CTL_VERSION 0xe2 > #define CTL_SDIF_MODE 0xe6 /* only known on R-Car 2+ */ > +#define CTL_SD_STATUS 0xf2 /* only known on RZ/G2L and RZ/V2H(P) */ > > /* Definitions for values the CTL_STOP_INTERNAL_ACTION register can take */ > #define TMIO_STOP_STP BIT(0) > @@ -102,6 +103,9 @@ > /* Definitions for values the CTL_SDIF_MODE register can take */ > #define SDIF_MODE_HS400 BIT(0) /* only known on R-Car 2+ */ > > +/* Definitions for values the CTL_SD_STATUS register can take */ > +#define SD_STATUS_PWEN BIT(0) /* only known on RZ/V2H(P) */ > + > /* Define some IRQ masks */ > /* This is the mask used at reset by the chip */ > #define TMIO_MASK_ALL 0x837f031d > -- > 2.34.1