|
32 | 32 | #include <linux/platform_device.h>
|
33 | 33 | #include <linux/pm_domain.h>
|
34 | 34 | #include <linux/regulator/consumer.h>
|
| 35 | +#include <linux/regulator/driver.h> |
| 36 | +#include <linux/regulator/of_regulator.h> |
35 | 37 | #include <linux/reset.h>
|
36 | 38 | #include <linux/sh_dma.h>
|
37 | 39 | #include <linux/slab.h>
|
@@ -581,12 +583,24 @@ static void renesas_sdhi_reset(struct tmio_mmc_host *host, bool preserve)
|
581 | 583 |
|
582 | 584 | if (!preserve) {
|
583 | 585 | if (priv->rstc) {
|
| 586 | + u32 sd_status; |
| 587 | + /* |
| 588 | + * HW reset might have toggled the regulator state in |
| 589 | + * HW which regulator core might be unaware of so save |
| 590 | + * and restore the regulator state during HW reset. |
| 591 | + */ |
| 592 | + if (priv->rdev) |
| 593 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 594 | + |
584 | 595 | reset_control_reset(priv->rstc);
|
585 | 596 | /* Unknown why but without polling reset status, it will hang */
|
586 | 597 | read_poll_timeout(reset_control_status, ret, ret == 0, 1, 100,
|
587 | 598 | false, priv->rstc);
|
588 | 599 | /* At least SDHI_VER_GEN2_SDR50 needs manual release of reset */
|
589 | 600 | sd_ctrl_write16(host, CTL_RESET_SD, 0x0001);
|
| 601 | + if (priv->rdev) |
| 602 | + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); |
| 603 | + |
590 | 604 | priv->needs_adjust_hs400 = false;
|
591 | 605 | renesas_sdhi_set_clock(host, host->clk_cache);
|
592 | 606 |
|
@@ -904,14 +918,113 @@ static void renesas_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
|
904 | 918 | renesas_sdhi_sdbuf_width(host, enable ? width : 16);
|
905 | 919 | }
|
906 | 920 |
|
| 921 | +static const unsigned int renesas_sdhi_vqmmc_voltages[] = { |
| 922 | + 3300000, 1800000 |
| 923 | +}; |
| 924 | + |
| 925 | +static int renesas_sdhi_regulator_disable(struct regulator_dev *rdev) |
| 926 | +{ |
| 927 | + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); |
| 928 | + u32 sd_status; |
| 929 | + |
| 930 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 931 | + sd_status &= ~SD_STATUS_PWEN; |
| 932 | + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); |
| 933 | + |
| 934 | + return 0; |
| 935 | +} |
| 936 | + |
| 937 | +static int renesas_sdhi_regulator_enable(struct regulator_dev *rdev) |
| 938 | +{ |
| 939 | + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); |
| 940 | + u32 sd_status; |
| 941 | + |
| 942 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 943 | + sd_status |= SD_STATUS_PWEN; |
| 944 | + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); |
| 945 | + |
| 946 | + return 0; |
| 947 | +} |
| 948 | + |
| 949 | +static int renesas_sdhi_regulator_is_enabled(struct regulator_dev *rdev) |
| 950 | +{ |
| 951 | + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); |
| 952 | + u32 sd_status; |
| 953 | + |
| 954 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 955 | + |
| 956 | + return (sd_status & SD_STATUS_PWEN) ? 1 : 0; |
| 957 | +} |
| 958 | + |
| 959 | +static int renesas_sdhi_regulator_get_voltage(struct regulator_dev *rdev) |
| 960 | +{ |
| 961 | + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); |
| 962 | + u32 sd_status; |
| 963 | + |
| 964 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 965 | + |
| 966 | + return (sd_status & SD_STATUS_IOVS) ? 1800000 : 3300000; |
| 967 | +} |
| 968 | + |
| 969 | +static int renesas_sdhi_regulator_set_voltage(struct regulator_dev *rdev, |
| 970 | + int min_uV, int max_uV, |
| 971 | + unsigned int *selector) |
| 972 | +{ |
| 973 | + struct tmio_mmc_host *host = rdev_get_drvdata(rdev); |
| 974 | + u32 sd_status; |
| 975 | + |
| 976 | + sd_status = sd_ctrl_read32(host, CTL_SD_STATUS); |
| 977 | + if (min_uV >= 1700000 && max_uV <= 1950000) { |
| 978 | + sd_status |= SD_STATUS_IOVS; |
| 979 | + *selector = 1; |
| 980 | + } else { |
| 981 | + sd_status &= ~SD_STATUS_IOVS; |
| 982 | + *selector = 0; |
| 983 | + } |
| 984 | + sd_ctrl_write32(host, CTL_SD_STATUS, sd_status); |
| 985 | + |
| 986 | + return 0; |
| 987 | +} |
| 988 | + |
| 989 | +static int renesas_sdhi_regulator_list_voltage(struct regulator_dev *rdev, |
| 990 | + unsigned int selector) |
| 991 | +{ |
| 992 | + if (selector >= ARRAY_SIZE(renesas_sdhi_vqmmc_voltages)) |
| 993 | + return -EINVAL; |
| 994 | + |
| 995 | + return renesas_sdhi_vqmmc_voltages[selector]; |
| 996 | +} |
| 997 | + |
| 998 | +static const struct regulator_ops renesas_sdhi_regulator_voltage_ops = { |
| 999 | + .enable = renesas_sdhi_regulator_enable, |
| 1000 | + .disable = renesas_sdhi_regulator_disable, |
| 1001 | + .is_enabled = renesas_sdhi_regulator_is_enabled, |
| 1002 | + .list_voltage = renesas_sdhi_regulator_list_voltage, |
| 1003 | + .get_voltage = renesas_sdhi_regulator_get_voltage, |
| 1004 | + .set_voltage = renesas_sdhi_regulator_set_voltage, |
| 1005 | +}; |
| 1006 | + |
| 1007 | +static const struct regulator_desc renesas_sdhi_vqmmc_regulator = { |
| 1008 | + .name = "sdhi-vqmmc-regulator", |
| 1009 | + .of_match = of_match_ptr("vqmmc-regulator"), |
| 1010 | + .type = REGULATOR_VOLTAGE, |
| 1011 | + .owner = THIS_MODULE, |
| 1012 | + .ops = &renesas_sdhi_regulator_voltage_ops, |
| 1013 | + .volt_table = renesas_sdhi_vqmmc_voltages, |
| 1014 | + .n_voltages = ARRAY_SIZE(renesas_sdhi_vqmmc_voltages), |
| 1015 | +}; |
| 1016 | + |
907 | 1017 | int renesas_sdhi_probe(struct platform_device *pdev,
|
908 | 1018 | const struct tmio_mmc_dma_ops *dma_ops,
|
909 | 1019 | const struct renesas_sdhi_of_data *of_data,
|
910 | 1020 | const struct renesas_sdhi_quirks *quirks)
|
911 | 1021 | {
|
912 | 1022 | struct tmio_mmc_data *mmd = pdev->dev.platform_data;
|
913 | 1023 | struct tmio_mmc_data *mmc_data;
|
| 1024 | + struct regulator_config rcfg = { .dev = &pdev->dev, }; |
| 1025 | + struct regulator_dev *rdev; |
914 | 1026 | struct renesas_sdhi_dma *dma_priv;
|
| 1027 | + struct device *dev = &pdev->dev; |
915 | 1028 | struct tmio_mmc_host *host;
|
916 | 1029 | struct renesas_sdhi *priv;
|
917 | 1030 | int num_irqs, irq, ret, i;
|
@@ -1053,6 +1166,23 @@ int renesas_sdhi_probe(struct platform_device *pdev,
|
1053 | 1166 | if (ret)
|
1054 | 1167 | goto efree;
|
1055 | 1168 |
|
| 1169 | + rcfg.of_node = of_get_child_by_name(dev->of_node, "vqmmc-regulator"); |
| 1170 | + if (!of_device_is_available(rcfg.of_node)) { |
| 1171 | + of_node_put(rcfg.of_node); |
| 1172 | + rcfg.of_node = NULL; |
| 1173 | + } |
| 1174 | + |
| 1175 | + if (rcfg.of_node) { |
| 1176 | + rcfg.driver_data = priv->host; |
| 1177 | + rdev = devm_regulator_register(dev, &renesas_sdhi_vqmmc_regulator, &rcfg); |
| 1178 | + of_node_put(rcfg.of_node); |
| 1179 | + if (IS_ERR(rdev)) { |
| 1180 | + dev_err(dev, "regulator register failed err=%ld", PTR_ERR(rdev)); |
| 1181 | + goto efree; |
| 1182 | + } |
| 1183 | + priv->rdev = rdev; |
| 1184 | + } |
| 1185 | + |
1056 | 1186 | ver = sd_ctrl_read16(host, CTL_VERSION);
|
1057 | 1187 | /* GEN2_SDR104 is first known SDHI to use 32bit block count */
|
1058 | 1188 | if (ver < SDHI_VER_GEN2_SDR104 && mmc_data->max_blk_count > U16_MAX)
|
|
0 commit comments