461 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// da9052-regulator.c: Regulator driver for DA90524//5// Copyright(c) 2011 Dialog Semiconductor Ltd.6//7// Author: David Dajun Chen <dchen@diasemi.com>8 9#include <linux/module.h>10#include <linux/moduleparam.h>11#include <linux/init.h>12#include <linux/err.h>13#include <linux/platform_device.h>14#include <linux/regulator/driver.h>15#include <linux/regulator/machine.h>16#include <linux/of.h>17#include <linux/regulator/of_regulator.h>18 19#include <linux/mfd/da9052/da9052.h>20#include <linux/mfd/da9052/reg.h>21#include <linux/mfd/da9052/pdata.h>22 23/* Buck step size */24#define DA9052_BUCK_PERI_3uV_STEP 10000025#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV 2426#define DA9052_CONST_3uV 300000027 28#define DA9052_MIN_UA 029#define DA9052_MAX_UA 330#define DA9052_CURRENT_RANGE 431 32/* Bit masks */33#define DA9052_BUCK_ILIM_MASK_EVEN 0x0c34#define DA9052_BUCK_ILIM_MASK_ODD 0xc035 36/* DA9052 REGULATOR IDs */37#define DA9052_ID_BUCK1 038#define DA9052_ID_BUCK2 139#define DA9052_ID_BUCK3 240#define DA9052_ID_BUCK4 341#define DA9052_ID_LDO1 442#define DA9052_ID_LDO2 543#define DA9052_ID_LDO3 644#define DA9052_ID_LDO4 745#define DA9052_ID_LDO5 846#define DA9052_ID_LDO6 947#define DA9052_ID_LDO7 1048#define DA9052_ID_LDO8 1149#define DA9052_ID_LDO9 1250#define DA9052_ID_LDO10 1351 52static const u32 da9052_current_limits[3][4] = {53 {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */54 {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */55 {800000, 1000000, 1200000, 1500000}, /* DA9053-AA/Bx BUCK-PRO,56 * BUCK-MEM and BUCK-PERI57 */58};59 60struct da9052_regulator_info {61 struct regulator_desc reg_desc;62 int step_uV;63 int min_uV;64 int max_uV;65 unsigned char activate_bit;66};67 68struct da9052_regulator {69 struct da9052 *da9052;70 const struct da9052_regulator_info *info;71 struct regulator_dev *rdev;72};73 74static int verify_range(const struct da9052_regulator_info *info,75 int min_uV, int max_uV)76{77 if (min_uV > info->max_uV || max_uV < info->min_uV)78 return -EINVAL;79 80 return 0;81}82 83static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev)84{85 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);86 int offset = rdev_get_id(rdev);87 int ret, row = 2;88 89 ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2);90 if (ret < 0)91 return ret;92 93 /* Determine the even or odd position of the buck current limit94 * register field95 */96 if (offset % 2 == 0)97 ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2;98 else99 ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6;100 101 /* Select the appropriate current limit range */102 if (regulator->da9052->chip_id == DA9052)103 row = 0;104 else if (offset == 0)105 row = 1;106 107 return da9052_current_limits[row][ret];108}109 110static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,111 int max_uA)112{113 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);114 int offset = rdev_get_id(rdev);115 int reg_val = 0;116 int i, row = 2;117 118 /* Select the appropriate current limit range */119 if (regulator->da9052->chip_id == DA9052)120 row = 0;121 else if (offset == 0)122 row = 1;123 124 for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {125 if ((min_uA <= da9052_current_limits[row][i]) &&126 (da9052_current_limits[row][i] <= max_uA)) {127 reg_val = i;128 break;129 }130 }131 132 if (i < 0)133 return -EINVAL;134 135 /* Determine the even or odd position of the buck current limit136 * register field137 */138 if (offset % 2 == 0)139 return da9052_reg_update(regulator->da9052,140 DA9052_BUCKA_REG + offset/2,141 DA9052_BUCK_ILIM_MASK_EVEN,142 reg_val << 2);143 else144 return da9052_reg_update(regulator->da9052,145 DA9052_BUCKA_REG + offset/2,146 DA9052_BUCK_ILIM_MASK_ODD,147 reg_val << 6);148}149 150static int da9052_list_voltage(struct regulator_dev *rdev,151 unsigned int selector)152{153 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);154 const struct da9052_regulator_info *info = regulator->info;155 int id = rdev_get_id(rdev);156 int volt_uV;157 158 if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)159 && (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) {160 volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV)161 + info->min_uV);162 volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)163 * (DA9052_BUCK_PERI_3uV_STEP);164 } else {165 volt_uV = (selector * info->step_uV) + info->min_uV;166 }167 168 if (volt_uV > info->max_uV)169 return -EINVAL;170 171 return volt_uV;172}173 174static int da9052_map_voltage(struct regulator_dev *rdev,175 int min_uV, int max_uV)176{177 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);178 const struct da9052_regulator_info *info = regulator->info;179 int id = rdev_get_id(rdev);180 int ret, sel;181 182 ret = verify_range(info, min_uV, max_uV);183 if (ret < 0)184 return ret;185 186 if (min_uV < info->min_uV)187 min_uV = info->min_uV;188 189 if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052)190 && (min_uV >= DA9052_CONST_3uV)) {191 sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV +192 DIV_ROUND_UP(min_uV - DA9052_CONST_3uV,193 DA9052_BUCK_PERI_3uV_STEP);194 } else {195 sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV);196 }197 198 ret = da9052_list_voltage(rdev, sel);199 if (ret < 0)200 return ret;201 202 return sel;203}204 205static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev,206 unsigned int selector)207{208 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);209 const struct da9052_regulator_info *info = regulator->info;210 int id = rdev_get_id(rdev);211 int ret;212 213 ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg,214 rdev->desc->vsel_mask, selector);215 if (ret < 0)216 return ret;217 218 /* Some LDOs and DCDCs are DVC controlled which requires enabling of219 * the activate bit to implment the changes on the output.220 */221 switch (id) {222 case DA9052_ID_BUCK1:223 case DA9052_ID_BUCK2:224 case DA9052_ID_BUCK3:225 case DA9052_ID_LDO2:226 case DA9052_ID_LDO3:227 ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG,228 info->activate_bit, info->activate_bit);229 break;230 }231 232 return ret;233}234 235static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev,236 unsigned int old_sel,237 unsigned int new_sel)238{239 struct da9052_regulator *regulator = rdev_get_drvdata(rdev);240 const struct da9052_regulator_info *info = regulator->info;241 int id = rdev_get_id(rdev);242 int ret = 0;243 244 /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling245 * the activate bit.246 */247 switch (id) {248 case DA9052_ID_BUCK1:249 case DA9052_ID_BUCK2:250 case DA9052_ID_BUCK3:251 case DA9052_ID_LDO2:252 case DA9052_ID_LDO3:253 ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV,254 6250);255 break;256 }257 258 return ret;259}260 261static const struct regulator_ops da9052_dcdc_ops = {262 .get_current_limit = da9052_dcdc_get_current_limit,263 .set_current_limit = da9052_dcdc_set_current_limit,264 265 .list_voltage = da9052_list_voltage,266 .map_voltage = da9052_map_voltage,267 .get_voltage_sel = regulator_get_voltage_sel_regmap,268 .set_voltage_sel = da9052_regulator_set_voltage_sel,269 .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,270 .is_enabled = regulator_is_enabled_regmap,271 .enable = regulator_enable_regmap,272 .disable = regulator_disable_regmap,273};274 275static const struct regulator_ops da9052_ldo_ops = {276 .list_voltage = da9052_list_voltage,277 .map_voltage = da9052_map_voltage,278 .get_voltage_sel = regulator_get_voltage_sel_regmap,279 .set_voltage_sel = da9052_regulator_set_voltage_sel,280 .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel,281 .is_enabled = regulator_is_enabled_regmap,282 .enable = regulator_enable_regmap,283 .disable = regulator_disable_regmap,284};285 286#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \287{\288 .reg_desc = {\289 .name = #_name,\290 .of_match = of_match_ptr(#_name),\291 .regulators_node = of_match_ptr("regulators"),\292 .ops = &da9052_ldo_ops,\293 .type = REGULATOR_VOLTAGE,\294 .id = DA9052_ID_##_id,\295 .n_voltages = (max - min) / step + 1, \296 .owner = THIS_MODULE,\297 .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \298 .vsel_mask = (1 << (sbits)) - 1,\299 .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \300 .enable_mask = 1 << (ebits),\301 },\302 .min_uV = (min) * 1000,\303 .max_uV = (max) * 1000,\304 .step_uV = (step) * 1000,\305 .activate_bit = (abits),\306}307 308#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \309{\310 .reg_desc = {\311 .name = #_name,\312 .of_match = of_match_ptr(#_name),\313 .regulators_node = of_match_ptr("regulators"),\314 .ops = &da9052_dcdc_ops,\315 .type = REGULATOR_VOLTAGE,\316 .id = DA9052_ID_##_id,\317 .n_voltages = (max - min) / step + 1, \318 .owner = THIS_MODULE,\319 .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \320 .vsel_mask = (1 << (sbits)) - 1,\321 .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \322 .enable_mask = 1 << (ebits),\323 },\324 .min_uV = (min) * 1000,\325 .max_uV = (max) * 1000,\326 .step_uV = (step) * 1000,\327 .activate_bit = (abits),\328}329 330static const struct da9052_regulator_info da9052_regulator_info[] = {331 DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),332 DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),333 DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),334 DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0),335 DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),336 DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),337 DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),338 DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),339 DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),340 DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),341 DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),342 DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),343 DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),344 DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),345};346 347static const struct da9052_regulator_info da9053_regulator_info[] = {348 DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO),349 DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO),350 DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO),351 DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0),352 DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0),353 DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO),354 DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO),355 DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0),356 DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0),357 DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0),358 DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0),359 DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0),360 DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0),361 DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0),362};363 364static inline const struct da9052_regulator_info *find_regulator_info(u8 chip_id,365 int id)366{367 const struct da9052_regulator_info *info;368 int i;369 370 switch (chip_id) {371 case DA9052:372 for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) {373 info = &da9052_regulator_info[i];374 if (info->reg_desc.id == id)375 return info;376 }377 break;378 case DA9053_AA:379 case DA9053_BA:380 case DA9053_BB:381 case DA9053_BC:382 for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) {383 info = &da9053_regulator_info[i];384 if (info->reg_desc.id == id)385 return info;386 }387 break;388 }389 390 return NULL;391}392 393static int da9052_regulator_probe(struct platform_device *pdev)394{395 const struct mfd_cell *cell = mfd_get_cell(pdev);396 struct regulator_config config = { };397 struct da9052_regulator *regulator;398 struct da9052 *da9052;399 struct da9052_pdata *pdata;400 401 regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator),402 GFP_KERNEL);403 if (!regulator)404 return -ENOMEM;405 406 da9052 = dev_get_drvdata(pdev->dev.parent);407 pdata = dev_get_platdata(da9052->dev);408 regulator->da9052 = da9052;409 410 regulator->info = find_regulator_info(regulator->da9052->chip_id,411 cell->id);412 if (regulator->info == NULL) {413 dev_err(&pdev->dev, "invalid regulator ID specified\n");414 return -EINVAL;415 }416 417 config.dev = da9052->dev;418 config.driver_data = regulator;419 config.regmap = da9052->regmap;420 if (pdata)421 config.init_data = pdata->regulators[cell->id];422 423 regulator->rdev = devm_regulator_register(&pdev->dev,424 ®ulator->info->reg_desc,425 &config);426 if (IS_ERR(regulator->rdev)) {427 dev_err(&pdev->dev, "failed to register regulator %s\n",428 regulator->info->reg_desc.name);429 return PTR_ERR(regulator->rdev);430 }431 432 platform_set_drvdata(pdev, regulator);433 434 return 0;435}436 437static struct platform_driver da9052_regulator_driver = {438 .probe = da9052_regulator_probe,439 .driver = {440 .name = "da9052-regulator",441 .probe_type = PROBE_PREFER_ASYNCHRONOUS,442 },443};444 445static int __init da9052_regulator_init(void)446{447 return platform_driver_register(&da9052_regulator_driver);448}449subsys_initcall(da9052_regulator_init);450 451static void __exit da9052_regulator_exit(void)452{453 platform_driver_unregister(&da9052_regulator_driver);454}455module_exit(da9052_regulator_exit);456 457MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");458MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC");459MODULE_LICENSE("GPL");460MODULE_ALIAS("platform:da9052-regulator");461