1fd2f02f9SAxel Lin // SPDX-License-Identifier: GPL-2.0+ 2fd2f02f9SAxel Lin // 3fd2f02f9SAxel Lin // da9052-regulator.c: Regulator driver for DA9052 4fd2f02f9SAxel Lin // 5fd2f02f9SAxel Lin // Copyright(c) 2011 Dialog Semiconductor Ltd. 6fd2f02f9SAxel Lin // 7fd2f02f9SAxel Lin // Author: David Dajun Chen <dchen@diasemi.com> 808bf1c0aSAshish Jangam 908bf1c0aSAshish Jangam #include <linux/module.h> 1008bf1c0aSAshish Jangam #include <linux/moduleparam.h> 1108bf1c0aSAshish Jangam #include <linux/init.h> 1208bf1c0aSAshish Jangam #include <linux/err.h> 1308bf1c0aSAshish Jangam #include <linux/platform_device.h> 1408bf1c0aSAshish Jangam #include <linux/regulator/driver.h> 1508bf1c0aSAshish Jangam #include <linux/regulator/machine.h> 16cd22a965SMark Brown #include <linux/of.h> 1788c84c14SYing-Chun Liu (PaulLiu) #include <linux/regulator/of_regulator.h> 1808bf1c0aSAshish Jangam 1908bf1c0aSAshish Jangam #include <linux/mfd/da9052/da9052.h> 2008bf1c0aSAshish Jangam #include <linux/mfd/da9052/reg.h> 2108bf1c0aSAshish Jangam #include <linux/mfd/da9052/pdata.h> 2208bf1c0aSAshish Jangam 2308bf1c0aSAshish Jangam /* Buck step size */ 2408bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_3uV_STEP 100000 2508bf1c0aSAshish Jangam #define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV 24 2608bf1c0aSAshish Jangam #define DA9052_CONST_3uV 3000000 2708bf1c0aSAshish Jangam 2808bf1c0aSAshish Jangam #define DA9052_MIN_UA 0 2908bf1c0aSAshish Jangam #define DA9052_MAX_UA 3 3008bf1c0aSAshish Jangam #define DA9052_CURRENT_RANGE 4 3108bf1c0aSAshish Jangam 3208bf1c0aSAshish Jangam /* Bit masks */ 3308bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_EVEN 0x0c 3408bf1c0aSAshish Jangam #define DA9052_BUCK_ILIM_MASK_ODD 0xc0 3508bf1c0aSAshish Jangam 369210f05bSAxel Lin /* DA9052 REGULATOR IDs */ 379210f05bSAxel Lin #define DA9052_ID_BUCK1 0 389210f05bSAxel Lin #define DA9052_ID_BUCK2 1 399210f05bSAxel Lin #define DA9052_ID_BUCK3 2 409210f05bSAxel Lin #define DA9052_ID_BUCK4 3 419210f05bSAxel Lin #define DA9052_ID_LDO1 4 429210f05bSAxel Lin #define DA9052_ID_LDO2 5 439210f05bSAxel Lin #define DA9052_ID_LDO3 6 449210f05bSAxel Lin #define DA9052_ID_LDO4 7 459210f05bSAxel Lin #define DA9052_ID_LDO5 8 469210f05bSAxel Lin #define DA9052_ID_LDO6 9 479210f05bSAxel Lin #define DA9052_ID_LDO7 10 489210f05bSAxel Lin #define DA9052_ID_LDO8 11 499210f05bSAxel Lin #define DA9052_ID_LDO9 12 509210f05bSAxel Lin #define DA9052_ID_LDO10 13 519210f05bSAxel Lin 5208bf1c0aSAshish Jangam static const u32 da9052_current_limits[3][4] = { 5308bf1c0aSAshish Jangam {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */ 5408bf1c0aSAshish Jangam {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */ 5508bf1c0aSAshish Jangam {800000, 1000000, 1200000, 1500000}, /* DA9053-AA/Bx BUCK-PRO, 5608bf1c0aSAshish Jangam * BUCK-MEM and BUCK-PERI 5708bf1c0aSAshish Jangam */ 5808bf1c0aSAshish Jangam }; 5908bf1c0aSAshish Jangam 6008bf1c0aSAshish Jangam struct da9052_regulator_info { 6108bf1c0aSAshish Jangam struct regulator_desc reg_desc; 6208bf1c0aSAshish Jangam int step_uV; 6308bf1c0aSAshish Jangam int min_uV; 6408bf1c0aSAshish Jangam int max_uV; 65d706b1e4SAxel Lin unsigned char activate_bit; 6608bf1c0aSAshish Jangam }; 6708bf1c0aSAshish Jangam 6808bf1c0aSAshish Jangam struct da9052_regulator { 6908bf1c0aSAshish Jangam struct da9052 *da9052; 7008bf1c0aSAshish Jangam struct da9052_regulator_info *info; 7108bf1c0aSAshish Jangam struct regulator_dev *rdev; 7208bf1c0aSAshish Jangam }; 7308bf1c0aSAshish Jangam 7408bf1c0aSAshish Jangam static int verify_range(struct da9052_regulator_info *info, 7508bf1c0aSAshish Jangam int min_uV, int max_uV) 7608bf1c0aSAshish Jangam { 7708bf1c0aSAshish Jangam if (min_uV > info->max_uV || max_uV < info->min_uV) 7808bf1c0aSAshish Jangam return -EINVAL; 7908bf1c0aSAshish Jangam 8008bf1c0aSAshish Jangam return 0; 8108bf1c0aSAshish Jangam } 8208bf1c0aSAshish Jangam 8308bf1c0aSAshish Jangam static int da9052_dcdc_get_current_limit(struct regulator_dev *rdev) 8408bf1c0aSAshish Jangam { 8508bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 8608bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 8708bf1c0aSAshish Jangam int ret, row = 2; 8808bf1c0aSAshish Jangam 8908bf1c0aSAshish Jangam ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2); 9008bf1c0aSAshish Jangam if (ret < 0) 9108bf1c0aSAshish Jangam return ret; 9208bf1c0aSAshish Jangam 9308bf1c0aSAshish Jangam /* Determine the even or odd position of the buck current limit 9408bf1c0aSAshish Jangam * register field 9508bf1c0aSAshish Jangam */ 9608bf1c0aSAshish Jangam if (offset % 2 == 0) 9708bf1c0aSAshish Jangam ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2; 9808bf1c0aSAshish Jangam else 9908bf1c0aSAshish Jangam ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6; 10008bf1c0aSAshish Jangam 10108bf1c0aSAshish Jangam /* Select the appropriate current limit range */ 10208bf1c0aSAshish Jangam if (regulator->da9052->chip_id == DA9052) 10308bf1c0aSAshish Jangam row = 0; 10408bf1c0aSAshish Jangam else if (offset == 0) 10508bf1c0aSAshish Jangam row = 1; 10608bf1c0aSAshish Jangam 10708bf1c0aSAshish Jangam return da9052_current_limits[row][ret]; 10808bf1c0aSAshish Jangam } 10908bf1c0aSAshish Jangam 11008bf1c0aSAshish Jangam static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, 11108bf1c0aSAshish Jangam int max_uA) 11208bf1c0aSAshish Jangam { 11308bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 11408bf1c0aSAshish Jangam int offset = rdev_get_id(rdev); 11508bf1c0aSAshish Jangam int reg_val = 0; 11608bf1c0aSAshish Jangam int i, row = 2; 11708bf1c0aSAshish Jangam 11808bf1c0aSAshish Jangam /* Select the appropriate current limit range */ 11908bf1c0aSAshish Jangam if (regulator->da9052->chip_id == DA9052) 12008bf1c0aSAshish Jangam row = 0; 12108bf1c0aSAshish Jangam else if (offset == 0) 12208bf1c0aSAshish Jangam row = 1; 12308bf1c0aSAshish Jangam 12419d23c21SAxel Lin for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) { 1251e369bcdSAxel Lin if ((min_uA <= da9052_current_limits[row][i]) && 1261e369bcdSAxel Lin (da9052_current_limits[row][i] <= max_uA)) { 12708bf1c0aSAshish Jangam reg_val = i; 12808bf1c0aSAshish Jangam break; 12908bf1c0aSAshish Jangam } 13008bf1c0aSAshish Jangam } 13108bf1c0aSAshish Jangam 1321e369bcdSAxel Lin if (i < 0) 1331e369bcdSAxel Lin return -EINVAL; 1341e369bcdSAxel Lin 13508bf1c0aSAshish Jangam /* Determine the even or odd position of the buck current limit 13608bf1c0aSAshish Jangam * register field 13708bf1c0aSAshish Jangam */ 13808bf1c0aSAshish Jangam if (offset % 2 == 0) 13908bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 14008bf1c0aSAshish Jangam DA9052_BUCKA_REG + offset/2, 14108bf1c0aSAshish Jangam DA9052_BUCK_ILIM_MASK_EVEN, 14208bf1c0aSAshish Jangam reg_val << 2); 14308bf1c0aSAshish Jangam else 14408bf1c0aSAshish Jangam return da9052_reg_update(regulator->da9052, 14508bf1c0aSAshish Jangam DA9052_BUCKA_REG + offset/2, 14608bf1c0aSAshish Jangam DA9052_BUCK_ILIM_MASK_ODD, 14708bf1c0aSAshish Jangam reg_val << 6); 14808bf1c0aSAshish Jangam } 14908bf1c0aSAshish Jangam 15008bf1c0aSAshish Jangam static int da9052_list_voltage(struct regulator_dev *rdev, 15108bf1c0aSAshish Jangam unsigned int selector) 15208bf1c0aSAshish Jangam { 15308bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 15408bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 1550ec446eaSAxel Lin int id = rdev_get_id(rdev); 15608bf1c0aSAshish Jangam int volt_uV; 15708bf1c0aSAshish Jangam 1580ec446eaSAxel Lin if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) 1590ec446eaSAxel Lin && (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { 1600ec446eaSAxel Lin volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) 1610ec446eaSAxel Lin + info->min_uV); 1620ec446eaSAxel Lin volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) 1630ec446eaSAxel Lin * (DA9052_BUCK_PERI_3uV_STEP); 1640ec446eaSAxel Lin } else { 1650ec446eaSAxel Lin volt_uV = (selector * info->step_uV) + info->min_uV; 1660ec446eaSAxel Lin } 16708bf1c0aSAshish Jangam 16808bf1c0aSAshish Jangam if (volt_uV > info->max_uV) 16908bf1c0aSAshish Jangam return -EINVAL; 17008bf1c0aSAshish Jangam 17108bf1c0aSAshish Jangam return volt_uV; 17208bf1c0aSAshish Jangam } 17308bf1c0aSAshish Jangam 1744923b48bSAxel Lin static int da9052_map_voltage(struct regulator_dev *rdev, 1754923b48bSAxel Lin int min_uV, int max_uV) 17608bf1c0aSAshish Jangam { 17708bf1c0aSAshish Jangam struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 17808bf1c0aSAshish Jangam struct da9052_regulator_info *info = regulator->info; 1790ec446eaSAxel Lin int id = rdev_get_id(rdev); 1804923b48bSAxel Lin int ret, sel; 18108bf1c0aSAshish Jangam 18208bf1c0aSAshish Jangam ret = verify_range(info, min_uV, max_uV); 18308bf1c0aSAshish Jangam if (ret < 0) 18408bf1c0aSAshish Jangam return ret; 18508bf1c0aSAshish Jangam 18608bf1c0aSAshish Jangam if (min_uV < info->min_uV) 18708bf1c0aSAshish Jangam min_uV = info->min_uV; 18808bf1c0aSAshish Jangam 1890ec446eaSAxel Lin if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) 1900ec446eaSAxel Lin && (min_uV >= DA9052_CONST_3uV)) { 1914923b48bSAxel Lin sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + 1920ec446eaSAxel Lin DIV_ROUND_UP(min_uV - DA9052_CONST_3uV, 1930ec446eaSAxel Lin DA9052_BUCK_PERI_3uV_STEP); 1940ec446eaSAxel Lin } else { 1954923b48bSAxel Lin sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); 1960ec446eaSAxel Lin } 19708bf1c0aSAshish Jangam 1984923b48bSAxel Lin ret = da9052_list_voltage(rdev, sel); 19908bf1c0aSAshish Jangam if (ret < 0) 20008bf1c0aSAshish Jangam return ret; 20108bf1c0aSAshish Jangam 2024923b48bSAxel Lin return sel; 2034923b48bSAxel Lin } 2044923b48bSAxel Lin 205d706b1e4SAxel Lin static int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, 206d706b1e4SAxel Lin unsigned int selector) 207d706b1e4SAxel Lin { 208d706b1e4SAxel Lin struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 209d706b1e4SAxel Lin struct da9052_regulator_info *info = regulator->info; 210d706b1e4SAxel Lin int id = rdev_get_id(rdev); 211d706b1e4SAxel Lin int ret; 212d706b1e4SAxel Lin 213d706b1e4SAxel Lin ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, 214d706b1e4SAxel Lin rdev->desc->vsel_mask, selector); 215d706b1e4SAxel Lin if (ret < 0) 216d706b1e4SAxel Lin return ret; 217d706b1e4SAxel Lin 218d706b1e4SAxel Lin /* Some LDOs and DCDCs are DVC controlled which requires enabling of 219d706b1e4SAxel Lin * the activate bit to implment the changes on the output. 220d706b1e4SAxel Lin */ 221d706b1e4SAxel Lin switch (id) { 222d706b1e4SAxel Lin case DA9052_ID_BUCK1: 223d706b1e4SAxel Lin case DA9052_ID_BUCK2: 224d706b1e4SAxel Lin case DA9052_ID_BUCK3: 225d706b1e4SAxel Lin case DA9052_ID_LDO2: 226d706b1e4SAxel Lin case DA9052_ID_LDO3: 227d706b1e4SAxel Lin ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 228d706b1e4SAxel Lin info->activate_bit, info->activate_bit); 229d706b1e4SAxel Lin break; 230d706b1e4SAxel Lin } 231d706b1e4SAxel Lin 232d706b1e4SAxel Lin return ret; 233d706b1e4SAxel Lin } 234d706b1e4SAxel Lin 2355c99a7b1SPhilipp Zabel static int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, 2365c99a7b1SPhilipp Zabel unsigned int old_sel, 2375c99a7b1SPhilipp Zabel unsigned int new_sel) 2385c99a7b1SPhilipp Zabel { 2395c99a7b1SPhilipp Zabel struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 2405c99a7b1SPhilipp Zabel struct da9052_regulator_info *info = regulator->info; 2415c99a7b1SPhilipp Zabel int id = rdev_get_id(rdev); 2425c99a7b1SPhilipp Zabel int ret = 0; 2435c99a7b1SPhilipp Zabel 2445c99a7b1SPhilipp Zabel /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling 2455c99a7b1SPhilipp Zabel * the activate bit. 2465c99a7b1SPhilipp Zabel */ 2475c99a7b1SPhilipp Zabel switch (id) { 2485c99a7b1SPhilipp Zabel case DA9052_ID_BUCK1: 2495c99a7b1SPhilipp Zabel case DA9052_ID_BUCK2: 2505c99a7b1SPhilipp Zabel case DA9052_ID_BUCK3: 2515c99a7b1SPhilipp Zabel case DA9052_ID_LDO2: 2525c99a7b1SPhilipp Zabel case DA9052_ID_LDO3: 253*a336dc8fSAxel Lin ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV, 254*a336dc8fSAxel Lin 6250); 2555c99a7b1SPhilipp Zabel break; 2565c99a7b1SPhilipp Zabel } 2575c99a7b1SPhilipp Zabel 2585c99a7b1SPhilipp Zabel return ret; 2595c99a7b1SPhilipp Zabel } 2605c99a7b1SPhilipp Zabel 26171242b49SJulia Lawall static const struct regulator_ops da9052_dcdc_ops = { 26208bf1c0aSAshish Jangam .get_current_limit = da9052_dcdc_get_current_limit, 26308bf1c0aSAshish Jangam .set_current_limit = da9052_dcdc_set_current_limit, 26408bf1c0aSAshish Jangam 26508bf1c0aSAshish Jangam .list_voltage = da9052_list_voltage, 2664923b48bSAxel Lin .map_voltage = da9052_map_voltage, 26709812bc4SAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 268d706b1e4SAxel Lin .set_voltage_sel = da9052_regulator_set_voltage_sel, 2695c99a7b1SPhilipp Zabel .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, 2700d481f74SAxel Lin .is_enabled = regulator_is_enabled_regmap, 2710d481f74SAxel Lin .enable = regulator_enable_regmap, 2720d481f74SAxel Lin .disable = regulator_disable_regmap, 27308bf1c0aSAshish Jangam }; 27408bf1c0aSAshish Jangam 27571242b49SJulia Lawall static const struct regulator_ops da9052_ldo_ops = { 27608bf1c0aSAshish Jangam .list_voltage = da9052_list_voltage, 2774923b48bSAxel Lin .map_voltage = da9052_map_voltage, 27809812bc4SAxel Lin .get_voltage_sel = regulator_get_voltage_sel_regmap, 279d706b1e4SAxel Lin .set_voltage_sel = da9052_regulator_set_voltage_sel, 2805c99a7b1SPhilipp Zabel .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, 2810d481f74SAxel Lin .is_enabled = regulator_is_enabled_regmap, 2820d481f74SAxel Lin .enable = regulator_enable_regmap, 2830d481f74SAxel Lin .disable = regulator_disable_regmap, 28408bf1c0aSAshish Jangam }; 28508bf1c0aSAshish Jangam 28645460fe9SRob Herring #define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \ 28708bf1c0aSAshish Jangam {\ 28808bf1c0aSAshish Jangam .reg_desc = {\ 28945460fe9SRob Herring .name = #_name,\ 29067ddc68aSAxel Lin .of_match = of_match_ptr(#_name),\ 29167ddc68aSAxel Lin .regulators_node = of_match_ptr("regulators"),\ 29208bf1c0aSAshish Jangam .ops = &da9052_ldo_ops,\ 29308bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 2949210f05bSAxel Lin .id = DA9052_ID_##_id,\ 2957b957654SAxel Lin .n_voltages = (max - min) / step + 1, \ 29608bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 29709812bc4SAxel Lin .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 29809812bc4SAxel Lin .vsel_mask = (1 << (sbits)) - 1,\ 2990d481f74SAxel Lin .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 3000d481f74SAxel Lin .enable_mask = 1 << (ebits),\ 30108bf1c0aSAshish Jangam },\ 30208bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 30308bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 30408bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 305d706b1e4SAxel Lin .activate_bit = (abits),\ 30608bf1c0aSAshish Jangam } 30708bf1c0aSAshish Jangam 30845460fe9SRob Herring #define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \ 30908bf1c0aSAshish Jangam {\ 31008bf1c0aSAshish Jangam .reg_desc = {\ 31145460fe9SRob Herring .name = #_name,\ 31267ddc68aSAxel Lin .of_match = of_match_ptr(#_name),\ 31367ddc68aSAxel Lin .regulators_node = of_match_ptr("regulators"),\ 31408bf1c0aSAshish Jangam .ops = &da9052_dcdc_ops,\ 31508bf1c0aSAshish Jangam .type = REGULATOR_VOLTAGE,\ 3169210f05bSAxel Lin .id = DA9052_ID_##_id,\ 3177b957654SAxel Lin .n_voltages = (max - min) / step + 1, \ 31808bf1c0aSAshish Jangam .owner = THIS_MODULE,\ 31909812bc4SAxel Lin .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 32009812bc4SAxel Lin .vsel_mask = (1 << (sbits)) - 1,\ 3210d481f74SAxel Lin .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 3220d481f74SAxel Lin .enable_mask = 1 << (ebits),\ 32308bf1c0aSAshish Jangam },\ 32408bf1c0aSAshish Jangam .min_uV = (min) * 1000,\ 32508bf1c0aSAshish Jangam .max_uV = (max) * 1000,\ 32608bf1c0aSAshish Jangam .step_uV = (step) * 1000,\ 327d706b1e4SAxel Lin .activate_bit = (abits),\ 32808bf1c0aSAshish Jangam } 32908bf1c0aSAshish Jangam 3306242eae9SAxel Lin static struct da9052_regulator_info da9052_regulator_info[] = { 33145460fe9SRob Herring DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 33245460fe9SRob Herring DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 33345460fe9SRob Herring DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), 33445460fe9SRob Herring DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0), 33545460fe9SRob Herring DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), 33645460fe9SRob Herring DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 33745460fe9SRob Herring DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 33845460fe9SRob Herring DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), 33945460fe9SRob Herring DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), 34045460fe9SRob Herring DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), 34145460fe9SRob Herring DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), 34245460fe9SRob Herring DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), 34345460fe9SRob Herring DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), 34445460fe9SRob Herring DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), 34508bf1c0aSAshish Jangam }; 34608bf1c0aSAshish Jangam 3476242eae9SAxel Lin static struct da9052_regulator_info da9053_regulator_info[] = { 34845460fe9SRob Herring DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 34945460fe9SRob Herring DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 35045460fe9SRob Herring DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), 35145460fe9SRob Herring DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0), 35245460fe9SRob Herring DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), 35345460fe9SRob Herring DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 35445460fe9SRob Herring DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 35545460fe9SRob Herring DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), 35645460fe9SRob Herring DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), 35745460fe9SRob Herring DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), 35845460fe9SRob Herring DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), 35945460fe9SRob Herring DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), 36045460fe9SRob Herring DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), 36145460fe9SRob Herring DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), 36208bf1c0aSAshish Jangam }; 36308bf1c0aSAshish Jangam 36408bf1c0aSAshish Jangam static inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, 36508bf1c0aSAshish Jangam int id) 36608bf1c0aSAshish Jangam { 36708bf1c0aSAshish Jangam struct da9052_regulator_info *info; 36808bf1c0aSAshish Jangam int i; 36908bf1c0aSAshish Jangam 370984b5a6bSAshish Jangam switch (chip_id) { 371984b5a6bSAshish Jangam case DA9052: 37208bf1c0aSAshish Jangam for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) { 37308bf1c0aSAshish Jangam info = &da9052_regulator_info[i]; 37408bf1c0aSAshish Jangam if (info->reg_desc.id == id) 37508bf1c0aSAshish Jangam return info; 37608bf1c0aSAshish Jangam } 377984b5a6bSAshish Jangam break; 378984b5a6bSAshish Jangam case DA9053_AA: 379984b5a6bSAshish Jangam case DA9053_BA: 380984b5a6bSAshish Jangam case DA9053_BB: 3818b708144SSteve Twiss case DA9053_BC: 38208bf1c0aSAshish Jangam for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { 38308bf1c0aSAshish Jangam info = &da9053_regulator_info[i]; 38408bf1c0aSAshish Jangam if (info->reg_desc.id == id) 38508bf1c0aSAshish Jangam return info; 38608bf1c0aSAshish Jangam } 387984b5a6bSAshish Jangam break; 38808bf1c0aSAshish Jangam } 38908bf1c0aSAshish Jangam 39008bf1c0aSAshish Jangam return NULL; 39108bf1c0aSAshish Jangam } 39208bf1c0aSAshish Jangam 393a5023574SBill Pemberton static int da9052_regulator_probe(struct platform_device *pdev) 39408bf1c0aSAshish Jangam { 395e0c21530SJohan Hovold const struct mfd_cell *cell = mfd_get_cell(pdev); 396c172708dSMark Brown struct regulator_config config = { }; 39708bf1c0aSAshish Jangam struct da9052_regulator *regulator; 39808bf1c0aSAshish Jangam struct da9052 *da9052; 39908bf1c0aSAshish Jangam struct da9052_pdata *pdata; 40008bf1c0aSAshish Jangam 401984b5a6bSAshish Jangam regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator), 402984b5a6bSAshish Jangam GFP_KERNEL); 40308bf1c0aSAshish Jangam if (!regulator) 40408bf1c0aSAshish Jangam return -ENOMEM; 40508bf1c0aSAshish Jangam 40608bf1c0aSAshish Jangam da9052 = dev_get_drvdata(pdev->dev.parent); 407dff91d0bSJingoo Han pdata = dev_get_platdata(da9052->dev); 40808bf1c0aSAshish Jangam regulator->da9052 = da9052; 40908bf1c0aSAshish Jangam 41008bf1c0aSAshish Jangam regulator->info = find_regulator_info(regulator->da9052->chip_id, 411e0c21530SJohan Hovold cell->id); 41208bf1c0aSAshish Jangam if (regulator->info == NULL) { 41308bf1c0aSAshish Jangam dev_err(&pdev->dev, "invalid regulator ID specified\n"); 4147eb6444fSAxel Lin return -EINVAL; 41508bf1c0aSAshish Jangam } 416c172708dSMark Brown 41767ddc68aSAxel Lin config.dev = da9052->dev; 418c172708dSMark Brown config.driver_data = regulator; 4190d481f74SAxel Lin config.regmap = da9052->regmap; 42067ddc68aSAxel Lin if (pdata) 421e0c21530SJohan Hovold config.init_data = pdata->regulators[cell->id]; 422c172708dSMark Brown 423ea49a5ebSAxel Lin regulator->rdev = devm_regulator_register(&pdev->dev, 424ea49a5ebSAxel Lin ®ulator->info->reg_desc, 425c172708dSMark Brown &config); 42608bf1c0aSAshish Jangam if (IS_ERR(regulator->rdev)) { 42708bf1c0aSAshish Jangam dev_err(&pdev->dev, "failed to register regulator %s\n", 42808bf1c0aSAshish Jangam regulator->info->reg_desc.name); 4297eb6444fSAxel Lin return PTR_ERR(regulator->rdev); 43008bf1c0aSAshish Jangam } 43108bf1c0aSAshish Jangam 43208bf1c0aSAshish Jangam platform_set_drvdata(pdev, regulator); 43308bf1c0aSAshish Jangam 43408bf1c0aSAshish Jangam return 0; 43508bf1c0aSAshish Jangam } 43608bf1c0aSAshish Jangam 43708bf1c0aSAshish Jangam static struct platform_driver da9052_regulator_driver = { 43808bf1c0aSAshish Jangam .probe = da9052_regulator_probe, 43908bf1c0aSAshish Jangam .driver = { 44008bf1c0aSAshish Jangam .name = "da9052-regulator", 44108bf1c0aSAshish Jangam }, 44208bf1c0aSAshish Jangam }; 44308bf1c0aSAshish Jangam 44408bf1c0aSAshish Jangam static int __init da9052_regulator_init(void) 44508bf1c0aSAshish Jangam { 44608bf1c0aSAshish Jangam return platform_driver_register(&da9052_regulator_driver); 44708bf1c0aSAshish Jangam } 44808bf1c0aSAshish Jangam subsys_initcall(da9052_regulator_init); 44908bf1c0aSAshish Jangam 45008bf1c0aSAshish Jangam static void __exit da9052_regulator_exit(void) 45108bf1c0aSAshish Jangam { 45208bf1c0aSAshish Jangam platform_driver_unregister(&da9052_regulator_driver); 45308bf1c0aSAshish Jangam } 45408bf1c0aSAshish Jangam module_exit(da9052_regulator_exit); 45508bf1c0aSAshish Jangam 45608bf1c0aSAshish Jangam MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 45708bf1c0aSAshish Jangam MODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); 45808bf1c0aSAshish Jangam MODULE_LICENSE("GPL"); 45908bf1c0aSAshish Jangam MODULE_ALIAS("platform:da9052-regulator"); 460