391 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// Copyright (c) 2013 Samsung Electronics Co., Ltd4// http://www.samsung.com5 6#include <linux/bug.h>7#include <linux/err.h>8#include <linux/slab.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/regmap.h>12#include <linux/platform_device.h>13#include <linux/regulator/driver.h>14#include <linux/regulator/machine.h>15#include <linux/regulator/of_regulator.h>16#include <linux/mfd/samsung/core.h>17#include <linux/mfd/samsung/s2mpa01.h>18 19struct s2mpa01_info {20 int ramp_delay24;21 int ramp_delay3;22 int ramp_delay5;23 int ramp_delay16;24 int ramp_delay7;25 int ramp_delay8910;26};27 28static int get_ramp_delay(int ramp_delay)29{30 unsigned char cnt = 0;31 32 ramp_delay /= 6250;33 34 while (true) {35 ramp_delay = ramp_delay >> 1;36 if (ramp_delay == 0)37 break;38 cnt++;39 }40 41 if (cnt > 3)42 cnt = 3;43 44 return cnt;45}46 47static int s2mpa01_regulator_set_voltage_time_sel(struct regulator_dev *rdev,48 unsigned int old_selector,49 unsigned int new_selector)50{51 struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);52 unsigned int ramp_delay = 0;53 int old_volt, new_volt;54 55 switch (rdev_get_id(rdev)) {56 case S2MPA01_BUCK2:57 case S2MPA01_BUCK4:58 ramp_delay = s2mpa01->ramp_delay24;59 break;60 case S2MPA01_BUCK3:61 ramp_delay = s2mpa01->ramp_delay3;62 break;63 case S2MPA01_BUCK5:64 ramp_delay = s2mpa01->ramp_delay5;65 break;66 case S2MPA01_BUCK1:67 case S2MPA01_BUCK6:68 ramp_delay = s2mpa01->ramp_delay16;69 break;70 case S2MPA01_BUCK7:71 ramp_delay = s2mpa01->ramp_delay7;72 break;73 case S2MPA01_BUCK8:74 case S2MPA01_BUCK9:75 case S2MPA01_BUCK10:76 ramp_delay = s2mpa01->ramp_delay8910;77 break;78 }79 80 if (ramp_delay == 0)81 ramp_delay = rdev->desc->ramp_delay;82 83 old_volt = rdev->desc->min_uV + (rdev->desc->uV_step * old_selector);84 new_volt = rdev->desc->min_uV + (rdev->desc->uV_step * new_selector);85 86 return DIV_ROUND_UP(abs(new_volt - old_volt), ramp_delay);87}88 89static int s2mpa01_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)90{91 struct s2mpa01_info *s2mpa01 = rdev_get_drvdata(rdev);92 unsigned int ramp_val, ramp_shift, ramp_reg = S2MPA01_REG_RAMP2;93 unsigned int ramp_enable = 1, enable_shift = 0;94 int ret;95 96 switch (rdev_get_id(rdev)) {97 case S2MPA01_BUCK1:98 enable_shift = S2MPA01_BUCK1_RAMP_EN_SHIFT;99 if (!ramp_delay) {100 ramp_enable = 0;101 break;102 }103 104 if (ramp_delay > s2mpa01->ramp_delay16)105 s2mpa01->ramp_delay16 = ramp_delay;106 else107 ramp_delay = s2mpa01->ramp_delay16;108 109 ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;110 break;111 case S2MPA01_BUCK2:112 enable_shift = S2MPA01_BUCK2_RAMP_EN_SHIFT;113 if (!ramp_delay) {114 ramp_enable = 0;115 break;116 }117 118 if (ramp_delay > s2mpa01->ramp_delay24)119 s2mpa01->ramp_delay24 = ramp_delay;120 else121 ramp_delay = s2mpa01->ramp_delay24;122 123 ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;124 ramp_reg = S2MPA01_REG_RAMP1;125 break;126 case S2MPA01_BUCK3:127 enable_shift = S2MPA01_BUCK3_RAMP_EN_SHIFT;128 if (!ramp_delay) {129 ramp_enable = 0;130 break;131 }132 133 s2mpa01->ramp_delay3 = ramp_delay;134 ramp_shift = S2MPA01_BUCK3_RAMP_SHIFT;135 ramp_reg = S2MPA01_REG_RAMP1;136 break;137 case S2MPA01_BUCK4:138 enable_shift = S2MPA01_BUCK4_RAMP_EN_SHIFT;139 if (!ramp_delay) {140 ramp_enable = 0;141 break;142 }143 144 if (ramp_delay > s2mpa01->ramp_delay24)145 s2mpa01->ramp_delay24 = ramp_delay;146 else147 ramp_delay = s2mpa01->ramp_delay24;148 149 ramp_shift = S2MPA01_BUCK24_RAMP_SHIFT;150 ramp_reg = S2MPA01_REG_RAMP1;151 break;152 case S2MPA01_BUCK5:153 s2mpa01->ramp_delay5 = ramp_delay;154 ramp_shift = S2MPA01_BUCK5_RAMP_SHIFT;155 break;156 case S2MPA01_BUCK6:157 if (ramp_delay > s2mpa01->ramp_delay16)158 s2mpa01->ramp_delay16 = ramp_delay;159 else160 ramp_delay = s2mpa01->ramp_delay16;161 162 ramp_shift = S2MPA01_BUCK16_RAMP_SHIFT;163 break;164 case S2MPA01_BUCK7:165 s2mpa01->ramp_delay7 = ramp_delay;166 ramp_shift = S2MPA01_BUCK7_RAMP_SHIFT;167 break;168 case S2MPA01_BUCK8:169 case S2MPA01_BUCK9:170 case S2MPA01_BUCK10:171 if (ramp_delay > s2mpa01->ramp_delay8910)172 s2mpa01->ramp_delay8910 = ramp_delay;173 else174 ramp_delay = s2mpa01->ramp_delay8910;175 176 ramp_shift = S2MPA01_BUCK8910_RAMP_SHIFT;177 break;178 default:179 return 0;180 }181 182 if (!ramp_enable)183 goto ramp_disable;184 185 /* Ramp delay can be enabled/disabled only for buck[1234] */186 if (rdev_get_id(rdev) >= S2MPA01_BUCK1 &&187 rdev_get_id(rdev) <= S2MPA01_BUCK4) {188 ret = regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,189 1 << enable_shift, 1 << enable_shift);190 if (ret) {191 dev_err(&rdev->dev, "failed to enable ramp rate\n");192 return ret;193 }194 }195 196 ramp_val = get_ramp_delay(ramp_delay);197 198 return regmap_update_bits(rdev->regmap, ramp_reg, 0x3 << ramp_shift,199 ramp_val << ramp_shift);200 201ramp_disable:202 return regmap_update_bits(rdev->regmap, S2MPA01_REG_RAMP1,203 1 << enable_shift, 0);204}205 206static const struct regulator_ops s2mpa01_ldo_ops = {207 .list_voltage = regulator_list_voltage_linear,208 .map_voltage = regulator_map_voltage_linear,209 .is_enabled = regulator_is_enabled_regmap,210 .enable = regulator_enable_regmap,211 .disable = regulator_disable_regmap,212 .get_voltage_sel = regulator_get_voltage_sel_regmap,213 .set_voltage_sel = regulator_set_voltage_sel_regmap,214 .set_voltage_time_sel = regulator_set_voltage_time_sel,215};216 217static const struct regulator_ops s2mpa01_buck_ops = {218 .list_voltage = regulator_list_voltage_linear,219 .map_voltage = regulator_map_voltage_linear,220 .is_enabled = regulator_is_enabled_regmap,221 .enable = regulator_enable_regmap,222 .disable = regulator_disable_regmap,223 .get_voltage_sel = regulator_get_voltage_sel_regmap,224 .set_voltage_sel = regulator_set_voltage_sel_regmap,225 .set_voltage_time_sel = s2mpa01_regulator_set_voltage_time_sel,226 .set_ramp_delay = s2mpa01_set_ramp_delay,227};228 229#define regulator_desc_ldo(num, step) { \230 .name = "LDO"#num, \231 .of_match = of_match_ptr("LDO"#num), \232 .regulators_node = of_match_ptr("regulators"), \233 .id = S2MPA01_LDO##num, \234 .ops = &s2mpa01_ldo_ops, \235 .type = REGULATOR_VOLTAGE, \236 .owner = THIS_MODULE, \237 .min_uV = MIN_800_MV, \238 .uV_step = step, \239 .n_voltages = S2MPA01_LDO_N_VOLTAGES, \240 .vsel_reg = S2MPA01_REG_L1CTRL + num - 1, \241 .vsel_mask = S2MPA01_LDO_VSEL_MASK, \242 .enable_reg = S2MPA01_REG_L1CTRL + num - 1, \243 .enable_mask = S2MPA01_ENABLE_MASK \244}245 246#define regulator_desc_buck1_4(num) { \247 .name = "BUCK"#num, \248 .of_match = of_match_ptr("BUCK"#num), \249 .regulators_node = of_match_ptr("regulators"), \250 .id = S2MPA01_BUCK##num, \251 .ops = &s2mpa01_buck_ops, \252 .type = REGULATOR_VOLTAGE, \253 .owner = THIS_MODULE, \254 .min_uV = MIN_600_MV, \255 .uV_step = STEP_6_25_MV, \256 .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \257 .ramp_delay = S2MPA01_RAMP_DELAY, \258 .vsel_reg = S2MPA01_REG_B1CTRL2 + (num - 1) * 2, \259 .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \260 .enable_reg = S2MPA01_REG_B1CTRL1 + (num - 1) * 2, \261 .enable_mask = S2MPA01_ENABLE_MASK \262}263 264#define regulator_desc_buck5 { \265 .name = "BUCK5", \266 .of_match = of_match_ptr("BUCK5"), \267 .regulators_node = of_match_ptr("regulators"), \268 .id = S2MPA01_BUCK5, \269 .ops = &s2mpa01_buck_ops, \270 .type = REGULATOR_VOLTAGE, \271 .owner = THIS_MODULE, \272 .min_uV = MIN_800_MV, \273 .uV_step = STEP_6_25_MV, \274 .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \275 .ramp_delay = S2MPA01_RAMP_DELAY, \276 .vsel_reg = S2MPA01_REG_B5CTRL2, \277 .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \278 .enable_reg = S2MPA01_REG_B5CTRL1, \279 .enable_mask = S2MPA01_ENABLE_MASK \280}281 282#define regulator_desc_buck6_10(num, min, step) { \283 .name = "BUCK"#num, \284 .of_match = of_match_ptr("BUCK"#num), \285 .regulators_node = of_match_ptr("regulators"), \286 .id = S2MPA01_BUCK##num, \287 .ops = &s2mpa01_buck_ops, \288 .type = REGULATOR_VOLTAGE, \289 .owner = THIS_MODULE, \290 .min_uV = min, \291 .uV_step = step, \292 .n_voltages = S2MPA01_BUCK_N_VOLTAGES, \293 .ramp_delay = S2MPA01_RAMP_DELAY, \294 .vsel_reg = S2MPA01_REG_B6CTRL2 + (num - 6) * 2, \295 .vsel_mask = S2MPA01_BUCK_VSEL_MASK, \296 .enable_reg = S2MPA01_REG_B6CTRL1 + (num - 6) * 2, \297 .enable_mask = S2MPA01_ENABLE_MASK \298}299 300static const struct regulator_desc regulators[] = {301 regulator_desc_ldo(1, STEP_25_MV),302 regulator_desc_ldo(2, STEP_50_MV),303 regulator_desc_ldo(3, STEP_50_MV),304 regulator_desc_ldo(4, STEP_50_MV),305 regulator_desc_ldo(5, STEP_25_MV),306 regulator_desc_ldo(6, STEP_25_MV),307 regulator_desc_ldo(7, STEP_50_MV),308 regulator_desc_ldo(8, STEP_50_MV),309 regulator_desc_ldo(9, STEP_50_MV),310 regulator_desc_ldo(10, STEP_50_MV),311 regulator_desc_ldo(11, STEP_50_MV),312 regulator_desc_ldo(12, STEP_50_MV),313 regulator_desc_ldo(13, STEP_50_MV),314 regulator_desc_ldo(14, STEP_50_MV),315 regulator_desc_ldo(15, STEP_50_MV),316 regulator_desc_ldo(16, STEP_50_MV),317 regulator_desc_ldo(17, STEP_50_MV),318 regulator_desc_ldo(18, STEP_50_MV),319 regulator_desc_ldo(19, STEP_50_MV),320 regulator_desc_ldo(20, STEP_50_MV),321 regulator_desc_ldo(21, STEP_50_MV),322 regulator_desc_ldo(22, STEP_50_MV),323 regulator_desc_ldo(23, STEP_50_MV),324 regulator_desc_ldo(24, STEP_50_MV),325 regulator_desc_ldo(25, STEP_50_MV),326 regulator_desc_ldo(26, STEP_25_MV),327 regulator_desc_buck1_4(1),328 regulator_desc_buck1_4(2),329 regulator_desc_buck1_4(3),330 regulator_desc_buck1_4(4),331 regulator_desc_buck5,332 regulator_desc_buck6_10(6, MIN_600_MV, STEP_6_25_MV),333 regulator_desc_buck6_10(7, MIN_600_MV, STEP_6_25_MV),334 regulator_desc_buck6_10(8, MIN_800_MV, STEP_12_5_MV),335 regulator_desc_buck6_10(9, MIN_1500_MV, STEP_12_5_MV),336 regulator_desc_buck6_10(10, MIN_1000_MV, STEP_12_5_MV),337};338 339static int s2mpa01_pmic_probe(struct platform_device *pdev)340{341 struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);342 struct regulator_config config = { };343 struct s2mpa01_info *s2mpa01;344 int i;345 346 s2mpa01 = devm_kzalloc(&pdev->dev, sizeof(*s2mpa01), GFP_KERNEL);347 if (!s2mpa01)348 return -ENOMEM;349 350 config.dev = iodev->dev;351 config.regmap = iodev->regmap_pmic;352 config.driver_data = s2mpa01;353 354 for (i = 0; i < S2MPA01_REGULATOR_MAX; i++) {355 struct regulator_dev *rdev;356 357 rdev = devm_regulator_register(&pdev->dev,358 ®ulators[i], &config);359 if (IS_ERR(rdev)) {360 dev_err(&pdev->dev, "regulator init failed for %d\n",361 i);362 return PTR_ERR(rdev);363 }364 }365 366 return 0;367}368 369static const struct platform_device_id s2mpa01_pmic_id[] = {370 { "s2mpa01-pmic", 0},371 { },372};373MODULE_DEVICE_TABLE(platform, s2mpa01_pmic_id);374 375static struct platform_driver s2mpa01_pmic_driver = {376 .driver = {377 .name = "s2mpa01-pmic",378 .probe_type = PROBE_PREFER_ASYNCHRONOUS,379 },380 .probe = s2mpa01_pmic_probe,381 .id_table = s2mpa01_pmic_id,382};383 384module_platform_driver(s2mpa01_pmic_driver);385 386/* Module information */387MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");388MODULE_AUTHOR("Sachin Kamat <sachin.kamat@samsung.com>");389MODULE_DESCRIPTION("Samsung S2MPA01 Regulator Driver");390MODULE_LICENSE("GPL");391