linux/drivers/regulator/isl6271a-regulator.c
<<
>>
Prefs
   1/*
   2 * isl6271a-regulator.c
   3 *
   4 * Support for Intersil ISL6271A voltage regulator
   5 *
   6 * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License as
  10 * published by the Free Software Foundation version 2.
  11 *
  12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind,
  13 * whether express or implied; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15 * General Public License for more details.
  16 */
  17
  18#include <linux/kernel.h>
  19#include <linux/module.h>
  20#include <linux/init.h>
  21#include <linux/err.h>
  22#include <linux/platform_device.h>
  23#include <linux/regulator/driver.h>
  24#include <linux/i2c.h>
  25#include <linux/delay.h>
  26#include <linux/slab.h>
  27
  28#define ISL6271A_VOLTAGE_MIN    850000
  29#define ISL6271A_VOLTAGE_MAX    1600000
  30#define ISL6271A_VOLTAGE_STEP   50000
  31
  32/* PMIC details */
  33struct isl_pmic {
  34        struct i2c_client       *client;
  35        struct regulator_dev    *rdev[3];
  36        struct mutex            mtx;
  37};
  38
  39static int isl6271a_get_voltage(struct regulator_dev *dev)
  40{
  41        struct isl_pmic *pmic = rdev_get_drvdata(dev);
  42        int idx, data;
  43
  44        mutex_lock(&pmic->mtx);
  45
  46        idx = i2c_smbus_read_byte(pmic->client);
  47        if (idx < 0) {
  48                dev_err(&pmic->client->dev, "Error getting voltage\n");
  49                data = idx;
  50                goto out;
  51        }
  52
  53        /* Convert the data from chip to microvolts */
  54        data = ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * (idx & 0xf));
  55
  56out:
  57        mutex_unlock(&pmic->mtx);
  58        return data;
  59}
  60
  61static int isl6271a_set_voltage(struct regulator_dev *dev,
  62                                int minuV, int maxuV,
  63                                unsigned *selector)
  64{
  65        struct isl_pmic *pmic = rdev_get_drvdata(dev);
  66        int vsel, err, data;
  67
  68        if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX)
  69                return -EINVAL;
  70        if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX)
  71                return -EINVAL;
  72
  73        /* Align to 50000 mV */
  74        vsel = minuV - (minuV % ISL6271A_VOLTAGE_STEP);
  75
  76        /* If the result fell out of [minuV,maxuV] range, put it back */
  77        if (vsel < minuV)
  78                vsel += ISL6271A_VOLTAGE_STEP;
  79
  80        /* Convert the microvolts to data for the chip */
  81        data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP;
  82
  83        *selector = data;
  84
  85        mutex_lock(&pmic->mtx);
  86
  87        err = i2c_smbus_write_byte(pmic->client, data);
  88        if (err < 0)
  89                dev_err(&pmic->client->dev, "Error setting voltage\n");
  90
  91        mutex_unlock(&pmic->mtx);
  92        return err;
  93}
  94
  95static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector)
  96{
  97        return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector);
  98}
  99
 100static struct regulator_ops isl_core_ops = {
 101        .get_voltage    = isl6271a_get_voltage,
 102        .set_voltage    = isl6271a_set_voltage,
 103        .list_voltage   = isl6271a_list_voltage,
 104};
 105
 106static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
 107{
 108        int id = rdev_get_id(dev);
 109        return (id == 1) ? 1100000 : 1300000;
 110}
 111
 112static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector)
 113{
 114        int id = rdev_get_id(dev);
 115        return (id == 1) ? 1100000 : 1300000;
 116}
 117
 118static struct regulator_ops isl_fixed_ops = {
 119        .get_voltage    = isl6271a_get_fixed_voltage,
 120        .list_voltage   = isl6271a_list_fixed_voltage,
 121};
 122
 123static struct regulator_desc isl_rd[] = {
 124        {
 125                .name           = "Core Buck",
 126                .id             = 0,
 127                .n_voltages     = 16,
 128                .ops            = &isl_core_ops,
 129                .type           = REGULATOR_VOLTAGE,
 130                .owner          = THIS_MODULE,
 131        }, {
 132                .name           = "LDO1",
 133                .id             = 1,
 134                .n_voltages     = 1,
 135                .ops            = &isl_fixed_ops,
 136                .type           = REGULATOR_VOLTAGE,
 137                .owner          = THIS_MODULE,
 138        }, {
 139                .name           = "LDO2",
 140                .id             = 2,
 141                .n_voltages     = 1,
 142                .ops            = &isl_fixed_ops,
 143                .type           = REGULATOR_VOLTAGE,
 144                .owner          = THIS_MODULE,
 145        },
 146};
 147
 148static int __devinit isl6271a_probe(struct i2c_client *i2c,
 149                                     const struct i2c_device_id *id)
 150{
 151        struct regulator_init_data *init_data   = i2c->dev.platform_data;
 152        struct isl_pmic *pmic;
 153        int err, i;
 154
 155        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 156                return -EIO;
 157
 158        if (!init_data) {
 159                dev_err(&i2c->dev, "no platform data supplied\n");
 160                return -EIO;
 161        }
 162
 163        pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL);
 164        if (!pmic)
 165                return -ENOMEM;
 166
 167        pmic->client = i2c;
 168
 169        mutex_init(&pmic->mtx);
 170
 171        for (i = 0; i < 3; i++) {
 172                pmic->rdev[i] = regulator_register(&isl_rd[i], &i2c->dev,
 173                                                init_data, pmic);
 174                if (IS_ERR(pmic->rdev[i])) {
 175                        dev_err(&i2c->dev, "failed to register %s\n", id->name);
 176                        err = PTR_ERR(pmic->rdev[i]);
 177                        goto error;
 178                }
 179        }
 180
 181        i2c_set_clientdata(i2c, pmic);
 182
 183        return 0;
 184
 185error:
 186        while (--i >= 0)
 187                regulator_unregister(pmic->rdev[i]);
 188
 189        kfree(pmic);
 190        return err;
 191}
 192
 193static int __devexit isl6271a_remove(struct i2c_client *i2c)
 194{
 195        struct isl_pmic *pmic = i2c_get_clientdata(i2c);
 196        int i;
 197
 198        for (i = 0; i < 3; i++)
 199                regulator_unregister(pmic->rdev[i]);
 200
 201        kfree(pmic);
 202
 203        return 0;
 204}
 205
 206static const struct i2c_device_id isl6271a_id[] = {
 207        {.name = "isl6271a", 0 },
 208        { },
 209};
 210
 211MODULE_DEVICE_TABLE(i2c, isl6271a_id);
 212
 213static struct i2c_driver isl6271a_i2c_driver = {
 214        .driver = {
 215                .name = "isl6271a",
 216                .owner = THIS_MODULE,
 217        },
 218        .probe = isl6271a_probe,
 219        .remove = __devexit_p(isl6271a_remove),
 220        .id_table = isl6271a_id,
 221};
 222
 223static int __init isl6271a_init(void)
 224{
 225        return i2c_add_driver(&isl6271a_i2c_driver);
 226}
 227
 228static void __exit isl6271a_cleanup(void)
 229{
 230        i2c_del_driver(&isl6271a_i2c_driver);
 231}
 232
 233subsys_initcall(isl6271a_init);
 234module_exit(isl6271a_cleanup);
 235
 236MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
 237MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver");
 238MODULE_LICENSE("GPL v2");
 239
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.