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