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/platform_device.h> 20 #include <linux/regulator/driver.h> 21 #include <linux/regulator/machine.h> 22 #include <linux/gpio.h> 23 #include <linux/slab.h> 24 25 #include <linux/mfd/arizona/core.h> 26 #include <linux/mfd/arizona/pdata.h> 27 #include <linux/mfd/arizona/registers.h> 28 29 struct arizona_ldo1 { 30 struct regulator_dev *regulator; 31 struct arizona *arizona; 32 33 struct regulator_consumer_supply supply; 34 struct regulator_init_data init_data; 35 }; 36 37 static int arizona_ldo1_hc_list_voltage(struct regulator_dev *rdev, 38 unsigned int selector) 39 { 40 if (selector >= rdev->desc->n_voltages) 41 return -EINVAL; 42 43 if (selector == rdev->desc->n_voltages - 1) 44 return 1800000; 45 else 46 return rdev->desc->min_uV + (rdev->desc->uV_step * selector); 47 } 48 49 static int arizona_ldo1_hc_map_voltage(struct regulator_dev *rdev, 50 int min_uV, int max_uV) 51 { 52 int sel; 53 54 sel = DIV_ROUND_UP(min_uV - rdev->desc->min_uV, rdev->desc->uV_step); 55 if (sel >= rdev->desc->n_voltages) 56 sel = rdev->desc->n_voltages - 1; 57 58 return sel; 59 } 60 61 static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev, 62 unsigned sel) 63 { 64 struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); 65 struct regmap *regmap = ldo->arizona->regmap; 66 unsigned int val; 67 int ret; 68 69 if (sel == rdev->desc->n_voltages - 1) 70 val = ARIZONA_LDO1_HI_PWR; 71 else 72 val = 0; 73 74 ret = regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_2, 75 ARIZONA_LDO1_HI_PWR, val); 76 if (ret != 0) 77 return ret; 78 79 ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1, 80 ARIZONA_SUBSYS_MAX_FREQ, val); 81 if (ret != 0) 82 return ret; 83 84 if (val) 85 return 0; 86 87 val = sel << ARIZONA_LDO1_VSEL_SHIFT; 88 89 return regmap_update_bits(regmap, ARIZONA_LDO1_CONTROL_1, 90 ARIZONA_LDO1_VSEL_MASK, val); 91 } 92 93 static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) 94 { 95 struct arizona_ldo1 *ldo = rdev_get_drvdata(rdev); 96 struct regmap *regmap = ldo->arizona->regmap; 97 unsigned int val; 98 int ret; 99 100 ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_2, &val); 101 if (ret != 0) 102 return ret; 103 104 if (val & ARIZONA_LDO1_HI_PWR) 105 return rdev->desc->n_voltages - 1; 106 107 ret = regmap_read(regmap, ARIZONA_LDO1_CONTROL_1, &val); 108 if (ret != 0) 109 return ret; 110 111 return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; 112 } 113 114 static struct regulator_ops arizona_ldo1_hc_ops = { 115 .list_voltage = arizona_ldo1_hc_list_voltage, 116 .map_voltage = arizona_ldo1_hc_map_voltage, 117 .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, 118 .set_voltage_sel = arizona_ldo1_hc_set_voltage_sel, 119 .get_bypass = regulator_get_bypass_regmap, 120 .set_bypass = regulator_set_bypass_regmap, 121 }; 122 123 static const struct regulator_desc arizona_ldo1_hc = { 124 .name = "LDO1", 125 .supply_name = "LDOVDD", 126 .type = REGULATOR_VOLTAGE, 127 .ops = &arizona_ldo1_hc_ops, 128 129 .bypass_reg = ARIZONA_LDO1_CONTROL_1, 130 .bypass_mask = ARIZONA_LDO1_BYPASS, 131 .min_uV = 900000, 132 .uV_step = 50000, 133 .n_voltages = 8, 134 .enable_time = 1500, 135 136 .owner = THIS_MODULE, 137 }; 138 139 static struct regulator_ops arizona_ldo1_ops = { 140 .list_voltage = regulator_list_voltage_linear, 141 .map_voltage = regulator_map_voltage_linear, 142 .get_voltage_sel = regulator_get_voltage_sel_regmap, 143 .set_voltage_sel = regulator_set_voltage_sel_regmap, 144 .get_bypass = regulator_get_bypass_regmap, 145 .set_bypass = regulator_set_bypass_regmap, 146 }; 147 148 static const struct regulator_desc arizona_ldo1 = { 149 .name = "LDO1", 150 .supply_name = "LDOVDD", 151 .type = REGULATOR_VOLTAGE, 152 .ops = &arizona_ldo1_ops, 153 154 .vsel_reg = ARIZONA_LDO1_CONTROL_1, 155 .vsel_mask = ARIZONA_LDO1_VSEL_MASK, 156 .bypass_reg = ARIZONA_LDO1_CONTROL_1, 157 .bypass_mask = ARIZONA_LDO1_BYPASS, 158 .min_uV = 900000, 159 .uV_step = 50000, 160 .n_voltages = 7, 161 .enable_time = 500, 162 163 .owner = THIS_MODULE, 164 }; 165 166 static const struct regulator_init_data arizona_ldo1_dvfs = { 167 .constraints = { 168 .min_uV = 1200000, 169 .max_uV = 1800000, 170 .valid_ops_mask = REGULATOR_CHANGE_STATUS | 171 REGULATOR_CHANGE_VOLTAGE, 172 }, 173 .num_consumer_supplies = 1, 174 }; 175 176 static const struct regulator_init_data arizona_ldo1_default = { 177 .constraints = { 178 .valid_ops_mask = REGULATOR_CHANGE_STATUS, 179 }, 180 .num_consumer_supplies = 1, 181 }; 182 183 static int arizona_ldo1_probe(struct platform_device *pdev) 184 { 185 struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); 186 const struct regulator_desc *desc; 187 struct regulator_config config = { }; 188 struct arizona_ldo1 *ldo1; 189 int ret; 190 191 ldo1 = devm_kzalloc(&pdev->dev, sizeof(*ldo1), GFP_KERNEL); 192 if (ldo1 == NULL) { 193 dev_err(&pdev->dev, "Unable to allocate private data\n"); 194 return -ENOMEM; 195 } 196 197 ldo1->arizona = arizona; 198 199 /* 200 * Since the chip usually supplies itself we provide some 201 * default init_data for it. This will be overridden with 202 * platform data if provided. 203 */ 204 switch (arizona->type) { 205 case WM5102: 206 desc = &arizona_ldo1_hc; 207 ldo1->init_data = arizona_ldo1_dvfs; 208 break; 209 default: 210 desc = &arizona_ldo1; 211 ldo1->init_data = arizona_ldo1_default; 212 break; 213 } 214 215 ldo1->init_data.consumer_supplies = &ldo1->supply; 216 ldo1->supply.supply = "DCVDD"; 217 ldo1->supply.dev_name = dev_name(arizona->dev); 218 219 config.dev = arizona->dev; 220 config.driver_data = ldo1; 221 config.regmap = arizona->regmap; 222 config.ena_gpio = arizona->pdata.ldoena; 223 224 if (arizona->pdata.ldo1) 225 config.init_data = arizona->pdata.ldo1; 226 else 227 config.init_data = &ldo1->init_data; 228 229 ldo1->regulator = devm_regulator_register(&pdev->dev, desc, &config); 230 if (IS_ERR(ldo1->regulator)) { 231 ret = PTR_ERR(ldo1->regulator); 232 dev_err(arizona->dev, "Failed to register LDO1 supply: %d\n", 233 ret); 234 return ret; 235 } 236 237 platform_set_drvdata(pdev, ldo1); 238 239 return 0; 240 } 241 242 static struct platform_driver arizona_ldo1_driver = { 243 .probe = arizona_ldo1_probe, 244 .driver = { 245 .name = "arizona-ldo1", 246 .owner = THIS_MODULE, 247 }, 248 }; 249 250 module_platform_driver(arizona_ldo1_driver); 251 252 /* Module information */ 253 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); 254 MODULE_DESCRIPTION("Arizona LDO1 driver"); 255 MODULE_LICENSE("GPL"); 256 MODULE_ALIAS("platform:arizona-ldo1"); 257