cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

atc260x-regulator.c (17016B)


      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
     14struct atc260x_regulator_data {
     15	int voltage_time_dcdc;
     16	int voltage_time_ldo;
     17};
     18
     19static 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
     24static 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
     29static const struct linear_range atc2609a_ldo_voltage_ranges0[] = {
     30	REGULATOR_LINEAR_RANGE(700000, 0, 15, 100000),
     31	REGULATOR_LINEAR_RANGE(2100000, 0, 12, 100000),
     32};
     33
     34static const struct linear_range atc2609a_ldo_voltage_ranges1[] = {
     35	REGULATOR_LINEAR_RANGE(850000, 0, 15, 100000),
     36	REGULATOR_LINEAR_RANGE(2100000, 0, 11, 100000),
     37};
     38
     39static const unsigned int atc260x_ldo_voltage_range_sel[] = {
     40	0x0, 0x20,
     41};
     42
     43static 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
     55static 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
     67static 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
     77static 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
     87static 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
     99static 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
    112static 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
    122static 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
    132static 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
    139static 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
    146static 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 */
    153enum 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	.active_discharge_on = BIT(1), \
    296	.owner = THIS_MODULE, \
    297}
    298
    299static const struct regulator_desc atc2603c_reg[] = {
    300	atc2603c_reg_desc_dcdc_fixed(1, 700000, 25000, 29, 11, 7),
    301	atc2603c_reg_desc_dcdc_range(2, 12, 8),
    302	atc2603c_reg_desc_dcdc_fixed(3, 2600000, 100000, 8, 11, 9),
    303	atc2603c_reg_desc_ldo_fixed(1, 2600000, 100000, 8, 15, 13),
    304	atc2603c_reg_desc_ldo_fixed(2, 2600000, 100000, 8, 15, 13),
    305	atc2603c_reg_desc_ldo_fixed(3, 1500000, 100000, 6, 15, 13),
    306	atc2603c_reg_desc_ldo(5, 2600000, 100000, 8, 15, 13),
    307	atc2603c_reg_desc_ldo_fixed(6, 700000, 25000, 29, 15, 11),
    308	atc2603c_reg_desc_ldo(7, 1500000, 100000, 6, 15, 13),
    309	atc2603c_reg_desc_ldo(8, 2300000, 100000, 11, 15, 12),
    310	atc2603c_reg_desc_ldo_fixed(11, 2600000, 100000, 8, 15, 13),
    311	atc2603c_reg_desc_ldo_noops(12, 1800000),
    312	atc2603c_reg_desc_ldo_switch(1, 3000000, 100000, 4, 4, 3),
    313};
    314
    315static const struct regulator_desc atc2603c_reg_dcdc2_ver_b =
    316	atc2603c_reg_desc_dcdc(2, 1000000, 50000, 18, 12, 8);
    317
    318enum atc2609a_reg_ids {
    319	ATC2609A_ID_DCDC0,
    320	ATC2609A_ID_DCDC1,
    321	ATC2609A_ID_DCDC2,
    322	ATC2609A_ID_DCDC3,
    323	ATC2609A_ID_DCDC4,
    324	ATC2609A_ID_LDO0,
    325	ATC2609A_ID_LDO1,
    326	ATC2609A_ID_LDO2,
    327	ATC2609A_ID_LDO3,
    328	ATC2609A_ID_LDO4,
    329	ATC2609A_ID_LDO5,
    330	ATC2609A_ID_LDO6,
    331	ATC2609A_ID_LDO7,
    332	ATC2609A_ID_LDO8,
    333	ATC2609A_ID_LDO9,
    334	ATC2609A_ID_MAX,
    335};
    336
    337#define atc2609a_reg_desc_dcdc(num, en_bit) { \
    338	.name = "DCDC"#num, \
    339	.supply_name = "dcdc"#num, \
    340	.of_match = of_match_ptr("dcdc"#num), \
    341	.regulators_node = of_match_ptr("regulators"), \
    342	.id = ATC2609A_ID_DCDC##num, \
    343	.ops = &atc260x_dcdc_ops, \
    344	.type = REGULATOR_VOLTAGE, \
    345	.min_uV = 600000, \
    346	.uV_step = 6250, \
    347	.n_voltages = 256, \
    348	.vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \
    349	.vsel_mask = GENMASK(15, 8), \
    350	.enable_reg = ATC2609A_PMU_DC_OSC, \
    351	.enable_mask = BIT(en_bit), \
    352	.enable_time = 800, \
    353	.owner = THIS_MODULE, \
    354}
    355
    356#define atc2609a_reg_desc_dcdc_range(num, en_bit) { \
    357	.name = "DCDC"#num, \
    358	.supply_name = "dcdc"#num, \
    359	.of_match = of_match_ptr("dcdc"#num), \
    360	.regulators_node = of_match_ptr("regulators"), \
    361	.id = ATC2609A_ID_DCDC##num, \
    362	.ops = &atc260x_dcdc_range_ops, \
    363	.type = REGULATOR_VOLTAGE, \
    364	.n_voltages = 233, \
    365	.linear_ranges = atc2609a_dcdc_voltage_ranges, \
    366	.n_linear_ranges = ARRAY_SIZE(atc2609a_dcdc_voltage_ranges), \
    367	.vsel_reg = ATC2609A_PMU_DC##num##_CTL0, \
    368	.vsel_mask = GENMASK(15, 8), \
    369	.enable_reg = ATC2609A_PMU_DC_OSC, \
    370	.enable_mask = BIT(en_bit), \
    371	.enable_time = 800, \
    372	.owner = THIS_MODULE, \
    373}
    374
    375#define atc2609a_reg_desc_ldo(num) { \
    376	.name = "LDO"#num, \
    377	.supply_name = "ldo"#num, \
    378	.of_match = of_match_ptr("ldo"#num), \
    379	.regulators_node = of_match_ptr("regulators"), \
    380	.id = ATC2609A_ID_LDO##num, \
    381	.ops = &atc260x_ldo_ops, \
    382	.type = REGULATOR_VOLTAGE, \
    383	.min_uV = 700000, \
    384	.uV_step = 100000, \
    385	.n_voltages = 16, \
    386	.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    387	.vsel_mask = GENMASK(4, 1), \
    388	.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    389	.enable_mask = BIT(0), \
    390	.enable_time = 2000, \
    391	.owner = THIS_MODULE, \
    392}
    393
    394#define atc2609a_reg_desc_ldo_bypass(num) { \
    395	.name = "LDO"#num, \
    396	.supply_name = "ldo"#num, \
    397	.of_match = of_match_ptr("ldo"#num), \
    398	.regulators_node = of_match_ptr("regulators"), \
    399	.id = ATC2609A_ID_LDO##num, \
    400	.ops = &atc260x_ldo_bypass_ops, \
    401	.type = REGULATOR_VOLTAGE, \
    402	.min_uV = 2300000, \
    403	.uV_step = 100000, \
    404	.n_voltages = 12, \
    405	.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    406	.vsel_mask = GENMASK(5, 2), \
    407	.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    408	.enable_mask = BIT(0), \
    409	.enable_time = 2000, \
    410	.bypass_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    411	.bypass_mask = BIT(1), \
    412	.owner = THIS_MODULE, \
    413}
    414
    415#define atc2609a_reg_desc_ldo_range_pick(num, n_range, n_volt) { \
    416	.name = "LDO"#num, \
    417	.supply_name = "ldo"#num, \
    418	.of_match = of_match_ptr("ldo"#num), \
    419	.regulators_node = of_match_ptr("regulators"), \
    420	.id = ATC2609A_ID_LDO##num, \
    421	.ops = &atc260x_ldo_range_pick_ops, \
    422	.type = REGULATOR_VOLTAGE, \
    423	.linear_ranges = atc2609a_ldo_voltage_ranges##n_range, \
    424	.n_linear_ranges = ARRAY_SIZE(atc2609a_ldo_voltage_ranges##n_range), \
    425	.n_voltages = n_volt, \
    426	.vsel_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    427	.vsel_mask = GENMASK(4, 1), \
    428	.vsel_range_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    429	.vsel_range_mask = BIT(5), \
    430	.linear_range_selectors = atc260x_ldo_voltage_range_sel, \
    431	.enable_reg = ATC2609A_PMU_LDO##num##_CTL0, \
    432	.enable_mask = BIT(0), \
    433	.enable_time = 2000, \
    434	.owner = THIS_MODULE, \
    435}
    436
    437#define atc2609a_reg_desc_ldo_fixed(num) { \
    438	.name = "LDO"#num, \
    439	.supply_name = "ldo"#num, \
    440	.of_match = of_match_ptr("ldo"#num), \
    441	.regulators_node = of_match_ptr("regulators"), \
    442	.id = ATC2609A_ID_LDO##num, \
    443	.ops = &atc260x_ldo_fixed_ops, \
    444	.type = REGULATOR_VOLTAGE, \
    445	.min_uV = 2600000, \
    446	.uV_step = 100000, \
    447	.n_voltages = 8, \
    448	.vsel_reg = ATC2609A_PMU_LDO##num##_CTL, \
    449	.vsel_mask = GENMASK(15, 13), \
    450	.enable_time = 2000, \
    451	.owner = THIS_MODULE, \
    452}
    453
    454static const struct regulator_desc atc2609a_reg[] = {
    455	atc2609a_reg_desc_dcdc(0, 4),
    456	atc2609a_reg_desc_dcdc(1, 5),
    457	atc2609a_reg_desc_dcdc(2, 6),
    458	atc2609a_reg_desc_dcdc_range(3, 7),
    459	atc2609a_reg_desc_dcdc(4, 8),
    460	atc2609a_reg_desc_ldo_bypass(0),
    461	atc2609a_reg_desc_ldo_bypass(1),
    462	atc2609a_reg_desc_ldo_bypass(2),
    463	atc2609a_reg_desc_ldo_range_pick(3, 0, 29),
    464	atc2609a_reg_desc_ldo_range_pick(4, 0, 29),
    465	atc2609a_reg_desc_ldo(5),
    466	atc2609a_reg_desc_ldo_range_pick(6, 1, 28),
    467	atc2609a_reg_desc_ldo_range_pick(7, 0, 29),
    468	atc2609a_reg_desc_ldo_range_pick(8, 0, 29),
    469	atc2609a_reg_desc_ldo_fixed(9),
    470};
    471
    472static int atc260x_regulator_probe(struct platform_device *pdev)
    473{
    474	struct atc260x *atc260x = dev_get_drvdata(pdev->dev.parent);
    475	struct device *dev = atc260x->dev;
    476	struct atc260x_regulator_data *atc260x_data;
    477	struct regulator_config config = {};
    478	struct regulator_dev *atc260x_rdev;
    479	const struct regulator_desc *regulators;
    480	bool atc2603c_ver_b = false;
    481	int i, nregulators;
    482
    483	atc260x_data = devm_kzalloc(&pdev->dev, sizeof(*atc260x_data), GFP_KERNEL);
    484	if (!atc260x_data)
    485		return -ENOMEM;
    486
    487	atc260x_data->voltage_time_dcdc = 350;
    488	atc260x_data->voltage_time_ldo = 800;
    489
    490	switch (atc260x->ic_type) {
    491	case ATC2603C:
    492		regulators = atc2603c_reg;
    493		nregulators = ATC2603C_ID_MAX;
    494		atc2603c_ver_b = atc260x->ic_ver == ATC260X_B;
    495		break;
    496	case ATC2609A:
    497		atc260x_data->voltage_time_dcdc = 250;
    498		regulators = atc2609a_reg;
    499		nregulators = ATC2609A_ID_MAX;
    500		break;
    501	default:
    502		dev_err(dev, "unsupported ATC260X ID %d\n", atc260x->ic_type);
    503		return -EINVAL;
    504	}
    505
    506	config.dev = dev;
    507	config.regmap = atc260x->regmap;
    508	config.driver_data = atc260x_data;
    509
    510	/* Instantiate the regulators */
    511	for (i = 0; i < nregulators; i++) {
    512		if (atc2603c_ver_b && regulators[i].id == ATC2603C_ID_DCDC2)
    513			atc260x_rdev = devm_regulator_register(&pdev->dev,
    514							       &atc2603c_reg_dcdc2_ver_b,
    515							       &config);
    516		else
    517			atc260x_rdev = devm_regulator_register(&pdev->dev,
    518							       &regulators[i],
    519							       &config);
    520		if (IS_ERR(atc260x_rdev)) {
    521			dev_err(dev, "failed to register regulator: %d\n", i);
    522			return PTR_ERR(atc260x_rdev);
    523		}
    524	}
    525
    526	return 0;
    527}
    528
    529static struct platform_driver atc260x_regulator_driver = {
    530	.probe = atc260x_regulator_probe,
    531	.driver = {
    532		.name = "atc260x-regulator",
    533	},
    534};
    535
    536module_platform_driver(atc260x_regulator_driver);
    537
    538MODULE_DESCRIPTION("Regulator driver for ATC260x PMICs");
    539MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
    540MODULE_AUTHOR("Cristian Ciocaltea <cristian.ciocaltea@gmail.com>");
    541MODULE_LICENSE("GPL");