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						&regulators[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