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