18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Regulators driver for Dialog Semiconductor DA903x 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2006-2008 Marvell International Ltd. 68c2ecf20Sopenharmony_ci// Copyright (C) 2008 Compulab Ltd. 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 148c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 158c2ecf20Sopenharmony_ci#include <linux/mfd/da903x.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* DA9030 Registers */ 188c2ecf20Sopenharmony_ci#define DA9030_INVAL (-1) 198c2ecf20Sopenharmony_ci#define DA9030_LDO1011 (0x10) 208c2ecf20Sopenharmony_ci#define DA9030_LDO15 (0x11) 218c2ecf20Sopenharmony_ci#define DA9030_LDO1416 (0x12) 228c2ecf20Sopenharmony_ci#define DA9030_LDO1819 (0x13) 238c2ecf20Sopenharmony_ci#define DA9030_LDO17 (0x14) 248c2ecf20Sopenharmony_ci#define DA9030_BUCK2DVM1 (0x15) 258c2ecf20Sopenharmony_ci#define DA9030_BUCK2DVM2 (0x16) 268c2ecf20Sopenharmony_ci#define DA9030_RCTL11 (0x17) 278c2ecf20Sopenharmony_ci#define DA9030_RCTL21 (0x18) 288c2ecf20Sopenharmony_ci#define DA9030_LDO1 (0x90) 298c2ecf20Sopenharmony_ci#define DA9030_LDO23 (0x91) 308c2ecf20Sopenharmony_ci#define DA9030_LDO45 (0x92) 318c2ecf20Sopenharmony_ci#define DA9030_LDO6 (0x93) 328c2ecf20Sopenharmony_ci#define DA9030_LDO78 (0x94) 338c2ecf20Sopenharmony_ci#define DA9030_LDO912 (0x95) 348c2ecf20Sopenharmony_ci#define DA9030_BUCK (0x96) 358c2ecf20Sopenharmony_ci#define DA9030_RCTL12 (0x97) 368c2ecf20Sopenharmony_ci#define DA9030_RCTL22 (0x98) 378c2ecf20Sopenharmony_ci#define DA9030_LDO_UNLOCK (0xa0) 388c2ecf20Sopenharmony_ci#define DA9030_LDO_UNLOCK_MASK (0xe0) 398c2ecf20Sopenharmony_ci#define DA9034_OVER1 (0x10) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* DA9034 Registers */ 428c2ecf20Sopenharmony_ci#define DA9034_INVAL (-1) 438c2ecf20Sopenharmony_ci#define DA9034_OVER2 (0x11) 448c2ecf20Sopenharmony_ci#define DA9034_OVER3 (0x12) 458c2ecf20Sopenharmony_ci#define DA9034_LDO643 (0x13) 468c2ecf20Sopenharmony_ci#define DA9034_LDO987 (0x14) 478c2ecf20Sopenharmony_ci#define DA9034_LDO1110 (0x15) 488c2ecf20Sopenharmony_ci#define DA9034_LDO1312 (0x16) 498c2ecf20Sopenharmony_ci#define DA9034_LDO1514 (0x17) 508c2ecf20Sopenharmony_ci#define DA9034_VCC1 (0x20) 518c2ecf20Sopenharmony_ci#define DA9034_ADTV1 (0x23) 528c2ecf20Sopenharmony_ci#define DA9034_ADTV2 (0x24) 538c2ecf20Sopenharmony_ci#define DA9034_AVRC (0x25) 548c2ecf20Sopenharmony_ci#define DA9034_CDTV1 (0x26) 558c2ecf20Sopenharmony_ci#define DA9034_CDTV2 (0x27) 568c2ecf20Sopenharmony_ci#define DA9034_CVRC (0x28) 578c2ecf20Sopenharmony_ci#define DA9034_SDTV1 (0x29) 588c2ecf20Sopenharmony_ci#define DA9034_SDTV2 (0x2a) 598c2ecf20Sopenharmony_ci#define DA9034_SVRC (0x2b) 608c2ecf20Sopenharmony_ci#define DA9034_MDTV1 (0x32) 618c2ecf20Sopenharmony_ci#define DA9034_MDTV2 (0x33) 628c2ecf20Sopenharmony_ci#define DA9034_MVRC (0x34) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* DA9035 Registers. DA9034 Registers are comptabile to DA9035. */ 658c2ecf20Sopenharmony_ci#define DA9035_OVER3 (0x12) 668c2ecf20Sopenharmony_ci#define DA9035_VCC2 (0x1f) 678c2ecf20Sopenharmony_ci#define DA9035_3DTV1 (0x2c) 688c2ecf20Sopenharmony_ci#define DA9035_3DTV2 (0x2d) 698c2ecf20Sopenharmony_ci#define DA9035_3VRC (0x2e) 708c2ecf20Sopenharmony_ci#define DA9035_AUTOSKIP (0x2f) 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct da903x_regulator_info { 738c2ecf20Sopenharmony_ci struct regulator_desc desc; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci int max_uV; 768c2ecf20Sopenharmony_ci int vol_reg; 778c2ecf20Sopenharmony_ci int vol_shift; 788c2ecf20Sopenharmony_ci int vol_nbits; 798c2ecf20Sopenharmony_ci int update_reg; 808c2ecf20Sopenharmony_ci int update_bit; 818c2ecf20Sopenharmony_ci int enable_reg; 828c2ecf20Sopenharmony_ci int enable_bit; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic inline struct device *to_da903x_dev(struct regulator_dev *rdev) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci return rdev_get_dev(rdev)->parent->parent; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic inline int check_range(struct da903x_regulator_info *info, 918c2ecf20Sopenharmony_ci int min_uV, int max_uV) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci if (min_uV < info->desc.min_uV || min_uV > info->max_uV) 948c2ecf20Sopenharmony_ci return -EINVAL; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci return 0; 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* DA9030/DA9034 common operations */ 1008c2ecf20Sopenharmony_cistatic int da903x_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1038c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 1048c2ecf20Sopenharmony_ci uint8_t val, mask; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (rdev->desc->n_voltages == 1) 1078c2ecf20Sopenharmony_ci return -EINVAL; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci val = selector << info->vol_shift; 1108c2ecf20Sopenharmony_ci mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return da903x_update(da9034_dev, info->vol_reg, val, mask); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int da903x_get_voltage_sel(struct regulator_dev *rdev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1188c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 1198c2ecf20Sopenharmony_ci uint8_t val, mask; 1208c2ecf20Sopenharmony_ci int ret; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if (rdev->desc->n_voltages == 1) 1238c2ecf20Sopenharmony_ci return 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci ret = da903x_read(da9034_dev, info->vol_reg, &val); 1268c2ecf20Sopenharmony_ci if (ret) 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 1308c2ecf20Sopenharmony_ci val = (val & mask) >> info->vol_shift; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return val; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int da903x_enable(struct regulator_dev *rdev) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1388c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return da903x_set_bits(da9034_dev, info->enable_reg, 1418c2ecf20Sopenharmony_ci 1 << info->enable_bit); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int da903x_disable(struct regulator_dev *rdev) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1478c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return da903x_clr_bits(da9034_dev, info->enable_reg, 1508c2ecf20Sopenharmony_ci 1 << info->enable_bit); 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic int da903x_is_enabled(struct regulator_dev *rdev) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1568c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 1578c2ecf20Sopenharmony_ci uint8_t reg_val; 1588c2ecf20Sopenharmony_ci int ret; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci ret = da903x_read(da9034_dev, info->enable_reg, ®_val); 1618c2ecf20Sopenharmony_ci if (ret) 1628c2ecf20Sopenharmony_ci return ret; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return !!(reg_val & (1 << info->enable_bit)); 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* DA9030 specific operations */ 1688c2ecf20Sopenharmony_cistatic int da9030_set_ldo1_15_voltage_sel(struct regulator_dev *rdev, 1698c2ecf20Sopenharmony_ci unsigned selector) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1728c2ecf20Sopenharmony_ci struct device *da903x_dev = to_da903x_dev(rdev); 1738c2ecf20Sopenharmony_ci uint8_t val, mask; 1748c2ecf20Sopenharmony_ci int ret; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci val = selector << info->vol_shift; 1778c2ecf20Sopenharmony_ci mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 1788c2ecf20Sopenharmony_ci val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */ 1798c2ecf20Sopenharmony_ci mask |= DA9030_LDO_UNLOCK_MASK; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* write twice */ 1828c2ecf20Sopenharmony_ci ret = da903x_update(da903x_dev, info->vol_reg, val, mask); 1838c2ecf20Sopenharmony_ci if (ret) 1848c2ecf20Sopenharmony_ci return ret; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return da903x_update(da903x_dev, info->vol_reg, val, mask); 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int da9030_map_ldo14_voltage(struct regulator_dev *rdev, 1908c2ecf20Sopenharmony_ci int min_uV, int max_uV) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 1938c2ecf20Sopenharmony_ci int thresh, sel; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (check_range(info, min_uV, max_uV)) { 1968c2ecf20Sopenharmony_ci pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); 1978c2ecf20Sopenharmony_ci return -EINVAL; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci thresh = (info->max_uV + info->desc.min_uV) / 2; 2018c2ecf20Sopenharmony_ci if (min_uV < thresh) { 2028c2ecf20Sopenharmony_ci sel = DIV_ROUND_UP(thresh - min_uV, info->desc.uV_step); 2038c2ecf20Sopenharmony_ci sel |= 0x4; 2048c2ecf20Sopenharmony_ci } else { 2058c2ecf20Sopenharmony_ci sel = DIV_ROUND_UP(min_uV - thresh, info->desc.uV_step); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return sel; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int da9030_list_ldo14_voltage(struct regulator_dev *rdev, 2128c2ecf20Sopenharmony_ci unsigned selector) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 2158c2ecf20Sopenharmony_ci int volt; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (selector & 0x4) 2188c2ecf20Sopenharmony_ci volt = rdev->desc->min_uV + 2198c2ecf20Sopenharmony_ci rdev->desc->uV_step * (3 - (selector & ~0x4)); 2208c2ecf20Sopenharmony_ci else 2218c2ecf20Sopenharmony_ci volt = (info->max_uV + rdev->desc->min_uV) / 2 + 2228c2ecf20Sopenharmony_ci rdev->desc->uV_step * (selector & ~0x4); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (volt > info->max_uV) 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return volt; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* DA9034 specific operations */ 2318c2ecf20Sopenharmony_cistatic int da9034_set_dvc_voltage_sel(struct regulator_dev *rdev, 2328c2ecf20Sopenharmony_ci unsigned selector) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct da903x_regulator_info *info = rdev_get_drvdata(rdev); 2358c2ecf20Sopenharmony_ci struct device *da9034_dev = to_da903x_dev(rdev); 2368c2ecf20Sopenharmony_ci uint8_t val, mask; 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci val = selector << info->vol_shift; 2408c2ecf20Sopenharmony_ci mask = ((1 << info->vol_nbits) - 1) << info->vol_shift; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci ret = da903x_update(da9034_dev, info->vol_reg, val, mask); 2438c2ecf20Sopenharmony_ci if (ret) 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci ret = da903x_set_bits(da9034_dev, info->update_reg, 2478c2ecf20Sopenharmony_ci 1 << info->update_bit); 2488c2ecf20Sopenharmony_ci return ret; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic const struct linear_range da9034_ldo12_ranges[] = { 2528c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(1700000, 0, 7, 50000), 2538c2ecf20Sopenharmony_ci REGULATOR_LINEAR_RANGE(2700000, 8, 15, 50000), 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct regulator_ops da903x_regulator_ldo_ops = { 2578c2ecf20Sopenharmony_ci .set_voltage_sel = da903x_set_voltage_sel, 2588c2ecf20Sopenharmony_ci .get_voltage_sel = da903x_get_voltage_sel, 2598c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2608c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 2618c2ecf20Sopenharmony_ci .enable = da903x_enable, 2628c2ecf20Sopenharmony_ci .disable = da903x_disable, 2638c2ecf20Sopenharmony_ci .is_enabled = da903x_is_enabled, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci/* NOTE: this is dedicated for the insane DA9030 LDO14 */ 2678c2ecf20Sopenharmony_cistatic const struct regulator_ops da9030_regulator_ldo14_ops = { 2688c2ecf20Sopenharmony_ci .set_voltage_sel = da903x_set_voltage_sel, 2698c2ecf20Sopenharmony_ci .get_voltage_sel = da903x_get_voltage_sel, 2708c2ecf20Sopenharmony_ci .list_voltage = da9030_list_ldo14_voltage, 2718c2ecf20Sopenharmony_ci .map_voltage = da9030_map_ldo14_voltage, 2728c2ecf20Sopenharmony_ci .enable = da903x_enable, 2738c2ecf20Sopenharmony_ci .disable = da903x_disable, 2748c2ecf20Sopenharmony_ci .is_enabled = da903x_is_enabled, 2758c2ecf20Sopenharmony_ci}; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */ 2788c2ecf20Sopenharmony_cistatic const struct regulator_ops da9030_regulator_ldo1_15_ops = { 2798c2ecf20Sopenharmony_ci .set_voltage_sel = da9030_set_ldo1_15_voltage_sel, 2808c2ecf20Sopenharmony_ci .get_voltage_sel = da903x_get_voltage_sel, 2818c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2828c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 2838c2ecf20Sopenharmony_ci .enable = da903x_enable, 2848c2ecf20Sopenharmony_ci .disable = da903x_disable, 2858c2ecf20Sopenharmony_ci .is_enabled = da903x_is_enabled, 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic const struct regulator_ops da9034_regulator_dvc_ops = { 2898c2ecf20Sopenharmony_ci .set_voltage_sel = da9034_set_dvc_voltage_sel, 2908c2ecf20Sopenharmony_ci .get_voltage_sel = da903x_get_voltage_sel, 2918c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2928c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 2938c2ecf20Sopenharmony_ci .enable = da903x_enable, 2948c2ecf20Sopenharmony_ci .disable = da903x_disable, 2958c2ecf20Sopenharmony_ci .is_enabled = da903x_is_enabled, 2968c2ecf20Sopenharmony_ci}; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci/* NOTE: this is dedicated for the insane LDO12 */ 2998c2ecf20Sopenharmony_cistatic const struct regulator_ops da9034_regulator_ldo12_ops = { 3008c2ecf20Sopenharmony_ci .set_voltage_sel = da903x_set_voltage_sel, 3018c2ecf20Sopenharmony_ci .get_voltage_sel = da903x_get_voltage_sel, 3028c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 3038c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 3048c2ecf20Sopenharmony_ci .enable = da903x_enable, 3058c2ecf20Sopenharmony_ci .disable = da903x_disable, 3068c2ecf20Sopenharmony_ci .is_enabled = da903x_is_enabled, 3078c2ecf20Sopenharmony_ci}; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit) \ 3108c2ecf20Sopenharmony_ci{ \ 3118c2ecf20Sopenharmony_ci .desc = { \ 3128c2ecf20Sopenharmony_ci .name = "LDO" #_id, \ 3138c2ecf20Sopenharmony_ci .ops = &da903x_regulator_ldo_ops, \ 3148c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3158c2ecf20Sopenharmony_ci .id = _pmic##_ID_LDO##_id, \ 3168c2ecf20Sopenharmony_ci .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ 3178c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 3188c2ecf20Sopenharmony_ci .min_uV = (min) * 1000, \ 3198c2ecf20Sopenharmony_ci .uV_step = (step) * 1000, \ 3208c2ecf20Sopenharmony_ci }, \ 3218c2ecf20Sopenharmony_ci .max_uV = (max) * 1000, \ 3228c2ecf20Sopenharmony_ci .vol_reg = _pmic##_##vreg, \ 3238c2ecf20Sopenharmony_ci .vol_shift = (shift), \ 3248c2ecf20Sopenharmony_ci .vol_nbits = (nbits), \ 3258c2ecf20Sopenharmony_ci .enable_reg = _pmic##_##ereg, \ 3268c2ecf20Sopenharmony_ci .enable_bit = (ebit), \ 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define DA903x_DVC(_pmic, _id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ 3308c2ecf20Sopenharmony_ci{ \ 3318c2ecf20Sopenharmony_ci .desc = { \ 3328c2ecf20Sopenharmony_ci .name = #_id, \ 3338c2ecf20Sopenharmony_ci .ops = &da9034_regulator_dvc_ops, \ 3348c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3358c2ecf20Sopenharmony_ci .id = _pmic##_ID_##_id, \ 3368c2ecf20Sopenharmony_ci .n_voltages = (step) ? ((max - min) / step + 1) : 1, \ 3378c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 3388c2ecf20Sopenharmony_ci .min_uV = (min) * 1000, \ 3398c2ecf20Sopenharmony_ci .uV_step = (step) * 1000, \ 3408c2ecf20Sopenharmony_ci }, \ 3418c2ecf20Sopenharmony_ci .max_uV = (max) * 1000, \ 3428c2ecf20Sopenharmony_ci .vol_reg = _pmic##_##vreg, \ 3438c2ecf20Sopenharmony_ci .vol_shift = (0), \ 3448c2ecf20Sopenharmony_ci .vol_nbits = (nbits), \ 3458c2ecf20Sopenharmony_ci .update_reg = _pmic##_##ureg, \ 3468c2ecf20Sopenharmony_ci .update_bit = (ubit), \ 3478c2ecf20Sopenharmony_ci .enable_reg = _pmic##_##ereg, \ 3488c2ecf20Sopenharmony_ci .enable_bit = (ebit), \ 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ 3528c2ecf20Sopenharmony_ci DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit) 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \ 3558c2ecf20Sopenharmony_ci DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit) 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci#define DA9030_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ 3588c2ecf20Sopenharmony_ci DA903x_DVC(DA9030, _id, min, max, step, vreg, nbits, ureg, ubit, \ 3598c2ecf20Sopenharmony_ci ereg, ebit) 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ 3628c2ecf20Sopenharmony_ci DA903x_DVC(DA9034, _id, min, max, step, vreg, nbits, ureg, ubit, \ 3638c2ecf20Sopenharmony_ci ereg, ebit) 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci#define DA9035_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \ 3668c2ecf20Sopenharmony_ci DA903x_DVC(DA9035, _id, min, max, step, vreg, nbits, ureg, ubit, \ 3678c2ecf20Sopenharmony_ci ereg, ebit) 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic struct da903x_regulator_info da903x_regulator_info[] = { 3708c2ecf20Sopenharmony_ci /* DA9030 */ 3718c2ecf20Sopenharmony_ci DA9030_DVC(BUCK2, 850, 1625, 25, BUCK2DVM1, 5, BUCK2DVM1, 7, RCTL11, 0), 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1), 3748c2ecf20Sopenharmony_ci DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2), 3758c2ecf20Sopenharmony_ci DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3), 3768c2ecf20Sopenharmony_ci DA9030_LDO( 4, 1800, 3200, 100, LDO45, 0, 4, RCTL12, 4), 3778c2ecf20Sopenharmony_ci DA9030_LDO( 5, 1800, 3200, 100, LDO45, 4, 4, RCTL12, 5), 3788c2ecf20Sopenharmony_ci DA9030_LDO( 6, 1800, 3200, 100, LDO6, 0, 4, RCTL12, 6), 3798c2ecf20Sopenharmony_ci DA9030_LDO( 7, 1800, 3200, 100, LDO78, 0, 4, RCTL12, 7), 3808c2ecf20Sopenharmony_ci DA9030_LDO( 8, 1800, 3200, 100, LDO78, 4, 4, RCTL22, 0), 3818c2ecf20Sopenharmony_ci DA9030_LDO( 9, 1800, 3200, 100, LDO912, 0, 4, RCTL22, 1), 3828c2ecf20Sopenharmony_ci DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2), 3838c2ecf20Sopenharmony_ci DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3), 3848c2ecf20Sopenharmony_ci DA9030_LDO(12, 1800, 3200, 100, LDO912, 4, 4, RCTL22, 4), 3858c2ecf20Sopenharmony_ci DA9030_LDO(14, 2760, 2940, 30, LDO1416, 0, 3, RCTL11, 4), 3868c2ecf20Sopenharmony_ci DA9030_LDO(15, 1100, 2650, 50, LDO15, 0, 5, RCTL11, 5), 3878c2ecf20Sopenharmony_ci DA9030_LDO(16, 1100, 2650, 50, LDO1416, 3, 5, RCTL11, 6), 3888c2ecf20Sopenharmony_ci DA9030_LDO(17, 1800, 3200, 100, LDO17, 0, 4, RCTL11, 7), 3898c2ecf20Sopenharmony_ci DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2), 3908c2ecf20Sopenharmony_ci DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1), 3918c2ecf20Sopenharmony_ci DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */ 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci /* DA9034 */ 3948c2ecf20Sopenharmony_ci DA9034_DVC(BUCK1, 725, 1500, 25, ADTV2, 5, VCC1, 0, OVER1, 0), 3958c2ecf20Sopenharmony_ci DA9034_DVC(BUCK2, 725, 1500, 25, CDTV2, 5, VCC1, 2, OVER1, 1), 3968c2ecf20Sopenharmony_ci DA9034_DVC(LDO2, 725, 1500, 25, SDTV2, 5, VCC1, 4, OVER1, 2), 3978c2ecf20Sopenharmony_ci DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4), 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5), 4008c2ecf20Sopenharmony_ci DA9034_LDO( 4, 1800, 2900,1100, LDO643, 4, 1, OVER3, 6), 4018c2ecf20Sopenharmony_ci DA9034_LDO( 6, 2500, 2850, 50, LDO643, 5, 3, OVER2, 0), 4028c2ecf20Sopenharmony_ci DA9034_LDO( 7, 2700, 3050, 50, LDO987, 0, 3, OVER2, 1), 4038c2ecf20Sopenharmony_ci DA9034_LDO( 8, 2700, 2850, 50, LDO987, 3, 2, OVER2, 2), 4048c2ecf20Sopenharmony_ci DA9034_LDO( 9, 2700, 3050, 50, LDO987, 5, 3, OVER2, 3), 4058c2ecf20Sopenharmony_ci DA9034_LDO(10, 2700, 3050, 50, LDO1110, 0, 3, OVER2, 4), 4068c2ecf20Sopenharmony_ci DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5), 4078c2ecf20Sopenharmony_ci DA9034_LDO(12, 1700, 3050, 50, LDO1312, 0, 4, OVER3, 6), 4088c2ecf20Sopenharmony_ci DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7), 4098c2ecf20Sopenharmony_ci DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0), 4108c2ecf20Sopenharmony_ci DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1), 4118c2ecf20Sopenharmony_ci DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */ 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* DA9035 */ 4148c2ecf20Sopenharmony_ci DA9035_DVC(BUCK3, 1800, 2200, 100, 3DTV1, 3, VCC2, 0, OVER3, 3), 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic inline struct da903x_regulator_info *find_regulator_info(int id) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci struct da903x_regulator_info *ri; 4208c2ecf20Sopenharmony_ci int i; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) { 4238c2ecf20Sopenharmony_ci ri = &da903x_regulator_info[i]; 4248c2ecf20Sopenharmony_ci if (ri->desc.id == id) 4258c2ecf20Sopenharmony_ci return ri; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci return NULL; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int da903x_regulator_probe(struct platform_device *pdev) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct da903x_regulator_info *ri = NULL; 4338c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 4348c2ecf20Sopenharmony_ci struct regulator_config config = { }; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ri = find_regulator_info(pdev->id); 4378c2ecf20Sopenharmony_ci if (ri == NULL) { 4388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid regulator ID specified\n"); 4398c2ecf20Sopenharmony_ci return -EINVAL; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* Workaround for the weird LDO12 voltage setting */ 4438c2ecf20Sopenharmony_ci if (ri->desc.id == DA9034_ID_LDO12) { 4448c2ecf20Sopenharmony_ci ri->desc.ops = &da9034_regulator_ldo12_ops; 4458c2ecf20Sopenharmony_ci ri->desc.n_voltages = 16; 4468c2ecf20Sopenharmony_ci ri->desc.linear_ranges = da9034_ldo12_ranges; 4478c2ecf20Sopenharmony_ci ri->desc.n_linear_ranges = ARRAY_SIZE(da9034_ldo12_ranges); 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (ri->desc.id == DA9030_ID_LDO14) 4518c2ecf20Sopenharmony_ci ri->desc.ops = &da9030_regulator_ldo14_ops; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15) 4548c2ecf20Sopenharmony_ci ri->desc.ops = &da9030_regulator_ldo1_15_ops; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci config.dev = &pdev->dev; 4578c2ecf20Sopenharmony_ci config.init_data = dev_get_platdata(&pdev->dev); 4588c2ecf20Sopenharmony_ci config.driver_data = ri; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, &ri->desc, &config); 4618c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 4628c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 4638c2ecf20Sopenharmony_ci ri->desc.name); 4648c2ecf20Sopenharmony_ci return PTR_ERR(rdev); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, rdev); 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic struct platform_driver da903x_regulator_driver = { 4728c2ecf20Sopenharmony_ci .driver = { 4738c2ecf20Sopenharmony_ci .name = "da903x-regulator", 4748c2ecf20Sopenharmony_ci }, 4758c2ecf20Sopenharmony_ci .probe = da903x_regulator_probe, 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int __init da903x_regulator_init(void) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci return platform_driver_register(&da903x_regulator_driver); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_cisubsys_initcall(da903x_regulator_init); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic void __exit da903x_regulator_exit(void) 4858c2ecf20Sopenharmony_ci{ 4868c2ecf20Sopenharmony_ci platform_driver_unregister(&da903x_regulator_driver); 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_cimodule_exit(da903x_regulator_exit); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>" 4928c2ecf20Sopenharmony_ci "Mike Rapoport <mike@compulab.co.il>"); 4938c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC"); 4948c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:da903x-regulator"); 495