1 /* 2 * arizona-ldo1.c -- LDO1 supply for Arizona devices 3 * 4 * Copyright 2012 Wolfson Microelectronics PLC. 5 * 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/moduleparam.h> 16 #include <linux/init.h> 17 #include <linux/bitops.h> 18 #include <linux/err.h> 19 #include <linux/of.h> 20 #include <linux/of_gpio.h> 21 #include <linux/platform_device.h> 22 #include <linux/regulator/driver.h> 23 #include <linux/regulator/machine.h> 24 #include <linux/regulator/of_regulator.h> 25 #include <linux/gpio.h> 26 #include <linux/slab.h> 27 28 #include <linux/mfd/arizona/core.h> 29 #include <linux/mfd/arizona/pdata.h> 30 #include <linux/mfd/arizona/registers.h> 31 32 struct arizona_ldo1 { 33 struct regulator_dev *regulator; 34 struct arizona *arizona; 35 36 struct regulator_consumer_supply supply; 37 struct regulator_init_data init_data; 38 }; 39 40 static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev, 41 unsigned int selector) 42 { 43 if (selector >= rdev->desc->n_voltages) 44 return -EINVAL; 45 46 if (selector == rdev->desc->n_voltages - 1) 47 return 1800000; 48 else 49 return rdev->desc->min_uV + (rdev->desc->uV_step * selector); 50 } 51 52 static int arizona_ldo1_hc_map_voltage(struct regulator_dev *rdev, 53 int min_uV, int max_uV) 54 { 55 int sel; 56 57 sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); 58 if (sel >= rdev->desc->n_voltages) 59 sel = rdev->desc->n_voltages - 1; 60 61 return sel; 62 } 63 64 static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, 65 unsigned sel) 66 { 67 struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); 68 struct regmap *regmap = ldo->arizona->regmap; 69 unsigned int val; 70 int ret; 71 72 if (sel == rdev->desc->n_voltages - 1) 73 val = ARIZONA_LDO1_HI_PWR; 74 else 75 val = 0; 76 77 ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2, 78 ARIZONA_LDO1_HI_PWR, val); 79 if (ret != 0) 80 return ret; 81 82 if (val) 83 return 0; 84 85 val = sel << ARIZONA_LDO1_VSEL_SHIFT; 86 87 return regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_1, 88 ARIZONA_LDO1_VSEL_MASK, val); 89 } 90 91 static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) 92 { 93 struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); 94 struct regmap *regmap = ldo->arizona->regmap; 95 unsigned int val; 96 int ret; 97 98 ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val); 99 if (ret != 0) 100 return ret; 101 102 if (val & ARIZONA_LDO1_HI_PWR) 103 return rdev->desc->n_voltages - 1; 104 105 ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_1, &val); 106 if (ret != 0) 107 return ret; 108 109 return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; 110 } 111 112 static const struct regulator_ops arizona_ldo1_hc_ops = { 113 .list_voltage = arizona_ldo1_hc_list_voltage, 114 .map_voltage = arizona_ldo1_hc_map_voltage, 115 .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, 116 .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, 117 .get_bypass = regulator_get_bypass_regmap, 118 .set_bypass = regulator_set_bypass_regmap, 119 }; 120 121 static const struct regulator_desc arizona_ldo1_hc = { 122 .name = "LDO1", 123 .supply_name = "LDOVDD", 124 .type = REGULATOR_VOLTAGE, 125 .ops = &arizona_ldo1_hc_ops, 126 127 .bypass_reg = ARIZONA_LDO1_CONTROL_1, 128 .bypass_mask = ARIZONA_LDO1_BYPASS, 129 .min_uV = 900000, 130 .uV_step = 50000, 131 .n_voltages = 8, 132 .enable_time = 1500, 133 .ramp_delay = 24000, 134 135 .owner = THIS_MODULE, 136 }; 137 138 static const struct regulator_ops arizona_ldo1_ops = { 139 .list_voltage = regulator_list_voltage_linear, 140 .map_voltage = regulator_map_voltage_linear, 141 .get_voltage_sel = regulator_get_voltage_sel_regmap, 142 .set_voltage_sel = regulator_set_voltage_sel_regmap, 143 }; 144 145 static const struct regulator_desc arizona_ldo1 = { 146 .name = "LDO1", 147 .supply_name = "LDOVDD", 148 .type = REGULATOR_VOLTAGE, 149 .ops = &arizona_ldo1_ops, 150 151 .vsel_reg = ARIZONA_LDO1_CONTROL_1, 152 .vsel_mask = ARIZONA_LDO1_VSEL_MASK, 153 .min_uV = 900000, 154 .uV_step = 25000, 155 .n_voltages = 13, 156 .enable_time = 500, 157 .ramp_delay = 24000, 158 159 .owner = THIS_MODULE, 160 }; 161 162 static const struct regulator_init_data arizona_ldo1_dvfs = { 163 .constraints = { 164 .min_uV = 1200000, 165 .max_uV = 1800000, 166 .valid_ops_mask = REGULATOR_CHANGE_STATUS | 167 REGULATOR_CHANGE_VOLTAGE, 168 }, 169 .num_consumer_supplies = 1, 170 }; 171 172 static const struct regulator_init_data arizona_ldo1_default = { 173 .constraints = { 174 .valid_ops_mask = REGULATOR_CHANGE_STATUS, 175 }, 176 .num_consumer_supplies = 1, 177 }; 178 179 static const struct regulator_init_data arizona_ldo1_wm5110 = { 180 .constraints = { 181 .min_uV = 1175000, 182 .max_uV = 1200000, 183 .valid_ops_mask = REGULATOR_CHANGE_STATUS | 184 REGULATOR_CHANGE_VOLTAGE, 185 }, 186 .num_consumer_supplies = 1, 187 }; 188 189 static int arizona_ldo1_of_get_pdata(struct arizona *arizona, 190 struct regulator_config *config, 191 const struct regulator_desc *desc) 192 { 193 struct arizona_pdata *pdata = &arizona->pdata; 194 struct arizona_ldo1 *ldo1 = config->driver_data; 195 struct device_node *np = arizona->dev->of_node; 196 struct device_node *init_node, *dcvdd_node; 197 struct regulator_init_data *init_data; 198 199 pdata->ldoena = of_get_named_gpio(np, "wlf,ldoena", 0); 200 if (pdata->ldoena < 0) { 201 dev_warn(arizona->dev, 202 "LDOENA GPIO property missing/malformed: %d\n", 203 pdata->ldoena); 204 pdata->ldoena = 0; 205 } else { 206 config->ena_gpio_initialized = true; 207 } 208 209 init_node = of_get_child_by_name(np, "ldo1"); 210 dcvdd_node = of_parse_phandle(np, "DCVDD-supply", 0); 211 212 if (init_node) { 213 config->of_node = init_node; 214 215 init_data = of_get_regulator_init_data(arizona->dev, init_node, 216 desc); 217 218 if (init_data) { 219 init_data->consumer_supplies = &ldo1->supply; 220 init_data->num_consumer_supplies = 1; 221 222 if (dcvdd_node && dcvdd_node != init_node) 223 arizona->external_dcvdd = true; 224 225 pdata->ldo1 = init_data; 226 } 227 } else if (dcvdd_node) { 228 arizona->external_dcvdd = true; 229 } 230 231 of_node_put(dcvdd_node); 232 233 return 0; 234 } 235 236 static int arizona_ldo1_probe(struct platform_device *pdev) 237 { 238 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); 239 const struct regulator_desc *desc; 240 struct regulator_config config = { }; 241 struct arizona_ldo1 *ldo1; 242 int ret; 243 244 arizona->external_dcvdd = false; 245 246 ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); 247 if (!ldo1) 248 return -ENOMEM; 249 250 ldo1->arizona = arizona; 251 252 /* 253 * Since the chip usually supplies itself we provide some 254 * default init_data for it. This will be overridden with 255 * platform data if provided. 256 */ 257 switch (arizona->type) { 258 case WM5102: 259 case WM8997: 260 case WM8998: 261 case WM1814: 262 desc = &arizona_ldo1_hc; 263 ldo1->init_data = arizona_ldo1_dvfs; 264 break; 265 case WM5110: 266 case WM8280: 267 desc = &arizona_ldo1; 268 ldo1->init_data = arizona_ldo1_wm5110; 269 break; 270 default: 271 desc = &arizona_ldo1; 272 ldo1->init_data = arizona_ldo1_default; 273 break; 274 } 275 276 ldo1->init_data.consumer_supplies = &ldo1->supply; 277 ldo1->supply.supply = "DCVDD"; 278 ldo1->supply.dev_name = dev_name(arizona->dev); 279 280 config.dev = arizona->dev; 281 config.driver_data = ldo1; 282 config.regmap = arizona->regmap; 283 284 if (IS_ENABLED(CONFIG_OF)) { 285 if (!dev_get_platdata(arizona->dev)) { 286 ret = arizona_ldo1_of_get_pdata(arizona, &config, desc); 287 if (ret < 0) 288 return ret; 289 } 290 } 291 292 config.ena_gpio = arizona->pdata.ldoena; 293 294 if (arizona->pdata.ldo1) 295 config.init_data = arizona->pdata.ldo1; 296 else 297 config.init_data = &ldo1->init_data; 298 299 /* 300 * LDO1 can only be used to supply DCVDD so if it has no 301 * consumers then DCVDD is supplied externally. 302 */ 303 if (config.init_data->num_consumer_supplies == 0) 304 arizona->external_dcvdd = true; 305 306 ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); 307 308 of_node_put(config.of_node); 309 310 if (IS_ERR(ldo1->regulator)) { 311 ret = PTR_ERR(ldo1->regulator); 312 dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", 313 ret); 314 return ret; 315 } 316 317 platform_set_drvdata(pdev, ldo1); 318 319 return 0; 320 } 321 322 static struct platform_driver arizona_ldo1_driver = { 323 .probe = arizona_ldo1_probe, 324 .driver = { 325 .name = "arizona-ldo1", 326 }, 327 }; 328 329 module_platform_driver(arizona_ldo1_driver); 330 331 /* Module information */ 332 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 333 MODULE_DESCRIPTION("Arizona LDO1 driver"); 334 MODULE_LICENSE("GPL"); 335 MODULE_ALIAS("platform:arizona-ldo1"); 336