18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// da9052-regulator.c: Regulator driver for DA9052 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright(c) 2011 Dialog Semiconductor Ltd. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Author: David Dajun Chen <dchen@diasemi.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 158c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/da9052.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/reg.h> 218c2ecf20Sopenharmony_ci#include <linux/mfd/da9052/pdata.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Buck step size */ 248c2ecf20Sopenharmony_ci#define DA9052_BUCK_PERI_3uV_STEP 100000 258c2ecf20Sopenharmony_ci#define DA9052_BUCK_PERI_REG_MAP_UPTO_3uV 24 268c2ecf20Sopenharmony_ci#define DA9052_CONST_3uV 3000000 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define DA9052_MIN_UA 0 298c2ecf20Sopenharmony_ci#define DA9052_MAX_UA 3 308c2ecf20Sopenharmony_ci#define DA9052_CURRENT_RANGE 4 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Bit masks */ 338c2ecf20Sopenharmony_ci#define DA9052_BUCK_ILIM_MASK_EVEN 0x0c 348c2ecf20Sopenharmony_ci#define DA9052_BUCK_ILIM_MASK_ODD 0xc0 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* DA9052 REGULATOR IDs */ 378c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK1 0 388c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK2 1 398c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK3 2 408c2ecf20Sopenharmony_ci#define DA9052_ID_BUCK4 3 418c2ecf20Sopenharmony_ci#define DA9052_ID_LDO1 4 428c2ecf20Sopenharmony_ci#define DA9052_ID_LDO2 5 438c2ecf20Sopenharmony_ci#define DA9052_ID_LDO3 6 448c2ecf20Sopenharmony_ci#define DA9052_ID_LDO4 7 458c2ecf20Sopenharmony_ci#define DA9052_ID_LDO5 8 468c2ecf20Sopenharmony_ci#define DA9052_ID_LDO6 9 478c2ecf20Sopenharmony_ci#define DA9052_ID_LDO7 10 488c2ecf20Sopenharmony_ci#define DA9052_ID_LDO8 11 498c2ecf20Sopenharmony_ci#define DA9052_ID_LDO9 12 508c2ecf20Sopenharmony_ci#define DA9052_ID_LDO10 13 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const u32 da9052_current_limits[3][4] = { 538c2ecf20Sopenharmony_ci {700000, 800000, 1000000, 1200000}, /* DA9052-BC BUCKs */ 548c2ecf20Sopenharmony_ci {1600000, 2000000, 2400000, 3000000}, /* DA9053-AA/Bx BUCK-CORE */ 558c2ecf20Sopenharmony_ci {800000, 1000000, 1200000, 1500000}, /* DA9053-AA/Bx BUCK-PRO, 568c2ecf20Sopenharmony_ci * BUCK-MEM and BUCK-PERI 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct da9052_regulator_info { 618c2ecf20Sopenharmony_ci struct regulator_desc reg_desc; 628c2ecf20Sopenharmony_ci int step_uV; 638c2ecf20Sopenharmony_ci int min_uV; 648c2ecf20Sopenharmony_ci int max_uV; 658c2ecf20Sopenharmony_ci unsigned char activate_bit; 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistruct da9052_regulator { 698c2ecf20Sopenharmony_ci struct da9052 *da9052; 708c2ecf20Sopenharmony_ci struct da9052_regulator_info *info; 718c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic int verify_range(struct da9052_regulator_info *info, 758c2ecf20Sopenharmony_ci int min_uV, int max_uV) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci if (min_uV > info->max_uV || max_uV < info->min_uV) 788c2ecf20Sopenharmony_ci return -EINVAL; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int da9052_dcdc_get_current_limit(struct regulator_dev *rdev) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 868c2ecf20Sopenharmony_ci int offset = rdev_get_id(rdev); 878c2ecf20Sopenharmony_ci int ret, row = 2; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret = da9052_reg_read(regulator->da9052, DA9052_BUCKA_REG + offset/2); 908c2ecf20Sopenharmony_ci if (ret < 0) 918c2ecf20Sopenharmony_ci return ret; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Determine the even or odd position of the buck current limit 948c2ecf20Sopenharmony_ci * register field 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci if (offset % 2 == 0) 978c2ecf20Sopenharmony_ci ret = (ret & DA9052_BUCK_ILIM_MASK_EVEN) >> 2; 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci ret = (ret & DA9052_BUCK_ILIM_MASK_ODD) >> 6; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* Select the appropriate current limit range */ 1028c2ecf20Sopenharmony_ci if (regulator->da9052->chip_id == DA9052) 1038c2ecf20Sopenharmony_ci row = 0; 1048c2ecf20Sopenharmony_ci else if (offset == 0) 1058c2ecf20Sopenharmony_ci row = 1; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return da9052_current_limits[row][ret]; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA, 1118c2ecf20Sopenharmony_ci int max_uA) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 1148c2ecf20Sopenharmony_ci int offset = rdev_get_id(rdev); 1158c2ecf20Sopenharmony_ci int reg_val = 0; 1168c2ecf20Sopenharmony_ci int i, row = 2; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Select the appropriate current limit range */ 1198c2ecf20Sopenharmony_ci if (regulator->da9052->chip_id == DA9052) 1208c2ecf20Sopenharmony_ci row = 0; 1218c2ecf20Sopenharmony_ci else if (offset == 0) 1228c2ecf20Sopenharmony_ci row = 1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) { 1258c2ecf20Sopenharmony_ci if ((min_uA <= da9052_current_limits[row][i]) && 1268c2ecf20Sopenharmony_ci (da9052_current_limits[row][i] <= max_uA)) { 1278c2ecf20Sopenharmony_ci reg_val = i; 1288c2ecf20Sopenharmony_ci break; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if (i < 0) 1338c2ecf20Sopenharmony_ci return -EINVAL; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Determine the even or odd position of the buck current limit 1368c2ecf20Sopenharmony_ci * register field 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci if (offset % 2 == 0) 1398c2ecf20Sopenharmony_ci return da9052_reg_update(regulator->da9052, 1408c2ecf20Sopenharmony_ci DA9052_BUCKA_REG + offset/2, 1418c2ecf20Sopenharmony_ci DA9052_BUCK_ILIM_MASK_EVEN, 1428c2ecf20Sopenharmony_ci reg_val << 2); 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci return da9052_reg_update(regulator->da9052, 1458c2ecf20Sopenharmony_ci DA9052_BUCKA_REG + offset/2, 1468c2ecf20Sopenharmony_ci DA9052_BUCK_ILIM_MASK_ODD, 1478c2ecf20Sopenharmony_ci reg_val << 6); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic int da9052_list_voltage(struct regulator_dev *rdev, 1518c2ecf20Sopenharmony_ci unsigned int selector) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 1548c2ecf20Sopenharmony_ci struct da9052_regulator_info *info = regulator->info; 1558c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 1568c2ecf20Sopenharmony_ci int volt_uV; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) 1598c2ecf20Sopenharmony_ci && (selector >= DA9052_BUCK_PERI_REG_MAP_UPTO_3uV)) { 1608c2ecf20Sopenharmony_ci volt_uV = ((DA9052_BUCK_PERI_REG_MAP_UPTO_3uV * info->step_uV) 1618c2ecf20Sopenharmony_ci + info->min_uV); 1628c2ecf20Sopenharmony_ci volt_uV += (selector - DA9052_BUCK_PERI_REG_MAP_UPTO_3uV) 1638c2ecf20Sopenharmony_ci * (DA9052_BUCK_PERI_3uV_STEP); 1648c2ecf20Sopenharmony_ci } else { 1658c2ecf20Sopenharmony_ci volt_uV = (selector * info->step_uV) + info->min_uV; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci if (volt_uV > info->max_uV) 1698c2ecf20Sopenharmony_ci return -EINVAL; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci return volt_uV; 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int da9052_map_voltage(struct regulator_dev *rdev, 1758c2ecf20Sopenharmony_ci int min_uV, int max_uV) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 1788c2ecf20Sopenharmony_ci struct da9052_regulator_info *info = regulator->info; 1798c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 1808c2ecf20Sopenharmony_ci int ret, sel; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ret = verify_range(info, min_uV, max_uV); 1838c2ecf20Sopenharmony_ci if (ret < 0) 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (min_uV < info->min_uV) 1878c2ecf20Sopenharmony_ci min_uV = info->min_uV; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if ((id == DA9052_ID_BUCK4) && (regulator->da9052->chip_id == DA9052) 1908c2ecf20Sopenharmony_ci && (min_uV >= DA9052_CONST_3uV)) { 1918c2ecf20Sopenharmony_ci sel = DA9052_BUCK_PERI_REG_MAP_UPTO_3uV + 1928c2ecf20Sopenharmony_ci DIV_ROUND_UP(min_uV - DA9052_CONST_3uV, 1938c2ecf20Sopenharmony_ci DA9052_BUCK_PERI_3uV_STEP); 1948c2ecf20Sopenharmony_ci } else { 1958c2ecf20Sopenharmony_ci sel = DIV_ROUND_UP(min_uV - info->min_uV, info->step_uV); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci ret = da9052_list_voltage(rdev, sel); 1998c2ecf20Sopenharmony_ci if (ret < 0) 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return sel; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic int da9052_regulator_set_voltage_sel(struct regulator_dev *rdev, 2068c2ecf20Sopenharmony_ci unsigned int selector) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 2098c2ecf20Sopenharmony_ci struct da9052_regulator_info *info = regulator->info; 2108c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 2118c2ecf20Sopenharmony_ci int ret; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci ret = da9052_reg_update(regulator->da9052, rdev->desc->vsel_reg, 2148c2ecf20Sopenharmony_ci rdev->desc->vsel_mask, selector); 2158c2ecf20Sopenharmony_ci if (ret < 0) 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci /* Some LDOs and DCDCs are DVC controlled which requires enabling of 2198c2ecf20Sopenharmony_ci * the activate bit to implment the changes on the output. 2208c2ecf20Sopenharmony_ci */ 2218c2ecf20Sopenharmony_ci switch (id) { 2228c2ecf20Sopenharmony_ci case DA9052_ID_BUCK1: 2238c2ecf20Sopenharmony_ci case DA9052_ID_BUCK2: 2248c2ecf20Sopenharmony_ci case DA9052_ID_BUCK3: 2258c2ecf20Sopenharmony_ci case DA9052_ID_LDO2: 2268c2ecf20Sopenharmony_ci case DA9052_ID_LDO3: 2278c2ecf20Sopenharmony_ci ret = da9052_reg_update(regulator->da9052, DA9052_SUPPLY_REG, 2288c2ecf20Sopenharmony_ci info->activate_bit, info->activate_bit); 2298c2ecf20Sopenharmony_ci break; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return ret; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic int da9052_regulator_set_voltage_time_sel(struct regulator_dev *rdev, 2368c2ecf20Sopenharmony_ci unsigned int old_sel, 2378c2ecf20Sopenharmony_ci unsigned int new_sel) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct da9052_regulator *regulator = rdev_get_drvdata(rdev); 2408c2ecf20Sopenharmony_ci struct da9052_regulator_info *info = regulator->info; 2418c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 2428c2ecf20Sopenharmony_ci int ret = 0; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* The DVC controlled LDOs and DCDCs ramp with 6.25mV/µs after enabling 2458c2ecf20Sopenharmony_ci * the activate bit. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci switch (id) { 2488c2ecf20Sopenharmony_ci case DA9052_ID_BUCK1: 2498c2ecf20Sopenharmony_ci case DA9052_ID_BUCK2: 2508c2ecf20Sopenharmony_ci case DA9052_ID_BUCK3: 2518c2ecf20Sopenharmony_ci case DA9052_ID_LDO2: 2528c2ecf20Sopenharmony_ci case DA9052_ID_LDO3: 2538c2ecf20Sopenharmony_ci ret = DIV_ROUND_UP(abs(new_sel - old_sel) * info->step_uV, 2548c2ecf20Sopenharmony_ci 6250); 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return ret; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic const struct regulator_ops da9052_dcdc_ops = { 2628c2ecf20Sopenharmony_ci .get_current_limit = da9052_dcdc_get_current_limit, 2638c2ecf20Sopenharmony_ci .set_current_limit = da9052_dcdc_set_current_limit, 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci .list_voltage = da9052_list_voltage, 2668c2ecf20Sopenharmony_ci .map_voltage = da9052_map_voltage, 2678c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 2688c2ecf20Sopenharmony_ci .set_voltage_sel = da9052_regulator_set_voltage_sel, 2698c2ecf20Sopenharmony_ci .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, 2708c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 2718c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 2728c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 2738c2ecf20Sopenharmony_ci}; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic const struct regulator_ops da9052_ldo_ops = { 2768c2ecf20Sopenharmony_ci .list_voltage = da9052_list_voltage, 2778c2ecf20Sopenharmony_ci .map_voltage = da9052_map_voltage, 2788c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 2798c2ecf20Sopenharmony_ci .set_voltage_sel = da9052_regulator_set_voltage_sel, 2808c2ecf20Sopenharmony_ci .set_voltage_time_sel = da9052_regulator_set_voltage_time_sel, 2818c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 2828c2ecf20Sopenharmony_ci .enable = regulator_enable_regmap, 2838c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define DA9052_LDO(_id, _name, step, min, max, sbits, ebits, abits) \ 2878c2ecf20Sopenharmony_ci{\ 2888c2ecf20Sopenharmony_ci .reg_desc = {\ 2898c2ecf20Sopenharmony_ci .name = #_name,\ 2908c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_name),\ 2918c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 2928c2ecf20Sopenharmony_ci .ops = &da9052_ldo_ops,\ 2938c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 2948c2ecf20Sopenharmony_ci .id = DA9052_ID_##_id,\ 2958c2ecf20Sopenharmony_ci .n_voltages = (max - min) / step + 1, \ 2968c2ecf20Sopenharmony_ci .owner = THIS_MODULE,\ 2978c2ecf20Sopenharmony_ci .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 2988c2ecf20Sopenharmony_ci .vsel_mask = (1 << (sbits)) - 1,\ 2998c2ecf20Sopenharmony_ci .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 3008c2ecf20Sopenharmony_ci .enable_mask = 1 << (ebits),\ 3018c2ecf20Sopenharmony_ci },\ 3028c2ecf20Sopenharmony_ci .min_uV = (min) * 1000,\ 3038c2ecf20Sopenharmony_ci .max_uV = (max) * 1000,\ 3048c2ecf20Sopenharmony_ci .step_uV = (step) * 1000,\ 3058c2ecf20Sopenharmony_ci .activate_bit = (abits),\ 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci#define DA9052_DCDC(_id, _name, step, min, max, sbits, ebits, abits) \ 3098c2ecf20Sopenharmony_ci{\ 3108c2ecf20Sopenharmony_ci .reg_desc = {\ 3118c2ecf20Sopenharmony_ci .name = #_name,\ 3128c2ecf20Sopenharmony_ci .of_match = of_match_ptr(#_name),\ 3138c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("regulators"),\ 3148c2ecf20Sopenharmony_ci .ops = &da9052_dcdc_ops,\ 3158c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE,\ 3168c2ecf20Sopenharmony_ci .id = DA9052_ID_##_id,\ 3178c2ecf20Sopenharmony_ci .n_voltages = (max - min) / step + 1, \ 3188c2ecf20Sopenharmony_ci .owner = THIS_MODULE,\ 3198c2ecf20Sopenharmony_ci .vsel_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 3208c2ecf20Sopenharmony_ci .vsel_mask = (1 << (sbits)) - 1,\ 3218c2ecf20Sopenharmony_ci .enable_reg = DA9052_BUCKCORE_REG + DA9052_ID_##_id, \ 3228c2ecf20Sopenharmony_ci .enable_mask = 1 << (ebits),\ 3238c2ecf20Sopenharmony_ci },\ 3248c2ecf20Sopenharmony_ci .min_uV = (min) * 1000,\ 3258c2ecf20Sopenharmony_ci .max_uV = (max) * 1000,\ 3268c2ecf20Sopenharmony_ci .step_uV = (step) * 1000,\ 3278c2ecf20Sopenharmony_ci .activate_bit = (abits),\ 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic struct da9052_regulator_info da9052_regulator_info[] = { 3318c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 3328c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 3338c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), 3348c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK4, buck4, 50, 1800, 3600, 5, 6, 0), 3358c2ecf20Sopenharmony_ci DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), 3368c2ecf20Sopenharmony_ci DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 3378c2ecf20Sopenharmony_ci DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 3388c2ecf20Sopenharmony_ci DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), 3398c2ecf20Sopenharmony_ci DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), 3408c2ecf20Sopenharmony_ci DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), 3418c2ecf20Sopenharmony_ci DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), 3428c2ecf20Sopenharmony_ci DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), 3438c2ecf20Sopenharmony_ci DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), 3448c2ecf20Sopenharmony_ci DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic struct da9052_regulator_info da9053_regulator_info[] = { 3488c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK1, buck1, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBCOREGO), 3498c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK2, buck2, 25, 500, 2075, 6, 6, DA9052_SUPPLY_VBPROGO), 3508c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK3, buck3, 25, 950, 2525, 6, 6, DA9052_SUPPLY_VBMEMGO), 3518c2ecf20Sopenharmony_ci DA9052_DCDC(BUCK4, buck4, 25, 950, 2525, 6, 6, 0), 3528c2ecf20Sopenharmony_ci DA9052_LDO(LDO1, ldo1, 50, 600, 1800, 5, 6, 0), 3538c2ecf20Sopenharmony_ci DA9052_LDO(LDO2, ldo2, 25, 600, 1800, 6, 6, DA9052_SUPPLY_VLDO2GO), 3548c2ecf20Sopenharmony_ci DA9052_LDO(LDO3, ldo3, 25, 1725, 3300, 6, 6, DA9052_SUPPLY_VLDO3GO), 3558c2ecf20Sopenharmony_ci DA9052_LDO(LDO4, ldo4, 25, 1725, 3300, 6, 6, 0), 3568c2ecf20Sopenharmony_ci DA9052_LDO(LDO5, ldo5, 50, 1200, 3600, 6, 6, 0), 3578c2ecf20Sopenharmony_ci DA9052_LDO(LDO6, ldo6, 50, 1200, 3600, 6, 6, 0), 3588c2ecf20Sopenharmony_ci DA9052_LDO(LDO7, ldo7, 50, 1200, 3600, 6, 6, 0), 3598c2ecf20Sopenharmony_ci DA9052_LDO(LDO8, ldo8, 50, 1200, 3600, 6, 6, 0), 3608c2ecf20Sopenharmony_ci DA9052_LDO(LDO9, ldo9, 50, 1250, 3650, 6, 6, 0), 3618c2ecf20Sopenharmony_ci DA9052_LDO(LDO10, ldo10, 50, 1200, 3600, 6, 6, 0), 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic inline struct da9052_regulator_info *find_regulator_info(u8 chip_id, 3658c2ecf20Sopenharmony_ci int id) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci struct da9052_regulator_info *info; 3688c2ecf20Sopenharmony_ci int i; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci switch (chip_id) { 3718c2ecf20Sopenharmony_ci case DA9052: 3728c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(da9052_regulator_info); i++) { 3738c2ecf20Sopenharmony_ci info = &da9052_regulator_info[i]; 3748c2ecf20Sopenharmony_ci if (info->reg_desc.id == id) 3758c2ecf20Sopenharmony_ci return info; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci case DA9053_AA: 3798c2ecf20Sopenharmony_ci case DA9053_BA: 3808c2ecf20Sopenharmony_ci case DA9053_BB: 3818c2ecf20Sopenharmony_ci case DA9053_BC: 3828c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(da9053_regulator_info); i++) { 3838c2ecf20Sopenharmony_ci info = &da9053_regulator_info[i]; 3848c2ecf20Sopenharmony_ci if (info->reg_desc.id == id) 3858c2ecf20Sopenharmony_ci return info; 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci return NULL; 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int da9052_regulator_probe(struct platform_device *pdev) 3948c2ecf20Sopenharmony_ci{ 3958c2ecf20Sopenharmony_ci const struct mfd_cell *cell = mfd_get_cell(pdev); 3968c2ecf20Sopenharmony_ci struct regulator_config config = { }; 3978c2ecf20Sopenharmony_ci struct da9052_regulator *regulator; 3988c2ecf20Sopenharmony_ci struct da9052 *da9052; 3998c2ecf20Sopenharmony_ci struct da9052_pdata *pdata; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci regulator = devm_kzalloc(&pdev->dev, sizeof(struct da9052_regulator), 4028c2ecf20Sopenharmony_ci GFP_KERNEL); 4038c2ecf20Sopenharmony_ci if (!regulator) 4048c2ecf20Sopenharmony_ci return -ENOMEM; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci da9052 = dev_get_drvdata(pdev->dev.parent); 4078c2ecf20Sopenharmony_ci pdata = dev_get_platdata(da9052->dev); 4088c2ecf20Sopenharmony_ci regulator->da9052 = da9052; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci regulator->info = find_regulator_info(regulator->da9052->chip_id, 4118c2ecf20Sopenharmony_ci cell->id); 4128c2ecf20Sopenharmony_ci if (regulator->info == NULL) { 4138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid regulator ID specified\n"); 4148c2ecf20Sopenharmony_ci return -EINVAL; 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci config.dev = da9052->dev; 4188c2ecf20Sopenharmony_ci config.driver_data = regulator; 4198c2ecf20Sopenharmony_ci config.regmap = da9052->regmap; 4208c2ecf20Sopenharmony_ci if (pdata) 4218c2ecf20Sopenharmony_ci config.init_data = pdata->regulators[cell->id]; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci regulator->rdev = devm_regulator_register(&pdev->dev, 4248c2ecf20Sopenharmony_ci ®ulator->info->reg_desc, 4258c2ecf20Sopenharmony_ci &config); 4268c2ecf20Sopenharmony_ci if (IS_ERR(regulator->rdev)) { 4278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 4288c2ecf20Sopenharmony_ci regulator->info->reg_desc.name); 4298c2ecf20Sopenharmony_ci return PTR_ERR(regulator->rdev); 4308c2ecf20Sopenharmony_ci } 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, regulator); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic struct platform_driver da9052_regulator_driver = { 4388c2ecf20Sopenharmony_ci .probe = da9052_regulator_probe, 4398c2ecf20Sopenharmony_ci .driver = { 4408c2ecf20Sopenharmony_ci .name = "da9052-regulator", 4418c2ecf20Sopenharmony_ci }, 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic int __init da9052_regulator_init(void) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci return platform_driver_register(&da9052_regulator_driver); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_cisubsys_initcall(da9052_regulator_init); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic void __exit da9052_regulator_exit(void) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci platform_driver_unregister(&da9052_regulator_driver); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_cimodule_exit(da9052_regulator_exit); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); 4578c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Power Regulator driver for Dialog DA9052 PMIC"); 4588c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4598c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:da9052-regulator"); 460