544 lines · c
1// SPDX-License-Identifier: GPL-2.0+2//3// Regulator driver for ATC260x PMICs4//5// Copyright (C) 2019 Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>6// Copyright (C) 2020 Cristian Ciocaltea <cristian.ciocaltea@gmail.com>7 8#include <linux/mfd/atc260x/core.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/regmap.h>13#include <linux/regulator/driver.h>14 15struct atc260x_regulator_data {16 int voltage_time_dcdc;17 int voltage_time_ldo;18};19 20static const struct linear_range atc2603c_dcdc_voltage_ranges[] = {21 REGULATOR_LINEAR_RANGE(1300000, 0, 13, 50000),22 REGULATOR_LINEAR_RANGE(1950000, 14, 15, 100000),23};24 25static const struct linear_range atc2609a_dcdc_voltage_ranges[] = {26 REGULATOR_LINEAR_RANGE(600000, 0, 127, 6250),27 REGULATOR_LINEAR_RANGE(1400000, 128, 232, 25000),28};29 30static const struct linear_range atc2609a_ldo_voltage_ranges0[] = {31 REGULATOR_LINEAR_RANGE(700000, 0, 15, 100000),32 REGULATOR_LINEAR_RANGE(2100000, 0, 12, 100000),33};34 35static const struct linear_range atc2609a_ldo_voltage_ranges1[] = {36 REGULATOR_LINEAR_RANGE(850000, 0, 15, 100000),37 REGULATOR_LINEAR_RANGE(2100000, 0, 11, 100000),38};39 40static const unsigned int atc260x_ldo_voltage_range_sel[] = {41 0x0, 0x1,42};43 44static int atc260x_dcdc_set_voltage_time_sel(struct regulator_dev *rdev,45 unsigned int old_selector,46 unsigned int new_selector)47{48 struct atc260x_regulator_data *data = rdev_get_drvdata(rdev);49 50 if (new_selector > old_selector)51 return data->voltage_time_dcdc;52 53 return 0;54}55 56static int atc260x_ldo_set_voltage_time_sel(struct regulator_dev *rdev,57 unsigned int old_selector,58 unsigned int new_selector)59{60 struct atc260x_regulator_data *data = rdev_get_drvdata(rdev);61 62 if (new_selector > old_selector)63 return data->voltage_time_ldo;64 65 return 0;66}67 68static const struct regulator_ops atc260x_dcdc_ops = {69 .enable = regulator_enable_regmap,70 .disable = regulator_disable_regmap,71 .is_enabled = regulator_is_enabled_regmap,72 .list_voltage = regulator_list_voltage_linear,73 .set_voltage_sel = regulator_set_voltage_sel_regmap,74 .get_voltage_sel = regulator_get_voltage_sel_regmap,75 .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel,76};77 78static const struct regulator_ops atc260x_ldo_ops = {79 .enable = regulator_enable_regmap,80 .disable = regulator_disable_regmap,81 .is_enabled = regulator_is_enabled_regmap,82 .list_voltage = regulator_list_voltage_linear,83 .set_voltage_sel = regulator_set_voltage_sel_regmap,84 .get_voltage_sel = regulator_get_voltage_sel_regmap,85 .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel,86};87 88static const struct regulator_ops atc260x_ldo_bypass_ops = {89 .enable = regulator_enable_regmap,90 .disable = regulator_disable_regmap,91 .is_enabled = regulator_is_enabled_regmap,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 .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel,96 .set_bypass = regulator_set_bypass_regmap,97 .get_bypass = regulator_get_bypass_regmap,98};99 100static const struct regulator_ops atc260x_ldo_bypass_discharge_ops = {101 .enable = regulator_enable_regmap,102 .disable = regulator_disable_regmap,103 .is_enabled = regulator_is_enabled_regmap,104 .list_voltage = regulator_list_voltage_linear,105 .set_voltage_sel = regulator_set_voltage_sel_regmap,106 .get_voltage_sel = regulator_get_voltage_sel_regmap,107 .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel,108 .set_bypass = regulator_set_bypass_regmap,109 .get_bypass = regulator_get_bypass_regmap,110 .set_active_discharge = regulator_set_active_discharge_regmap,111};112 113static const struct regulator_ops atc260x_dcdc_range_ops = {114 .enable = regulator_enable_regmap,115 .disable = regulator_disable_regmap,116 .is_enabled = regulator_is_enabled_regmap,117 .list_voltage = regulator_list_voltage_linear_range,118 .set_voltage_sel = regulator_set_voltage_sel_regmap,119 .get_voltage_sel = regulator_get_voltage_sel_regmap,120 .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel,121};122 123static const struct regulator_ops atc260x_ldo_range_pick_ops = {124 .enable = regulator_enable_regmap,125 .disable = regulator_disable_regmap,126 .is_enabled = regulator_is_enabled_regmap,127 .list_voltage = regulator_list_voltage_pickable_linear_range,128 .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,129 .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,130 .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel,131};132 133static const struct regulator_ops atc260x_dcdc_fixed_ops = {134 .list_voltage = regulator_list_voltage_linear,135 .set_voltage_sel = regulator_set_voltage_sel_regmap,136 .get_voltage_sel = regulator_get_voltage_sel_regmap,137 .set_voltage_time_sel = atc260x_dcdc_set_voltage_time_sel,138};139 140static const struct regulator_ops atc260x_ldo_fixed_ops = {141 .list_voltage = regulator_list_voltage_linear,142 .set_voltage_sel = regulator_set_voltage_sel_regmap,143 .get_voltage_sel = regulator_get_voltage_sel_regmap,144 .set_voltage_time_sel = atc260x_ldo_set_voltage_time_sel,145};146 147static const struct regulator_ops atc260x_no_ops = {148};149 150/*151 * Note LDO8 is not documented in datasheet (v2.4), but supported152 * in the vendor's driver implementation (xapp-le-kernel).153 */154enum atc2603c_reg_ids {155 ATC2603C_ID_DCDC1,156 ATC2603C_ID_DCDC2,157 ATC2603C_ID_DCDC3,158 ATC2603C_ID_LDO1,159 ATC2603C_ID_LDO2,160 ATC2603C_ID_LDO3,161 ATC2603C_ID_LDO5,162 ATC2603C_ID_LDO6,163 ATC2603C_ID_LDO7,164 ATC2603C_ID_LDO8,165 ATC2603C_ID_LDO11,166 ATC2603C_ID_LDO12,167 ATC2603C_ID_SWITCHLDO1,168 ATC2603C_ID_MAX,169};170 171#define atc2603c_reg_desc_dcdc(num, min, step, n_volt, vsel_h, vsel_l) { \172 .name = "DCDC"#num, \173 .supply_name = "dcdc"#num, \174 .of_match = of_match_ptr("dcdc"#num), \175 .regulators_node = of_match_ptr("regulators"), \176 .id = ATC2603C_ID_DCDC##num, \177 .ops = &atc260x_dcdc_ops, \178 .type = REGULATOR_VOLTAGE, \179 .min_uV = min, \180 .uV_step = step, \181 .n_voltages = n_volt, \182 .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \183 .vsel_mask = GENMASK(vsel_h, vsel_l), \184 .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \185 .enable_mask = BIT(15), \186 .enable_time = 800, \187 .owner = THIS_MODULE, \188}189 190#define atc2603c_reg_desc_dcdc_range(num, vsel_h, vsel_l) { \191 .name = "DCDC"#num, \192 .supply_name = "dcdc"#num, \193 .of_match = of_match_ptr("dcdc"#num), \194 .regulators_node = of_match_ptr("regulators"), \195 .id = ATC2603C_ID_DCDC##num, \196 .ops = &atc260x_dcdc_range_ops, \197 .type = REGULATOR_VOLTAGE, \198 .n_voltages = 16, \199 .linear_ranges = atc2603c_dcdc_voltage_ranges, \200 .n_linear_ranges = ARRAY_SIZE(atc2603c_dcdc_voltage_ranges), \201 .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \202 .vsel_mask = GENMASK(vsel_h, vsel_l), \203 .enable_reg = ATC2603C_PMU_DC##num##_CTL0, \204 .enable_mask = BIT(15), \205 .enable_time = 800, \206 .owner = THIS_MODULE, \207}208 209#define atc2603c_reg_desc_dcdc_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \210 .name = "DCDC"#num, \211 .supply_name = "dcdc"#num, \212 .of_match = of_match_ptr("dcdc"#num), \213 .regulators_node = of_match_ptr("regulators"), \214 .id = ATC2603C_ID_DCDC##num, \215 .ops = &atc260x_dcdc_fixed_ops, \216 .type = REGULATOR_VOLTAGE, \217 .min_uV = min, \218 .uV_step = step, \219 .n_voltages = n_volt, \220 .vsel_reg = ATC2603C_PMU_DC##num##_CTL0, \221 .vsel_mask = GENMASK(vsel_h, vsel_l), \222 .enable_time = 800, \223 .owner = THIS_MODULE, \224}225 226#define atc2603c_reg_desc_ldo(num, min, step, n_volt, vsel_h, vsel_l) { \227 .name = "LDO"#num, \228 .supply_name = "ldo"#num, \229 .of_match = of_match_ptr("ldo"#num), \230 .regulators_node = of_match_ptr("regulators"), \231 .id = ATC2603C_ID_LDO##num, \232 .ops = &atc260x_ldo_ops, \233 .type = REGULATOR_VOLTAGE, \234 .min_uV = min, \235 .uV_step = step, \236 .n_voltages = n_volt, \237 .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \238 .vsel_mask = GENMASK(vsel_h, vsel_l), \239 .enable_reg = ATC2603C_PMU_LDO##num##_CTL, \240 .enable_mask = BIT(0), \241 .enable_time = 2000, \242 .owner = THIS_MODULE, \243}244 245#define atc2603c_reg_desc_ldo_fixed(num, min, step, n_volt, vsel_h, vsel_l) { \246 .name = "LDO"#num, \247 .supply_name = "ldo"#num, \248 .of_match = of_match_ptr("ldo"#num), \249 .regulators_node = of_match_ptr("regulators"), \250 .id = ATC2603C_ID_LDO##num, \251 .ops = &atc260x_ldo_fixed_ops, \252 .type = REGULATOR_VOLTAGE, \253 .min_uV = min, \254 .uV_step = step, \255 .n_voltages = n_volt, \256 .vsel_reg = ATC2603C_PMU_LDO##num##_CTL, \257 .vsel_mask = GENMASK(vsel_h, vsel_l), \258 .enable_time = 2000, \259 .owner = THIS_MODULE, \260}261 262#define atc2603c_reg_desc_ldo_noops(num, vfixed) { \263 .name = "LDO"#num, \264 .supply_name = "ldo"#num, \265 .of_match = of_match_ptr("ldo"#num), \266 .regulators_node = of_match_ptr("regulators"), \267 .id = ATC2603C_ID_LDO##num, \268 .ops = &atc260x_no_ops, \269 .type = REGULATOR_VOLTAGE, \270 .fixed_uV = vfixed, \271 .n_voltages = 1, \272 .owner = THIS_MODULE, \273}274 275#define atc2603c_reg_desc_ldo_switch(num, min, step, n_volt, vsel_h, vsel_l) { \276 .name = "SWITCHLDO"#num, \277 .supply_name = "switchldo"#num, \278 .of_match = of_match_ptr("switchldo"#num), \279 .regulators_node = of_match_ptr("regulators"), \280 .id = ATC2603C_ID_SWITCHLDO##num, \281 .ops = &atc260x_ldo_bypass_discharge_ops, \282 .type = REGULATOR_VOLTAGE, \283 .min_uV = min, \284 .uV_step = step, \285 .n_voltages = n_volt, \286 .vsel_reg = ATC2603C_PMU_SWITCH_CTL, \287 .vsel_mask = GENMASK(vsel_h, vsel_l), \288 .enable_reg = ATC2603C_PMU_SWITCH_CTL, \289 .enable_mask = BIT(15), \290 .enable_is_inverted = true, \291 .enable_time = 2000, \292 .bypass_reg = ATC2603C_PMU_SWITCH_CTL, \293 .bypass_mask = BIT(5), \294 .active_discharge_reg = ATC2603C_PMU_SWITCH_CTL, \295 .active_discharge_mask = BIT(1), \296 .active_discharge_on = BIT(1), \297 .owner = THIS_MODULE, \298}299 300static const struct regulator_desc atc2603c_reg[] = {301 atc2603c_reg_desc_dcdc_fixed(1, 700000, 25000, 29, 11, 7),302 atc2603c_reg_desc_dcdc_range(2, 12, 8),303 atc2603c_reg_desc_dcdc_fixed(3, 2600000, 100000, 8, 11, 9),304 atc2603c_reg_desc_ldo_fixed(1, 2600000, 100000, 8, 15, 13),305 atc2603c_reg_desc_ldo_fixed(2, 2600000, 100000, 8, 15, 13),306 atc2603c_reg_desc_ldo_fixed(3, 1500000, 100000, 6, 15, 13),307 atc2603c_reg_desc_ldo(5, 2600000, 100000, 8, 15, 13),308 atc2603c_reg_desc_ldo_fixed(6, 700000, 25000, 29, 15, 11),309 atc2603c_reg_desc_ldo(7, 1500000, 100000, 6, 15, 13),310 atc2603c_reg_desc_ldo(8, 2300000, 100000, 11, 15, 12),311 atc2603c_reg_desc_ldo_fixed(11, 2600000, 100000, 8, 15, 13),312 atc2603c_reg_desc_ldo_noops(12, 1800000),313 atc2603c_reg_desc_ldo_switch(1, 3000000, 100000, 4, 4, 3),314};315 316static const struct regulator_desc atc2603c_reg_dcdc2_ver_b =317 atc2603c_reg_desc_dcdc(2, 1000000, 50000, 18, 12, 8);318 319enum atc2609a_reg_ids {320 ATC2609A_ID_DCDC0,321 ATC2609A_ID_DCDC1,322 ATC2609A_ID_DCDC2,323 ATC2609A_ID_DCDC3,324 ATC2609A_ID_DCDC4,325 ATC2609A_ID_LDO0,326 ATC2609A_ID_LDO1,327 ATC2609A_ID_LDO2,328 ATC2609A_ID_LDO3,329 ATC2609A_ID_LDO4,330 ATC2609A_ID_LDO5,331 ATC2609A_ID_LDO6,332 ATC2609A_ID_LDO7,333 ATC2609A_ID_LDO8,334 ATC2609A_ID_LDO9,335 ATC2609A_ID_MAX,336};337 338#define atc2609a_reg_desc_dcdc(num, en_bit) { \339 .name = "DCDC"#num, \340 .supply_name = "dcdc"#num, \341 .of_match = of_match_ptr("dcdc"#num), \342 .regulators_node = of_match_ptr("regulators"), \343 .id = ATC2609A_ID_DCDC##num, \344 .ops = &atc260x_dcdc_ops, \345 .type = REGULATOR_VOLTAGE, \346 .min_uV = 600000, \347 .uV_step = 6250, \348 .n_voltages = 256, \349 .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \350 .vsel_mask = GENMASK(15, 8), \351 .enable_reg = ATC2609A_PMU_DC_OSC, \352 .enable_mask = BIT(en_bit), \353 .enable_time = 800, \354 .owner = THIS_MODULE, \355}356 357#define atc2609a_reg_desc_dcdc_range(num, en_bit) { \358 .name = "DCDC"#num, \359 .supply_name = "dcdc"#num, \360 .of_match = of_match_ptr("dcdc"#num), \361 .regulators_node = of_match_ptr("regulators"), \362 .id = ATC2609A_ID_DCDC##num, \363 .ops = &atc260x_dcdc_range_ops, \364 .type = REGULATOR_VOLTAGE, \365 .n_voltages = 233, \366 .linear_ranges = atc2609a_dcdc_voltage_ranges, \367 .n_linear_ranges = ARRAY_SIZE(atc2609a_dcdc_voltage_ranges), \368 .vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \369 .vsel_mask = GENMASK(15, 8), \370 .enable_reg = ATC2609A_PMU_DC_OSC, \371 .enable_mask = BIT(en_bit), \372 .enable_time = 800, \373 .owner = THIS_MODULE, \374}375 376#define atc2609a_reg_desc_ldo(num) { \377 .name = "LDO"#num, \378 .supply_name = "ldo"#num, \379 .of_match = of_match_ptr("ldo"#num), \380 .regulators_node = of_match_ptr("regulators"), \381 .id = ATC2609A_ID_LDO##num, \382 .ops = &atc260x_ldo_ops, \383 .type = REGULATOR_VOLTAGE, \384 .min_uV = 700000, \385 .uV_step = 100000, \386 .n_voltages = 16, \387 .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \388 .vsel_mask = GENMASK(4, 1), \389 .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \390 .enable_mask = BIT(0), \391 .enable_time = 2000, \392 .owner = THIS_MODULE, \393}394 395#define atc2609a_reg_desc_ldo_bypass(num) { \396 .name = "LDO"#num, \397 .supply_name = "ldo"#num, \398 .of_match = of_match_ptr("ldo"#num), \399 .regulators_node = of_match_ptr("regulators"), \400 .id = ATC2609A_ID_LDO##num, \401 .ops = &atc260x_ldo_bypass_ops, \402 .type = REGULATOR_VOLTAGE, \403 .min_uV = 2300000, \404 .uV_step = 100000, \405 .n_voltages = 12, \406 .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \407 .vsel_mask = GENMASK(5, 2), \408 .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \409 .enable_mask = BIT(0), \410 .enable_time = 2000, \411 .bypass_reg = ATC2609A_PMU_LDO##num##_CTL0, \412 .bypass_mask = BIT(1), \413 .owner = THIS_MODULE, \414}415 416#define atc2609a_reg_desc_ldo_range_pick(num, n_range, n_volt) { \417 .name = "LDO"#num, \418 .supply_name = "ldo"#num, \419 .of_match = of_match_ptr("ldo"#num), \420 .regulators_node = of_match_ptr("regulators"), \421 .id = ATC2609A_ID_LDO##num, \422 .ops = &atc260x_ldo_range_pick_ops, \423 .type = REGULATOR_VOLTAGE, \424 .linear_ranges = atc2609a_ldo_voltage_ranges##n_range, \425 .n_linear_ranges = ARRAY_SIZE(atc2609a_ldo_voltage_ranges##n_range), \426 .n_voltages = n_volt, \427 .vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \428 .vsel_mask = GENMASK(4, 1), \429 .vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \430 .vsel_range_mask = BIT(5), \431 .linear_range_selectors_bitfield = atc260x_ldo_voltage_range_sel, \432 .enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \433 .enable_mask = BIT(0), \434 .enable_time = 2000, \435 .owner = THIS_MODULE, \436}437 438#define atc2609a_reg_desc_ldo_fixed(num) { \439 .name = "LDO"#num, \440 .supply_name = "ldo"#num, \441 .of_match = of_match_ptr("ldo"#num), \442 .regulators_node = of_match_ptr("regulators"), \443 .id = ATC2609A_ID_LDO##num, \444 .ops = &atc260x_ldo_fixed_ops, \445 .type = REGULATOR_VOLTAGE, \446 .min_uV = 2600000, \447 .uV_step = 100000, \448 .n_voltages = 8, \449 .vsel_reg = ATC2609A_PMU_LDO##num##_CTL, \450 .vsel_mask = GENMASK(15, 13), \451 .enable_time = 2000, \452 .owner = THIS_MODULE, \453}454 455static const struct regulator_desc atc2609a_reg[] = {456 atc2609a_reg_desc_dcdc(0, 4),457 atc2609a_reg_desc_dcdc(1, 5),458 atc2609a_reg_desc_dcdc(2, 6),459 atc2609a_reg_desc_dcdc_range(3, 7),460 atc2609a_reg_desc_dcdc(4, 8),461 atc2609a_reg_desc_ldo_bypass(0),462 atc2609a_reg_desc_ldo_bypass(1),463 atc2609a_reg_desc_ldo_bypass(2),464 atc2609a_reg_desc_ldo_range_pick(3, 0, 29),465 atc2609a_reg_desc_ldo_range_pick(4, 0, 29),466 atc2609a_reg_desc_ldo(5),467 atc2609a_reg_desc_ldo_range_pick(6, 1, 28),468 atc2609a_reg_desc_ldo_range_pick(7, 0, 29),469 atc2609a_reg_desc_ldo_range_pick(8, 0, 29),470 atc2609a_reg_desc_ldo_fixed(9),471};472 473static int atc260x_regulator_probe(struct platform_device *pdev)474{475 struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);476 struct device *dev = atc260x->dev;477 struct atc260x_regulator_data *atc260x_data;478 struct regulator_config config = {};479 struct regulator_dev *atc260x_rdev;480 const struct regulator_desc *regulators;481 bool atc2603c_ver_b = false;482 int i, nregulators;483 484 atc260x_data = devm_kzalloc(&pdev->dev, sizeof(*atc260x_data), GFP_KERNEL);485 if (!atc260x_data)486 return -ENOMEM;487 488 atc260x_data->voltage_time_dcdc = 350;489 atc260x_data->voltage_time_ldo = 800;490 491 switch (atc260x->ic_type) {492 case ATC2603C:493 regulators = atc2603c_reg;494 nregulators = ATC2603C_ID_MAX;495 atc2603c_ver_b = atc260x->ic_ver == ATC260X_B;496 break;497 case ATC2609A:498 atc260x_data->voltage_time_dcdc = 250;499 regulators = atc2609a_reg;500 nregulators = ATC2609A_ID_MAX;501 break;502 default:503 dev_err(dev, "unsupported ATC260X ID %d\n", atc260x->ic_type);504 return -EINVAL;505 }506 507 config.dev = dev;508 config.regmap = atc260x->regmap;509 config.driver_data = atc260x_data;510 511 /* Instantiate the regulators */512 for (i = 0; i < nregulators; i++) {513 if (atc2603c_ver_b && regulators[i].id == ATC2603C_ID_DCDC2)514 atc260x_rdev = devm_regulator_register(&pdev->dev,515 &atc2603c_reg_dcdc2_ver_b,516 &config);517 else518 atc260x_rdev = devm_regulator_register(&pdev->dev,519 ®ulators[i],520 &config);521 if (IS_ERR(atc260x_rdev)) {522 dev_err(dev, "failed to register regulator: %d\n", i);523 return PTR_ERR(atc260x_rdev);524 }525 }526 527 return 0;528}529 530static struct platform_driver atc260x_regulator_driver = {531 .probe = atc260x_regulator_probe,532 .driver = {533 .name = "atc260x-regulator",534 .probe_type = PROBE_PREFER_ASYNCHRONOUS,535 },536};537 538module_platform_driver(atc260x_regulator_driver);539 540MODULE_DESCRIPTION("Regulator driver for ATC260x PMICs");541MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");542MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");543MODULE_LICENSE("GPL");544