18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// max77686.c - Regulator driver for the Maxim 77686 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2012 Samsung Electronics 68c2ecf20Sopenharmony_ci// Chiwoong Byun <woong.byun@samsung.com> 78c2ecf20Sopenharmony_ci// Jonghwa Lee <jonghwa3.lee@samsung.com> 88c2ecf20Sopenharmony_ci// 98c2ecf20Sopenharmony_ci// This driver is based on max8997.c 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/bug.h> 138c2ecf20Sopenharmony_ci#include <linux/err.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/regulator/driver.h> 188c2ecf20Sopenharmony_ci#include <linux/regulator/machine.h> 198c2ecf20Sopenharmony_ci#include <linux/regulator/of_regulator.h> 208c2ecf20Sopenharmony_ci#include <linux/mfd/max77686.h> 218c2ecf20Sopenharmony_ci#include <linux/mfd/max77686-private.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MAX77686_LDO_MINUV 800000 248c2ecf20Sopenharmony_ci#define MAX77686_LDO_UVSTEP 50000 258c2ecf20Sopenharmony_ci#define MAX77686_LDO_LOW_MINUV 800000 268c2ecf20Sopenharmony_ci#define MAX77686_LDO_LOW_UVSTEP 25000 278c2ecf20Sopenharmony_ci#define MAX77686_BUCK_MINUV 750000 288c2ecf20Sopenharmony_ci#define MAX77686_BUCK_UVSTEP 50000 298c2ecf20Sopenharmony_ci#define MAX77686_BUCK_ENABLE_TIME 40 /* us */ 308c2ecf20Sopenharmony_ci#define MAX77686_DVS_ENABLE_TIME 22 /* us */ 318c2ecf20Sopenharmony_ci#define MAX77686_RAMP_DELAY 100000 /* uV/us */ 328c2ecf20Sopenharmony_ci#define MAX77686_DVS_RAMP_DELAY 27500 /* uV/us */ 338c2ecf20Sopenharmony_ci#define MAX77686_DVS_MINUV 600000 348c2ecf20Sopenharmony_ci#define MAX77686_DVS_UVSTEP 12500 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Value for configuring buck[89] and LDO{20,21,22} as GPIO control. 388c2ecf20Sopenharmony_ci * It is the same as 'off' for other regulators. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci#define MAX77686_GPIO_CONTROL 0x0 418c2ecf20Sopenharmony_ci/* 428c2ecf20Sopenharmony_ci * Values used for configuring LDOs and bucks. 438c2ecf20Sopenharmony_ci * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci#define MAX77686_LDO_LOWPOWER 0x1 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * On/off controlled by PWRREQ: 488c2ecf20Sopenharmony_ci * - LDO2, 6-8, 10-12, 14-16 498c2ecf20Sopenharmony_ci * - buck[1234] 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci#define MAX77686_OFF_PWRREQ 0x1 528c2ecf20Sopenharmony_ci/* Low power mode controlled by PWRREQ: All LDOs */ 538c2ecf20Sopenharmony_ci#define MAX77686_LDO_LOWPOWER_PWRREQ 0x2 548c2ecf20Sopenharmony_ci/* Forcing low power mode: buck[234] */ 558c2ecf20Sopenharmony_ci#define MAX77686_BUCK_LOWPOWER 0x2 568c2ecf20Sopenharmony_ci#define MAX77686_NORMAL 0x3 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#define MAX77686_OPMODE_SHIFT 6 598c2ecf20Sopenharmony_ci#define MAX77686_OPMODE_BUCK234_SHIFT 4 608c2ecf20Sopenharmony_ci#define MAX77686_OPMODE_MASK 0x3 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define MAX77686_VSEL_MASK 0x3F 638c2ecf20Sopenharmony_ci#define MAX77686_DVS_VSEL_MASK 0xFF 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define MAX77686_RAMP_RATE_MASK 0xC0 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define MAX77686_REGULATORS MAX77686_REG_MAX 688c2ecf20Sopenharmony_ci#define MAX77686_LDOS 26 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cienum max77686_ramp_rate { 718c2ecf20Sopenharmony_ci RAMP_RATE_13P75MV, 728c2ecf20Sopenharmony_ci RAMP_RATE_27P5MV, 738c2ecf20Sopenharmony_ci RAMP_RATE_55MV, 748c2ecf20Sopenharmony_ci RAMP_RATE_NO_CTRL, /* 100mV/us */ 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct max77686_data { 788c2ecf20Sopenharmony_ci struct device *dev; 798c2ecf20Sopenharmony_ci DECLARE_BITMAP(gpio_enabled, MAX77686_REGULATORS); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* Array indexed by regulator id */ 828c2ecf20Sopenharmony_ci unsigned int opmode[MAX77686_REGULATORS]; 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic unsigned int max77686_get_opmode_shift(int id) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci switch (id) { 888c2ecf20Sopenharmony_ci case MAX77686_BUCK1: 898c2ecf20Sopenharmony_ci case MAX77686_BUCK5 ... MAX77686_BUCK9: 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci case MAX77686_BUCK2 ... MAX77686_BUCK4: 928c2ecf20Sopenharmony_ci return MAX77686_OPMODE_BUCK234_SHIFT; 938c2ecf20Sopenharmony_ci default: 948c2ecf20Sopenharmony_ci /* all LDOs */ 958c2ecf20Sopenharmony_ci return MAX77686_OPMODE_SHIFT; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci} 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* 1008c2ecf20Sopenharmony_ci * When regulator is configured for GPIO control then it 1018c2ecf20Sopenharmony_ci * replaces "normal" mode. Any change from low power mode to normal 1028c2ecf20Sopenharmony_ci * should actually change to GPIO control. 1038c2ecf20Sopenharmony_ci * Map normal mode to proper value for such regulators. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic unsigned int max77686_map_normal_mode(struct max77686_data *max77686, 1068c2ecf20Sopenharmony_ci int id) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci switch (id) { 1098c2ecf20Sopenharmony_ci case MAX77686_BUCK8: 1108c2ecf20Sopenharmony_ci case MAX77686_BUCK9: 1118c2ecf20Sopenharmony_ci case MAX77686_LDO20 ... MAX77686_LDO22: 1128c2ecf20Sopenharmony_ci if (test_bit(id, max77686->gpio_enabled)) 1138c2ecf20Sopenharmony_ci return MAX77686_GPIO_CONTROL; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return MAX77686_NORMAL; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */ 1208c2ecf20Sopenharmony_cistatic int max77686_set_suspend_disable(struct regulator_dev *rdev) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci unsigned int val, shift; 1238c2ecf20Sopenharmony_ci struct max77686_data *max77686 = rdev_get_drvdata(rdev); 1248c2ecf20Sopenharmony_ci int ret, id = rdev_get_id(rdev); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci shift = max77686_get_opmode_shift(id); 1278c2ecf20Sopenharmony_ci val = MAX77686_OFF_PWRREQ; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 1308c2ecf20Sopenharmony_ci rdev->desc->enable_mask, val << shift); 1318c2ecf20Sopenharmony_ci if (ret) 1328c2ecf20Sopenharmony_ci return ret; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci max77686->opmode[id] = val; 1358c2ecf20Sopenharmony_ci return 0; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Some LDOs supports [LPM/Normal]ON mode during suspend state */ 1398c2ecf20Sopenharmony_cistatic int max77686_set_suspend_mode(struct regulator_dev *rdev, 1408c2ecf20Sopenharmony_ci unsigned int mode) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct max77686_data *max77686 = rdev_get_drvdata(rdev); 1438c2ecf20Sopenharmony_ci unsigned int val; 1448c2ecf20Sopenharmony_ci int ret, id = rdev_get_id(rdev); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* BUCK[5-9] doesn't support this feature */ 1478c2ecf20Sopenharmony_ci if (id >= MAX77686_BUCK5) 1488c2ecf20Sopenharmony_ci return 0; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci switch (mode) { 1518c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: /* ON in LP Mode */ 1528c2ecf20Sopenharmony_ci val = MAX77686_LDO_LOWPOWER_PWRREQ; 1538c2ecf20Sopenharmony_ci break; 1548c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ 1558c2ecf20Sopenharmony_ci val = max77686_map_normal_mode(max77686, id); 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci default: 1588c2ecf20Sopenharmony_ci pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", 1598c2ecf20Sopenharmony_ci rdev->desc->name, mode); 1608c2ecf20Sopenharmony_ci return -EINVAL; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 1648c2ecf20Sopenharmony_ci rdev->desc->enable_mask, 1658c2ecf20Sopenharmony_ci val << MAX77686_OPMODE_SHIFT); 1668c2ecf20Sopenharmony_ci if (ret) 1678c2ecf20Sopenharmony_ci return ret; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci max77686->opmode[id] = val; 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci/* Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state */ 1748c2ecf20Sopenharmony_cistatic int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev, 1758c2ecf20Sopenharmony_ci unsigned int mode) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci unsigned int val; 1788c2ecf20Sopenharmony_ci struct max77686_data *max77686 = rdev_get_drvdata(rdev); 1798c2ecf20Sopenharmony_ci int ret, id = rdev_get_id(rdev); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci switch (mode) { 1828c2ecf20Sopenharmony_ci case REGULATOR_MODE_STANDBY: /* switch off */ 1838c2ecf20Sopenharmony_ci val = MAX77686_OFF_PWRREQ; 1848c2ecf20Sopenharmony_ci break; 1858c2ecf20Sopenharmony_ci case REGULATOR_MODE_IDLE: /* ON in LP Mode */ 1868c2ecf20Sopenharmony_ci val = MAX77686_LDO_LOWPOWER_PWRREQ; 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */ 1898c2ecf20Sopenharmony_ci val = max77686_map_normal_mode(max77686, id); 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n", 1938c2ecf20Sopenharmony_ci rdev->desc->name, mode); 1948c2ecf20Sopenharmony_ci return -EINVAL; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 1988c2ecf20Sopenharmony_ci rdev->desc->enable_mask, 1998c2ecf20Sopenharmony_ci val << MAX77686_OPMODE_SHIFT); 2008c2ecf20Sopenharmony_ci if (ret) 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci max77686->opmode[id] = val; 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int max77686_enable(struct regulator_dev *rdev) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct max77686_data *max77686 = rdev_get_drvdata(rdev); 2108c2ecf20Sopenharmony_ci unsigned int shift; 2118c2ecf20Sopenharmony_ci int id = rdev_get_id(rdev); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci shift = max77686_get_opmode_shift(id); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (max77686->opmode[id] == MAX77686_OFF_PWRREQ) 2168c2ecf20Sopenharmony_ci max77686->opmode[id] = max77686_map_normal_mode(max77686, id); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 2198c2ecf20Sopenharmony_ci rdev->desc->enable_mask, 2208c2ecf20Sopenharmony_ci max77686->opmode[id] << shift); 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci unsigned int ramp_value = RAMP_RATE_NO_CTRL; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci switch (ramp_delay) { 2288c2ecf20Sopenharmony_ci case 1 ... 13750: 2298c2ecf20Sopenharmony_ci ramp_value = RAMP_RATE_13P75MV; 2308c2ecf20Sopenharmony_ci break; 2318c2ecf20Sopenharmony_ci case 13751 ... 27500: 2328c2ecf20Sopenharmony_ci ramp_value = RAMP_RATE_27P5MV; 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case 27501 ... 55000: 2358c2ecf20Sopenharmony_ci ramp_value = RAMP_RATE_55MV; 2368c2ecf20Sopenharmony_ci break; 2378c2ecf20Sopenharmony_ci case 55001 ... 100000: 2388c2ecf20Sopenharmony_ci break; 2398c2ecf20Sopenharmony_ci default: 2408c2ecf20Sopenharmony_ci pr_warn("%s: ramp_delay: %d not supported, setting 100000\n", 2418c2ecf20Sopenharmony_ci rdev->desc->name, ramp_delay); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 2458c2ecf20Sopenharmony_ci MAX77686_RAMP_RATE_MASK, ramp_value << 6); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int max77686_of_parse_cb(struct device_node *np, 2498c2ecf20Sopenharmony_ci const struct regulator_desc *desc, 2508c2ecf20Sopenharmony_ci struct regulator_config *config) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct max77686_data *max77686 = config->driver_data; 2538c2ecf20Sopenharmony_ci int ret; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci switch (desc->id) { 2568c2ecf20Sopenharmony_ci case MAX77686_BUCK8: 2578c2ecf20Sopenharmony_ci case MAX77686_BUCK9: 2588c2ecf20Sopenharmony_ci case MAX77686_LDO20 ... MAX77686_LDO22: 2598c2ecf20Sopenharmony_ci config->ena_gpiod = fwnode_gpiod_get_index( 2608c2ecf20Sopenharmony_ci of_fwnode_handle(np), 2618c2ecf20Sopenharmony_ci "maxim,ena", 2628c2ecf20Sopenharmony_ci 0, 2638c2ecf20Sopenharmony_ci GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, 2648c2ecf20Sopenharmony_ci "max77686-regulator"); 2658c2ecf20Sopenharmony_ci if (IS_ERR(config->ena_gpiod)) 2668c2ecf20Sopenharmony_ci config->ena_gpiod = NULL; 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci default: 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (config->ena_gpiod) { 2738c2ecf20Sopenharmony_ci set_bit(desc->id, max77686->gpio_enabled); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ret = regmap_update_bits(config->regmap, desc->enable_reg, 2768c2ecf20Sopenharmony_ci desc->enable_mask, 2778c2ecf20Sopenharmony_ci MAX77686_GPIO_CONTROL); 2788c2ecf20Sopenharmony_ci if (ret) { 2798c2ecf20Sopenharmony_ci gpiod_put(config->ena_gpiod); 2808c2ecf20Sopenharmony_ci config->ena_gpiod = NULL; 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic const struct regulator_ops max77686_ops = { 2888c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 2898c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 2908c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 2918c2ecf20Sopenharmony_ci .enable = max77686_enable, 2928c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 2938c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 2948c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 2958c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 2968c2ecf20Sopenharmony_ci .set_suspend_mode = max77686_set_suspend_mode, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic const struct regulator_ops max77686_ldo_ops = { 3008c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 3018c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 3028c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 3038c2ecf20Sopenharmony_ci .enable = max77686_enable, 3048c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 3058c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 3068c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 3078c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 3088c2ecf20Sopenharmony_ci .set_suspend_mode = max77686_ldo_set_suspend_mode, 3098c2ecf20Sopenharmony_ci .set_suspend_disable = max77686_set_suspend_disable, 3108c2ecf20Sopenharmony_ci}; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic const struct regulator_ops max77686_buck1_ops = { 3138c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 3148c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 3158c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 3168c2ecf20Sopenharmony_ci .enable = max77686_enable, 3178c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 3188c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 3198c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 3208c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 3218c2ecf20Sopenharmony_ci .set_suspend_disable = max77686_set_suspend_disable, 3228c2ecf20Sopenharmony_ci}; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic const struct regulator_ops max77686_buck_dvs_ops = { 3258c2ecf20Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 3268c2ecf20Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 3278c2ecf20Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 3288c2ecf20Sopenharmony_ci .enable = max77686_enable, 3298c2ecf20Sopenharmony_ci .disable = regulator_disable_regmap, 3308c2ecf20Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 3318c2ecf20Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 3328c2ecf20Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 3338c2ecf20Sopenharmony_ci .set_ramp_delay = max77686_set_ramp_delay, 3348c2ecf20Sopenharmony_ci .set_suspend_disable = max77686_set_suspend_disable, 3358c2ecf20Sopenharmony_ci}; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci#define regulator_desc_ldo(num) { \ 3388c2ecf20Sopenharmony_ci .name = "LDO"#num, \ 3398c2ecf20Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 3408c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 3418c2ecf20Sopenharmony_ci .of_parse_cb = max77686_of_parse_cb, \ 3428c2ecf20Sopenharmony_ci .id = MAX77686_LDO##num, \ 3438c2ecf20Sopenharmony_ci .ops = &max77686_ops, \ 3448c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3458c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 3468c2ecf20Sopenharmony_ci .min_uV = MAX77686_LDO_MINUV, \ 3478c2ecf20Sopenharmony_ci .uV_step = MAX77686_LDO_UVSTEP, \ 3488c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 3498c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 3508c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3518c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 3528c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3538c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK \ 3548c2ecf20Sopenharmony_ci << MAX77686_OPMODE_SHIFT, \ 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci#define regulator_desc_lpm_ldo(num) { \ 3578c2ecf20Sopenharmony_ci .name = "LDO"#num, \ 3588c2ecf20Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 3598c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 3608c2ecf20Sopenharmony_ci .id = MAX77686_LDO##num, \ 3618c2ecf20Sopenharmony_ci .ops = &max77686_ldo_ops, \ 3628c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3638c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 3648c2ecf20Sopenharmony_ci .min_uV = MAX77686_LDO_MINUV, \ 3658c2ecf20Sopenharmony_ci .uV_step = MAX77686_LDO_UVSTEP, \ 3668c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 3678c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 3688c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3698c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 3708c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3718c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK \ 3728c2ecf20Sopenharmony_ci << MAX77686_OPMODE_SHIFT, \ 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci#define regulator_desc_ldo_low(num) { \ 3758c2ecf20Sopenharmony_ci .name = "LDO"#num, \ 3768c2ecf20Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 3778c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 3788c2ecf20Sopenharmony_ci .id = MAX77686_LDO##num, \ 3798c2ecf20Sopenharmony_ci .ops = &max77686_ldo_ops, \ 3808c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3818c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 3828c2ecf20Sopenharmony_ci .min_uV = MAX77686_LDO_LOW_MINUV, \ 3838c2ecf20Sopenharmony_ci .uV_step = MAX77686_LDO_LOW_UVSTEP, \ 3848c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 3858c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 3868c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3878c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 3888c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 3898c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK \ 3908c2ecf20Sopenharmony_ci << MAX77686_OPMODE_SHIFT, \ 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci#define regulator_desc_ldo1_low(num) { \ 3938c2ecf20Sopenharmony_ci .name = "LDO"#num, \ 3948c2ecf20Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 3958c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 3968c2ecf20Sopenharmony_ci .id = MAX77686_LDO##num, \ 3978c2ecf20Sopenharmony_ci .ops = &max77686_ops, \ 3988c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 3998c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 4008c2ecf20Sopenharmony_ci .min_uV = MAX77686_LDO_LOW_MINUV, \ 4018c2ecf20Sopenharmony_ci .uV_step = MAX77686_LDO_LOW_UVSTEP, \ 4028c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 4038c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 4048c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 4058c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 4068c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_LDO1CTRL1 + num - 1, \ 4078c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK \ 4088c2ecf20Sopenharmony_ci << MAX77686_OPMODE_SHIFT, \ 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci#define regulator_desc_buck(num) { \ 4118c2ecf20Sopenharmony_ci .name = "BUCK"#num, \ 4128c2ecf20Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 4138c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 4148c2ecf20Sopenharmony_ci .of_parse_cb = max77686_of_parse_cb, \ 4158c2ecf20Sopenharmony_ci .id = MAX77686_BUCK##num, \ 4168c2ecf20Sopenharmony_ci .ops = &max77686_ops, \ 4178c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 4188c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 4198c2ecf20Sopenharmony_ci .min_uV = MAX77686_BUCK_MINUV, \ 4208c2ecf20Sopenharmony_ci .uV_step = MAX77686_BUCK_UVSTEP, \ 4218c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 4228c2ecf20Sopenharmony_ci .enable_time = MAX77686_BUCK_ENABLE_TIME, \ 4238c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 4248c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_BUCK5OUT + (num - 5) * 2, \ 4258c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 4268c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_BUCK5CTRL + (num - 5) * 2, \ 4278c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK, \ 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci#define regulator_desc_buck1(num) { \ 4308c2ecf20Sopenharmony_ci .name = "BUCK"#num, \ 4318c2ecf20Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 4328c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 4338c2ecf20Sopenharmony_ci .id = MAX77686_BUCK##num, \ 4348c2ecf20Sopenharmony_ci .ops = &max77686_buck1_ops, \ 4358c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 4368c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 4378c2ecf20Sopenharmony_ci .min_uV = MAX77686_BUCK_MINUV, \ 4388c2ecf20Sopenharmony_ci .uV_step = MAX77686_BUCK_UVSTEP, \ 4398c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_RAMP_DELAY, \ 4408c2ecf20Sopenharmony_ci .enable_time = MAX77686_BUCK_ENABLE_TIME, \ 4418c2ecf20Sopenharmony_ci .n_voltages = MAX77686_VSEL_MASK + 1, \ 4428c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_BUCK1OUT, \ 4438c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_VSEL_MASK, \ 4448c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_BUCK1CTRL, \ 4458c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK, \ 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci#define regulator_desc_buck_dvs(num) { \ 4488c2ecf20Sopenharmony_ci .name = "BUCK"#num, \ 4498c2ecf20Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 4508c2ecf20Sopenharmony_ci .regulators_node = of_match_ptr("voltage-regulators"), \ 4518c2ecf20Sopenharmony_ci .id = MAX77686_BUCK##num, \ 4528c2ecf20Sopenharmony_ci .ops = &max77686_buck_dvs_ops, \ 4538c2ecf20Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 4548c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 4558c2ecf20Sopenharmony_ci .min_uV = MAX77686_DVS_MINUV, \ 4568c2ecf20Sopenharmony_ci .uV_step = MAX77686_DVS_UVSTEP, \ 4578c2ecf20Sopenharmony_ci .ramp_delay = MAX77686_DVS_RAMP_DELAY, \ 4588c2ecf20Sopenharmony_ci .enable_time = MAX77686_DVS_ENABLE_TIME, \ 4598c2ecf20Sopenharmony_ci .n_voltages = MAX77686_DVS_VSEL_MASK + 1, \ 4608c2ecf20Sopenharmony_ci .vsel_reg = MAX77686_REG_BUCK2DVS1 + (num - 2) * 10, \ 4618c2ecf20Sopenharmony_ci .vsel_mask = MAX77686_DVS_VSEL_MASK, \ 4628c2ecf20Sopenharmony_ci .enable_reg = MAX77686_REG_BUCK2CTRL1 + (num - 2) * 10, \ 4638c2ecf20Sopenharmony_ci .enable_mask = MAX77686_OPMODE_MASK \ 4648c2ecf20Sopenharmony_ci << MAX77686_OPMODE_BUCK234_SHIFT, \ 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic const struct regulator_desc regulators[] = { 4688c2ecf20Sopenharmony_ci regulator_desc_ldo1_low(1), 4698c2ecf20Sopenharmony_ci regulator_desc_ldo_low(2), 4708c2ecf20Sopenharmony_ci regulator_desc_ldo(3), 4718c2ecf20Sopenharmony_ci regulator_desc_ldo(4), 4728c2ecf20Sopenharmony_ci regulator_desc_ldo(5), 4738c2ecf20Sopenharmony_ci regulator_desc_ldo_low(6), 4748c2ecf20Sopenharmony_ci regulator_desc_ldo_low(7), 4758c2ecf20Sopenharmony_ci regulator_desc_ldo_low(8), 4768c2ecf20Sopenharmony_ci regulator_desc_ldo(9), 4778c2ecf20Sopenharmony_ci regulator_desc_lpm_ldo(10), 4788c2ecf20Sopenharmony_ci regulator_desc_lpm_ldo(11), 4798c2ecf20Sopenharmony_ci regulator_desc_lpm_ldo(12), 4808c2ecf20Sopenharmony_ci regulator_desc_ldo(13), 4818c2ecf20Sopenharmony_ci regulator_desc_lpm_ldo(14), 4828c2ecf20Sopenharmony_ci regulator_desc_ldo_low(15), 4838c2ecf20Sopenharmony_ci regulator_desc_lpm_ldo(16), 4848c2ecf20Sopenharmony_ci regulator_desc_ldo(17), 4858c2ecf20Sopenharmony_ci regulator_desc_ldo(18), 4868c2ecf20Sopenharmony_ci regulator_desc_ldo(19), 4878c2ecf20Sopenharmony_ci regulator_desc_ldo(20), 4888c2ecf20Sopenharmony_ci regulator_desc_ldo(21), 4898c2ecf20Sopenharmony_ci regulator_desc_ldo(22), 4908c2ecf20Sopenharmony_ci regulator_desc_ldo(23), 4918c2ecf20Sopenharmony_ci regulator_desc_ldo(24), 4928c2ecf20Sopenharmony_ci regulator_desc_ldo(25), 4938c2ecf20Sopenharmony_ci regulator_desc_ldo(26), 4948c2ecf20Sopenharmony_ci regulator_desc_buck1(1), 4958c2ecf20Sopenharmony_ci regulator_desc_buck_dvs(2), 4968c2ecf20Sopenharmony_ci regulator_desc_buck_dvs(3), 4978c2ecf20Sopenharmony_ci regulator_desc_buck_dvs(4), 4988c2ecf20Sopenharmony_ci regulator_desc_buck(5), 4998c2ecf20Sopenharmony_ci regulator_desc_buck(6), 5008c2ecf20Sopenharmony_ci regulator_desc_buck(7), 5018c2ecf20Sopenharmony_ci regulator_desc_buck(8), 5028c2ecf20Sopenharmony_ci regulator_desc_buck(9), 5038c2ecf20Sopenharmony_ci}; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic int max77686_pmic_probe(struct platform_device *pdev) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); 5088c2ecf20Sopenharmony_ci struct max77686_data *max77686; 5098c2ecf20Sopenharmony_ci int i; 5108c2ecf20Sopenharmony_ci struct regulator_config config = { }; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "%s\n", __func__); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data), 5158c2ecf20Sopenharmony_ci GFP_KERNEL); 5168c2ecf20Sopenharmony_ci if (!max77686) 5178c2ecf20Sopenharmony_ci return -ENOMEM; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci max77686->dev = &pdev->dev; 5208c2ecf20Sopenharmony_ci config.dev = iodev->dev; 5218c2ecf20Sopenharmony_ci config.regmap = iodev->regmap; 5228c2ecf20Sopenharmony_ci config.driver_data = max77686; 5238c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, max77686); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci for (i = 0; i < MAX77686_REGULATORS; i++) { 5268c2ecf20Sopenharmony_ci struct regulator_dev *rdev; 5278c2ecf20Sopenharmony_ci int id = regulators[i].id; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci max77686->opmode[id] = MAX77686_NORMAL; 5308c2ecf20Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, 5318c2ecf20Sopenharmony_ci ®ulators[i], &config); 5328c2ecf20Sopenharmony_ci if (IS_ERR(rdev)) { 5338c2ecf20Sopenharmony_ci int ret = PTR_ERR(rdev); 5348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 5358c2ecf20Sopenharmony_ci "regulator init failed for %d: %d\n", i, ret); 5368c2ecf20Sopenharmony_ci return ret; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic const struct platform_device_id max77686_pmic_id[] = { 5448c2ecf20Sopenharmony_ci {"max77686-pmic", 0}, 5458c2ecf20Sopenharmony_ci { }, 5468c2ecf20Sopenharmony_ci}; 5478c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77686_pmic_id); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_cistatic struct platform_driver max77686_pmic_driver = { 5508c2ecf20Sopenharmony_ci .driver = { 5518c2ecf20Sopenharmony_ci .name = "max77686-pmic", 5528c2ecf20Sopenharmony_ci }, 5538c2ecf20Sopenharmony_ci .probe = max77686_pmic_probe, 5548c2ecf20Sopenharmony_ci .id_table = max77686_pmic_id, 5558c2ecf20Sopenharmony_ci}; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cimodule_platform_driver(max77686_pmic_driver); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 77686 Regulator Driver"); 5608c2ecf20Sopenharmony_ciMODULE_AUTHOR("Chiwoong Byun <woong.byun@samsung.com>"); 5618c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 562