1 /* 2 * TI LM363X Regulator Driver 3 * 4 * Copyright 2015 Texas Instruments 5 * 6 * Author: Milo Kim <milo.kim@ti.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13 #include <linux/err.h> 14 #include <linux/kernel.h> 15 #include <linux/mfd/ti-lmu.h> 16 #include <linux/mfd/ti-lmu-register.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/of_gpio.h> 20 #include <linux/platform_device.h> 21 #include <linux/regulator/driver.h> 22 #include <linux/regulator/of_regulator.h> 23 #include <linux/slab.h> 24 25 /* LM3631 */ 26 #define LM3631_BOOST_VSEL_MAX 0x25 27 #define LM3631_LDO_VSEL_MAX 0x28 28 #define LM3631_CONT_VSEL_MAX 0x03 29 #define LM3631_VBOOST_MIN 4500000 30 #define LM3631_VCONT_MIN 1800000 31 #define LM3631_VLDO_MIN 4000000 32 #define ENABLE_TIME_USEC 1000 33 34 /* LM3632 */ 35 #define LM3632_BOOST_VSEL_MAX 0x26 36 #define LM3632_LDO_VSEL_MAX 0x29 37 #define LM3632_VBOOST_MIN 4500000 38 #define LM3632_VLDO_MIN 4000000 39 40 /* Common */ 41 #define LM363X_STEP_50mV 50000 42 #define LM363X_STEP_500mV 500000 43 44 static const int ldo_cont_enable_time[] = { 45 0, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 46 }; 47 48 static int lm363x_regulator_enable_time(struct regulator_dev *rdev) 49 { 50 enum lm363x_regulator_id id = rdev_get_id(rdev); 51 u8 val, addr, mask; 52 53 switch (id) { 54 case LM3631_LDO_CONT: 55 addr = LM3631_REG_ENTIME_VCONT; 56 mask = LM3631_ENTIME_CONT_MASK; 57 break; 58 case LM3631_LDO_OREF: 59 addr = LM3631_REG_ENTIME_VOREF; 60 mask = LM3631_ENTIME_MASK; 61 break; 62 case LM3631_LDO_POS: 63 addr = LM3631_REG_ENTIME_VPOS; 64 mask = LM3631_ENTIME_MASK; 65 break; 66 case LM3631_LDO_NEG: 67 addr = LM3631_REG_ENTIME_VNEG; 68 mask = LM3631_ENTIME_MASK; 69 break; 70 default: 71 return 0; 72 } 73 74 if (regmap_read(rdev->regmap, addr, (unsigned int *)&val)) 75 return -EINVAL; 76 77 val = (val & mask) >> LM3631_ENTIME_SHIFT; 78 79 if (id == LM3631_LDO_CONT) 80 return ldo_cont_enable_time[val]; 81 else 82 return ENABLE_TIME_USEC * val; 83 } 84 85 static struct regulator_ops lm363x_boost_voltage_table_ops = { 86 .list_voltage = regulator_list_voltage_linear, 87 .set_voltage_sel = regulator_set_voltage_sel_regmap, 88 .get_voltage_sel = regulator_get_voltage_sel_regmap, 89 }; 90 91 static struct regulator_ops lm363x_regulator_voltage_table_ops = { 92 .list_voltage = regulator_list_voltage_linear, 93 .set_voltage_sel = regulator_set_voltage_sel_regmap, 94 .get_voltage_sel = regulator_get_voltage_sel_regmap, 95 .enable = regulator_enable_regmap, 96 .disable = regulator_disable_regmap, 97 .is_enabled = regulator_is_enabled_regmap, 98 .enable_time = lm363x_regulator_enable_time, 99 }; 100 101 static const struct regulator_desc lm363x_regulator_desc[] = { 102 /* LM3631 */ 103 { 104 .name = "vboost", 105 .of_match = "vboost", 106 .id = LM3631_BOOST, 107 .ops = &lm363x_boost_voltage_table_ops, 108 .n_voltages = LM3631_BOOST_VSEL_MAX + 1, 109 .min_uV = LM3631_VBOOST_MIN, 110 .uV_step = LM363X_STEP_50mV, 111 .type = REGULATOR_VOLTAGE, 112 .owner = THIS_MODULE, 113 .vsel_reg = LM3631_REG_VOUT_BOOST, 114 .vsel_mask = LM3631_VOUT_MASK, 115 }, 116 { 117 .name = "ldo_cont", 118 .of_match = "vcont", 119 .id = LM3631_LDO_CONT, 120 .ops = &lm363x_regulator_voltage_table_ops, 121 .n_voltages = LM3631_CONT_VSEL_MAX + 1, 122 .min_uV = LM3631_VCONT_MIN, 123 .uV_step = LM363X_STEP_500mV, 124 .type = REGULATOR_VOLTAGE, 125 .owner = THIS_MODULE, 126 .vsel_reg = LM3631_REG_VOUT_CONT, 127 .vsel_mask = LM3631_VOUT_CONT_MASK, 128 .enable_reg = LM3631_REG_LDO_CTRL2, 129 .enable_mask = LM3631_EN_CONT_MASK, 130 }, 131 { 132 .name = "ldo_oref", 133 .of_match = "voref", 134 .id = LM3631_LDO_OREF, 135 .ops = &lm363x_regulator_voltage_table_ops, 136 .n_voltages = LM3631_LDO_VSEL_MAX + 1, 137 .min_uV = LM3631_VLDO_MIN, 138 .uV_step = LM363X_STEP_50mV, 139 .type = REGULATOR_VOLTAGE, 140 .owner = THIS_MODULE, 141 .vsel_reg = LM3631_REG_VOUT_OREF, 142 .vsel_mask = LM3631_VOUT_MASK, 143 .enable_reg = LM3631_REG_LDO_CTRL1, 144 .enable_mask = LM3631_EN_OREF_MASK, 145 }, 146 { 147 .name = "ldo_vpos", 148 .of_match = "vpos", 149 .id = LM3631_LDO_POS, 150 .ops = &lm363x_regulator_voltage_table_ops, 151 .n_voltages = LM3631_LDO_VSEL_MAX + 1, 152 .min_uV = LM3631_VLDO_MIN, 153 .uV_step = LM363X_STEP_50mV, 154 .type = REGULATOR_VOLTAGE, 155 .owner = THIS_MODULE, 156 .vsel_reg = LM3631_REG_VOUT_POS, 157 .vsel_mask = LM3631_VOUT_MASK, 158 .enable_reg = LM3631_REG_LDO_CTRL1, 159 .enable_mask = LM3631_EN_VPOS_MASK, 160 }, 161 { 162 .name = "ldo_vneg", 163 .of_match = "vneg", 164 .id = LM3631_LDO_NEG, 165 .ops = &lm363x_regulator_voltage_table_ops, 166 .n_voltages = LM3631_LDO_VSEL_MAX + 1, 167 .min_uV = LM3631_VLDO_MIN, 168 .uV_step = LM363X_STEP_50mV, 169 .type = REGULATOR_VOLTAGE, 170 .owner = THIS_MODULE, 171 .vsel_reg = LM3631_REG_VOUT_NEG, 172 .vsel_mask = LM3631_VOUT_MASK, 173 .enable_reg = LM3631_REG_LDO_CTRL1, 174 .enable_mask = LM3631_EN_VNEG_MASK, 175 }, 176 /* LM3632 */ 177 { 178 .name = "vboost", 179 .of_match = "vboost", 180 .id = LM3632_BOOST, 181 .ops = &lm363x_boost_voltage_table_ops, 182 .n_voltages = LM3632_BOOST_VSEL_MAX + 1, 183 .min_uV = LM3632_VBOOST_MIN, 184 .uV_step = LM363X_STEP_50mV, 185 .type = REGULATOR_VOLTAGE, 186 .owner = THIS_MODULE, 187 .vsel_reg = LM3632_REG_VOUT_BOOST, 188 .vsel_mask = LM3632_VOUT_MASK, 189 }, 190 { 191 .name = "ldo_vpos", 192 .of_match = "vpos", 193 .id = LM3632_LDO_POS, 194 .ops = &lm363x_regulator_voltage_table_ops, 195 .n_voltages = LM3632_LDO_VSEL_MAX + 1, 196 .min_uV = LM3632_VLDO_MIN, 197 .uV_step = LM363X_STEP_50mV, 198 .type = REGULATOR_VOLTAGE, 199 .owner = THIS_MODULE, 200 .vsel_reg = LM3632_REG_VOUT_POS, 201 .vsel_mask = LM3632_VOUT_MASK, 202 .enable_reg = LM3632_REG_BIAS_CONFIG, 203 .enable_mask = LM3632_EN_VPOS_MASK, 204 }, 205 { 206 .name = "ldo_vneg", 207 .of_match = "vneg", 208 .id = LM3632_LDO_NEG, 209 .ops = &lm363x_regulator_voltage_table_ops, 210 .n_voltages = LM3632_LDO_VSEL_MAX + 1, 211 .min_uV = LM3632_VLDO_MIN, 212 .uV_step = LM363X_STEP_50mV, 213 .type = REGULATOR_VOLTAGE, 214 .owner = THIS_MODULE, 215 .vsel_reg = LM3632_REG_VOUT_NEG, 216 .vsel_mask = LM3632_VOUT_MASK, 217 .enable_reg = LM3632_REG_BIAS_CONFIG, 218 .enable_mask = LM3632_EN_VNEG_MASK, 219 }, 220 }; 221 222 static int lm363x_regulator_of_get_enable_gpio(struct device_node *np, int id) 223 { 224 /* 225 * Check LCM_EN1/2_GPIO is configured. 226 * Those pins are used for enabling VPOS/VNEG LDOs. 227 */ 228 switch (id) { 229 case LM3632_LDO_POS: 230 return of_get_named_gpio(np, "enable-gpios", 0); 231 case LM3632_LDO_NEG: 232 return of_get_named_gpio(np, "enable-gpios", 1); 233 default: 234 return -EINVAL; 235 } 236 } 237 238 static int lm363x_regulator_probe(struct platform_device *pdev) 239 { 240 struct ti_lmu *lmu = dev_get_drvdata(pdev->dev.parent); 241 struct regmap *regmap = lmu->regmap; 242 struct regulator_config cfg = { }; 243 struct regulator_dev *rdev; 244 struct device *dev = &pdev->dev; 245 int id = pdev->id; 246 int ret, ena_gpio; 247 248 cfg.dev = dev; 249 cfg.regmap = regmap; 250 251 /* 252 * LM3632 LDOs can be controlled by external pin. 253 * Register update is required if the pin is used. 254 */ 255 ena_gpio = lm363x_regulator_of_get_enable_gpio(dev->of_node, id); 256 if (gpio_is_valid(ena_gpio)) { 257 cfg.ena_gpio = ena_gpio; 258 cfg.ena_gpio_flags = GPIOF_OUT_INIT_LOW; 259 260 ret = regmap_update_bits(regmap, LM3632_REG_BIAS_CONFIG, 261 LM3632_EXT_EN_MASK, 262 LM3632_EXT_EN_MASK); 263 if (ret) { 264 dev_err(dev, "External pin err: %d\n", ret); 265 return ret; 266 } 267 } 268 269 rdev = devm_regulator_register(dev, &lm363x_regulator_desc[id], &cfg); 270 if (IS_ERR(rdev)) { 271 ret = PTR_ERR(rdev); 272 dev_err(dev, "[%d] regulator register err: %d\n", id, ret); 273 return ret; 274 } 275 276 return 0; 277 } 278 279 static struct platform_driver lm363x_regulator_driver = { 280 .probe = lm363x_regulator_probe, 281 .driver = { 282 .name = "lm363x-regulator", 283 }, 284 }; 285 286 module_platform_driver(lm363x_regulator_driver); 287 288 MODULE_DESCRIPTION("TI LM363X Regulator Driver"); 289 MODULE_AUTHOR("Milo Kim"); 290 MODULE_LICENSE("GPL v2"); 291 MODULE_ALIAS("platform:lm363x-regulator"); 292