Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ISL6271A voltage regulator support.

This device is very simple, it supports one buck and two LDOs. The LDOs are
fixed-voltage. Only the buck is programable over the I2C bus to 16 possible
voltages.

Signed-off-by: Marek Vasut <marek.vasut@gmail.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

authored by

Marek Vasut and committed by
Liam Girdwood
51bd6943 839b8362

+243
+6
drivers/regulator/Kconfig
··· 201 201 help 202 202 This driver supports 88PM8607 voltage regulator chips. 203 203 204 + config REGULATOR_ISL6271A 205 + tristate "Intersil ISL6271A Power regulator" 206 + depends on I2C 207 + help 208 + This driver supports ISL6271A voltage regulator chip. 209 + 204 210 config REGULATOR_AD5398 205 211 tristate "Analog Devices AD5398/AD5821 regulators" 206 212 depends on I2C
+1
drivers/regulator/Makefile
··· 32 32 obj-$(CONFIG_REGULATOR_TPS65023) += tps65023-regulator.o 33 33 obj-$(CONFIG_REGULATOR_TPS6507X) += tps6507x-regulator.o 34 34 obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o 35 + obj-$(CONFIG_REGULATOR_ISL6271A) += isl6271a-regulator.o 35 36 36 37 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
+236
drivers/regulator/isl6271a-regulator.c
··· 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 */ 33 + struct isl_pmic { 34 + struct i2c_client *client; 35 + struct regulator_dev *rdev[3]; 36 + struct mutex mtx; 37 + }; 38 + 39 + static 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 + 56 + out: 57 + mutex_unlock(&pmic->mtx); 58 + return data; 59 + } 60 + 61 + static int isl6271a_set_voltage(struct regulator_dev *dev, int minuV, int maxuV) 62 + { 63 + struct isl_pmic *pmic = rdev_get_drvdata(dev); 64 + int vsel, err, data; 65 + 66 + if (minuV < ISL6271A_VOLTAGE_MIN || minuV > ISL6271A_VOLTAGE_MAX) 67 + return -EINVAL; 68 + if (maxuV < ISL6271A_VOLTAGE_MIN || maxuV > ISL6271A_VOLTAGE_MAX) 69 + return -EINVAL; 70 + 71 + /* Align to 50000 mV */ 72 + vsel = minuV - (minuV % ISL6271A_VOLTAGE_STEP); 73 + 74 + /* If the result fell out of [minuV,maxuV] range, put it back */ 75 + if (vsel < minuV) 76 + vsel += ISL6271A_VOLTAGE_STEP; 77 + 78 + /* Convert the microvolts to data for the chip */ 79 + data = (vsel - ISL6271A_VOLTAGE_MIN) / ISL6271A_VOLTAGE_STEP; 80 + 81 + mutex_lock(&pmic->mtx); 82 + 83 + err = i2c_smbus_write_byte(pmic->client, data); 84 + if (err < 0) 85 + dev_err(&pmic->client->dev, "Error setting voltage\n"); 86 + 87 + mutex_unlock(&pmic->mtx); 88 + return err; 89 + } 90 + 91 + static int isl6271a_list_voltage(struct regulator_dev *dev, unsigned selector) 92 + { 93 + return ISL6271A_VOLTAGE_MIN + (ISL6271A_VOLTAGE_STEP * selector); 94 + } 95 + 96 + static struct regulator_ops isl_core_ops = { 97 + .get_voltage = isl6271a_get_voltage, 98 + .set_voltage = isl6271a_set_voltage, 99 + .list_voltage = isl6271a_list_voltage, 100 + }; 101 + 102 + static int isl6271a_get_fixed_voltage(struct regulator_dev *dev) 103 + { 104 + int id = rdev_get_id(dev); 105 + return (id == 1) ? 1100000 : 1300000; 106 + } 107 + 108 + static int isl6271a_list_fixed_voltage(struct regulator_dev *dev, unsigned selector) 109 + { 110 + int id = rdev_get_id(dev); 111 + return (id == 1) ? 1100000 : 1300000; 112 + } 113 + 114 + static struct regulator_ops isl_fixed_ops = { 115 + .get_voltage = isl6271a_get_fixed_voltage, 116 + .list_voltage = isl6271a_list_fixed_voltage, 117 + }; 118 + 119 + static struct regulator_desc isl_rd[] = { 120 + { 121 + .name = "Core Buck", 122 + .id = 0, 123 + .n_voltages = 16, 124 + .ops = &isl_core_ops, 125 + .type = REGULATOR_VOLTAGE, 126 + .owner = THIS_MODULE, 127 + }, { 128 + .name = "LDO1", 129 + .id = 1, 130 + .n_voltages = 1, 131 + .ops = &isl_fixed_ops, 132 + .type = REGULATOR_VOLTAGE, 133 + .owner = THIS_MODULE, 134 + }, { 135 + .name = "LDO2", 136 + .id = 2, 137 + .n_voltages = 1, 138 + .ops = &isl_fixed_ops, 139 + .type = REGULATOR_VOLTAGE, 140 + .owner = THIS_MODULE, 141 + }, 142 + }; 143 + 144 + static int __devinit isl6271a_probe(struct i2c_client *i2c, 145 + const struct i2c_device_id *id) 146 + { 147 + struct regulator_init_data *init_data = i2c->dev.platform_data; 148 + struct isl_pmic *pmic; 149 + int err, i; 150 + 151 + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 152 + return -EIO; 153 + 154 + if (!init_data) { 155 + dev_err(&i2c->dev, "no platform data supplied\n"); 156 + return -EIO; 157 + } 158 + 159 + pmic = kzalloc(sizeof(struct isl_pmic), GFP_KERNEL); 160 + if (!pmic) 161 + return -ENOMEM; 162 + 163 + pmic->client = i2c; 164 + 165 + mutex_init(&pmic->mtx); 166 + 167 + for (i = 0; i < 3; i++) { 168 + pmic->rdev[i] = regulator_register(&isl_rd[0], &i2c->dev, 169 + init_data, pmic); 170 + if (IS_ERR(pmic->rdev[i])) { 171 + dev_err(&i2c->dev, "failed to register %s\n", id->name); 172 + err = PTR_ERR(pmic->rdev); 173 + goto error; 174 + } 175 + } 176 + 177 + i2c_set_clientdata(i2c, pmic); 178 + 179 + return 0; 180 + 181 + error: 182 + while (--i >= 0) 183 + regulator_unregister(pmic->rdev[i]); 184 + 185 + kfree(pmic); 186 + return err; 187 + } 188 + 189 + static int __devexit isl6271a_remove(struct i2c_client *i2c) 190 + { 191 + struct isl_pmic *pmic = i2c_get_clientdata(i2c); 192 + int i; 193 + 194 + i2c_set_clientdata(i2c, NULL); 195 + 196 + for (i = 0; i < 3; i++) 197 + regulator_unregister(pmic->rdev[i]); 198 + 199 + kfree(pmic); 200 + 201 + return 0; 202 + } 203 + 204 + static const struct i2c_device_id isl6271a_id[] = { 205 + {.name = "isl6271a", 0 }, 206 + { }, 207 + }; 208 + 209 + MODULE_DEVICE_TABLE(i2c, isl6271a_id); 210 + 211 + static struct i2c_driver isl6271a_i2c_driver = { 212 + .driver = { 213 + .name = "isl6271a", 214 + .owner = THIS_MODULE, 215 + }, 216 + .probe = isl6271a_probe, 217 + .remove = __devexit_p(isl6271a_remove), 218 + .id_table = isl6271a_id, 219 + }; 220 + 221 + static int __init isl6271a_init(void) 222 + { 223 + return i2c_add_driver(&isl6271a_i2c_driver); 224 + } 225 + 226 + static void __exit isl6271a_cleanup(void) 227 + { 228 + i2c_del_driver(&isl6271a_i2c_driver); 229 + } 230 + 231 + subsys_initcall(isl6271a_init); 232 + module_exit(isl6271a_cleanup); 233 + 234 + MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); 235 + MODULE_DESCRIPTION("Intersil ISL6271A voltage regulator driver"); 236 + MODULE_LICENSE("GPL v2");