linux/drivers/regulator/act8865-regulator.c
<<
>>
Prefs
   1/*
   2 * act8865-regulator.c - Voltage regulation for active-semi ACT88xx PMUs
   3 *
   4 * http://www.active-semi.com/products/power-management-units/act88xx/
   5 *
   6 * Copyright (C) 2013 Atmel Corporation
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/init.h>
  21#include <linux/i2c.h>
  22#include <linux/err.h>
  23#include <linux/platform_device.h>
  24#include <linux/regulator/driver.h>
  25#include <linux/regulator/act8865.h>
  26#include <linux/of.h>
  27#include <linux/of_device.h>
  28#include <linux/regulator/of_regulator.h>
  29#include <linux/regmap.h>
  30
  31/*
  32 * ACT8846 Global Register Map.
  33 */
  34#define ACT8846_SYS0            0x00
  35#define ACT8846_SYS1            0x01
  36#define ACT8846_REG1_VSET       0x10
  37#define ACT8846_REG1_CTRL       0x12
  38#define ACT8846_REG2_VSET0      0x20
  39#define ACT8846_REG2_VSET1      0x21
  40#define ACT8846_REG2_CTRL       0x22
  41#define ACT8846_REG3_VSET0      0x30
  42#define ACT8846_REG3_VSET1      0x31
  43#define ACT8846_REG3_CTRL       0x32
  44#define ACT8846_REG4_VSET0      0x40
  45#define ACT8846_REG4_VSET1      0x41
  46#define ACT8846_REG4_CTRL       0x42
  47#define ACT8846_REG5_VSET       0x50
  48#define ACT8846_REG5_CTRL       0x51
  49#define ACT8846_REG6_VSET       0x58
  50#define ACT8846_REG6_CTRL       0x59
  51#define ACT8846_REG7_VSET       0x60
  52#define ACT8846_REG7_CTRL       0x61
  53#define ACT8846_REG8_VSET       0x68
  54#define ACT8846_REG8_CTRL       0x69
  55#define ACT8846_REG9_VSET       0x70
  56#define ACT8846_REG9_CTRL       0x71
  57#define ACT8846_REG10_VSET      0x80
  58#define ACT8846_REG10_CTRL      0x81
  59#define ACT8846_REG11_VSET      0x90
  60#define ACT8846_REG11_CTRL      0x91
  61#define ACT8846_REG12_VSET      0xa0
  62#define ACT8846_REG12_CTRL      0xa1
  63#define ACT8846_REG13_CTRL      0xb1
  64#define ACT8846_GLB_OFF_CTRL    0xc3
  65#define ACT8846_OFF_SYSMASK     0x18
  66
  67/*
  68 * ACT8865 Global Register Map.
  69 */
  70#define ACT8865_SYS_MODE        0x00
  71#define ACT8865_SYS_CTRL        0x01
  72#define ACT8865_DCDC1_VSET1     0x20
  73#define ACT8865_DCDC1_VSET2     0x21
  74#define ACT8865_DCDC1_CTRL      0x22
  75#define ACT8865_DCDC2_VSET1     0x30
  76#define ACT8865_DCDC2_VSET2     0x31
  77#define ACT8865_DCDC2_CTRL      0x32
  78#define ACT8865_DCDC3_VSET1     0x40
  79#define ACT8865_DCDC3_VSET2     0x41
  80#define ACT8865_DCDC3_CTRL      0x42
  81#define ACT8865_LDO1_VSET       0x50
  82#define ACT8865_LDO1_CTRL       0x51
  83#define ACT8865_LDO2_VSET       0x54
  84#define ACT8865_LDO2_CTRL       0x55
  85#define ACT8865_LDO3_VSET       0x60
  86#define ACT8865_LDO3_CTRL       0x61
  87#define ACT8865_LDO4_VSET       0x64
  88#define ACT8865_LDO4_CTRL       0x65
  89#define ACT8865_MSTROFF         0x20
  90
  91/*
  92 * Field Definitions.
  93 */
  94#define ACT8865_ENA             0x80    /* ON - [7] */
  95#define ACT8865_VSEL_MASK       0x3F    /* VSET - [5:0] */
  96
  97/*
  98 * ACT8865 voltage number
  99 */
 100#define ACT8865_VOLTAGE_NUM     64
 101
 102struct act8865 {
 103        struct regmap *regmap;
 104        int off_reg;
 105        int off_mask;
 106};
 107
 108static const struct regmap_config act8865_regmap_config = {
 109        .reg_bits = 8,
 110        .val_bits = 8,
 111};
 112
 113static const struct regulator_linear_range act8865_voltage_ranges[] = {
 114        REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000),
 115        REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000),
 116        REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000),
 117};
 118
 119static struct regulator_ops act8865_ops = {
 120        .list_voltage           = regulator_list_voltage_linear_range,
 121        .map_voltage            = regulator_map_voltage_linear_range,
 122        .get_voltage_sel        = regulator_get_voltage_sel_regmap,
 123        .set_voltage_sel        = regulator_set_voltage_sel_regmap,
 124        .enable                 = regulator_enable_regmap,
 125        .disable                = regulator_disable_regmap,
 126        .is_enabled             = regulator_is_enabled_regmap,
 127};
 128
 129#define ACT88xx_REG(_name, _family, _id, _vsel_reg)                     \
 130        [_family##_ID_##_id] = {                                        \
 131                .name                   = _name,                        \
 132                .id                     = _family##_ID_##_id,           \
 133                .type                   = REGULATOR_VOLTAGE,            \
 134                .ops                    = &act8865_ops,                 \
 135                .n_voltages             = ACT8865_VOLTAGE_NUM,          \
 136                .linear_ranges          = act8865_voltage_ranges,       \
 137                .n_linear_ranges        = ARRAY_SIZE(act8865_voltage_ranges), \
 138                .vsel_reg               = _family##_##_id##_##_vsel_reg, \
 139                .vsel_mask              = ACT8865_VSEL_MASK,            \
 140                .enable_reg             = _family##_##_id##_CTRL,       \
 141                .enable_mask            = ACT8865_ENA,                  \
 142                .owner                  = THIS_MODULE,                  \
 143        }
 144
 145static const struct regulator_desc act8846_regulators[] = {
 146        ACT88xx_REG("REG1", ACT8846, REG1, VSET),
 147        ACT88xx_REG("REG2", ACT8846, REG2, VSET0),
 148        ACT88xx_REG("REG3", ACT8846, REG3, VSET0),
 149        ACT88xx_REG("REG4", ACT8846, REG4, VSET0),
 150        ACT88xx_REG("REG5", ACT8846, REG5, VSET),
 151        ACT88xx_REG("REG6", ACT8846, REG6, VSET),
 152        ACT88xx_REG("REG7", ACT8846, REG7, VSET),
 153        ACT88xx_REG("REG8", ACT8846, REG8, VSET),
 154        ACT88xx_REG("REG9", ACT8846, REG9, VSET),
 155        ACT88xx_REG("REG10", ACT8846, REG10, VSET),
 156        ACT88xx_REG("REG11", ACT8846, REG11, VSET),
 157        ACT88xx_REG("REG12", ACT8846, REG12, VSET),
 158};
 159
 160static const struct regulator_desc act8865_regulators[] = {
 161        ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1),
 162        ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1),
 163        ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1),
 164        ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET),
 165        ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET),
 166        ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET),
 167        ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET),
 168};
 169
 170#ifdef CONFIG_OF
 171static const struct of_device_id act8865_dt_ids[] = {
 172        { .compatible = "active-semi,act8846", .data = (void *)ACT8846 },
 173        { .compatible = "active-semi,act8865", .data = (void *)ACT8865 },
 174        { }
 175};
 176MODULE_DEVICE_TABLE(of, act8865_dt_ids);
 177
 178static struct of_regulator_match act8846_matches[] = {
 179        [ACT8846_ID_REG1]       = { .name = "REG1" },
 180        [ACT8846_ID_REG2]       = { .name = "REG2" },
 181        [ACT8846_ID_REG3]       = { .name = "REG3" },
 182        [ACT8846_ID_REG4]       = { .name = "REG4" },
 183        [ACT8846_ID_REG5]       = { .name = "REG5" },
 184        [ACT8846_ID_REG6]       = { .name = "REG6" },
 185        [ACT8846_ID_REG7]       = { .name = "REG7" },
 186        [ACT8846_ID_REG8]       = { .name = "REG8" },
 187        [ACT8846_ID_REG9]       = { .name = "REG9" },
 188        [ACT8846_ID_REG10]      = { .name = "REG10" },
 189        [ACT8846_ID_REG11]      = { .name = "REG11" },
 190        [ACT8846_ID_REG12]      = { .name = "REG12" },
 191};
 192
 193static struct of_regulator_match act8865_matches[] = {
 194        [ACT8865_ID_DCDC1]      = { .name = "DCDC_REG1"},
 195        [ACT8865_ID_DCDC2]      = { .name = "DCDC_REG2"},
 196        [ACT8865_ID_DCDC3]      = { .name = "DCDC_REG3"},
 197        [ACT8865_ID_LDO1]       = { .name = "LDO_REG1"},
 198        [ACT8865_ID_LDO2]       = { .name = "LDO_REG2"},
 199        [ACT8865_ID_LDO3]       = { .name = "LDO_REG3"},
 200        [ACT8865_ID_LDO4]       = { .name = "LDO_REG4"},
 201};
 202
 203static int act8865_pdata_from_dt(struct device *dev,
 204                                 struct device_node **of_node,
 205                                 struct act8865_platform_data *pdata,
 206                                 unsigned long type)
 207{
 208        int matched, i, num_matches;
 209        struct device_node *np;
 210        struct act8865_regulator_data *regulator;
 211        struct of_regulator_match *matches;
 212
 213        np = of_get_child_by_name(dev->of_node, "regulators");
 214        if (!np) {
 215                dev_err(dev, "missing 'regulators' subnode in DT\n");
 216                return -EINVAL;
 217        }
 218
 219        switch (type) {
 220        case ACT8846:
 221                matches = act8846_matches;
 222                num_matches = ARRAY_SIZE(act8846_matches);
 223                break;
 224        case ACT8865:
 225                matches = act8865_matches;
 226                num_matches = ARRAY_SIZE(act8865_matches);
 227                break;
 228        default:
 229                dev_err(dev, "invalid device id %lu\n", type);
 230                return -EINVAL;
 231        }
 232
 233        matched = of_regulator_match(dev, np, matches, num_matches);
 234        of_node_put(np);
 235        if (matched <= 0)
 236                return matched;
 237
 238        pdata->regulators = devm_kzalloc(dev,
 239                                         sizeof(struct act8865_regulator_data) *
 240                                         num_matches, GFP_KERNEL);
 241        if (!pdata->regulators)
 242                return -ENOMEM;
 243
 244        pdata->num_regulators = num_matches;
 245        regulator = pdata->regulators;
 246
 247        for (i = 0; i < num_matches; i++) {
 248                regulator->id = i;
 249                regulator->name = matches[i].name;
 250                regulator->platform_data = matches[i].init_data;
 251                of_node[i] = matches[i].of_node;
 252                regulator++;
 253        }
 254
 255        return 0;
 256}
 257#else
 258static inline int act8865_pdata_from_dt(struct device *dev,
 259                                        struct device_node **of_node,
 260                                        struct act8865_platform_data *pdata,
 261                                        unsigned long type)
 262{
 263        return 0;
 264}
 265#endif
 266
 267static struct regulator_init_data
 268*act8865_get_init_data(int id, struct act8865_platform_data *pdata)
 269{
 270        int i;
 271
 272        if (!pdata)
 273                return NULL;
 274
 275        for (i = 0; i < pdata->num_regulators; i++) {
 276                if (pdata->regulators[i].id == id)
 277                        return pdata->regulators[i].platform_data;
 278        }
 279
 280        return NULL;
 281}
 282
 283static struct i2c_client *act8865_i2c_client;
 284static void act8865_power_off(void)
 285{
 286        struct act8865 *act8865;
 287
 288        act8865 = i2c_get_clientdata(act8865_i2c_client);
 289        regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask);
 290        while (1);
 291}
 292
 293static int act8865_pmic_probe(struct i2c_client *client,
 294                              const struct i2c_device_id *i2c_id)
 295{
 296        static const struct regulator_desc *regulators;
 297        struct act8865_platform_data pdata_of, *pdata;
 298        struct device *dev = &client->dev;
 299        struct device_node **of_node;
 300        int i, ret, num_regulators;
 301        struct act8865 *act8865;
 302        unsigned long type;
 303        int off_reg, off_mask;
 304
 305        pdata = dev_get_platdata(dev);
 306
 307        if (dev->of_node && !pdata) {
 308                const struct of_device_id *id;
 309
 310                id = of_match_device(of_match_ptr(act8865_dt_ids), dev);
 311                if (!id)
 312                        return -ENODEV;
 313
 314                type = (unsigned long) id->data;
 315        } else {
 316                type = i2c_id->driver_data;
 317        }
 318
 319        switch (type) {
 320        case ACT8846:
 321                regulators = act8846_regulators;
 322                num_regulators = ARRAY_SIZE(act8846_regulators);
 323                off_reg = ACT8846_GLB_OFF_CTRL;
 324                off_mask = ACT8846_OFF_SYSMASK;
 325                break;
 326        case ACT8865:
 327                regulators = act8865_regulators;
 328                num_regulators = ARRAY_SIZE(act8865_regulators);
 329                off_reg = ACT8865_SYS_CTRL;
 330                off_mask = ACT8865_MSTROFF;
 331                break;
 332        default:
 333                dev_err(dev, "invalid device id %lu\n", type);
 334                return -EINVAL;
 335        }
 336
 337        of_node = devm_kzalloc(dev, sizeof(struct device_node *) *
 338                               num_regulators, GFP_KERNEL);
 339        if (!of_node)
 340                return -ENOMEM;
 341
 342        if (dev->of_node && !pdata) {
 343                ret = act8865_pdata_from_dt(dev, of_node, &pdata_of, type);
 344                if (ret < 0)
 345                        return ret;
 346
 347                pdata = &pdata_of;
 348        }
 349
 350        if (pdata->num_regulators > num_regulators) {
 351                dev_err(dev, "too many regulators: %d\n",
 352                        pdata->num_regulators);
 353                return -EINVAL;
 354        }
 355
 356        act8865 = devm_kzalloc(dev, sizeof(struct act8865), GFP_KERNEL);
 357        if (!act8865)
 358                return -ENOMEM;
 359
 360        act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config);
 361        if (IS_ERR(act8865->regmap)) {
 362                ret = PTR_ERR(act8865->regmap);
 363                dev_err(&client->dev, "Failed to allocate register map: %d\n",
 364                        ret);
 365                return ret;
 366        }
 367
 368        if (of_device_is_system_power_controller(dev->of_node)) {
 369                if (!pm_power_off) {
 370                        act8865_i2c_client = client;
 371                        act8865->off_reg = off_reg;
 372                        act8865->off_mask = off_mask;
 373                        pm_power_off = act8865_power_off;
 374                } else {
 375                        dev_err(dev, "Failed to set poweroff capability, already defined\n");
 376                }
 377        }
 378
 379        /* Finally register devices */
 380        for (i = 0; i < num_regulators; i++) {
 381                const struct regulator_desc *desc = &regulators[i];
 382                struct regulator_config config = { };
 383                struct regulator_dev *rdev;
 384
 385                config.dev = dev;
 386                config.init_data = act8865_get_init_data(desc->id, pdata);
 387                config.of_node = of_node[i];
 388                config.driver_data = act8865;
 389                config.regmap = act8865->regmap;
 390
 391                rdev = devm_regulator_register(&client->dev, desc, &config);
 392                if (IS_ERR(rdev)) {
 393                        dev_err(dev, "failed to register %s\n", desc->name);
 394                        return PTR_ERR(rdev);
 395                }
 396        }
 397
 398        i2c_set_clientdata(client, act8865);
 399        devm_kfree(dev, of_node);
 400
 401        return 0;
 402}
 403
 404static const struct i2c_device_id act8865_ids[] = {
 405        { .name = "act8846", .driver_data = ACT8846 },
 406        { .name = "act8865", .driver_data = ACT8865 },
 407        { },
 408};
 409MODULE_DEVICE_TABLE(i2c, act8865_ids);
 410
 411static struct i2c_driver act8865_pmic_driver = {
 412        .driver = {
 413                .name   = "act8865",
 414                .owner  = THIS_MODULE,
 415        },
 416        .probe          = act8865_pmic_probe,
 417        .id_table       = act8865_ids,
 418};
 419
 420module_i2c_driver(act8865_pmic_driver);
 421
 422MODULE_DESCRIPTION("active-semi act88xx voltage regulator driver");
 423MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>");
 424MODULE_LICENSE("GPL v2");
 425
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.