| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame^] | 1 | // SPDX-License-Identifier: GPL-2.0+ | 
|  | 2 | // | 
|  | 3 | // Copyright (c) 2011 Samsung Electronics Co., Ltd | 
|  | 4 | //              http://www.samsung.com | 
|  | 5 |  | 
|  | 6 | #include <linux/err.h> | 
|  | 7 | #include <linux/of_gpio.h> | 
|  | 8 | #include <linux/gpio/consumer.h> | 
|  | 9 | #include <linux/module.h> | 
|  | 10 | #include <linux/platform_device.h> | 
|  | 11 | #include <linux/regulator/driver.h> | 
|  | 12 | #include <linux/regulator/machine.h> | 
|  | 13 | #include <linux/mfd/samsung/core.h> | 
|  | 14 | #include <linux/mfd/samsung/s5m8767.h> | 
|  | 15 | #include <linux/regulator/of_regulator.h> | 
|  | 16 | #include <linux/regmap.h> | 
|  | 17 |  | 
|  | 18 | #define S5M8767_OPMODE_NORMAL_MODE 0x1 | 
|  | 19 |  | 
|  | 20 | struct s5m8767_info { | 
|  | 21 | struct device *dev; | 
|  | 22 | struct sec_pmic_dev *iodev; | 
|  | 23 | int num_regulators; | 
|  | 24 | struct sec_opmode_data *opmode; | 
|  | 25 |  | 
|  | 26 | int ramp_delay; | 
|  | 27 | bool buck2_ramp; | 
|  | 28 | bool buck3_ramp; | 
|  | 29 | bool buck4_ramp; | 
|  | 30 |  | 
|  | 31 | bool buck2_gpiodvs; | 
|  | 32 | bool buck3_gpiodvs; | 
|  | 33 | bool buck4_gpiodvs; | 
|  | 34 | u8 buck2_vol[8]; | 
|  | 35 | u8 buck3_vol[8]; | 
|  | 36 | u8 buck4_vol[8]; | 
|  | 37 | int buck_gpios[3]; | 
|  | 38 | int buck_ds[3]; | 
|  | 39 | int buck_gpioindex; | 
|  | 40 | }; | 
|  | 41 |  | 
|  | 42 | struct sec_voltage_desc { | 
|  | 43 | int max; | 
|  | 44 | int min; | 
|  | 45 | int step; | 
|  | 46 | }; | 
|  | 47 |  | 
|  | 48 | static const struct sec_voltage_desc buck_voltage_val1 = { | 
|  | 49 | .max = 2225000, | 
|  | 50 | .min =  650000, | 
|  | 51 | .step =   6250, | 
|  | 52 | }; | 
|  | 53 |  | 
|  | 54 | static const struct sec_voltage_desc buck_voltage_val2 = { | 
|  | 55 | .max = 1600000, | 
|  | 56 | .min =  600000, | 
|  | 57 | .step =   6250, | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | static const struct sec_voltage_desc buck_voltage_val3 = { | 
|  | 61 | .max = 3000000, | 
|  | 62 | .min =  750000, | 
|  | 63 | .step =  12500, | 
|  | 64 | }; | 
|  | 65 |  | 
|  | 66 | static const struct sec_voltage_desc ldo_voltage_val1 = { | 
|  | 67 | .max = 3950000, | 
|  | 68 | .min =  800000, | 
|  | 69 | .step =  50000, | 
|  | 70 | }; | 
|  | 71 |  | 
|  | 72 | static const struct sec_voltage_desc ldo_voltage_val2 = { | 
|  | 73 | .max = 2375000, | 
|  | 74 | .min =  800000, | 
|  | 75 | .step =  25000, | 
|  | 76 | }; | 
|  | 77 |  | 
|  | 78 | static const struct sec_voltage_desc *reg_voltage_map[] = { | 
|  | 79 | [S5M8767_LDO1] = &ldo_voltage_val2, | 
|  | 80 | [S5M8767_LDO2] = &ldo_voltage_val2, | 
|  | 81 | [S5M8767_LDO3] = &ldo_voltage_val1, | 
|  | 82 | [S5M8767_LDO4] = &ldo_voltage_val1, | 
|  | 83 | [S5M8767_LDO5] = &ldo_voltage_val1, | 
|  | 84 | [S5M8767_LDO6] = &ldo_voltage_val2, | 
|  | 85 | [S5M8767_LDO7] = &ldo_voltage_val2, | 
|  | 86 | [S5M8767_LDO8] = &ldo_voltage_val2, | 
|  | 87 | [S5M8767_LDO9] = &ldo_voltage_val1, | 
|  | 88 | [S5M8767_LDO10] = &ldo_voltage_val1, | 
|  | 89 | [S5M8767_LDO11] = &ldo_voltage_val1, | 
|  | 90 | [S5M8767_LDO12] = &ldo_voltage_val1, | 
|  | 91 | [S5M8767_LDO13] = &ldo_voltage_val1, | 
|  | 92 | [S5M8767_LDO14] = &ldo_voltage_val1, | 
|  | 93 | [S5M8767_LDO15] = &ldo_voltage_val2, | 
|  | 94 | [S5M8767_LDO16] = &ldo_voltage_val1, | 
|  | 95 | [S5M8767_LDO17] = &ldo_voltage_val1, | 
|  | 96 | [S5M8767_LDO18] = &ldo_voltage_val1, | 
|  | 97 | [S5M8767_LDO19] = &ldo_voltage_val1, | 
|  | 98 | [S5M8767_LDO20] = &ldo_voltage_val1, | 
|  | 99 | [S5M8767_LDO21] = &ldo_voltage_val1, | 
|  | 100 | [S5M8767_LDO22] = &ldo_voltage_val1, | 
|  | 101 | [S5M8767_LDO23] = &ldo_voltage_val1, | 
|  | 102 | [S5M8767_LDO24] = &ldo_voltage_val1, | 
|  | 103 | [S5M8767_LDO25] = &ldo_voltage_val1, | 
|  | 104 | [S5M8767_LDO26] = &ldo_voltage_val1, | 
|  | 105 | [S5M8767_LDO27] = &ldo_voltage_val1, | 
|  | 106 | [S5M8767_LDO28] = &ldo_voltage_val1, | 
|  | 107 | [S5M8767_BUCK1] = &buck_voltage_val1, | 
|  | 108 | [S5M8767_BUCK2] = &buck_voltage_val2, | 
|  | 109 | [S5M8767_BUCK3] = &buck_voltage_val2, | 
|  | 110 | [S5M8767_BUCK4] = &buck_voltage_val2, | 
|  | 111 | [S5M8767_BUCK5] = &buck_voltage_val1, | 
|  | 112 | [S5M8767_BUCK6] = &buck_voltage_val1, | 
|  | 113 | [S5M8767_BUCK7] = &buck_voltage_val3, | 
|  | 114 | [S5M8767_BUCK8] = &buck_voltage_val3, | 
|  | 115 | [S5M8767_BUCK9] = &buck_voltage_val3, | 
|  | 116 | }; | 
|  | 117 |  | 
|  | 118 | static unsigned int s5m8767_opmode_reg[][4] = { | 
|  | 119 | /* {OFF, ON, LOWPOWER, SUSPEND} */ | 
|  | 120 | /* LDO1 ... LDO28 */ | 
|  | 121 | {0x0, 0x3, 0x2, 0x1}, /* LDO1 */ | 
|  | 122 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 123 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 124 | {0x0, 0x0, 0x0, 0x0}, | 
|  | 125 | {0x0, 0x3, 0x2, 0x1}, /* LDO5 */ | 
|  | 126 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 127 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 128 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 129 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 130 | {0x0, 0x3, 0x2, 0x1}, /* LDO10 */ | 
|  | 131 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 132 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 133 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 134 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 135 | {0x0, 0x3, 0x2, 0x1}, /* LDO15 */ | 
|  | 136 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 137 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 138 | {0x0, 0x0, 0x0, 0x0}, | 
|  | 139 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 140 | {0x0, 0x3, 0x2, 0x1}, /* LDO20 */ | 
|  | 141 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 142 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 143 | {0x0, 0x0, 0x0, 0x0}, | 
|  | 144 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 145 | {0x0, 0x3, 0x2, 0x1}, /* LDO25 */ | 
|  | 146 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 147 | {0x0, 0x3, 0x2, 0x1}, | 
|  | 148 | {0x0, 0x3, 0x2, 0x1}, /* LDO28 */ | 
|  | 149 |  | 
|  | 150 | /* BUCK1 ... BUCK9 */ | 
|  | 151 | {0x0, 0x3, 0x1, 0x1}, /* BUCK1 */ | 
|  | 152 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 153 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 154 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 155 | {0x0, 0x3, 0x2, 0x1}, /* BUCK5 */ | 
|  | 156 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 157 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 158 | {0x0, 0x3, 0x1, 0x1}, | 
|  | 159 | {0x0, 0x3, 0x1, 0x1}, /* BUCK9 */ | 
|  | 160 | }; | 
|  | 161 |  | 
|  | 162 | static int s5m8767_get_register(struct s5m8767_info *s5m8767, int reg_id, | 
|  | 163 | int *reg, int *enable_ctrl) | 
|  | 164 | { | 
|  | 165 | int i; | 
|  | 166 | unsigned int mode; | 
|  | 167 |  | 
|  | 168 | switch (reg_id) { | 
|  | 169 | case S5M8767_LDO1 ... S5M8767_LDO2: | 
|  | 170 | *reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | 
|  | 171 | break; | 
|  | 172 | case S5M8767_LDO3 ... S5M8767_LDO28: | 
|  | 173 | *reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | 
|  | 174 | break; | 
|  | 175 | case S5M8767_BUCK1: | 
|  | 176 | *reg = S5M8767_REG_BUCK1CTRL1; | 
|  | 177 | break; | 
|  | 178 | case S5M8767_BUCK2 ... S5M8767_BUCK4: | 
|  | 179 | *reg = S5M8767_REG_BUCK2CTRL + (reg_id - S5M8767_BUCK2) * 9; | 
|  | 180 | break; | 
|  | 181 | case S5M8767_BUCK5: | 
|  | 182 | *reg = S5M8767_REG_BUCK5CTRL1; | 
|  | 183 | break; | 
|  | 184 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | 
|  | 185 | *reg = S5M8767_REG_BUCK6CTRL1 + (reg_id - S5M8767_BUCK6) * 2; | 
|  | 186 | break; | 
|  | 187 | default: | 
|  | 188 | return -EINVAL; | 
|  | 189 | } | 
|  | 190 |  | 
|  | 191 | for (i = 0; i < s5m8767->num_regulators; i++) { | 
|  | 192 | if (s5m8767->opmode[i].id == reg_id) { | 
|  | 193 | mode = s5m8767->opmode[i].mode; | 
|  | 194 | break; | 
|  | 195 | } | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | if (i >= s5m8767->num_regulators) | 
|  | 199 | return -EINVAL; | 
|  | 200 |  | 
|  | 201 | *enable_ctrl = s5m8767_opmode_reg[reg_id][mode] << S5M8767_ENCTRL_SHIFT; | 
|  | 202 |  | 
|  | 203 | return 0; | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | static int s5m8767_get_vsel_reg(int reg_id, struct s5m8767_info *s5m8767) | 
|  | 207 | { | 
|  | 208 | int reg; | 
|  | 209 |  | 
|  | 210 | switch (reg_id) { | 
|  | 211 | case S5M8767_LDO1 ... S5M8767_LDO2: | 
|  | 212 | reg = S5M8767_REG_LDO1CTRL + (reg_id - S5M8767_LDO1); | 
|  | 213 | break; | 
|  | 214 | case S5M8767_LDO3 ... S5M8767_LDO28: | 
|  | 215 | reg = S5M8767_REG_LDO3CTRL + (reg_id - S5M8767_LDO3); | 
|  | 216 | break; | 
|  | 217 | case S5M8767_BUCK1: | 
|  | 218 | reg = S5M8767_REG_BUCK1CTRL2; | 
|  | 219 | break; | 
|  | 220 | case S5M8767_BUCK2: | 
|  | 221 | reg = S5M8767_REG_BUCK2DVS1; | 
|  | 222 | if (s5m8767->buck2_gpiodvs) | 
|  | 223 | reg += s5m8767->buck_gpioindex; | 
|  | 224 | break; | 
|  | 225 | case S5M8767_BUCK3: | 
|  | 226 | reg = S5M8767_REG_BUCK3DVS1; | 
|  | 227 | if (s5m8767->buck3_gpiodvs) | 
|  | 228 | reg += s5m8767->buck_gpioindex; | 
|  | 229 | break; | 
|  | 230 | case S5M8767_BUCK4: | 
|  | 231 | reg = S5M8767_REG_BUCK4DVS1; | 
|  | 232 | if (s5m8767->buck4_gpiodvs) | 
|  | 233 | reg += s5m8767->buck_gpioindex; | 
|  | 234 | break; | 
|  | 235 | case S5M8767_BUCK5: | 
|  | 236 | reg = S5M8767_REG_BUCK5CTRL2; | 
|  | 237 | break; | 
|  | 238 | case S5M8767_BUCK6 ... S5M8767_BUCK9: | 
|  | 239 | reg = S5M8767_REG_BUCK6CTRL2 + (reg_id - S5M8767_BUCK6) * 2; | 
|  | 240 | break; | 
|  | 241 | default: | 
|  | 242 | return -EINVAL; | 
|  | 243 | } | 
|  | 244 |  | 
|  | 245 | return reg; | 
|  | 246 | } | 
|  | 247 |  | 
|  | 248 | static int s5m8767_convert_voltage_to_sel(const struct sec_voltage_desc *desc, | 
|  | 249 | int min_vol) | 
|  | 250 | { | 
|  | 251 | int selector = 0; | 
|  | 252 |  | 
|  | 253 | if (desc == NULL) | 
|  | 254 | return -EINVAL; | 
|  | 255 |  | 
|  | 256 | if (min_vol > desc->max) | 
|  | 257 | return -EINVAL; | 
|  | 258 |  | 
|  | 259 | if (min_vol < desc->min) | 
|  | 260 | min_vol = desc->min; | 
|  | 261 |  | 
|  | 262 | selector = DIV_ROUND_UP(min_vol - desc->min, desc->step); | 
|  | 263 |  | 
|  | 264 | if (desc->min + desc->step * selector > desc->max) | 
|  | 265 | return -EINVAL; | 
|  | 266 |  | 
|  | 267 | return selector; | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | static inline int s5m8767_set_high(struct s5m8767_info *s5m8767) | 
|  | 271 | { | 
|  | 272 | int temp_index = s5m8767->buck_gpioindex; | 
|  | 273 |  | 
|  | 274 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | 
|  | 275 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | 
|  | 276 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | 
|  | 277 |  | 
|  | 278 | return 0; | 
|  | 279 | } | 
|  | 280 |  | 
|  | 281 | static inline int s5m8767_set_low(struct s5m8767_info *s5m8767) | 
|  | 282 | { | 
|  | 283 | int temp_index = s5m8767->buck_gpioindex; | 
|  | 284 |  | 
|  | 285 | gpio_set_value(s5m8767->buck_gpios[2], temp_index & 0x1); | 
|  | 286 | gpio_set_value(s5m8767->buck_gpios[1], (temp_index >> 1) & 0x1); | 
|  | 287 | gpio_set_value(s5m8767->buck_gpios[0], (temp_index >> 2) & 0x1); | 
|  | 288 |  | 
|  | 289 | return 0; | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | static int s5m8767_set_voltage_sel(struct regulator_dev *rdev, | 
|  | 293 | unsigned selector) | 
|  | 294 | { | 
|  | 295 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 
|  | 296 | int reg_id = rdev_get_id(rdev); | 
|  | 297 | int old_index, index = 0; | 
|  | 298 | u8 *buck234_vol = NULL; | 
|  | 299 |  | 
|  | 300 | switch (reg_id) { | 
|  | 301 | case S5M8767_LDO1 ... S5M8767_LDO28: | 
|  | 302 | break; | 
|  | 303 | case S5M8767_BUCK1 ... S5M8767_BUCK6: | 
|  | 304 | if (reg_id == S5M8767_BUCK2 && s5m8767->buck2_gpiodvs) | 
|  | 305 | buck234_vol = &s5m8767->buck2_vol[0]; | 
|  | 306 | else if (reg_id == S5M8767_BUCK3 && s5m8767->buck3_gpiodvs) | 
|  | 307 | buck234_vol = &s5m8767->buck3_vol[0]; | 
|  | 308 | else if (reg_id == S5M8767_BUCK4 && s5m8767->buck4_gpiodvs) | 
|  | 309 | buck234_vol = &s5m8767->buck4_vol[0]; | 
|  | 310 | break; | 
|  | 311 | case S5M8767_BUCK7 ... S5M8767_BUCK8: | 
|  | 312 | return -EINVAL; | 
|  | 313 | case S5M8767_BUCK9: | 
|  | 314 | break; | 
|  | 315 | default: | 
|  | 316 | return -EINVAL; | 
|  | 317 | } | 
|  | 318 |  | 
|  | 319 | /* buck234_vol != NULL means to control buck234 voltage via DVS GPIO */ | 
|  | 320 | if (buck234_vol) { | 
|  | 321 | while (*buck234_vol != selector) { | 
|  | 322 | buck234_vol++; | 
|  | 323 | index++; | 
|  | 324 | } | 
|  | 325 | old_index = s5m8767->buck_gpioindex; | 
|  | 326 | s5m8767->buck_gpioindex = index; | 
|  | 327 |  | 
|  | 328 | if (index > old_index) | 
|  | 329 | return s5m8767_set_high(s5m8767); | 
|  | 330 | else | 
|  | 331 | return s5m8767_set_low(s5m8767); | 
|  | 332 | } else { | 
|  | 333 | return regulator_set_voltage_sel_regmap(rdev, selector); | 
|  | 334 | } | 
|  | 335 | } | 
|  | 336 |  | 
|  | 337 | static int s5m8767_set_voltage_time_sel(struct regulator_dev *rdev, | 
|  | 338 | unsigned int old_sel, | 
|  | 339 | unsigned int new_sel) | 
|  | 340 | { | 
|  | 341 | struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); | 
|  | 342 | const struct sec_voltage_desc *desc; | 
|  | 343 | int reg_id = rdev_get_id(rdev); | 
|  | 344 |  | 
|  | 345 | desc = reg_voltage_map[reg_id]; | 
|  | 346 |  | 
|  | 347 | if ((old_sel < new_sel) && s5m8767->ramp_delay) | 
|  | 348 | return DIV_ROUND_UP(desc->step * (new_sel - old_sel), | 
|  | 349 | s5m8767->ramp_delay * 1000); | 
|  | 350 | return 0; | 
|  | 351 | } | 
|  | 352 |  | 
|  | 353 | static const struct regulator_ops s5m8767_ops = { | 
|  | 354 | .list_voltage		= regulator_list_voltage_linear, | 
|  | 355 | .is_enabled		= regulator_is_enabled_regmap, | 
|  | 356 | .enable			= regulator_enable_regmap, | 
|  | 357 | .disable		= regulator_disable_regmap, | 
|  | 358 | .get_voltage_sel	= regulator_get_voltage_sel_regmap, | 
|  | 359 | .set_voltage_sel	= s5m8767_set_voltage_sel, | 
|  | 360 | .set_voltage_time_sel	= s5m8767_set_voltage_time_sel, | 
|  | 361 | }; | 
|  | 362 |  | 
|  | 363 | static const struct regulator_ops s5m8767_buck78_ops = { | 
|  | 364 | .list_voltage		= regulator_list_voltage_linear, | 
|  | 365 | .is_enabled		= regulator_is_enabled_regmap, | 
|  | 366 | .enable			= regulator_enable_regmap, | 
|  | 367 | .disable		= regulator_disable_regmap, | 
|  | 368 | .get_voltage_sel	= regulator_get_voltage_sel_regmap, | 
|  | 369 | .set_voltage_sel	= regulator_set_voltage_sel_regmap, | 
|  | 370 | }; | 
|  | 371 |  | 
|  | 372 | #define s5m8767_regulator_desc(_name) {		\ | 
|  | 373 | .name		= #_name,		\ | 
|  | 374 | .id		= S5M8767_##_name,	\ | 
|  | 375 | .ops		= &s5m8767_ops,		\ | 
|  | 376 | .type		= REGULATOR_VOLTAGE,	\ | 
|  | 377 | .owner		= THIS_MODULE,		\ | 
|  | 378 | } | 
|  | 379 |  | 
|  | 380 | #define s5m8767_regulator_buck78_desc(_name) {	\ | 
|  | 381 | .name		= #_name,		\ | 
|  | 382 | .id		= S5M8767_##_name,	\ | 
|  | 383 | .ops		= &s5m8767_buck78_ops,	\ | 
|  | 384 | .type		= REGULATOR_VOLTAGE,	\ | 
|  | 385 | .owner		= THIS_MODULE,		\ | 
|  | 386 | } | 
|  | 387 |  | 
|  | 388 | static struct regulator_desc regulators[] = { | 
|  | 389 | s5m8767_regulator_desc(LDO1), | 
|  | 390 | s5m8767_regulator_desc(LDO2), | 
|  | 391 | s5m8767_regulator_desc(LDO3), | 
|  | 392 | s5m8767_regulator_desc(LDO4), | 
|  | 393 | s5m8767_regulator_desc(LDO5), | 
|  | 394 | s5m8767_regulator_desc(LDO6), | 
|  | 395 | s5m8767_regulator_desc(LDO7), | 
|  | 396 | s5m8767_regulator_desc(LDO8), | 
|  | 397 | s5m8767_regulator_desc(LDO9), | 
|  | 398 | s5m8767_regulator_desc(LDO10), | 
|  | 399 | s5m8767_regulator_desc(LDO11), | 
|  | 400 | s5m8767_regulator_desc(LDO12), | 
|  | 401 | s5m8767_regulator_desc(LDO13), | 
|  | 402 | s5m8767_regulator_desc(LDO14), | 
|  | 403 | s5m8767_regulator_desc(LDO15), | 
|  | 404 | s5m8767_regulator_desc(LDO16), | 
|  | 405 | s5m8767_regulator_desc(LDO17), | 
|  | 406 | s5m8767_regulator_desc(LDO18), | 
|  | 407 | s5m8767_regulator_desc(LDO19), | 
|  | 408 | s5m8767_regulator_desc(LDO20), | 
|  | 409 | s5m8767_regulator_desc(LDO21), | 
|  | 410 | s5m8767_regulator_desc(LDO22), | 
|  | 411 | s5m8767_regulator_desc(LDO23), | 
|  | 412 | s5m8767_regulator_desc(LDO24), | 
|  | 413 | s5m8767_regulator_desc(LDO25), | 
|  | 414 | s5m8767_regulator_desc(LDO26), | 
|  | 415 | s5m8767_regulator_desc(LDO27), | 
|  | 416 | s5m8767_regulator_desc(LDO28), | 
|  | 417 | s5m8767_regulator_desc(BUCK1), | 
|  | 418 | s5m8767_regulator_desc(BUCK2), | 
|  | 419 | s5m8767_regulator_desc(BUCK3), | 
|  | 420 | s5m8767_regulator_desc(BUCK4), | 
|  | 421 | s5m8767_regulator_desc(BUCK5), | 
|  | 422 | s5m8767_regulator_desc(BUCK6), | 
|  | 423 | s5m8767_regulator_buck78_desc(BUCK7), | 
|  | 424 | s5m8767_regulator_buck78_desc(BUCK8), | 
|  | 425 | s5m8767_regulator_desc(BUCK9), | 
|  | 426 | }; | 
|  | 427 |  | 
|  | 428 | /* | 
|  | 429 | * Enable GPIO control over BUCK9 in regulator_config for that regulator. | 
|  | 430 | */ | 
|  | 431 | static void s5m8767_regulator_config_ext_control(struct s5m8767_info *s5m8767, | 
|  | 432 | struct sec_regulator_data *rdata, | 
|  | 433 | struct regulator_config *config) | 
|  | 434 | { | 
|  | 435 | int i, mode = 0; | 
|  | 436 |  | 
|  | 437 | if (rdata->id != S5M8767_BUCK9) | 
|  | 438 | return; | 
|  | 439 |  | 
|  | 440 | /* Check if opmode for regulator matches S5M8767_ENCTRL_USE_GPIO */ | 
|  | 441 | for (i = 0; i < s5m8767->num_regulators; i++) { | 
|  | 442 | const struct sec_opmode_data *opmode = &s5m8767->opmode[i]; | 
|  | 443 | if (opmode->id == rdata->id) { | 
|  | 444 | mode = s5m8767_opmode_reg[rdata->id][opmode->mode]; | 
|  | 445 | break; | 
|  | 446 | } | 
|  | 447 | } | 
|  | 448 | if (mode != S5M8767_ENCTRL_USE_GPIO) { | 
|  | 449 | dev_warn(s5m8767->dev, | 
|  | 450 | "ext-control for %s: mismatched op_mode (%x), ignoring\n", | 
|  | 451 | rdata->reg_node->name, mode); | 
|  | 452 | return; | 
|  | 453 | } | 
|  | 454 |  | 
|  | 455 | if (!rdata->ext_control_gpiod) { | 
|  | 456 | dev_warn(s5m8767->dev, | 
|  | 457 | "ext-control for %s: GPIO not valid, ignoring\n", | 
|  | 458 | rdata->reg_node->name); | 
|  | 459 | return; | 
|  | 460 | } | 
|  | 461 |  | 
|  | 462 | config->ena_gpiod = rdata->ext_control_gpiod; | 
|  | 463 | } | 
|  | 464 |  | 
|  | 465 | /* | 
|  | 466 | * Turn on GPIO control over BUCK9. | 
|  | 467 | */ | 
|  | 468 | static int s5m8767_enable_ext_control(struct s5m8767_info *s5m8767, | 
|  | 469 | struct regulator_dev *rdev) | 
|  | 470 | { | 
|  | 471 | int id = rdev_get_id(rdev); | 
|  | 472 | int ret, reg, enable_ctrl; | 
|  | 473 |  | 
|  | 474 | if (id != S5M8767_BUCK9) | 
|  | 475 | return -EINVAL; | 
|  | 476 |  | 
|  | 477 | ret = s5m8767_get_register(s5m8767, id, ®, &enable_ctrl); | 
|  | 478 | if (ret) | 
|  | 479 | return ret; | 
|  | 480 |  | 
|  | 481 | return regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 482 | reg, S5M8767_ENCTRL_MASK, | 
|  | 483 | S5M8767_ENCTRL_USE_GPIO << S5M8767_ENCTRL_SHIFT); | 
|  | 484 | } | 
|  | 485 |  | 
|  | 486 |  | 
|  | 487 | #ifdef CONFIG_OF | 
|  | 488 | static int s5m8767_pmic_dt_parse_dvs_gpio(struct sec_pmic_dev *iodev, | 
|  | 489 | struct sec_platform_data *pdata, | 
|  | 490 | struct device_node *pmic_np) | 
|  | 491 | { | 
|  | 492 | int i, gpio; | 
|  | 493 |  | 
|  | 494 | for (i = 0; i < 3; i++) { | 
|  | 495 | gpio = of_get_named_gpio(pmic_np, | 
|  | 496 | "s5m8767,pmic-buck-dvs-gpios", i); | 
|  | 497 | if (!gpio_is_valid(gpio)) { | 
|  | 498 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | 
|  | 499 | return -EINVAL; | 
|  | 500 | } | 
|  | 501 | pdata->buck_gpios[i] = gpio; | 
|  | 502 | } | 
|  | 503 | return 0; | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | static int s5m8767_pmic_dt_parse_ds_gpio(struct sec_pmic_dev *iodev, | 
|  | 507 | struct sec_platform_data *pdata, | 
|  | 508 | struct device_node *pmic_np) | 
|  | 509 | { | 
|  | 510 | int i, gpio; | 
|  | 511 |  | 
|  | 512 | for (i = 0; i < 3; i++) { | 
|  | 513 | gpio = of_get_named_gpio(pmic_np, | 
|  | 514 | "s5m8767,pmic-buck-ds-gpios", i); | 
|  | 515 | if (!gpio_is_valid(gpio)) { | 
|  | 516 | dev_err(iodev->dev, "invalid gpio[%d]: %d\n", i, gpio); | 
|  | 517 | return -EINVAL; | 
|  | 518 | } | 
|  | 519 | pdata->buck_ds[i] = gpio; | 
|  | 520 | } | 
|  | 521 | return 0; | 
|  | 522 | } | 
|  | 523 |  | 
|  | 524 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | 
|  | 525 | struct sec_platform_data *pdata) | 
|  | 526 | { | 
|  | 527 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 
|  | 528 | struct device_node *pmic_np, *regulators_np, *reg_np; | 
|  | 529 | struct sec_regulator_data *rdata; | 
|  | 530 | struct sec_opmode_data *rmode; | 
|  | 531 | unsigned int i, dvs_voltage_nr = 8, ret; | 
|  | 532 |  | 
|  | 533 | pmic_np = iodev->dev->of_node; | 
|  | 534 | if (!pmic_np) { | 
|  | 535 | dev_err(iodev->dev, "could not find pmic sub-node\n"); | 
|  | 536 | return -ENODEV; | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | regulators_np = of_get_child_by_name(pmic_np, "regulators"); | 
|  | 540 | if (!regulators_np) { | 
|  | 541 | dev_err(iodev->dev, "could not find regulators sub-node\n"); | 
|  | 542 | return -EINVAL; | 
|  | 543 | } | 
|  | 544 |  | 
|  | 545 | /* count the number of regulators to be supported in pmic */ | 
|  | 546 | pdata->num_regulators = of_get_child_count(regulators_np); | 
|  | 547 |  | 
|  | 548 | rdata = devm_kcalloc(&pdev->dev, | 
|  | 549 | pdata->num_regulators, sizeof(*rdata), | 
|  | 550 | GFP_KERNEL); | 
|  | 551 | if (!rdata) | 
|  | 552 | return -ENOMEM; | 
|  | 553 |  | 
|  | 554 | rmode = devm_kcalloc(&pdev->dev, | 
|  | 555 | pdata->num_regulators, sizeof(*rmode), | 
|  | 556 | GFP_KERNEL); | 
|  | 557 | if (!rmode) | 
|  | 558 | return -ENOMEM; | 
|  | 559 |  | 
|  | 560 | pdata->regulators = rdata; | 
|  | 561 | pdata->opmode = rmode; | 
|  | 562 | for_each_child_of_node(regulators_np, reg_np) { | 
|  | 563 | for (i = 0; i < ARRAY_SIZE(regulators); i++) | 
|  | 564 | if (!of_node_cmp(reg_np->name, regulators[i].name)) | 
|  | 565 | break; | 
|  | 566 |  | 
|  | 567 | if (i == ARRAY_SIZE(regulators)) { | 
|  | 568 | dev_warn(iodev->dev, | 
|  | 569 | "don't know how to configure regulator %s\n", | 
|  | 570 | reg_np->name); | 
|  | 571 | continue; | 
|  | 572 | } | 
|  | 573 |  | 
|  | 574 | rdata->ext_control_gpiod = devm_gpiod_get_from_of_node(&pdev->dev, | 
|  | 575 | reg_np, | 
|  | 576 | "s5m8767,pmic-ext-control-gpios", | 
|  | 577 | 0, | 
|  | 578 | GPIOD_OUT_HIGH, | 
|  | 579 | "s5m8767"); | 
|  | 580 | if (IS_ERR(rdata->ext_control_gpiod)) | 
|  | 581 | return PTR_ERR(rdata->ext_control_gpiod); | 
|  | 582 |  | 
|  | 583 | rdata->id = i; | 
|  | 584 | rdata->initdata = of_get_regulator_init_data( | 
|  | 585 | &pdev->dev, reg_np, | 
|  | 586 | ®ulators[i]); | 
|  | 587 | rdata->reg_node = reg_np; | 
|  | 588 | rdata++; | 
|  | 589 | rmode->id = i; | 
|  | 590 | if (of_property_read_u32(reg_np, "op_mode", | 
|  | 591 | &rmode->mode)) { | 
|  | 592 | dev_warn(iodev->dev, | 
|  | 593 | "no op_mode property property at %pOF\n", | 
|  | 594 | reg_np); | 
|  | 595 |  | 
|  | 596 | rmode->mode = S5M8767_OPMODE_NORMAL_MODE; | 
|  | 597 | } | 
|  | 598 | rmode++; | 
|  | 599 | } | 
|  | 600 |  | 
|  | 601 | of_node_put(regulators_np); | 
|  | 602 |  | 
|  | 603 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) { | 
|  | 604 | pdata->buck2_gpiodvs = true; | 
|  | 605 |  | 
|  | 606 | if (of_property_read_u32_array(pmic_np, | 
|  | 607 | "s5m8767,pmic-buck2-dvs-voltage", | 
|  | 608 | pdata->buck2_voltage, dvs_voltage_nr)) { | 
|  | 609 | dev_err(iodev->dev, "buck2 voltages not specified\n"); | 
|  | 610 | return -EINVAL; | 
|  | 611 | } | 
|  | 612 | } | 
|  | 613 |  | 
|  | 614 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-uses-gpio-dvs", NULL)) { | 
|  | 615 | pdata->buck3_gpiodvs = true; | 
|  | 616 |  | 
|  | 617 | if (of_property_read_u32_array(pmic_np, | 
|  | 618 | "s5m8767,pmic-buck3-dvs-voltage", | 
|  | 619 | pdata->buck3_voltage, dvs_voltage_nr)) { | 
|  | 620 | dev_err(iodev->dev, "buck3 voltages not specified\n"); | 
|  | 621 | return -EINVAL; | 
|  | 622 | } | 
|  | 623 | } | 
|  | 624 |  | 
|  | 625 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-uses-gpio-dvs", NULL)) { | 
|  | 626 | pdata->buck4_gpiodvs = true; | 
|  | 627 |  | 
|  | 628 | if (of_property_read_u32_array(pmic_np, | 
|  | 629 | "s5m8767,pmic-buck4-dvs-voltage", | 
|  | 630 | pdata->buck4_voltage, dvs_voltage_nr)) { | 
|  | 631 | dev_err(iodev->dev, "buck4 voltages not specified\n"); | 
|  | 632 | return -EINVAL; | 
|  | 633 | } | 
|  | 634 | } | 
|  | 635 |  | 
|  | 636 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 
|  | 637 | pdata->buck4_gpiodvs) { | 
|  | 638 | ret = s5m8767_pmic_dt_parse_dvs_gpio(iodev, pdata, pmic_np); | 
|  | 639 | if (ret) | 
|  | 640 | return -EINVAL; | 
|  | 641 |  | 
|  | 642 | if (of_property_read_u32(pmic_np, | 
|  | 643 | "s5m8767,pmic-buck-default-dvs-idx", | 
|  | 644 | &pdata->buck_default_idx)) { | 
|  | 645 | pdata->buck_default_idx = 0; | 
|  | 646 | } else { | 
|  | 647 | if (pdata->buck_default_idx >= 8) { | 
|  | 648 | pdata->buck_default_idx = 0; | 
|  | 649 | dev_info(iodev->dev, | 
|  | 650 | "invalid value for default dvs index, use 0\n"); | 
|  | 651 | } | 
|  | 652 | } | 
|  | 653 | } | 
|  | 654 |  | 
|  | 655 | ret = s5m8767_pmic_dt_parse_ds_gpio(iodev, pdata, pmic_np); | 
|  | 656 | if (ret) | 
|  | 657 | return -EINVAL; | 
|  | 658 |  | 
|  | 659 | if (of_get_property(pmic_np, "s5m8767,pmic-buck2-ramp-enable", NULL)) | 
|  | 660 | pdata->buck2_ramp_enable = true; | 
|  | 661 |  | 
|  | 662 | if (of_get_property(pmic_np, "s5m8767,pmic-buck3-ramp-enable", NULL)) | 
|  | 663 | pdata->buck3_ramp_enable = true; | 
|  | 664 |  | 
|  | 665 | if (of_get_property(pmic_np, "s5m8767,pmic-buck4-ramp-enable", NULL)) | 
|  | 666 | pdata->buck4_ramp_enable = true; | 
|  | 667 |  | 
|  | 668 | if (pdata->buck2_ramp_enable || pdata->buck3_ramp_enable | 
|  | 669 | || pdata->buck4_ramp_enable) { | 
|  | 670 | if (of_property_read_u32(pmic_np, "s5m8767,pmic-buck-ramp-delay", | 
|  | 671 | &pdata->buck_ramp_delay)) | 
|  | 672 | pdata->buck_ramp_delay = 0; | 
|  | 673 | } | 
|  | 674 |  | 
|  | 675 | return 0; | 
|  | 676 | } | 
|  | 677 | #else | 
|  | 678 | static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, | 
|  | 679 | struct sec_platform_data *pdata) | 
|  | 680 | { | 
|  | 681 | return 0; | 
|  | 682 | } | 
|  | 683 | #endif /* CONFIG_OF */ | 
|  | 684 |  | 
|  | 685 | static int s5m8767_pmic_probe(struct platform_device *pdev) | 
|  | 686 | { | 
|  | 687 | struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); | 
|  | 688 | struct sec_platform_data *pdata = iodev->pdata; | 
|  | 689 | struct regulator_config config = { }; | 
|  | 690 | struct s5m8767_info *s5m8767; | 
|  | 691 | int i, ret, buck_init; | 
|  | 692 |  | 
|  | 693 | if (!pdata) { | 
|  | 694 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); | 
|  | 695 | return -ENODEV; | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | if (iodev->dev->of_node) { | 
|  | 699 | ret = s5m8767_pmic_dt_parse_pdata(pdev, pdata); | 
|  | 700 | if (ret) | 
|  | 701 | return ret; | 
|  | 702 | } | 
|  | 703 |  | 
|  | 704 | if (pdata->buck2_gpiodvs) { | 
|  | 705 | if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) { | 
|  | 706 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 
|  | 707 | return -EINVAL; | 
|  | 708 | } | 
|  | 709 | } | 
|  | 710 |  | 
|  | 711 | if (pdata->buck3_gpiodvs) { | 
|  | 712 | if (pdata->buck2_gpiodvs || pdata->buck4_gpiodvs) { | 
|  | 713 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 
|  | 714 | return -EINVAL; | 
|  | 715 | } | 
|  | 716 | } | 
|  | 717 |  | 
|  | 718 | if (pdata->buck4_gpiodvs) { | 
|  | 719 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs) { | 
|  | 720 | dev_err(&pdev->dev, "S5M8767 GPIO DVS NOT VALID\n"); | 
|  | 721 | return -EINVAL; | 
|  | 722 | } | 
|  | 723 | } | 
|  | 724 |  | 
|  | 725 | s5m8767 = devm_kzalloc(&pdev->dev, sizeof(struct s5m8767_info), | 
|  | 726 | GFP_KERNEL); | 
|  | 727 | if (!s5m8767) | 
|  | 728 | return -ENOMEM; | 
|  | 729 |  | 
|  | 730 | s5m8767->dev = &pdev->dev; | 
|  | 731 | s5m8767->iodev = iodev; | 
|  | 732 | s5m8767->num_regulators = pdata->num_regulators; | 
|  | 733 | platform_set_drvdata(pdev, s5m8767); | 
|  | 734 |  | 
|  | 735 | s5m8767->buck_gpioindex = pdata->buck_default_idx; | 
|  | 736 | s5m8767->buck2_gpiodvs = pdata->buck2_gpiodvs; | 
|  | 737 | s5m8767->buck3_gpiodvs = pdata->buck3_gpiodvs; | 
|  | 738 | s5m8767->buck4_gpiodvs = pdata->buck4_gpiodvs; | 
|  | 739 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; | 
|  | 740 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; | 
|  | 741 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; | 
|  | 742 | s5m8767->buck_ds[0] = pdata->buck_ds[0]; | 
|  | 743 | s5m8767->buck_ds[1] = pdata->buck_ds[1]; | 
|  | 744 | s5m8767->buck_ds[2] = pdata->buck_ds[2]; | 
|  | 745 |  | 
|  | 746 | s5m8767->ramp_delay = pdata->buck_ramp_delay; | 
|  | 747 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; | 
|  | 748 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; | 
|  | 749 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; | 
|  | 750 | s5m8767->opmode = pdata->opmode; | 
|  | 751 |  | 
|  | 752 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 
|  | 753 | pdata->buck2_init); | 
|  | 754 |  | 
|  | 755 | regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK2DVS2, | 
|  | 756 | buck_init); | 
|  | 757 |  | 
|  | 758 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 
|  | 759 | pdata->buck3_init); | 
|  | 760 |  | 
|  | 761 | regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK3DVS2, | 
|  | 762 | buck_init); | 
|  | 763 |  | 
|  | 764 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | 
|  | 765 | pdata->buck4_init); | 
|  | 766 |  | 
|  | 767 | regmap_write(s5m8767->iodev->regmap_pmic, S5M8767_REG_BUCK4DVS2, | 
|  | 768 | buck_init); | 
|  | 769 |  | 
|  | 770 | for (i = 0; i < 8; i++) { | 
|  | 771 | if (s5m8767->buck2_gpiodvs) { | 
|  | 772 | s5m8767->buck2_vol[i] = | 
|  | 773 | s5m8767_convert_voltage_to_sel( | 
|  | 774 | &buck_voltage_val2, | 
|  | 775 | pdata->buck2_voltage[i]); | 
|  | 776 | } | 
|  | 777 |  | 
|  | 778 | if (s5m8767->buck3_gpiodvs) { | 
|  | 779 | s5m8767->buck3_vol[i] = | 
|  | 780 | s5m8767_convert_voltage_to_sel( | 
|  | 781 | &buck_voltage_val2, | 
|  | 782 | pdata->buck3_voltage[i]); | 
|  | 783 | } | 
|  | 784 |  | 
|  | 785 | if (s5m8767->buck4_gpiodvs) { | 
|  | 786 | s5m8767->buck4_vol[i] = | 
|  | 787 | s5m8767_convert_voltage_to_sel( | 
|  | 788 | &buck_voltage_val2, | 
|  | 789 | pdata->buck4_voltage[i]); | 
|  | 790 | } | 
|  | 791 | } | 
|  | 792 |  | 
|  | 793 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 
|  | 794 | pdata->buck4_gpiodvs) { | 
|  | 795 |  | 
|  | 796 | if (!gpio_is_valid(pdata->buck_gpios[0]) || | 
|  | 797 | !gpio_is_valid(pdata->buck_gpios[1]) || | 
|  | 798 | !gpio_is_valid(pdata->buck_gpios[2])) { | 
|  | 799 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); | 
|  | 800 | return -EINVAL; | 
|  | 801 | } | 
|  | 802 |  | 
|  | 803 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[0], | 
|  | 804 | "S5M8767 SET1"); | 
|  | 805 | if (ret) | 
|  | 806 | return ret; | 
|  | 807 |  | 
|  | 808 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[1], | 
|  | 809 | "S5M8767 SET2"); | 
|  | 810 | if (ret) | 
|  | 811 | return ret; | 
|  | 812 |  | 
|  | 813 | ret = devm_gpio_request(&pdev->dev, pdata->buck_gpios[2], | 
|  | 814 | "S5M8767 SET3"); | 
|  | 815 | if (ret) | 
|  | 816 | return ret; | 
|  | 817 |  | 
|  | 818 | /* SET1 GPIO */ | 
|  | 819 | gpio_direction_output(pdata->buck_gpios[0], | 
|  | 820 | (s5m8767->buck_gpioindex >> 2) & 0x1); | 
|  | 821 | /* SET2 GPIO */ | 
|  | 822 | gpio_direction_output(pdata->buck_gpios[1], | 
|  | 823 | (s5m8767->buck_gpioindex >> 1) & 0x1); | 
|  | 824 | /* SET3 GPIO */ | 
|  | 825 | gpio_direction_output(pdata->buck_gpios[2], | 
|  | 826 | (s5m8767->buck_gpioindex >> 0) & 0x1); | 
|  | 827 | } | 
|  | 828 |  | 
|  | 829 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[0], "S5M8767 DS2"); | 
|  | 830 | if (ret) | 
|  | 831 | return ret; | 
|  | 832 |  | 
|  | 833 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[1], "S5M8767 DS3"); | 
|  | 834 | if (ret) | 
|  | 835 | return ret; | 
|  | 836 |  | 
|  | 837 | ret = devm_gpio_request(&pdev->dev, pdata->buck_ds[2], "S5M8767 DS4"); | 
|  | 838 | if (ret) | 
|  | 839 | return ret; | 
|  | 840 |  | 
|  | 841 | /* DS2 GPIO */ | 
|  | 842 | gpio_direction_output(pdata->buck_ds[0], 0x0); | 
|  | 843 | /* DS3 GPIO */ | 
|  | 844 | gpio_direction_output(pdata->buck_ds[1], 0x0); | 
|  | 845 | /* DS4 GPIO */ | 
|  | 846 | gpio_direction_output(pdata->buck_ds[2], 0x0); | 
|  | 847 |  | 
|  | 848 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 
|  | 849 | pdata->buck4_gpiodvs) { | 
|  | 850 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 851 | S5M8767_REG_BUCK2CTRL, 1 << 1, | 
|  | 852 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1)); | 
|  | 853 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 854 | S5M8767_REG_BUCK3CTRL, 1 << 1, | 
|  | 855 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1)); | 
|  | 856 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 857 | S5M8767_REG_BUCK4CTRL, 1 << 1, | 
|  | 858 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1)); | 
|  | 859 | } | 
|  | 860 |  | 
|  | 861 | /* Initialize GPIO DVS registers */ | 
|  | 862 | for (i = 0; i < 8; i++) { | 
|  | 863 | if (s5m8767->buck2_gpiodvs) { | 
|  | 864 | regmap_write(s5m8767->iodev->regmap_pmic, | 
|  | 865 | S5M8767_REG_BUCK2DVS1 + i, | 
|  | 866 | s5m8767->buck2_vol[i]); | 
|  | 867 | } | 
|  | 868 |  | 
|  | 869 | if (s5m8767->buck3_gpiodvs) { | 
|  | 870 | regmap_write(s5m8767->iodev->regmap_pmic, | 
|  | 871 | S5M8767_REG_BUCK3DVS1 + i, | 
|  | 872 | s5m8767->buck3_vol[i]); | 
|  | 873 | } | 
|  | 874 |  | 
|  | 875 | if (s5m8767->buck4_gpiodvs) { | 
|  | 876 | regmap_write(s5m8767->iodev->regmap_pmic, | 
|  | 877 | S5M8767_REG_BUCK4DVS1 + i, | 
|  | 878 | s5m8767->buck4_vol[i]); | 
|  | 879 | } | 
|  | 880 | } | 
|  | 881 |  | 
|  | 882 | if (s5m8767->buck2_ramp) | 
|  | 883 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 884 | S5M8767_REG_DVSRAMP, 0x08, 0x08); | 
|  | 885 |  | 
|  | 886 | if (s5m8767->buck3_ramp) | 
|  | 887 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 888 | S5M8767_REG_DVSRAMP, 0x04, 0x04); | 
|  | 889 |  | 
|  | 890 | if (s5m8767->buck4_ramp) | 
|  | 891 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 892 | S5M8767_REG_DVSRAMP, 0x02, 0x02); | 
|  | 893 |  | 
|  | 894 | if (s5m8767->buck2_ramp || s5m8767->buck3_ramp | 
|  | 895 | || s5m8767->buck4_ramp) { | 
|  | 896 | unsigned int val; | 
|  | 897 | switch (s5m8767->ramp_delay) { | 
|  | 898 | case 5: | 
|  | 899 | val = S5M8767_DVS_BUCK_RAMP_5; | 
|  | 900 | break; | 
|  | 901 | case 10: | 
|  | 902 | val = S5M8767_DVS_BUCK_RAMP_10; | 
|  | 903 | break; | 
|  | 904 | case 25: | 
|  | 905 | val = S5M8767_DVS_BUCK_RAMP_25; | 
|  | 906 | break; | 
|  | 907 | case 50: | 
|  | 908 | val = S5M8767_DVS_BUCK_RAMP_50; | 
|  | 909 | break; | 
|  | 910 | case 100: | 
|  | 911 | val = S5M8767_DVS_BUCK_RAMP_100; | 
|  | 912 | break; | 
|  | 913 | default: | 
|  | 914 | val = S5M8767_DVS_BUCK_RAMP_10; | 
|  | 915 | } | 
|  | 916 | regmap_update_bits(s5m8767->iodev->regmap_pmic, | 
|  | 917 | S5M8767_REG_DVSRAMP, | 
|  | 918 | S5M8767_DVS_BUCK_RAMP_MASK, | 
|  | 919 | val << S5M8767_DVS_BUCK_RAMP_SHIFT); | 
|  | 920 | } | 
|  | 921 |  | 
|  | 922 | for (i = 0; i < pdata->num_regulators; i++) { | 
|  | 923 | const struct sec_voltage_desc *desc; | 
|  | 924 | int id = pdata->regulators[i].id; | 
|  | 925 | int enable_reg, enable_val; | 
|  | 926 | struct regulator_dev *rdev; | 
|  | 927 |  | 
|  | 928 | desc = reg_voltage_map[id]; | 
|  | 929 | if (desc) { | 
|  | 930 | regulators[id].n_voltages = | 
|  | 931 | (desc->max - desc->min) / desc->step + 1; | 
|  | 932 | regulators[id].min_uV = desc->min; | 
|  | 933 | regulators[id].uV_step = desc->step; | 
|  | 934 | regulators[id].vsel_reg = | 
|  | 935 | s5m8767_get_vsel_reg(id, s5m8767); | 
|  | 936 | if (id < S5M8767_BUCK1) | 
|  | 937 | regulators[id].vsel_mask = 0x3f; | 
|  | 938 | else | 
|  | 939 | regulators[id].vsel_mask = 0xff; | 
|  | 940 |  | 
|  | 941 | ret = s5m8767_get_register(s5m8767, id, &enable_reg, | 
|  | 942 | &enable_val); | 
|  | 943 | if (ret) { | 
|  | 944 | dev_err(s5m8767->dev, "error reading registers\n"); | 
|  | 945 | return ret; | 
|  | 946 | } | 
|  | 947 | regulators[id].enable_reg = enable_reg; | 
|  | 948 | regulators[id].enable_mask = S5M8767_ENCTRL_MASK; | 
|  | 949 | regulators[id].enable_val = enable_val; | 
|  | 950 | } | 
|  | 951 |  | 
|  | 952 | config.dev = s5m8767->dev; | 
|  | 953 | config.init_data = pdata->regulators[i].initdata; | 
|  | 954 | config.driver_data = s5m8767; | 
|  | 955 | config.regmap = iodev->regmap_pmic; | 
|  | 956 | config.of_node = pdata->regulators[i].reg_node; | 
|  | 957 | config.ena_gpiod = NULL; | 
|  | 958 | if (pdata->regulators[i].ext_control_gpiod) | 
|  | 959 | s5m8767_regulator_config_ext_control(s5m8767, | 
|  | 960 | &pdata->regulators[i], &config); | 
|  | 961 |  | 
|  | 962 | rdev = devm_regulator_register(&pdev->dev, ®ulators[id], | 
|  | 963 | &config); | 
|  | 964 | if (IS_ERR(rdev)) { | 
|  | 965 | ret = PTR_ERR(rdev); | 
|  | 966 | dev_err(s5m8767->dev, "regulator init failed for %d\n", | 
|  | 967 | id); | 
|  | 968 | return ret; | 
|  | 969 | } | 
|  | 970 |  | 
|  | 971 | if (pdata->regulators[i].ext_control_gpiod) { | 
|  | 972 | ret = s5m8767_enable_ext_control(s5m8767, rdev); | 
|  | 973 | if (ret < 0) { | 
|  | 974 | dev_err(s5m8767->dev, | 
|  | 975 | "failed to enable gpio control over %s: %d\n", | 
|  | 976 | rdev->desc->name, ret); | 
|  | 977 | return ret; | 
|  | 978 | } | 
|  | 979 | } | 
|  | 980 | } | 
|  | 981 |  | 
|  | 982 | return 0; | 
|  | 983 | } | 
|  | 984 |  | 
|  | 985 | static const struct platform_device_id s5m8767_pmic_id[] = { | 
|  | 986 | { "s5m8767-pmic", 0}, | 
|  | 987 | { }, | 
|  | 988 | }; | 
|  | 989 | MODULE_DEVICE_TABLE(platform, s5m8767_pmic_id); | 
|  | 990 |  | 
|  | 991 | static struct platform_driver s5m8767_pmic_driver = { | 
|  | 992 | .driver = { | 
|  | 993 | .name = "s5m8767-pmic", | 
|  | 994 | }, | 
|  | 995 | .probe = s5m8767_pmic_probe, | 
|  | 996 | .id_table = s5m8767_pmic_id, | 
|  | 997 | }; | 
|  | 998 |  | 
|  | 999 | static int __init s5m8767_pmic_init(void) | 
|  | 1000 | { | 
|  | 1001 | return platform_driver_register(&s5m8767_pmic_driver); | 
|  | 1002 | } | 
|  | 1003 | subsys_initcall(s5m8767_pmic_init); | 
|  | 1004 |  | 
|  | 1005 | static void __exit s5m8767_pmic_exit(void) | 
|  | 1006 | { | 
|  | 1007 | platform_driver_unregister(&s5m8767_pmic_driver); | 
|  | 1008 | } | 
|  | 1009 | module_exit(s5m8767_pmic_exit); | 
|  | 1010 |  | 
|  | 1011 | /* Module information */ | 
|  | 1012 | MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); | 
|  | 1013 | MODULE_DESCRIPTION("SAMSUNG S5M8767 Regulator Driver"); | 
|  | 1014 | MODULE_LICENSE("GPL"); |