1 /* 2 * AS3711 PMIC regulator driver, using DCDC Step Down and LDO supplies 3 * 4 * Copyright (C) 2012 Renesas Electronics Corporation 5 * Author: Guennadi Liakhovetski, <g.liakhovetski@gmx.de> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the version 2 of the GNU General Public License as 9 * published by the Free Software Foundation 10 */ 11 12 #include <linux/err.h> 13 #include <linux/init.h> 14 #include <linux/mfd/as3711.h> 15 #include <linux/module.h> 16 #include <linux/platform_device.h> 17 #include <linux/regmap.h> 18 #include <linux/regulator/driver.h> 19 #include <linux/slab.h> 20 21 struct as3711_regulator_info { 22 struct regulator_desc desc; 23 unsigned int max_uV; 24 }; 25 26 struct as3711_regulator { 27 struct as3711_regulator_info *reg_info; 28 struct regulator_dev *rdev; 29 }; 30 31 static int as3711_list_voltage_sd(struct regulator_dev *rdev, 32 unsigned int selector) 33 { 34 if (selector >= rdev->desc->n_voltages) 35 return -EINVAL; 36 37 if (!selector) 38 return 0; 39 if (selector < 0x41) 40 return 600000 + selector * 12500; 41 if (selector < 0x71) 42 return 1400000 + (selector - 0x40) * 25000; 43 return 2600000 + (selector - 0x70) * 50000; 44 } 45 46 static int as3711_list_voltage_aldo(struct regulator_dev *rdev, 47 unsigned int selector) 48 { 49 if (selector >= rdev->desc->n_voltages) 50 return -EINVAL; 51 52 if (selector < 0x10) 53 return 1200000 + selector * 50000; 54 return 1800000 + (selector - 0x10) * 100000; 55 } 56 57 static int as3711_list_voltage_dldo(struct regulator_dev *rdev, 58 unsigned int selector) 59 { 60 if (selector >= rdev->desc->n_voltages || 61 (selector > 0x10 && selector < 0x20)) 62 return -EINVAL; 63 64 if (selector < 0x11) 65 return 900000 + selector * 50000; 66 return 1750000 + (selector - 0x20) * 50000; 67 } 68 69 static int as3711_bound_check(struct regulator_dev *rdev, 70 int *min_uV, int *max_uV) 71 { 72 struct as3711_regulator *reg = rdev_get_drvdata(rdev); 73 struct as3711_regulator_info *info = reg->reg_info; 74 75 dev_dbg(&rdev->dev, "%s(), %d, %d, %d\n", __func__, 76 *min_uV, rdev->desc->min_uV, info->max_uV); 77 78 if (*max_uV < *min_uV || 79 *min_uV > info->max_uV || rdev->desc->min_uV > *max_uV) 80 return -EINVAL; 81 82 if (rdev->desc->n_voltages == 1) 83 return 0; 84 85 if (*max_uV > info->max_uV) 86 *max_uV = info->max_uV; 87 88 if (*min_uV < rdev->desc->min_uV) 89 *min_uV = rdev->desc->min_uV; 90 91 return *min_uV; 92 } 93 94 static int as3711_sel_check(int min, int max, int bottom, int step) 95 { 96 int sel, voltage; 97 98 /* Round up min, when dividing: keeps us within the range */ 99 sel = DIV_ROUND_UP(min - bottom, step); 100 voltage = sel * step + bottom; 101 pr_debug("%s(): select %d..%d in %d+N*%d: %d\n", __func__, 102 min, max, bottom, step, sel); 103 if (voltage > max) 104 return -EINVAL; 105 106 return sel; 107 } 108 109 static int as3711_map_voltage_sd(struct regulator_dev *rdev, 110 int min_uV, int max_uV) 111 { 112 int ret; 113 114 ret = as3711_bound_check(rdev, &min_uV, &max_uV); 115 if (ret <= 0) 116 return ret; 117 118 if (min_uV <= 1400000) 119 return as3711_sel_check(min_uV, max_uV, 600000, 12500); 120 121 if (min_uV <= 2600000) 122 return as3711_sel_check(min_uV, max_uV, 1400000, 25000) + 0x40; 123 124 return as3711_sel_check(min_uV, max_uV, 2600000, 50000) + 0x70; 125 } 126 127 /* 128 * The regulator API supports 4 modes of operataion: FAST, NORMAL, IDLE and 129 * STANDBY. We map them in the following way to AS3711 SD1-4 DCDC modes: 130 * FAST: sdX_fast=1 131 * NORMAL: low_noise=1 132 * IDLE: low_noise=0 133 */ 134 135 static int as3711_set_mode_sd(struct regulator_dev *rdev, unsigned int mode) 136 { 137 unsigned int fast_bit = rdev->desc->enable_mask, 138 low_noise_bit = fast_bit << 4; 139 u8 val; 140 141 switch (mode) { 142 case REGULATOR_MODE_FAST: 143 val = fast_bit | low_noise_bit; 144 break; 145 case REGULATOR_MODE_NORMAL: 146 val = low_noise_bit; 147 break; 148 case REGULATOR_MODE_IDLE: 149 val = 0; 150 break; 151 default: 152 return -EINVAL; 153 } 154 155 return regmap_update_bits(rdev->regmap, AS3711_SD_CONTROL_1, 156 low_noise_bit | fast_bit, val); 157 } 158 159 static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev) 160 { 161 unsigned int fast_bit = rdev->desc->enable_mask, 162 low_noise_bit = fast_bit << 4, mask = fast_bit | low_noise_bit; 163 unsigned int val; 164 int ret = regmap_read(rdev->regmap, AS3711_SD_CONTROL_1, &val); 165 166 if (ret < 0) 167 return ret; 168 169 if ((val & mask) == mask) 170 return REGULATOR_MODE_FAST; 171 172 if ((val & mask) == low_noise_bit) 173 return REGULATOR_MODE_NORMAL; 174 175 if (!(val & mask)) 176 return REGULATOR_MODE_IDLE; 177 178 return -EINVAL; 179 } 180 181 static int as3711_map_voltage_aldo(struct regulator_dev *rdev, 182 int min_uV, int max_uV) 183 { 184 int ret; 185 186 ret = as3711_bound_check(rdev, &min_uV, &max_uV); 187 if (ret <= 0) 188 return ret; 189 190 if (min_uV <= 1800000) 191 return as3711_sel_check(min_uV, max_uV, 1200000, 50000); 192 193 return as3711_sel_check(min_uV, max_uV, 1800000, 100000) + 0x10; 194 } 195 196 static int as3711_map_voltage_dldo(struct regulator_dev *rdev, 197 int min_uV, int max_uV) 198 { 199 int ret; 200 201 ret = as3711_bound_check(rdev, &min_uV, &max_uV); 202 if (ret <= 0) 203 return ret; 204 205 if (min_uV <= 1700000) 206 return as3711_sel_check(min_uV, max_uV, 900000, 50000); 207 208 return as3711_sel_check(min_uV, max_uV, 1750000, 50000) + 0x20; 209 } 210 211 static struct regulator_ops as3711_sd_ops = { 212 .is_enabled = regulator_is_enabled_regmap, 213 .enable = regulator_enable_regmap, 214 .disable = regulator_disable_regmap, 215 .get_voltage_sel = regulator_get_voltage_sel_regmap, 216 .set_voltage_sel = regulator_set_voltage_sel_regmap, 217 .list_voltage = as3711_list_voltage_sd, 218 .map_voltage = as3711_map_voltage_sd, 219 .get_mode = as3711_get_mode_sd, 220 .set_mode = as3711_set_mode_sd, 221 }; 222 223 static struct regulator_ops as3711_aldo_ops = { 224 .is_enabled = regulator_is_enabled_regmap, 225 .enable = regulator_enable_regmap, 226 .disable = regulator_disable_regmap, 227 .get_voltage_sel = regulator_get_voltage_sel_regmap, 228 .set_voltage_sel = regulator_set_voltage_sel_regmap, 229 .list_voltage = as3711_list_voltage_aldo, 230 .map_voltage = as3711_map_voltage_aldo, 231 }; 232 233 static struct regulator_ops as3711_dldo_ops = { 234 .is_enabled = regulator_is_enabled_regmap, 235 .enable = regulator_enable_regmap, 236 .disable = regulator_disable_regmap, 237 .get_voltage_sel = regulator_get_voltage_sel_regmap, 238 .set_voltage_sel = regulator_set_voltage_sel_regmap, 239 .list_voltage = as3711_list_voltage_dldo, 240 .map_voltage = as3711_map_voltage_dldo, 241 }; 242 243 #define AS3711_REG(_id, _en_reg, _en_bit, _vmask, _vshift, _min_uV, _max_uV, _sfx) \ 244 [AS3711_REGULATOR_ ## _id] = { \ 245 .desc = { \ 246 .name = "as3711-regulator-" # _id, \ 247 .id = AS3711_REGULATOR_ ## _id, \ 248 .n_voltages = (_vmask + 1), \ 249 .ops = &as3711_ ## _sfx ## _ops, \ 250 .type = REGULATOR_VOLTAGE, \ 251 .owner = THIS_MODULE, \ 252 .vsel_reg = AS3711_ ## _id ## _VOLTAGE, \ 253 .vsel_mask = _vmask << _vshift, \ 254 .enable_reg = AS3711_ ## _en_reg, \ 255 .enable_mask = BIT(_en_bit), \ 256 .min_uV = _min_uV, \ 257 }, \ 258 .max_uV = _max_uV, \ 259 } 260 261 static struct as3711_regulator_info as3711_reg_info[] = { 262 AS3711_REG(SD_1, SD_CONTROL, 0, 0x7f, 0, 612500, 3350000, sd), 263 AS3711_REG(SD_2, SD_CONTROL, 1, 0x7f, 0, 612500, 3350000, sd), 264 AS3711_REG(SD_3, SD_CONTROL, 2, 0x7f, 0, 612500, 3350000, sd), 265 AS3711_REG(SD_4, SD_CONTROL, 3, 0x7f, 0, 612500, 3350000, sd), 266 AS3711_REG(LDO_1, LDO_1_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), 267 AS3711_REG(LDO_2, LDO_2_VOLTAGE, 7, 0x1f, 0, 1200000, 3300000, aldo), 268 AS3711_REG(LDO_3, LDO_3_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 269 AS3711_REG(LDO_4, LDO_4_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 270 AS3711_REG(LDO_5, LDO_5_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 271 AS3711_REG(LDO_6, LDO_6_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 272 AS3711_REG(LDO_7, LDO_7_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 273 AS3711_REG(LDO_8, LDO_8_VOLTAGE, 7, 0x3f, 0, 900000, 3300000, dldo), 274 /* StepUp output voltage depends on supplying regulator */ 275 }; 276 277 #define AS3711_REGULATOR_NUM ARRAY_SIZE(as3711_reg_info) 278 279 static int as3711_regulator_probe(struct platform_device *pdev) 280 { 281 struct as3711_regulator_pdata *pdata = dev_get_platdata(&pdev->dev); 282 struct as3711 *as3711 = dev_get_drvdata(pdev->dev.parent); 283 struct regulator_init_data *reg_data; 284 struct regulator_config config = {.dev = &pdev->dev,}; 285 struct as3711_regulator *reg = NULL; 286 struct as3711_regulator *regs; 287 struct regulator_dev *rdev; 288 struct as3711_regulator_info *ri; 289 int ret; 290 int id; 291 292 if (!pdata) 293 dev_dbg(&pdev->dev, "No platform data...\n"); 294 295 regs = devm_kzalloc(&pdev->dev, AS3711_REGULATOR_NUM * 296 sizeof(struct as3711_regulator), GFP_KERNEL); 297 if (!regs) { 298 dev_err(&pdev->dev, "Memory allocation failed exiting..\n"); 299 return -ENOMEM; 300 } 301 302 for (id = 0, ri = as3711_reg_info; id < AS3711_REGULATOR_NUM; ++id, ri++) { 303 reg_data = pdata ? pdata->init_data[id] : NULL; 304 305 /* No need to register if there is no regulator data */ 306 if (!ri->desc.name) 307 continue; 308 309 reg = ®s[id]; 310 reg->reg_info = ri; 311 312 config.init_data = reg_data; 313 config.driver_data = reg; 314 config.regmap = as3711->regmap; 315 316 rdev = regulator_register(&ri->desc, &config); 317 if (IS_ERR(rdev)) { 318 dev_err(&pdev->dev, "Failed to register regulator %s\n", 319 ri->desc.name); 320 ret = PTR_ERR(rdev); 321 goto eregreg; 322 } 323 reg->rdev = rdev; 324 } 325 platform_set_drvdata(pdev, regs); 326 return 0; 327 328 eregreg: 329 while (--id >= 0) 330 regulator_unregister(regs[id].rdev); 331 332 return ret; 333 } 334 335 static int as3711_regulator_remove(struct platform_device *pdev) 336 { 337 struct as3711_regulator *regs = platform_get_drvdata(pdev); 338 int id; 339 340 for (id = 0; id < AS3711_REGULATOR_NUM; ++id) 341 regulator_unregister(regs[id].rdev); 342 return 0; 343 } 344 345 static struct platform_driver as3711_regulator_driver = { 346 .driver = { 347 .name = "as3711-regulator", 348 .owner = THIS_MODULE, 349 }, 350 .probe = as3711_regulator_probe, 351 .remove = as3711_regulator_remove, 352 }; 353 354 static int __init as3711_regulator_init(void) 355 { 356 return platform_driver_register(&as3711_regulator_driver); 357 } 358 subsys_initcall(as3711_regulator_init); 359 360 static void __exit as3711_regulator_exit(void) 361 { 362 platform_driver_unregister(&as3711_regulator_driver); 363 } 364 module_exit(as3711_regulator_exit); 365 366 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>"); 367 MODULE_DESCRIPTION("AS3711 regulator driver"); 368 MODULE_ALIAS("platform:as3711-regulator"); 369 MODULE_LICENSE("GPL v2"); 370