linux/drivers/power/avs/rockchip-io-domain.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Rockchip IO Voltage Domain driver
   4 *
   5 * Copyright 2014 MundoReader S.L.
   6 * Copyright 2014 Google, Inc.
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/err.h>
  12#include <linux/mfd/syscon.h>
  13#include <linux/of.h>
  14#include <linux/platform_device.h>
  15#include <linux/regmap.h>
  16#include <linux/regulator/consumer.h>
  17
  18#define MAX_SUPPLIES            16
  19
  20/*
  21 * The max voltage for 1.8V and 3.3V come from the Rockchip datasheet under
  22 * "Recommended Operating Conditions" for "Digital GPIO".   When the typical
  23 * is 3.3V the max is 3.6V.  When the typical is 1.8V the max is 1.98V.
  24 *
  25 * They are used like this:
  26 * - If the voltage on a rail is above the "1.8" voltage (1.98V) we'll tell the
  27 *   SoC we're at 3.3.
  28 * - If the voltage on a rail is above the "3.3" voltage (3.6V) we'll consider
  29 *   that to be an error.
  30 */
  31#define MAX_VOLTAGE_1_8         1980000
  32#define MAX_VOLTAGE_3_3         3600000
  33
  34#define PX30_IO_VSEL                    0x180
  35#define PX30_IO_VSEL_VCCIO6_SRC         BIT(0)
  36#define PX30_IO_VSEL_VCCIO6_SUPPLY_NUM  1
  37
  38#define RK3288_SOC_CON2                 0x24c
  39#define RK3288_SOC_CON2_FLASH0          BIT(7)
  40#define RK3288_SOC_FLASH_SUPPLY_NUM     2
  41
  42#define RK3328_SOC_CON4                 0x410
  43#define RK3328_SOC_CON4_VCCIO2          BIT(7)
  44#define RK3328_SOC_VCCIO2_SUPPLY_NUM    1
  45
  46#define RK3368_SOC_CON15                0x43c
  47#define RK3368_SOC_CON15_FLASH0         BIT(14)
  48#define RK3368_SOC_FLASH_SUPPLY_NUM     2
  49
  50#define RK3399_PMUGRF_CON0              0x180
  51#define RK3399_PMUGRF_CON0_VSEL         BIT(8)
  52#define RK3399_PMUGRF_VSEL_SUPPLY_NUM   9
  53
  54struct rockchip_iodomain;
  55
  56/**
  57 * @supplies: voltage settings matching the register bits.
  58 */
  59struct rockchip_iodomain_soc_data {
  60        int grf_offset;
  61        const char *supply_names[MAX_SUPPLIES];
  62        void (*init)(struct rockchip_iodomain *iod);
  63};
  64
  65struct rockchip_iodomain_supply {
  66        struct rockchip_iodomain *iod;
  67        struct regulator *reg;
  68        struct notifier_block nb;
  69        int idx;
  70};
  71
  72struct rockchip_iodomain {
  73        struct device *dev;
  74        struct regmap *grf;
  75        const struct rockchip_iodomain_soc_data *soc_data;
  76        struct rockchip_iodomain_supply supplies[MAX_SUPPLIES];
  77};
  78
  79static int rockchip_iodomain_write(struct rockchip_iodomain_supply *supply,
  80                                   int uV)
  81{
  82        struct rockchip_iodomain *iod = supply->iod;
  83        u32 val;
  84        int ret;
  85
  86        /* set value bit */
  87        val = (uV > MAX_VOLTAGE_1_8) ? 0 : 1;
  88        val <<= supply->idx;
  89
  90        /* apply hiword-mask */
  91        val |= (BIT(supply->idx) << 16);
  92
  93        ret = regmap_write(iod->grf, iod->soc_data->grf_offset, val);
  94        if (ret)
  95                dev_err(iod->dev, "Couldn't write to GRF\n");
  96
  97        return ret;
  98}
  99
 100static int rockchip_iodomain_notify(struct notifier_block *nb,
 101                                    unsigned long event,
 102                                    void *data)
 103{
 104        struct rockchip_iodomain_supply *supply =
 105                        container_of(nb, struct rockchip_iodomain_supply, nb);
 106        int uV;
 107        int ret;
 108
 109        /*
 110         * According to Rockchip it's important to keep the SoC IO domain
 111         * higher than (or equal to) the external voltage.  That means we need
 112         * to change it before external voltage changes happen in the case
 113         * of an increase.
 114         *
 115         * Note that in the "pre" change we pick the max possible voltage that
 116         * the regulator might end up at (the client requests a range and we
 117         * don't know for certain the exact voltage).  Right now we rely on the
 118         * slop in MAX_VOLTAGE_1_8 and MAX_VOLTAGE_3_3 to save us if clients
 119         * request something like a max of 3.6V when they really want 3.3V.
 120         * We could attempt to come up with better rules if this fails.
 121         */
 122        if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) {
 123                struct pre_voltage_change_data *pvc_data = data;
 124
 125                uV = max_t(unsigned long, pvc_data->old_uV, pvc_data->max_uV);
 126        } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE |
 127                            REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) {
 128                uV = (unsigned long)data;
 129        } else {
 130                return NOTIFY_OK;
 131        }
 132
 133        dev_dbg(supply->iod->dev, "Setting to %d\n", uV);
 134
 135        if (uV > MAX_VOLTAGE_3_3) {
 136                dev_err(supply->iod->dev, "Voltage too high: %d\n", uV);
 137
 138                if (event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
 139                        return NOTIFY_BAD;
 140        }
 141
 142        ret = rockchip_iodomain_write(supply, uV);
 143        if (ret && event == REGULATOR_EVENT_PRE_VOLTAGE_CHANGE)
 144                return NOTIFY_BAD;
 145
 146        dev_dbg(supply->iod->dev, "Setting to %d done\n", uV);
 147        return NOTIFY_OK;
 148}
 149
 150static void px30_iodomain_init(struct rockchip_iodomain *iod)
 151{
 152        int ret;
 153        u32 val;
 154
 155        /* if no VCCIO0 supply we should leave things alone */
 156        if (!iod->supplies[PX30_IO_VSEL_VCCIO6_SUPPLY_NUM].reg)
 157                return;
 158
 159        /*
 160         * set vccio0 iodomain to also use this framework
 161         * instead of a special gpio.
 162         */
 163        val = PX30_IO_VSEL_VCCIO6_SRC | (PX30_IO_VSEL_VCCIO6_SRC << 16);
 164        ret = regmap_write(iod->grf, PX30_IO_VSEL, val);
 165        if (ret < 0)
 166                dev_warn(iod->dev, "couldn't update vccio0 ctrl\n");
 167}
 168
 169static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
 170{
 171        int ret;
 172        u32 val;
 173
 174        /* if no flash supply we should leave things alone */
 175        if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
 176                return;
 177
 178        /*
 179         * set flash0 iodomain to also use this framework
 180         * instead of a special gpio.
 181         */
 182        val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
 183        ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
 184        if (ret < 0)
 185                dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
 186}
 187
 188static void rk3328_iodomain_init(struct rockchip_iodomain *iod)
 189{
 190        int ret;
 191        u32 val;
 192
 193        /* if no vccio2 supply we should leave things alone */
 194        if (!iod->supplies[RK3328_SOC_VCCIO2_SUPPLY_NUM].reg)
 195                return;
 196
 197        /*
 198         * set vccio2 iodomain to also use this framework
 199         * instead of a special gpio.
 200         */
 201        val = RK3328_SOC_CON4_VCCIO2 | (RK3328_SOC_CON4_VCCIO2 << 16);
 202        ret = regmap_write(iod->grf, RK3328_SOC_CON4, val);
 203        if (ret < 0)
 204                dev_warn(iod->dev, "couldn't update vccio2 vsel ctrl\n");
 205}
 206
 207static void rk3368_iodomain_init(struct rockchip_iodomain *iod)
 208{
 209        int ret;
 210        u32 val;
 211
 212        /* if no flash supply we should leave things alone */
 213        if (!iod->supplies[RK3368_SOC_FLASH_SUPPLY_NUM].reg)
 214                return;
 215
 216        /*
 217         * set flash0 iodomain to also use this framework
 218         * instead of a special gpio.
 219         */
 220        val = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
 221        ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
 222        if (ret < 0)
 223                dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
 224}
 225
 226static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
 227{
 228        int ret;
 229        u32 val;
 230
 231        /* if no pmu io supply we should leave things alone */
 232        if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
 233                return;
 234
 235        /*
 236         * set pmu io iodomain to also use this framework
 237         * instead of a special gpio.
 238         */
 239        val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
 240        ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
 241        if (ret < 0)
 242                dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
 243}
 244
 245static const struct rockchip_iodomain_soc_data soc_data_px30 = {
 246        .grf_offset = 0x180,
 247        .supply_names = {
 248                NULL,
 249                "vccio6",
 250                "vccio1",
 251                "vccio2",
 252                "vccio3",
 253                "vccio4",
 254                "vccio5",
 255                "vccio-oscgpi",
 256        },
 257        .init = px30_iodomain_init,
 258};
 259
 260static const struct rockchip_iodomain_soc_data soc_data_px30_pmu = {
 261        .grf_offset = 0x100,
 262        .supply_names = {
 263                NULL,
 264                NULL,
 265                NULL,
 266                NULL,
 267                NULL,
 268                NULL,
 269                NULL,
 270                NULL,
 271                NULL,
 272                NULL,
 273                NULL,
 274                NULL,
 275                NULL,
 276                NULL,
 277                "pmuio1",
 278                "pmuio2",
 279        },
 280};
 281
 282/*
 283 * On the rk3188 the io-domains are handled by a shared register with the
 284 * lower 8 bits being still being continuing drive-strength settings.
 285 */
 286static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
 287        .grf_offset = 0x104,
 288        .supply_names = {
 289                NULL,
 290                NULL,
 291                NULL,
 292                NULL,
 293                NULL,
 294                NULL,
 295                NULL,
 296                NULL,
 297                "ap0",
 298                "ap1",
 299                "cif",
 300                "flash",
 301                "vccio0",
 302                "vccio1",
 303                "lcdc0",
 304                "lcdc1",
 305        },
 306};
 307
 308static const struct rockchip_iodomain_soc_data soc_data_rk3228 = {
 309        .grf_offset = 0x418,
 310        .supply_names = {
 311                "vccio1",
 312                "vccio2",
 313                "vccio3",
 314                "vccio4",
 315        },
 316};
 317
 318static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
 319        .grf_offset = 0x380,
 320        .supply_names = {
 321                "lcdc",         /* LCDC_VDD */
 322                "dvp",          /* DVPIO_VDD */
 323                "flash0",       /* FLASH0_VDD (emmc) */
 324                "flash1",       /* FLASH1_VDD (sdio1) */
 325                "wifi",         /* APIO3_VDD  (sdio0) */
 326                "bb",           /* APIO5_VDD */
 327                "audio",        /* APIO4_VDD */
 328                "sdcard",       /* SDMMC0_VDD (sdmmc) */
 329                "gpio30",       /* APIO1_VDD */
 330                "gpio1830",     /* APIO2_VDD */
 331        },
 332        .init = rk3288_iodomain_init,
 333};
 334
 335static const struct rockchip_iodomain_soc_data soc_data_rk3328 = {
 336        .grf_offset = 0x410,
 337        .supply_names = {
 338                "vccio1",
 339                "vccio2",
 340                "vccio3",
 341                "vccio4",
 342                "vccio5",
 343                "vccio6",
 344                "pmuio",
 345        },
 346        .init = rk3328_iodomain_init,
 347};
 348
 349static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
 350        .grf_offset = 0x900,
 351        .supply_names = {
 352                NULL,           /* reserved */
 353                "dvp",          /* DVPIO_VDD */
 354                "flash0",       /* FLASH0_VDD (emmc) */
 355                "wifi",         /* APIO2_VDD (sdio0) */
 356                NULL,
 357                "audio",        /* APIO3_VDD */
 358                "sdcard",       /* SDMMC0_VDD (sdmmc) */
 359                "gpio30",       /* APIO1_VDD */
 360                "gpio1830",     /* APIO4_VDD (gpujtag) */
 361        },
 362        .init = rk3368_iodomain_init,
 363};
 364
 365static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
 366        .grf_offset = 0x100,
 367        .supply_names = {
 368                NULL,
 369                NULL,
 370                NULL,
 371                NULL,
 372                "pmu",          /*PMU IO domain*/
 373                "vop",          /*LCDC IO domain*/
 374        },
 375};
 376
 377static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
 378        .grf_offset = 0xe640,
 379        .supply_names = {
 380                "bt656",                /* APIO2_VDD */
 381                "audio",                /* APIO5_VDD */
 382                "sdmmc",                /* SDMMC0_VDD */
 383                "gpio1830",             /* APIO4_VDD */
 384        },
 385};
 386
 387static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
 388        .grf_offset = 0x180,
 389        .supply_names = {
 390                NULL,
 391                NULL,
 392                NULL,
 393                NULL,
 394                NULL,
 395                NULL,
 396                NULL,
 397                NULL,
 398                NULL,
 399                "pmu1830",              /* PMUIO2_VDD */
 400        },
 401        .init = rk3399_pmu_iodomain_init,
 402};
 403
 404static const struct rockchip_iodomain_soc_data soc_data_rv1108 = {
 405        .grf_offset = 0x404,
 406        .supply_names = {
 407                NULL,
 408                NULL,
 409                NULL,
 410                NULL,
 411                NULL,
 412                NULL,
 413                NULL,
 414                NULL,
 415                NULL,
 416                NULL,
 417                NULL,
 418                "vccio1",
 419                "vccio2",
 420                "vccio3",
 421                "vccio5",
 422                "vccio6",
 423        },
 424
 425};
 426
 427static const struct rockchip_iodomain_soc_data soc_data_rv1108_pmu = {
 428        .grf_offset = 0x104,
 429        .supply_names = {
 430                "pmu",
 431        },
 432};
 433
 434static const struct of_device_id rockchip_iodomain_match[] = {
 435        {
 436                .compatible = "rockchip,px30-io-voltage-domain",
 437                .data = (void *)&soc_data_px30
 438        },
 439        {
 440                .compatible = "rockchip,px30-pmu-io-voltage-domain",
 441                .data = (void *)&soc_data_px30_pmu
 442        },
 443        {
 444                .compatible = "rockchip,rk3188-io-voltage-domain",
 445                .data = &soc_data_rk3188
 446        },
 447        {
 448                .compatible = "rockchip,rk3228-io-voltage-domain",
 449                .data = &soc_data_rk3228
 450        },
 451        {
 452                .compatible = "rockchip,rk3288-io-voltage-domain",
 453                .data = &soc_data_rk3288
 454        },
 455        {
 456                .compatible = "rockchip,rk3328-io-voltage-domain",
 457                .data = &soc_data_rk3328
 458        },
 459        {
 460                .compatible = "rockchip,rk3368-io-voltage-domain",
 461                .data = &soc_data_rk3368
 462        },
 463        {
 464                .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
 465                .data = &soc_data_rk3368_pmu
 466        },
 467        {
 468                .compatible = "rockchip,rk3399-io-voltage-domain",
 469                .data = &soc_data_rk3399
 470        },
 471        {
 472                .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
 473                .data = &soc_data_rk3399_pmu
 474        },
 475        {
 476                .compatible = "rockchip,rv1108-io-voltage-domain",
 477                .data = &soc_data_rv1108
 478        },
 479        {
 480                .compatible = "rockchip,rv1108-pmu-io-voltage-domain",
 481                .data = &soc_data_rv1108_pmu
 482        },
 483        { /* sentinel */ },
 484};
 485MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
 486
 487static int rockchip_iodomain_probe(struct platform_device *pdev)
 488{
 489        struct device_node *np = pdev->dev.of_node;
 490        const struct of_device_id *match;
 491        struct rockchip_iodomain *iod;
 492        struct device *parent;
 493        int i, ret = 0;
 494
 495        if (!np)
 496                return -ENODEV;
 497
 498        iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
 499        if (!iod)
 500                return -ENOMEM;
 501
 502        iod->dev = &pdev->dev;
 503        platform_set_drvdata(pdev, iod);
 504
 505        match = of_match_node(rockchip_iodomain_match, np);
 506        iod->soc_data = match->data;
 507
 508        parent = pdev->dev.parent;
 509        if (parent && parent->of_node) {
 510                iod->grf = syscon_node_to_regmap(parent->of_node);
 511        } else {
 512                dev_dbg(&pdev->dev, "falling back to old binding\n");
 513                iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 514        }
 515
 516        if (IS_ERR(iod->grf)) {
 517                dev_err(&pdev->dev, "couldn't find grf regmap\n");
 518                return PTR_ERR(iod->grf);
 519        }
 520
 521        for (i = 0; i < MAX_SUPPLIES; i++) {
 522                const char *supply_name = iod->soc_data->supply_names[i];
 523                struct rockchip_iodomain_supply *supply = &iod->supplies[i];
 524                struct regulator *reg;
 525                int uV;
 526
 527                if (!supply_name)
 528                        continue;
 529
 530                reg = devm_regulator_get_optional(iod->dev, supply_name);
 531                if (IS_ERR(reg)) {
 532                        ret = PTR_ERR(reg);
 533
 534                        /* If a supply wasn't specified, that's OK */
 535                        if (ret == -ENODEV)
 536                                continue;
 537                        else if (ret != -EPROBE_DEFER)
 538                                dev_err(iod->dev, "couldn't get regulator %s\n",
 539                                        supply_name);
 540                        goto unreg_notify;
 541                }
 542
 543                /* set initial correct value */
 544                uV = regulator_get_voltage(reg);
 545
 546                /* must be a regulator we can get the voltage of */
 547                if (uV < 0) {
 548                        dev_err(iod->dev, "Can't determine voltage: %s\n",
 549                                supply_name);
 550                        goto unreg_notify;
 551                }
 552
 553                if (uV > MAX_VOLTAGE_3_3) {
 554                        dev_crit(iod->dev,
 555                                 "%d uV is too high. May damage SoC!\n",
 556                                 uV);
 557                        ret = -EINVAL;
 558                        goto unreg_notify;
 559                }
 560
 561                /* setup our supply */
 562                supply->idx = i;
 563                supply->iod = iod;
 564                supply->reg = reg;
 565                supply->nb.notifier_call = rockchip_iodomain_notify;
 566
 567                ret = rockchip_iodomain_write(supply, uV);
 568                if (ret) {
 569                        supply->reg = NULL;
 570                        goto unreg_notify;
 571                }
 572
 573                /* register regulator notifier */
 574                ret = regulator_register_notifier(reg, &supply->nb);
 575                if (ret) {
 576                        dev_err(&pdev->dev,
 577                                "regulator notifier request failed\n");
 578                        supply->reg = NULL;
 579                        goto unreg_notify;
 580                }
 581        }
 582
 583        if (iod->soc_data->init)
 584                iod->soc_data->init(iod);
 585
 586        return 0;
 587
 588unreg_notify:
 589        for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
 590                struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
 591
 592                if (io_supply->reg)
 593                        regulator_unregister_notifier(io_supply->reg,
 594                                                      &io_supply->nb);
 595        }
 596
 597        return ret;
 598}
 599
 600static int rockchip_iodomain_remove(struct platform_device *pdev)
 601{
 602        struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
 603        int i;
 604
 605        for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
 606                struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
 607
 608                if (io_supply->reg)
 609                        regulator_unregister_notifier(io_supply->reg,
 610                                                      &io_supply->nb);
 611        }
 612
 613        return 0;
 614}
 615
 616static struct platform_driver rockchip_iodomain_driver = {
 617        .probe   = rockchip_iodomain_probe,
 618        .remove  = rockchip_iodomain_remove,
 619        .driver  = {
 620                .name  = "rockchip-iodomain",
 621                .of_match_table = rockchip_iodomain_match,
 622        },
 623};
 624
 625module_platform_driver(rockchip_iodomain_driver);
 626
 627MODULE_DESCRIPTION("Rockchip IO-domain driver");
 628MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
 629MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
 630MODULE_LICENSE("GPL v2");
 631