Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: Add regulator driver for ATC260x PMICs

Add support for the DC-DC converters and LDO regulators found in
the ATC2603C and ATC2609A chip variants of the Actions Semi ATC260x
family of PMICs.

Co-developed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@gmail.com>
Link: https://lore.kernel.org/r/1117b1a01b3948446cb3cc407e52de3a5d4212b0.1609258905.git.cristian.ciocaltea@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Cristian Ciocaltea and committed by
Mark Brown
3b15ccac 9351ab8b

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