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

regulator: act8865: add PMIC act8865 driver

Signed-off-by: Wenyou Yang <wenyou.yang@atmel.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Wenyou Yang and committed by
Mark Brown
33036f48 6ce4eac1

+430
+8
drivers/regulator/Kconfig
··· 70 70 help 71 71 This driver supports 88PM8607 voltage regulator chips. 72 72 73 + config REGULATOR_ACT8865 74 + tristate "Active-semi act8865 voltage regulator" 75 + depends on I2C 76 + select REGMAP_I2C 77 + help 78 + This driver controls a active-semi act8865 voltage output 79 + regulator via I2C bus. 80 + 73 81 config REGULATOR_AD5398 74 82 tristate "Analog Devices AD5398/AD5821 regulators" 75 83 depends on I2C
+1
drivers/regulator/Makefile
··· 14 14 obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o 15 15 obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o 16 16 obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o 17 + obj-$(CONFIG_REGULATOR_ACT8865) += act8865-regulator.o 17 18 obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o 18 19 obj-$(CONFIG_REGULATOR_ANATOP) += anatop-regulator.o 19 20 obj-$(CONFIG_REGULATOR_ARIZONA) += arizona-micsupp.o arizona-ldo1.o
+368
drivers/regulator/act8865-regulator.c
··· 1 + /* 2 + * act8865-regulator.c - Voltage regulation for the active-semi ACT8865 3 + * http://www.active-semi.com/sheets/ACT8865_Datasheet.pdf 4 + * 5 + * Copyright (C) 2013 Atmel Corporation 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/init.h> 20 + #include <linux/i2c.h> 21 + #include <linux/err.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/regulator/driver.h> 24 + #include <linux/regulator/act8865.h> 25 + #include <linux/of.h> 26 + #include <linux/of_device.h> 27 + #include <linux/regulator/of_regulator.h> 28 + #include <linux/regmap.h> 29 + 30 + /* 31 + * ACT8865 Global Register Map. 32 + */ 33 + #define ACT8865_SYS_MODE 0x00 34 + #define ACT8865_SYS_CTRL 0x01 35 + #define ACT8865_DCDC1_VSET1 0x20 36 + #define ACT8865_DCDC1_VSET2 0x21 37 + #define ACT8865_DCDC1_CTRL 0x22 38 + #define ACT8865_DCDC2_VSET1 0x30 39 + #define ACT8865_DCDC2_VSET2 0x31 40 + #define ACT8865_DCDC2_CTRL 0x32 41 + #define ACT8865_DCDC3_VSET1 0x40 42 + #define ACT8865_DCDC3_VSET2 0x41 43 + #define ACT8865_DCDC3_CTRL 0x42 44 + #define ACT8865_LDO1_VSET 0x50 45 + #define ACT8865_LDO1_CTRL 0x51 46 + #define ACT8865_LDO2_VSET 0x54 47 + #define ACT8865_LDO2_CTRL 0x55 48 + #define ACT8865_LDO3_VSET 0x60 49 + #define ACT8865_LDO3_CTRL 0x61 50 + #define ACT8865_LDO4_VSET 0x64 51 + #define ACT8865_LDO4_CTRL 0x65 52 + 53 + /* 54 + * Field Definitions. 55 + */ 56 + #define ACT8865_ENA 0x80 /* ON - [7] */ 57 + #define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */ 58 + 59 + /* 60 + * ACT8865 voltage number 61 + */ 62 + #define ACT8865_VOLTAGE_NUM 64 63 + 64 + struct act8865 { 65 + struct regulator_dev *rdev[ACT8865_REG_NUM]; 66 + struct regmap *regmap; 67 + }; 68 + 69 + static const struct regmap_config act8865_regmap_config = { 70 + .reg_bits = 8, 71 + .val_bits = 8, 72 + }; 73 + 74 + static const struct regulator_linear_range act8865_volatge_ranges[] = { 75 + REGULATOR_LINEAR_RANGE(600000, 0, 23, 25000), 76 + REGULATOR_LINEAR_RANGE(1200000, 24, 47, 50000), 77 + REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), 78 + }; 79 + 80 + static struct regulator_ops act8865_ops = { 81 + .list_voltage = regulator_list_voltage_linear_range, 82 + .map_voltage = regulator_map_voltage_linear_range, 83 + .get_voltage_sel = regulator_get_voltage_sel_regmap, 84 + .set_voltage_sel = regulator_set_voltage_sel_regmap, 85 + .enable = regulator_enable_regmap, 86 + .disable = regulator_disable_regmap, 87 + .is_enabled = regulator_is_enabled_regmap, 88 + .set_suspend_enable = regulator_enable_regmap, 89 + .set_suspend_disable = regulator_disable_regmap, 90 + }; 91 + 92 + static const struct regulator_desc act8865_reg[] = { 93 + { 94 + .name = "DCDC_REG1", 95 + .id = ACT8865_ID_DCDC1, 96 + .ops = &act8865_ops, 97 + .type = REGULATOR_VOLTAGE, 98 + .n_voltages = ACT8865_VOLTAGE_NUM, 99 + .linear_ranges = act8865_volatge_ranges, 100 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 101 + .vsel_reg = ACT8865_DCDC1_VSET1, 102 + .vsel_mask = ACT8865_VSEL_MASK, 103 + .enable_reg = ACT8865_DCDC1_CTRL, 104 + .enable_mask = ACT8865_ENA, 105 + .owner = THIS_MODULE, 106 + }, 107 + { 108 + .name = "DCDC_REG2", 109 + .id = ACT8865_ID_DCDC2, 110 + .ops = &act8865_ops, 111 + .type = REGULATOR_VOLTAGE, 112 + .n_voltages = ACT8865_VOLTAGE_NUM, 113 + .linear_ranges = act8865_volatge_ranges, 114 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 115 + .vsel_reg = ACT8865_DCDC2_VSET1, 116 + .vsel_mask = ACT8865_VSEL_MASK, 117 + .enable_reg = ACT8865_DCDC2_CTRL, 118 + .enable_mask = ACT8865_ENA, 119 + .owner = THIS_MODULE, 120 + }, 121 + { 122 + .name = "DCDC_REG3", 123 + .id = ACT8865_ID_DCDC3, 124 + .ops = &act8865_ops, 125 + .type = REGULATOR_VOLTAGE, 126 + .n_voltages = ACT8865_VOLTAGE_NUM, 127 + .linear_ranges = act8865_volatge_ranges, 128 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 129 + .vsel_reg = ACT8865_DCDC3_VSET1, 130 + .vsel_mask = ACT8865_VSEL_MASK, 131 + .enable_reg = ACT8865_DCDC3_CTRL, 132 + .enable_mask = ACT8865_ENA, 133 + .owner = THIS_MODULE, 134 + }, 135 + { 136 + .name = "LDO_REG1", 137 + .id = ACT8865_ID_LDO1, 138 + .ops = &act8865_ops, 139 + .type = REGULATOR_VOLTAGE, 140 + .n_voltages = ACT8865_VOLTAGE_NUM, 141 + .linear_ranges = act8865_volatge_ranges, 142 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 143 + .vsel_reg = ACT8865_LDO1_VSET, 144 + .vsel_mask = ACT8865_VSEL_MASK, 145 + .enable_reg = ACT8865_LDO1_CTRL, 146 + .enable_mask = ACT8865_ENA, 147 + .owner = THIS_MODULE, 148 + }, 149 + { 150 + .name = "LDO_REG2", 151 + .id = ACT8865_ID_LDO2, 152 + .ops = &act8865_ops, 153 + .type = REGULATOR_VOLTAGE, 154 + .n_voltages = ACT8865_VOLTAGE_NUM, 155 + .linear_ranges = act8865_volatge_ranges, 156 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 157 + .vsel_reg = ACT8865_LDO2_VSET, 158 + .vsel_mask = ACT8865_VSEL_MASK, 159 + .enable_reg = ACT8865_LDO2_CTRL, 160 + .enable_mask = ACT8865_ENA, 161 + .owner = THIS_MODULE, 162 + }, 163 + { 164 + .name = "LDO_REG3", 165 + .id = ACT8865_ID_LDO3, 166 + .ops = &act8865_ops, 167 + .type = REGULATOR_VOLTAGE, 168 + .n_voltages = ACT8865_VOLTAGE_NUM, 169 + .linear_ranges = act8865_volatge_ranges, 170 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 171 + .vsel_reg = ACT8865_LDO3_VSET, 172 + .vsel_mask = ACT8865_VSEL_MASK, 173 + .enable_reg = ACT8865_LDO3_CTRL, 174 + .enable_mask = ACT8865_ENA, 175 + .owner = THIS_MODULE, 176 + }, 177 + { 178 + .name = "LDO_REG4", 179 + .id = ACT8865_ID_LDO4, 180 + .ops = &act8865_ops, 181 + .type = REGULATOR_VOLTAGE, 182 + .n_voltages = ACT8865_VOLTAGE_NUM, 183 + .linear_ranges = act8865_volatge_ranges, 184 + .n_linear_ranges = ARRAY_SIZE(act8865_volatge_ranges), 185 + .vsel_reg = ACT8865_LDO4_VSET, 186 + .vsel_mask = ACT8865_VSEL_MASK, 187 + .enable_reg = ACT8865_LDO4_CTRL, 188 + .enable_mask = ACT8865_ENA, 189 + .owner = THIS_MODULE, 190 + }, 191 + }; 192 + 193 + #ifdef CONFIG_OF 194 + static const struct of_device_id act8865_dt_ids[] = { 195 + { .compatible = "active-semi,act8865" }, 196 + { } 197 + }; 198 + MODULE_DEVICE_TABLE(of, act8865_dt_ids); 199 + 200 + static struct of_regulator_match act8865_matches[] = { 201 + [ACT8865_ID_DCDC1] = { .name = "DCDC_REG1"}, 202 + [ACT8865_ID_DCDC2] = { .name = "DCDC_REG2"}, 203 + [ACT8865_ID_DCDC3] = { .name = "DCDC_REG3"}, 204 + [ACT8865_ID_LDO1] = { .name = "LDO_REG1"}, 205 + [ACT8865_ID_LDO2] = { .name = "LDO_REG2"}, 206 + [ACT8865_ID_LDO3] = { .name = "LDO_REG3"}, 207 + [ACT8865_ID_LDO4] = { .name = "LDO_REG4"}, 208 + }; 209 + 210 + static int act8865_pdata_from_dt(struct device *dev, 211 + struct device_node **of_node, 212 + struct act8865_platform_data *pdata) 213 + { 214 + int matched, i; 215 + struct device_node *np; 216 + struct act8865_regulator_data *regulator; 217 + 218 + np = of_find_node_by_name(dev->of_node, "regulators"); 219 + if (!np) { 220 + dev_err(dev, "missing 'regulators' subnode in DT\n"); 221 + return -EINVAL; 222 + } 223 + 224 + matched = of_regulator_match(dev, np, 225 + act8865_matches, ARRAY_SIZE(act8865_matches)); 226 + if (matched <= 0) 227 + return matched; 228 + 229 + pdata->regulators = devm_kzalloc(dev, 230 + sizeof(struct act8865_regulator_data) * matched, 231 + GFP_KERNEL); 232 + if (!pdata->regulators) { 233 + dev_err(dev, "%s: failed to allocate act8865 registor\n", 234 + __func__); 235 + return -ENOMEM; 236 + } 237 + 238 + pdata->num_regulators = matched; 239 + regulator = pdata->regulators; 240 + 241 + for (i = 0; i < matched; i++) { 242 + if (!act8865_matches[i].init_data) 243 + continue; 244 + 245 + regulator->id = i; 246 + regulator->name = act8865_matches[i].name; 247 + regulator->platform_data = act8865_matches[i].init_data; 248 + of_node[i] = act8865_matches[i].of_node; 249 + regulator++; 250 + } 251 + 252 + return 0; 253 + } 254 + #else 255 + static inline int act8865_pdata_from_dt(struct device *dev, 256 + struct device_node **of_node, 257 + struct act8865_platform_data *pdata) 258 + { 259 + return 0; 260 + } 261 + #endif 262 + 263 + static int act8865_pmic_probe(struct i2c_client *client, 264 + const struct i2c_device_id *i2c_id) 265 + { 266 + struct regulator_dev **rdev; 267 + struct device *dev = &client->dev; 268 + struct act8865_platform_data *pdata = dev_get_platdata(dev); 269 + struct regulator_config config = { }; 270 + struct act8865 *act8865; 271 + struct device_node *of_node[ACT8865_REG_NUM]; 272 + int i, id; 273 + int ret = -EINVAL; 274 + int error; 275 + 276 + if (dev->of_node && !pdata) { 277 + const struct of_device_id *id; 278 + struct act8865_platform_data pdata_of; 279 + 280 + id = of_match_device(of_match_ptr(act8865_dt_ids), dev); 281 + if (!id) 282 + return -ENODEV; 283 + 284 + ret = act8865_pdata_from_dt(dev, of_node, &pdata_of); 285 + if (ret < 0) 286 + return ret; 287 + 288 + pdata = &pdata_of; 289 + } 290 + 291 + if (pdata->num_regulators > ACT8865_REG_NUM) { 292 + dev_err(dev, "Too many regulators found!\n"); 293 + return -EINVAL; 294 + } 295 + 296 + act8865 = devm_kzalloc(dev, sizeof(struct act8865) + 297 + sizeof(struct regulator_dev *) * ACT8865_REG_NUM, 298 + GFP_KERNEL); 299 + if (!act8865) 300 + return -ENOMEM; 301 + 302 + rdev = act8865->rdev; 303 + 304 + act8865->regmap = devm_regmap_init_i2c(client, &act8865_regmap_config); 305 + if (IS_ERR(act8865->regmap)) { 306 + error = PTR_ERR(act8865->regmap); 307 + dev_err(&client->dev, "Failed to allocate register map: %d\n", 308 + error); 309 + return error; 310 + } 311 + 312 + /* Finally register devices */ 313 + for (i = 0; i < pdata->num_regulators; i++) { 314 + 315 + id = pdata->regulators[i].id; 316 + 317 + config.dev = dev; 318 + config.init_data = pdata->regulators[i].platform_data; 319 + config.of_node = of_node[i]; 320 + config.driver_data = act8865; 321 + config.regmap = act8865->regmap; 322 + 323 + rdev[i] = devm_regulator_register(&client->dev, 324 + &act8865_reg[i], &config); 325 + if (IS_ERR(rdev[i])) { 326 + dev_err(dev, "failed to register %s\n", 327 + act8865_reg[id].name); 328 + return PTR_ERR(rdev[i]); 329 + } 330 + } 331 + 332 + i2c_set_clientdata(client, act8865); 333 + 334 + return 0; 335 + } 336 + 337 + static int act8865_pmic_remove(struct i2c_client *client) 338 + { 339 + struct act8865 *act8865 = i2c_get_clientdata(client); 340 + int i; 341 + 342 + for (i = 0; i < ACT8865_REG_NUM; i++) 343 + regulator_unregister(act8865->rdev[i]); 344 + 345 + return 0; 346 + } 347 + 348 + static const struct i2c_device_id act8865_ids[] = { 349 + { "act8865", 0 }, 350 + { }, 351 + }; 352 + MODULE_DEVICE_TABLE(i2c, act8865_ids); 353 + 354 + static struct i2c_driver act8865_pmic_driver = { 355 + .driver = { 356 + .name = "act8865", 357 + .owner = THIS_MODULE, 358 + }, 359 + .probe = act8865_pmic_probe, 360 + .remove = act8865_pmic_remove, 361 + .id_table = act8865_ids, 362 + }; 363 + 364 + module_i2c_driver(act8865_pmic_driver); 365 + 366 + MODULE_DESCRIPTION("active-semi act8865 voltage regulator driver"); 367 + MODULE_AUTHOR("Wenyou Yang <wenyou.yang@atmel.com>"); 368 + MODULE_LICENSE("GPL v2");
+53
include/linux/regulator/act8865.h
··· 1 + /* 2 + * act8865.h -- Voltage regulation for the active-semi act8865 3 + * 4 + * Copyright (C) 2013 Atmel Corporation. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; version 2 of the License. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 + * GNU General Public License for more details. 14 + */ 15 + 16 + #ifndef __LINUX_REGULATOR_ACT8865_H 17 + #define __LINUX_REGULATOR_ACT8865_H 18 + 19 + #include <linux/regulator/machine.h> 20 + 21 + enum { 22 + ACT8865_ID_DCDC1, 23 + ACT8865_ID_DCDC2, 24 + ACT8865_ID_DCDC3, 25 + ACT8865_ID_LDO1, 26 + ACT8865_ID_LDO2, 27 + ACT8865_ID_LDO3, 28 + ACT8865_ID_LDO4, 29 + ACT8865_REG_NUM, 30 + }; 31 + 32 + /** 33 + * act8865_regulator_data - regulator data 34 + * @id: regulator id 35 + * @name: regulator name 36 + * @platform_data: regulator init data 37 + */ 38 + struct act8865_regulator_data { 39 + int id; 40 + const char *name; 41 + struct regulator_init_data *platform_data; 42 + }; 43 + 44 + /** 45 + * act8865_platform_data - platform data for act8865 46 + * @num_regulators: number of regulators used 47 + * @regulators: pointer to regulators used 48 + */ 49 + struct act8865_platform_data { 50 + int num_regulators; 51 + struct act8865_regulator_data *regulators; 52 + }; 53 + #endif