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 RK3288_SOC_CON2                 0x24c
  43#define RK3288_SOC_CON2_FLASH0          BIT(7)
  44#define RK3288_SOC_FLASH_SUPPLY_NUM     2
  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        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_info(supply->iod->dev, "Setting to %d done\n", uV);
 147        return NOTIFY_OK;
 148}
 149
 150static void rk3288_iodomain_init(struct rockchip_iodomain *iod)
 151{
 152        int ret;
 153        u32 val;
 154
 155        /* if no flash supply we should leave things alone */
 156        if (!iod->supplies[RK3288_SOC_FLASH_SUPPLY_NUM].reg)
 157                return;
 158
 159        /*
 160         * set flash0 iodomain to also use this framework
 161         * instead of a special gpio.
 162         */
 163        val = RK3288_SOC_CON2_FLASH0 | (RK3288_SOC_CON2_FLASH0 << 16);
 164        ret = regmap_write(iod->grf, RK3288_SOC_CON2, val);
 165        if (ret < 0)
 166                dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
 167}
 168
 169static void rk3368_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[RK3368_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 = RK3368_SOC_CON15_FLASH0 | (RK3368_SOC_CON15_FLASH0 << 16);
 183        ret = regmap_write(iod->grf, RK3368_SOC_CON15, val);
 184        if (ret < 0)
 185                dev_warn(iod->dev, "couldn't update flash0 ctrl\n");
 186}
 187
 188static void rk3399_pmu_iodomain_init(struct rockchip_iodomain *iod)
 189{
 190        int ret;
 191        u32 val;
 192
 193        /* if no pmu io supply we should leave things alone */
 194        if (!iod->supplies[RK3399_PMUGRF_VSEL_SUPPLY_NUM].reg)
 195                return;
 196
 197        /*
 198         * set pmu io iodomain to also use this framework
 199         * instead of a special gpio.
 200         */
 201        val = RK3399_PMUGRF_CON0_VSEL | (RK3399_PMUGRF_CON0_VSEL << 16);
 202        ret = regmap_write(iod->grf, RK3399_PMUGRF_CON0, val);
 203        if (ret < 0)
 204                dev_warn(iod->dev, "couldn't update pmu io iodomain ctrl\n");
 205}
 206
 207/*
 208 * On the rk3188 the io-domains are handled by a shared register with the
 209 * lower 8 bits being still being continuing drive-strength settings.
 210 */
 211static const struct rockchip_iodomain_soc_data soc_data_rk3188 = {
 212        .grf_offset = 0x104,
 213        .supply_names = {
 214                NULL,
 215                NULL,
 216                NULL,
 217                NULL,
 218                NULL,
 219                NULL,
 220                NULL,
 221                NULL,
 222                "ap0",
 223                "ap1",
 224                "cif",
 225                "flash",
 226                "vccio0",
 227                "vccio1",
 228                "lcdc0",
 229                "lcdc1",
 230        },
 231};
 232
 233static const struct rockchip_iodomain_soc_data soc_data_rk3288 = {
 234        .grf_offset = 0x380,
 235        .supply_names = {
 236                "lcdc",         /* LCDC_VDD */
 237                "dvp",          /* DVPIO_VDD */
 238                "flash0",       /* FLASH0_VDD (emmc) */
 239                "flash1",       /* FLASH1_VDD (sdio1) */
 240                "wifi",         /* APIO3_VDD  (sdio0) */
 241                "bb",           /* APIO5_VDD */
 242                "audio",        /* APIO4_VDD */
 243                "sdcard",       /* SDMMC0_VDD (sdmmc) */
 244                "gpio30",       /* APIO1_VDD */
 245                "gpio1830",     /* APIO2_VDD */
 246        },
 247        .init = rk3288_iodomain_init,
 248};
 249
 250static const struct rockchip_iodomain_soc_data soc_data_rk3368 = {
 251        .grf_offset = 0x900,
 252        .supply_names = {
 253                NULL,           /* reserved */
 254                "dvp",          /* DVPIO_VDD */
 255                "flash0",       /* FLASH0_VDD (emmc) */
 256                "wifi",         /* APIO2_VDD (sdio0) */
 257                NULL,
 258                "audio",        /* APIO3_VDD */
 259                "sdcard",       /* SDMMC0_VDD (sdmmc) */
 260                "gpio30",       /* APIO1_VDD */
 261                "gpio1830",     /* APIO4_VDD (gpujtag) */
 262        },
 263        .init = rk3368_iodomain_init,
 264};
 265
 266static const struct rockchip_iodomain_soc_data soc_data_rk3368_pmu = {
 267        .grf_offset = 0x100,
 268        .supply_names = {
 269                NULL,
 270                NULL,
 271                NULL,
 272                NULL,
 273                "pmu",          /*PMU IO domain*/
 274                "vop",          /*LCDC IO domain*/
 275        },
 276};
 277
 278static const struct rockchip_iodomain_soc_data soc_data_rk3399 = {
 279        .grf_offset = 0xe640,
 280        .supply_names = {
 281                "bt656",                /* APIO2_VDD */
 282                "audio",                /* APIO5_VDD */
 283                "sdmmc",                /* SDMMC0_VDD */
 284                "gpio1830",             /* APIO4_VDD */
 285        },
 286};
 287
 288static const struct rockchip_iodomain_soc_data soc_data_rk3399_pmu = {
 289        .grf_offset = 0x180,
 290        .supply_names = {
 291                NULL,
 292                NULL,
 293                NULL,
 294                NULL,
 295                NULL,
 296                NULL,
 297                NULL,
 298                NULL,
 299                NULL,
 300                "pmu1830",              /* PMUIO2_VDD */
 301        },
 302        .init = rk3399_pmu_iodomain_init,
 303};
 304
 305static const struct of_device_id rockchip_iodomain_match[] = {
 306        {
 307                .compatible = "rockchip,rk3188-io-voltage-domain",
 308                .data = (void *)&soc_data_rk3188
 309        },
 310        {
 311                .compatible = "rockchip,rk3288-io-voltage-domain",
 312                .data = (void *)&soc_data_rk3288
 313        },
 314        {
 315                .compatible = "rockchip,rk3368-io-voltage-domain",
 316                .data = (void *)&soc_data_rk3368
 317        },
 318        {
 319                .compatible = "rockchip,rk3368-pmu-io-voltage-domain",
 320                .data = (void *)&soc_data_rk3368_pmu
 321        },
 322        {
 323                .compatible = "rockchip,rk3399-io-voltage-domain",
 324                .data = (void *)&soc_data_rk3399
 325        },
 326        {
 327                .compatible = "rockchip,rk3399-pmu-io-voltage-domain",
 328                .data = (void *)&soc_data_rk3399_pmu
 329        },
 330        { /* sentinel */ },
 331};
 332MODULE_DEVICE_TABLE(of, rockchip_iodomain_match);
 333
 334static int rockchip_iodomain_probe(struct platform_device *pdev)
 335{
 336        struct device_node *np = pdev->dev.of_node;
 337        const struct of_device_id *match;
 338        struct rockchip_iodomain *iod;
 339        struct device *parent;
 340        int i, ret = 0;
 341
 342        if (!np)
 343                return -ENODEV;
 344
 345        iod = devm_kzalloc(&pdev->dev, sizeof(*iod), GFP_KERNEL);
 346        if (!iod)
 347                return -ENOMEM;
 348
 349        iod->dev = &pdev->dev;
 350        platform_set_drvdata(pdev, iod);
 351
 352        match = of_match_node(rockchip_iodomain_match, np);
 353        iod->soc_data = (struct rockchip_iodomain_soc_data *)match->data;
 354
 355        parent = pdev->dev.parent;
 356        if (parent && parent->of_node) {
 357                iod->grf = syscon_node_to_regmap(parent->of_node);
 358        } else {
 359                dev_dbg(&pdev->dev, "falling back to old binding\n");
 360                iod->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
 361        }
 362
 363        if (IS_ERR(iod->grf)) {
 364                dev_err(&pdev->dev, "couldn't find grf regmap\n");
 365                return PTR_ERR(iod->grf);
 366        }
 367
 368        for (i = 0; i < MAX_SUPPLIES; i++) {
 369                const char *supply_name = iod->soc_data->supply_names[i];
 370                struct rockchip_iodomain_supply *supply = &iod->supplies[i];
 371                struct regulator *reg;
 372                int uV;
 373
 374                if (!supply_name)
 375                        continue;
 376
 377                reg = devm_regulator_get_optional(iod->dev, supply_name);
 378                if (IS_ERR(reg)) {
 379                        ret = PTR_ERR(reg);
 380
 381                        /* If a supply wasn't specified, that's OK */
 382                        if (ret == -ENODEV)
 383                                continue;
 384                        else if (ret != -EPROBE_DEFER)
 385                                dev_err(iod->dev, "couldn't get regulator %s\n",
 386                                        supply_name);
 387                        goto unreg_notify;
 388                }
 389
 390                /* set initial correct value */
 391                uV = regulator_get_voltage(reg);
 392
 393                /* must be a regulator we can get the voltage of */
 394                if (uV < 0) {
 395                        dev_err(iod->dev, "Can't determine voltage: %s\n",
 396                                supply_name);
 397                        goto unreg_notify;
 398                }
 399
 400                if (uV > MAX_VOLTAGE_3_3) {
 401                        dev_crit(iod->dev,
 402                                 "%d uV is too high. May damage SoC!\n",
 403                                 uV);
 404                        ret = -EINVAL;
 405                        goto unreg_notify;
 406                }
 407
 408                /* setup our supply */
 409                supply->idx = i;
 410                supply->iod = iod;
 411                supply->reg = reg;
 412                supply->nb.notifier_call = rockchip_iodomain_notify;
 413
 414                ret = rockchip_iodomain_write(supply, uV);
 415                if (ret) {
 416                        supply->reg = NULL;
 417                        goto unreg_notify;
 418                }
 419
 420                /* register regulator notifier */
 421                ret = regulator_register_notifier(reg, &supply->nb);
 422                if (ret) {
 423                        dev_err(&pdev->dev,
 424                                "regulator notifier request failed\n");
 425                        supply->reg = NULL;
 426                        goto unreg_notify;
 427                }
 428        }
 429
 430        if (iod->soc_data->init)
 431                iod->soc_data->init(iod);
 432
 433        return 0;
 434
 435unreg_notify:
 436        for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
 437                struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
 438
 439                if (io_supply->reg)
 440                        regulator_unregister_notifier(io_supply->reg,
 441                                                      &io_supply->nb);
 442        }
 443
 444        return ret;
 445}
 446
 447static int rockchip_iodomain_remove(struct platform_device *pdev)
 448{
 449        struct rockchip_iodomain *iod = platform_get_drvdata(pdev);
 450        int i;
 451
 452        for (i = MAX_SUPPLIES - 1; i >= 0; i--) {
 453                struct rockchip_iodomain_supply *io_supply = &iod->supplies[i];
 454
 455                if (io_supply->reg)
 456                        regulator_unregister_notifier(io_supply->reg,
 457                                                      &io_supply->nb);
 458        }
 459
 460        return 0;
 461}
 462
 463static struct platform_driver rockchip_iodomain_driver = {
 464        .probe   = rockchip_iodomain_probe,
 465        .remove  = rockchip_iodomain_remove,
 466        .driver  = {
 467                .name  = "rockchip-iodomain",
 468                .of_match_table = rockchip_iodomain_match,
 469        },
 470};
 471
 472module_platform_driver(rockchip_iodomain_driver);
 473
 474MODULE_DESCRIPTION("Rockchip IO-domain driver");
 475MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
 476MODULE_AUTHOR("Doug Anderson <dianders@chromium.org>");
 477MODULE_LICENSE("GPL v2");
 478