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

regulator: PCF50633 pmic driver

Changes from V1:
- Removed support for suspend_enable & suspend_disable functions.

Signed-off-by: Balaji Rao <balajirrao@openmoko.org>
Cc: Andy Green <andy@openmoko.com>
Cc: Liam Girdwood <lrg@slimlogic.co.uk>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@openedhand.com>

authored by

Balaji Rao and committed by
Samuel Ortiz
5ec271e7 1851b06a

+404
+7
drivers/regulator/Kconfig
··· 73 73 Say y here to support the BUCKs and LDOs regulators found on 74 74 Dialog Semiconductor DA9030/DA9034 PMIC. 75 75 76 + config REGULATOR_PCF50633 77 + tristate "PCF50633 regulator driver" 78 + depends on MFD_PCF50633 79 + help 80 + Say Y here to support the voltage regulators and convertors 81 + on PCF50633 82 + 76 83 endif
+1
drivers/regulator/Makefile
··· 11 11 obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o 12 12 obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o 13 13 obj-$(CONFIG_REGULATOR_DA903X) += da903x.o 14 + obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o 14 15 15 16 ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
+329
drivers/regulator/pcf50633-regulator.c
··· 1 + /* NXP PCF50633 PMIC Driver 2 + * 3 + * (C) 2006-2008 by Openmoko, Inc. 4 + * Author: Balaji Rao <balajirrao@openmoko.org> 5 + * All rights reserved. 6 + * 7 + * Broken down from monstrous PCF50633 driver mainly by 8 + * Harald Welte and Andy Green and Werner Almesberger 9 + * 10 + * This program is free software; you can redistribute it and/or modify it 11 + * under the terms of the GNU General Public License as published by the 12 + * Free Software Foundation; either version 2 of the License, or (at your 13 + * option) any later version. 14 + * 15 + */ 16 + 17 + #include <linux/kernel.h> 18 + #include <linux/module.h> 19 + #include <linux/init.h> 20 + #include <linux/device.h> 21 + #include <linux/err.h> 22 + #include <linux/platform_device.h> 23 + 24 + #include <linux/mfd/pcf50633/core.h> 25 + #include <linux/mfd/pcf50633/pmic.h> 26 + 27 + #define PCF50633_REGULATOR(_name, _id) \ 28 + { \ 29 + .name = _name, \ 30 + .id = _id, \ 31 + .ops = &pcf50633_regulator_ops, \ 32 + .type = REGULATOR_VOLTAGE, \ 33 + .owner = THIS_MODULE, \ 34 + } 35 + 36 + static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = { 37 + [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT, 38 + [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT, 39 + [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT, 40 + [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT, 41 + [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT, 42 + [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT, 43 + [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT, 44 + [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT, 45 + [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT, 46 + [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT, 47 + [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT, 48 + }; 49 + 50 + /* Bits from voltage value */ 51 + static u8 auto_voltage_bits(unsigned int millivolts) 52 + { 53 + if (millivolts < 1800) 54 + return 0; 55 + if (millivolts > 3800) 56 + return 0xff; 57 + 58 + millivolts -= 625; 59 + 60 + return millivolts / 25; 61 + } 62 + 63 + static u8 down_voltage_bits(unsigned int millivolts) 64 + { 65 + if (millivolts < 625) 66 + return 0; 67 + else if (millivolts > 3000) 68 + return 0xff; 69 + 70 + millivolts -= 625; 71 + 72 + return millivolts / 25; 73 + } 74 + 75 + static u8 ldo_voltage_bits(unsigned int millivolts) 76 + { 77 + if (millivolts < 900) 78 + return 0; 79 + else if (millivolts > 3600) 80 + return 0x1f; 81 + 82 + millivolts -= 900; 83 + return millivolts / 100; 84 + } 85 + 86 + /* Obtain voltage value from bits */ 87 + static unsigned int auto_voltage_value(u8 bits) 88 + { 89 + if (bits < 0x2f) 90 + return 0; 91 + 92 + return 625 + (bits * 25); 93 + } 94 + 95 + 96 + static unsigned int down_voltage_value(u8 bits) 97 + { 98 + return 625 + (bits * 25); 99 + } 100 + 101 + 102 + static unsigned int ldo_voltage_value(u8 bits) 103 + { 104 + bits &= 0x1f; 105 + 106 + return 900 + (bits * 100); 107 + } 108 + 109 + static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, 110 + int min_uV, int max_uV) 111 + { 112 + struct pcf50633 *pcf; 113 + int regulator_id, millivolts; 114 + u8 volt_bits, regnr; 115 + 116 + pcf = rdev_get_drvdata(rdev); 117 + 118 + regulator_id = rdev_get_id(rdev); 119 + if (regulator_id >= PCF50633_NUM_REGULATORS) 120 + return -EINVAL; 121 + 122 + millivolts = min_uV / 1000; 123 + 124 + regnr = pcf50633_regulator_registers[regulator_id]; 125 + 126 + switch (regulator_id) { 127 + case PCF50633_REGULATOR_AUTO: 128 + volt_bits = auto_voltage_bits(millivolts); 129 + break; 130 + case PCF50633_REGULATOR_DOWN1: 131 + volt_bits = down_voltage_bits(millivolts); 132 + break; 133 + case PCF50633_REGULATOR_DOWN2: 134 + volt_bits = down_voltage_bits(millivolts); 135 + break; 136 + case PCF50633_REGULATOR_LDO1: 137 + case PCF50633_REGULATOR_LDO2: 138 + case PCF50633_REGULATOR_LDO3: 139 + case PCF50633_REGULATOR_LDO4: 140 + case PCF50633_REGULATOR_LDO5: 141 + case PCF50633_REGULATOR_LDO6: 142 + case PCF50633_REGULATOR_HCLDO: 143 + volt_bits = ldo_voltage_bits(millivolts); 144 + break; 145 + default: 146 + return -EINVAL; 147 + } 148 + 149 + return pcf50633_reg_write(pcf, regnr, volt_bits); 150 + } 151 + 152 + static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) 153 + { 154 + struct pcf50633 *pcf; 155 + int regulator_id, millivolts, volt_bits; 156 + u8 regnr; 157 + 158 + pcf = rdev_get_drvdata(rdev);; 159 + 160 + regulator_id = rdev_get_id(rdev); 161 + if (regulator_id >= PCF50633_NUM_REGULATORS) 162 + return -EINVAL; 163 + 164 + regnr = pcf50633_regulator_registers[regulator_id]; 165 + 166 + volt_bits = pcf50633_reg_read(pcf, regnr); 167 + if (volt_bits < 0) 168 + return -1; 169 + 170 + switch (regulator_id) { 171 + case PCF50633_REGULATOR_AUTO: 172 + millivolts = auto_voltage_value(volt_bits); 173 + break; 174 + case PCF50633_REGULATOR_DOWN1: 175 + millivolts = down_voltage_value(volt_bits); 176 + break; 177 + case PCF50633_REGULATOR_DOWN2: 178 + millivolts = down_voltage_value(volt_bits); 179 + break; 180 + case PCF50633_REGULATOR_LDO1: 181 + case PCF50633_REGULATOR_LDO2: 182 + case PCF50633_REGULATOR_LDO3: 183 + case PCF50633_REGULATOR_LDO4: 184 + case PCF50633_REGULATOR_LDO5: 185 + case PCF50633_REGULATOR_LDO6: 186 + case PCF50633_REGULATOR_HCLDO: 187 + millivolts = ldo_voltage_value(volt_bits); 188 + break; 189 + default: 190 + return -EINVAL; 191 + } 192 + 193 + return millivolts * 1000; 194 + } 195 + 196 + static int pcf50633_regulator_enable(struct regulator_dev *rdev) 197 + { 198 + struct pcf50633 *pcf = rdev_get_drvdata(rdev); 199 + int regulator_id; 200 + u8 regnr; 201 + 202 + regulator_id = rdev_get_id(rdev); 203 + if (regulator_id >= PCF50633_NUM_REGULATORS) 204 + return -EINVAL; 205 + 206 + /* The *ENA register is always one after the *OUT register */ 207 + regnr = pcf50633_regulator_registers[regulator_id] + 1; 208 + 209 + return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON, 210 + PCF50633_REGULATOR_ON); 211 + } 212 + 213 + static int pcf50633_regulator_disable(struct regulator_dev *rdev) 214 + { 215 + struct pcf50633 *pcf = rdev_get_drvdata(rdev); 216 + int regulator_id; 217 + u8 regnr; 218 + 219 + regulator_id = rdev_get_id(rdev); 220 + if (regulator_id >= PCF50633_NUM_REGULATORS) 221 + return -EINVAL; 222 + 223 + /* the *ENA register is always one after the *OUT register */ 224 + regnr = pcf50633_regulator_registers[regulator_id] + 1; 225 + 226 + return pcf50633_reg_set_bit_mask(pcf, regnr, 227 + PCF50633_REGULATOR_ON, 0); 228 + } 229 + 230 + static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev) 231 + { 232 + struct pcf50633 *pcf = rdev_get_drvdata(rdev); 233 + int regulator_id = rdev_get_id(rdev); 234 + u8 regnr; 235 + 236 + regulator_id = rdev_get_id(rdev); 237 + if (regulator_id >= PCF50633_NUM_REGULATORS) 238 + return -EINVAL; 239 + 240 + /* the *ENA register is always one after the *OUT register */ 241 + regnr = pcf50633_regulator_registers[regulator_id] + 1; 242 + 243 + return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON; 244 + } 245 + 246 + static struct regulator_ops pcf50633_regulator_ops = { 247 + .set_voltage = pcf50633_regulator_set_voltage, 248 + .get_voltage = pcf50633_regulator_get_voltage, 249 + .enable = pcf50633_regulator_enable, 250 + .disable = pcf50633_regulator_disable, 251 + .is_enabled = pcf50633_regulator_is_enabled, 252 + }; 253 + 254 + static struct regulator_desc regulators[] = { 255 + [PCF50633_REGULATOR_AUTO] = 256 + PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO), 257 + [PCF50633_REGULATOR_DOWN1] = 258 + PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1), 259 + [PCF50633_REGULATOR_DOWN2] = 260 + PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2), 261 + [PCF50633_REGULATOR_LDO1] = 262 + PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1), 263 + [PCF50633_REGULATOR_LDO2] = 264 + PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2), 265 + [PCF50633_REGULATOR_LDO3] = 266 + PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3), 267 + [PCF50633_REGULATOR_LDO4] = 268 + PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4), 269 + [PCF50633_REGULATOR_LDO5] = 270 + PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5), 271 + [PCF50633_REGULATOR_LDO6] = 272 + PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6), 273 + [PCF50633_REGULATOR_HCLDO] = 274 + PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO), 275 + [PCF50633_REGULATOR_MEMLDO] = 276 + PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO), 277 + }; 278 + 279 + static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) 280 + { 281 + struct regulator_dev *rdev; 282 + struct pcf50633 *pcf; 283 + 284 + /* Already set by core driver */ 285 + pcf = platform_get_drvdata(pdev); 286 + 287 + rdev = regulator_register(&regulators[pdev->id], &pdev->dev, pcf); 288 + if (IS_ERR(rdev)) 289 + return PTR_ERR(rdev); 290 + 291 + if (pcf->pdata->regulator_registered) 292 + pcf->pdata->regulator_registered(pcf, pdev->id); 293 + 294 + return 0; 295 + } 296 + 297 + static int __devexit pcf50633_regulator_remove(struct platform_device *pdev) 298 + { 299 + struct regulator_dev *rdev = platform_get_drvdata(pdev); 300 + 301 + regulator_unregister(rdev); 302 + 303 + return 0; 304 + } 305 + 306 + static struct platform_driver pcf50633_regulator_driver = { 307 + .driver = { 308 + .name = "pcf50633-regltr", 309 + }, 310 + .probe = pcf50633_regulator_probe, 311 + .remove = __devexit_p(pcf50633_regulator_remove), 312 + }; 313 + 314 + static int __init pcf50633_regulator_init(void) 315 + { 316 + return platform_driver_register(&pcf50633_regulator_driver); 317 + } 318 + module_init(pcf50633_regulator_init); 319 + 320 + static void __exit pcf50633_regulator_exit(void) 321 + { 322 + platform_driver_unregister(&pcf50633_regulator_driver); 323 + } 324 + module_exit(pcf50633_regulator_exit); 325 + 326 + MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); 327 + MODULE_DESCRIPTION("PCF50633 regulator driver"); 328 + MODULE_LICENSE("GPL"); 329 + MODULE_ALIAS("platform:pcf50633-regulator");
+67
include/linux/mfd/pcf50633/pmic.h
··· 1 + #ifndef __LINUX_MFD_PCF50633_PMIC_H 2 + #define __LINUX_MFD_PCF50633_PMIC_H 3 + 4 + #include <linux/mfd/pcf50633/core.h> 5 + #include <linux/platform_device.h> 6 + 7 + #define PCF50633_REG_AUTOOUT 0x1a 8 + #define PCF50633_REG_AUTOENA 0x1b 9 + #define PCF50633_REG_AUTOCTL 0x1c 10 + #define PCF50633_REG_AUTOMXC 0x1d 11 + #define PCF50633_REG_DOWN1OUT 0x1e 12 + #define PCF50633_REG_DOWN1ENA 0x1f 13 + #define PCF50633_REG_DOWN1CTL 0x20 14 + #define PCF50633_REG_DOWN1MXC 0x21 15 + #define PCF50633_REG_DOWN2OUT 0x22 16 + #define PCF50633_REG_DOWN2ENA 0x23 17 + #define PCF50633_REG_DOWN2CTL 0x24 18 + #define PCF50633_REG_DOWN2MXC 0x25 19 + #define PCF50633_REG_MEMLDOOUT 0x26 20 + #define PCF50633_REG_MEMLDOENA 0x27 21 + #define PCF50633_REG_LDO1OUT 0x2d 22 + #define PCF50633_REG_LDO1ENA 0x2e 23 + #define PCF50633_REG_LDO2OUT 0x2f 24 + #define PCF50633_REG_LDO2ENA 0x30 25 + #define PCF50633_REG_LDO3OUT 0x31 26 + #define PCF50633_REG_LDO3ENA 0x32 27 + #define PCF50633_REG_LDO4OUT 0x33 28 + #define PCF50633_REG_LDO4ENA 0x34 29 + #define PCF50633_REG_LDO5OUT 0x35 30 + #define PCF50633_REG_LDO5ENA 0x36 31 + #define PCF50633_REG_LDO6OUT 0x37 32 + #define PCF50633_REG_LDO6ENA 0x38 33 + #define PCF50633_REG_HCLDOOUT 0x39 34 + #define PCF50633_REG_HCLDOENA 0x3a 35 + #define PCF50633_REG_HCLDOOVL 0x40 36 + 37 + enum pcf50633_regulator_enable { 38 + PCF50633_REGULATOR_ON = 0x01, 39 + PCF50633_REGULATOR_ON_GPIO1 = 0x02, 40 + PCF50633_REGULATOR_ON_GPIO2 = 0x04, 41 + PCF50633_REGULATOR_ON_GPIO3 = 0x08, 42 + }; 43 + #define PCF50633_REGULATOR_ON_MASK 0x0f 44 + 45 + enum pcf50633_regulator_phase { 46 + PCF50633_REGULATOR_ACTPH1 = 0x00, 47 + PCF50633_REGULATOR_ACTPH2 = 0x10, 48 + PCF50633_REGULATOR_ACTPH3 = 0x20, 49 + PCF50633_REGULATOR_ACTPH4 = 0x30, 50 + }; 51 + #define PCF50633_REGULATOR_ACTPH_MASK 0x30 52 + 53 + enum pcf50633_regulator_id { 54 + PCF50633_REGULATOR_AUTO, 55 + PCF50633_REGULATOR_DOWN1, 56 + PCF50633_REGULATOR_DOWN2, 57 + PCF50633_REGULATOR_LDO1, 58 + PCF50633_REGULATOR_LDO2, 59 + PCF50633_REGULATOR_LDO3, 60 + PCF50633_REGULATOR_LDO4, 61 + PCF50633_REGULATOR_LDO5, 62 + PCF50633_REGULATOR_LDO6, 63 + PCF50633_REGULATOR_HCLDO, 64 + PCF50633_REGULATOR_MEMLDO, 65 + }; 66 + #endif 67 +