13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0
23d0407baSopenharmony_ci/*
33d0407baSopenharmony_ci * Regulator driver for Rockchip RK806
43d0407baSopenharmony_ci *
53d0407baSopenharmony_ci * Copyright (c) 2021 Rockchip Electronics Co., Ltd.
63d0407baSopenharmony_ci *
73d0407baSopenharmony_ci * Author: Xu Shengfei <xsf@rock-chips.com>
83d0407baSopenharmony_ci */
93d0407baSopenharmony_ci
103d0407baSopenharmony_ci#include <linux/delay.h>
113d0407baSopenharmony_ci#include <linux/gpio.h>
123d0407baSopenharmony_ci#include <linux/gpio/consumer.h>
133d0407baSopenharmony_ci#include <linux/mfd/rk806.h>
143d0407baSopenharmony_ci#include <linux/mod_devicetable.h>
153d0407baSopenharmony_ci#include <linux/module.h>
163d0407baSopenharmony_ci#include <linux/of_device.h>
173d0407baSopenharmony_ci#include <linux/platform_device.h>
183d0407baSopenharmony_ci#include <linux/regulator/driver.h>
193d0407baSopenharmony_ci#include "internal.h"
203d0407baSopenharmony_ci
213d0407baSopenharmony_cistatic int dbg_enable;
223d0407baSopenharmony_ci
233d0407baSopenharmony_cimodule_param_named(dbg_level, dbg_enable, int, 0644);
243d0407baSopenharmony_ci
253d0407baSopenharmony_ci#define REG_DBG(args...) \
263d0407baSopenharmony_ci	do { \
273d0407baSopenharmony_ci		if (dbg_enable) { \
283d0407baSopenharmony_ci			pr_info(args); \
293d0407baSopenharmony_ci		} \
303d0407baSopenharmony_ci	} while (0)
313d0407baSopenharmony_ci
323d0407baSopenharmony_ci#define RK806_BUCK_MIN0		500000
333d0407baSopenharmony_ci#define RK806_BUCK_MAX0		1500000
343d0407baSopenharmony_ci#define RK806_BUCK_MIN1		1500000
353d0407baSopenharmony_ci#define RK806_BUCK_MAX1		3400000
363d0407baSopenharmony_ci#define RK806_BUCK_STP0		6250
373d0407baSopenharmony_ci#define RK806_BUCK_STP1		25000
383d0407baSopenharmony_ci
393d0407baSopenharmony_ci#define RK806_NLDO_MIN		500000
403d0407baSopenharmony_ci#define RK806_NLDO_MAX		3400000
413d0407baSopenharmony_ci#define RK806_NLDO_STP0		1250
423d0407baSopenharmony_ci#define RK806_NLDO_SEL		((RK806_NLDO_MAX - RK806_NLDO_MIN) / RK806_NLDO_STP0 + 1)
433d0407baSopenharmony_ci
443d0407baSopenharmony_ci#define ENABLE_MASK(id)		(BIT(id) | BIT(4 + (id)))
453d0407baSopenharmony_ci#define DISABLE_VAL(id)		(BIT(4 + (id)))
463d0407baSopenharmony_ci#define PWM_MODE_MSK		BIT(0)
473d0407baSopenharmony_ci#define FPWM_MODE		BIT(0)
483d0407baSopenharmony_ci#define AUTO_PWM_MODE		0
493d0407baSopenharmony_ci
503d0407baSopenharmony_ci#define RK806_DCDC_SLP_REG_OFFSET	0x0A
513d0407baSopenharmony_ci#define RK806_NLDO_SLP_REG_OFFSET	0x05
523d0407baSopenharmony_ci#define RK806_PLDO_SLP_REG_OFFSET	0x06
533d0407baSopenharmony_ci
543d0407baSopenharmony_ci#define RK806_BUCK_SEL_CNT		0xff
553d0407baSopenharmony_ci#define RK806_LDO_SEL_CNT		0xff
563d0407baSopenharmony_ci
573d0407baSopenharmony_ci#define RK806_RAMP_RATE_4LSB_PER_1CLK	0x00/* LDO 100mV/uS buck 50mV/us */
583d0407baSopenharmony_ci#define RK806_RAMP_RATE_2LSB_PER_1CLK	0x01/* LDO 50mV/uS buck 25mV/us */
593d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_1CLK	0x02/* LDO 25mV/uS buck 12.5mV/us */
603d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_2CLK	0x03/* LDO 12.5mV/uS buck 6.25mV/us */
613d0407baSopenharmony_ci
623d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_4CLK	0x04/* LDO 6.28/2mV/uS buck 3.125mV/us */
633d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_8CLK	0x05/* LDO 3.12mV/uS buck 1.56mV/us */
643d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_13CLK	0x06/* LDO 1.9mV/uS buck 961mV/us */
653d0407baSopenharmony_ci#define RK806_RAMP_RATE_1LSB_PER_32CLK	0x07/* LDO 0.78mV/uS buck 0.39mV/us */
663d0407baSopenharmony_ci
673d0407baSopenharmony_cistatic int vsel_ctr_sel_id[RK806_ID_END] = {
683d0407baSopenharmony_ci	BUCK1_VSEL_CTR_SEL,
693d0407baSopenharmony_ci	BUCK2_VSEL_CTR_SEL,
703d0407baSopenharmony_ci	BUCK3_VSEL_CTR_SEL,
713d0407baSopenharmony_ci	BUCK4_VSEL_CTR_SEL,
723d0407baSopenharmony_ci	BUCK5_VSEL_CTR_SEL,
733d0407baSopenharmony_ci	BUCK6_VSEL_CTR_SEL,
743d0407baSopenharmony_ci	BUCK7_VSEL_CTR_SEL,
753d0407baSopenharmony_ci	BUCK8_VSEL_CTR_SEL,
763d0407baSopenharmony_ci	BUCK9_VSEL_CTR_SEL,
773d0407baSopenharmony_ci	BUCK10_VSEL_CTR_SEL,
783d0407baSopenharmony_ci	NLDO1_VSEL_CTR_SEL,
793d0407baSopenharmony_ci	NLDO2_VSEL_CTR_SEL,
803d0407baSopenharmony_ci	NLDO3_VSEL_CTR_SEL,
813d0407baSopenharmony_ci	NLDO4_VSEL_CTR_SEL,
823d0407baSopenharmony_ci	NLDO5_VSEL_CTR_SEL,
833d0407baSopenharmony_ci	PLDO1_VSEL_CTR_SEL,
843d0407baSopenharmony_ci	PLDO2_VSEL_CTR_SEL,
853d0407baSopenharmony_ci	PLDO3_VSEL_CTR_SEL,
863d0407baSopenharmony_ci	PLDO4_VSEL_CTR_SEL,
873d0407baSopenharmony_ci	PLDO5_VSEL_CTR_SEL,
883d0407baSopenharmony_ci	PLDO6_VSEL_CTR_SEL,
893d0407baSopenharmony_ci};
903d0407baSopenharmony_ci
913d0407baSopenharmony_cistatic int start_dvs_id[RK806_ID_END] = {
923d0407baSopenharmony_ci	BUCK1_DVS_CTR_SEL,
933d0407baSopenharmony_ci	BUCK2_DVS_CTR_SEL,
943d0407baSopenharmony_ci	BUCK3_DVS_CTR_SEL,
953d0407baSopenharmony_ci	BUCK4_DVS_CTR_SEL,
963d0407baSopenharmony_ci	BUCK5_DVS_CTR_SEL,
973d0407baSopenharmony_ci	BUCK6_DVS_CTR_SEL,
983d0407baSopenharmony_ci	BUCK7_DVS_CTR_SEL,
993d0407baSopenharmony_ci	BUCK8_DVS_CTR_SEL,
1003d0407baSopenharmony_ci	BUCK9_DVS_CTR_SEL,
1013d0407baSopenharmony_ci	BUCK10_DVS_CTR_SEL,
1023d0407baSopenharmony_ci	NLDO1_DVS_CTR_SEL,
1033d0407baSopenharmony_ci	NLDO2_DVS_CTR_SEL,
1043d0407baSopenharmony_ci	NLDO3_DVS_CTR_SEL,
1053d0407baSopenharmony_ci	NLDO4_DVS_CTR_SEL,
1063d0407baSopenharmony_ci	NLDO5_DVS_CTR_SEL,
1073d0407baSopenharmony_ci	PLDO1_DVS_CTR_SEL,
1083d0407baSopenharmony_ci	PLDO2_DVS_CTR_SEL,
1093d0407baSopenharmony_ci	PLDO3_DVS_CTR_SEL,
1103d0407baSopenharmony_ci	PLDO4_DVS_CTR_SEL,
1113d0407baSopenharmony_ci	PLDO5_DVS_CTR_SEL,
1123d0407baSopenharmony_ci	PLDO6_DVS_CTR_SEL,
1133d0407baSopenharmony_ci};
1143d0407baSopenharmony_ci
1153d0407baSopenharmony_cistatic const int rk806_buck_rate_config_field[10][2] = {
1163d0407baSopenharmony_ci	{ BUCK1_RATE, BUCK1_RATE2 },
1173d0407baSopenharmony_ci	{ BUCK2_RATE, BUCK2_RATE2 },
1183d0407baSopenharmony_ci	{ BUCK3_RATE, BUCK3_RATE2 },
1193d0407baSopenharmony_ci	{ BUCK4_RATE, BUCK4_RATE2 },
1203d0407baSopenharmony_ci	{ BUCK5_RATE, BUCK5_RATE2 },
1213d0407baSopenharmony_ci	{ BUCK6_RATE, BUCK6_RATE2 },
1223d0407baSopenharmony_ci	{ BUCK7_RATE, BUCK7_RATE2 },
1233d0407baSopenharmony_ci	{ BUCK8_RATE, BUCK8_RATE2 },
1243d0407baSopenharmony_ci	{ BUCK9_RATE, BUCK9_RATE2 },
1253d0407baSopenharmony_ci	{ BUCK10_RATE, BUCK10_RATE2 },
1263d0407baSopenharmony_ci};
1273d0407baSopenharmony_ci
1283d0407baSopenharmony_cistruct rk806_dvs_field {
1293d0407baSopenharmony_ci	int en_reg;
1303d0407baSopenharmony_ci	int en_bit;
1313d0407baSopenharmony_ci	int sleep_en;
1323d0407baSopenharmony_ci	int on_vsel;
1333d0407baSopenharmony_ci	int sleep_vsel;
1343d0407baSopenharmony_ci	int vsel_ctrl_sel;
1353d0407baSopenharmony_ci};
1363d0407baSopenharmony_ci
1373d0407baSopenharmony_cistruct rk806_dvs_status {
1383d0407baSopenharmony_ci	int en_reg_val;
1393d0407baSopenharmony_ci	int en_bit_val;
1403d0407baSopenharmony_ci	int sleep_en_val;
1413d0407baSopenharmony_ci	int on_vsel_val;
1423d0407baSopenharmony_ci	int sleep_vsel_val;
1433d0407baSopenharmony_ci	int vsel_ctrl_sel_val;
1443d0407baSopenharmony_ci	int dvs_gpio_level[3];
1453d0407baSopenharmony_ci};
1463d0407baSopenharmony_ci
1473d0407baSopenharmony_cistruct rk806_regulator_data {
1483d0407baSopenharmony_ci	struct device_node *dvs_dn[RK806_DVS_END][RK806_ID_END];
1493d0407baSopenharmony_ci	struct rk806_dvs_field dvs_field[RK806_ID_END];
1503d0407baSopenharmony_ci	struct rk806_dvs_status dvs_mode[RK806_ID_END];
1513d0407baSopenharmony_ci	struct rk806_dvs_status sleep_mode[RK806_ID_END];
1523d0407baSopenharmony_ci
1533d0407baSopenharmony_ci	int dvs_ctrl_mode_init[RK806_ID_END];
1543d0407baSopenharmony_ci	int dvs_ctrl_mode[RK806_ID_END];
1553d0407baSopenharmony_ci	int dvs_ctrl_id[RK806_ID_END];
1563d0407baSopenharmony_ci	int vsel_ctrl_id[RK806_ID_END];
1573d0407baSopenharmony_ci
1583d0407baSopenharmony_ci	int dvs_flag[RK806_DVS_END];
1593d0407baSopenharmony_ci	int dvs_used[RK806_DVS_END];
1603d0407baSopenharmony_ci	int dvs_count[RK806_DVS_END];
1613d0407baSopenharmony_ci
1623d0407baSopenharmony_ci	int regulator_init;
1633d0407baSopenharmony_ci	int support_dvs;
1643d0407baSopenharmony_ci	struct gpio_desc *dvs_gpios[3];
1653d0407baSopenharmony_ci	struct rk806 *rk806;
1663d0407baSopenharmony_ci};
1673d0407baSopenharmony_ci
1683d0407baSopenharmony_ci#define INIT_DVS_FIELD(_en_reg, _en_bit, _sleep_en, _on_vsel,	\
1693d0407baSopenharmony_ci			_sleep_vsel, _vsel_ctrl_sel)	\
1703d0407baSopenharmony_ci{	\
1713d0407baSopenharmony_ci	.en_reg = _en_reg,	\
1723d0407baSopenharmony_ci	.en_bit = _en_bit,	\
1733d0407baSopenharmony_ci	.sleep_en = _sleep_en,	\
1743d0407baSopenharmony_ci	.on_vsel = _on_vsel,	\
1753d0407baSopenharmony_ci	.sleep_vsel = _sleep_vsel,	\
1763d0407baSopenharmony_ci	.vsel_ctrl_sel = _vsel_ctrl_sel,	\
1773d0407baSopenharmony_ci}
1783d0407baSopenharmony_ci
1793d0407baSopenharmony_cistatic const struct rk806_dvs_field rk806_dvs_fields[RK806_ID_END] = {
1803d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN0, BIT(0), BUCK1_SLP_EN,
1813d0407baSopenharmony_ci		       BUCK1_ON_VSEL, BUCK1_SLP_VSEL, BUCK1_VSEL_CTR_SEL),
1823d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN0, BIT(1), BUCK2_SLP_EN,
1833d0407baSopenharmony_ci		       BUCK2_ON_VSEL, BUCK2_SLP_VSEL, BUCK2_VSEL_CTR_SEL),
1843d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN0, BIT(2), BUCK3_SLP_EN,
1853d0407baSopenharmony_ci		       BUCK3_ON_VSEL, BUCK3_SLP_VSEL, BUCK3_VSEL_CTR_SEL),
1863d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN0, BIT(3), BUCK4_SLP_EN,
1873d0407baSopenharmony_ci		       BUCK4_ON_VSEL, BUCK4_SLP_VSEL, BUCK4_VSEL_CTR_SEL),
1883d0407baSopenharmony_ci
1893d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN1, BIT(0), BUCK5_SLP_EN,
1903d0407baSopenharmony_ci		       BUCK5_ON_VSEL, BUCK5_SLP_VSEL, BUCK5_VSEL_CTR_SEL),
1913d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN1, BIT(1), BUCK6_SLP_EN,
1923d0407baSopenharmony_ci		       BUCK6_ON_VSEL, BUCK6_SLP_VSEL, BUCK6_VSEL_CTR_SEL),
1933d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN1, BIT(2), BUCK7_SLP_EN,
1943d0407baSopenharmony_ci		       BUCK7_ON_VSEL, BUCK7_SLP_VSEL, BUCK7_VSEL_CTR_SEL),
1953d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN1, BIT(3), BUCK8_SLP_EN,
1963d0407baSopenharmony_ci		       BUCK8_ON_VSEL, BUCK8_SLP_VSEL, BUCK8_VSEL_CTR_SEL),
1973d0407baSopenharmony_ci
1983d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN2, BIT(0), BUCK9_SLP_EN,
1993d0407baSopenharmony_ci		       BUCK9_ON_VSEL, BUCK9_SLP_VSEL, BUCK9_VSEL_CTR_SEL),
2003d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN2, BIT(1), BUCK10_SLP_EN,
2013d0407baSopenharmony_ci		       BUCK10_ON_VSEL, BUCK10_SLP_VSEL, BUCK10_VSEL_CTR_SEL),
2023d0407baSopenharmony_ci
2033d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN3, BIT(0), NLDO1_SLP_EN,
2043d0407baSopenharmony_ci		       NLDO1_ON_VSEL, NLDO1_SLP_VSEL, NLDO1_VSEL_CTR_SEL),
2053d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN3, BIT(1), NLDO2_SLP_EN,
2063d0407baSopenharmony_ci		       NLDO2_ON_VSEL, NLDO2_SLP_VSEL, NLDO2_VSEL_CTR_SEL),
2073d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN3, BIT(2), NLDO3_SLP_EN,
2083d0407baSopenharmony_ci		       NLDO3_ON_VSEL, NLDO3_SLP_VSEL, NLDO3_VSEL_CTR_SEL),
2093d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN3, BIT(3), NLDO4_SLP_EN,
2103d0407baSopenharmony_ci		       NLDO4_ON_VSEL, NLDO4_SLP_VSEL, NLDO4_VSEL_CTR_SEL),
2113d0407baSopenharmony_ci
2123d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN5, BIT(2), NLDO5_SLP_EN,
2133d0407baSopenharmony_ci		       NLDO5_ON_VSEL, NLDO5_SLP_VSEL, NLDO5_VSEL_CTR_SEL),
2143d0407baSopenharmony_ci
2153d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN4, BIT(1), PLDO1_SLP_EN,
2163d0407baSopenharmony_ci		       PLDO1_ON_VSEL, PLDO1_SLP_VSEL, PLDO1_VSEL_CTR_SEL),
2173d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN4, BIT(2), PLDO2_SLP_EN,
2183d0407baSopenharmony_ci		       PLDO2_ON_VSEL, PLDO2_SLP_VSEL, PLDO2_VSEL_CTR_SEL),
2193d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN4, BIT(3), PLDO3_SLP_EN,
2203d0407baSopenharmony_ci		       PLDO3_ON_VSEL, PLDO3_SLP_VSEL, PLDO3_VSEL_CTR_SEL),
2213d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN5, BIT(0), PLDO4_SLP_EN,
2223d0407baSopenharmony_ci		       PLDO4_ON_VSEL, PLDO4_SLP_VSEL, PLDO4_VSEL_CTR_SEL),
2233d0407baSopenharmony_ci
2243d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN5, BIT(1), PLDO5_SLP_EN,
2253d0407baSopenharmony_ci		       PLDO5_ON_VSEL, PLDO5_SLP_VSEL, PLDO5_VSEL_CTR_SEL),
2263d0407baSopenharmony_ci	INIT_DVS_FIELD(POWER_EN4, BIT(0), PLDO6_SLP_EN,
2273d0407baSopenharmony_ci		       PLDO6_ON_VSEL, PLDO6_SLP_VSEL, PLDO6_VSEL_CTR_SEL),
2283d0407baSopenharmony_ci};
2293d0407baSopenharmony_ci
2303d0407baSopenharmony_cistatic const struct linear_range rk806_buck_voltage_ranges[] = {
2313d0407baSopenharmony_ci	REGULATOR_LINEAR_RANGE(500000, 0, 160, 6250), /* 500mV ~ 1500mV */
2323d0407baSopenharmony_ci	REGULATOR_LINEAR_RANGE(1500000, 161, 237, 25000), /* 1500mV ~ 3400mV */
2333d0407baSopenharmony_ci	REGULATOR_LINEAR_RANGE(3400000, 238, 255, 0),
2343d0407baSopenharmony_ci};
2353d0407baSopenharmony_ci
2363d0407baSopenharmony_cistatic const struct linear_range rk806_ldo_voltage_ranges[] = {
2373d0407baSopenharmony_ci	REGULATOR_LINEAR_RANGE(500000, 0, 232, 12500), /* 500mV ~ 3400mV */
2383d0407baSopenharmony_ci	REGULATOR_LINEAR_RANGE(3400000, 233, 255, 0), /* 500mV ~ 3400mV */
2393d0407baSopenharmony_ci};
2403d0407baSopenharmony_ci
2413d0407baSopenharmony_cistatic int get_count(int value)
2423d0407baSopenharmony_ci{
2433d0407baSopenharmony_ci	int count = 0;
2443d0407baSopenharmony_ci
2453d0407baSopenharmony_ci	while (value != 0) {
2463d0407baSopenharmony_ci		if (value % 2 == 1)
2473d0407baSopenharmony_ci			count++;
2483d0407baSopenharmony_ci		value >>= 1;
2493d0407baSopenharmony_ci	}
2503d0407baSopenharmony_ci
2513d0407baSopenharmony_ci	return count;
2523d0407baSopenharmony_ci}
2533d0407baSopenharmony_ci
2543d0407baSopenharmony_cistatic void rk806_dvs_start_fun_init(struct regulator_dev *rdev)
2553d0407baSopenharmony_ci{
2563d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
2573d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
2583d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
2593d0407baSopenharmony_ci
2603d0407baSopenharmony_ci	rk806_field_write(rk806,
2613d0407baSopenharmony_ci			  pdata->dvs_ctrl_id[rid],
2623d0407baSopenharmony_ci			  pdata->dvs_ctrl_mode[rid]);
2633d0407baSopenharmony_ci}
2643d0407baSopenharmony_ci
2653d0407baSopenharmony_cistatic void rk806_dvs_pwrctrl_fun_init(struct regulator_dev *rdev)
2663d0407baSopenharmony_ci{
2673d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
2683d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
2693d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
2703d0407baSopenharmony_ci	int offset;
2713d0407baSopenharmony_ci
2723d0407baSopenharmony_ci	/* init dvs pin function */
2733d0407baSopenharmony_ci	offset = pdata->dvs_ctrl_mode[rid] - RK806_DVS_PWRCTRL1;
2743d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_FUN + offset, PWRCTRL_DVS_FUN);
2753d0407baSopenharmony_ci
2763d0407baSopenharmony_ci	rk806_field_write(rk806,
2773d0407baSopenharmony_ci			  pdata->dvs_ctrl_id[rid],
2783d0407baSopenharmony_ci			  pdata->dvs_ctrl_mode[rid] - RK806_DVS_START3);
2793d0407baSopenharmony_ci}
2803d0407baSopenharmony_ci
2813d0407baSopenharmony_cistatic void rk806_dvs_start_pwrctrl_fun_init(struct regulator_dev *rdev)
2823d0407baSopenharmony_ci{
2833d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
2843d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
2853d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
2863d0407baSopenharmony_ci	int offset;
2873d0407baSopenharmony_ci
2883d0407baSopenharmony_ci	/* init dvs pin function */
2893d0407baSopenharmony_ci	offset = pdata->dvs_ctrl_mode[rid] - RK806_DVS_START_PWRCTR1;
2903d0407baSopenharmony_ci	/*set pin polarity, active high */
2913d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_POL + offset, POL_HIGH);
2923d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_FUN + offset, PWRCTRL_DVS_FUN);
2933d0407baSopenharmony_ci
2943d0407baSopenharmony_ci	/* enable start bit dvs  function */
2953d0407baSopenharmony_ci	rk806_field_write(rk806,
2963d0407baSopenharmony_ci			  pdata->dvs_ctrl_id[rid],
2973d0407baSopenharmony_ci			  pdata->dvs_ctrl_mode[rid] - RK806_DVS_PWRCTRL3);
2983d0407baSopenharmony_ci	rk806_field_write(rk806,
2993d0407baSopenharmony_ci			  pdata->vsel_ctrl_id[rid],
3003d0407baSopenharmony_ci			  pdata->dvs_ctrl_mode[rid] - RK806_DVS_PWRCTRL3);
3013d0407baSopenharmony_ci
3023d0407baSopenharmony_ci}
3033d0407baSopenharmony_ci
3043d0407baSopenharmony_cistatic int rk806_dvs_mode_init(struct regulator_dev *rdev)
3053d0407baSopenharmony_ci{
3063d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
3073d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
3083d0407baSopenharmony_ci	int mode, j;
3093d0407baSopenharmony_ci
3103d0407baSopenharmony_ci	for (mode = RK806_DVS_START1; mode < RK806_DVS_END; mode++) {
3113d0407baSopenharmony_ci		for (j = 0; j < RK806_ID_END; j++) {
3123d0407baSopenharmony_ci			if ((pdata->dvs_dn[mode][j] == NULL) ||
3133d0407baSopenharmony_ci			    (strcmp(pdata->dvs_dn[mode][j]->name, rdev->desc->name)))
3143d0407baSopenharmony_ci				continue;
3153d0407baSopenharmony_ci
3163d0407baSopenharmony_ci			pdata->dvs_ctrl_mode[rid] = mode;
3173d0407baSopenharmony_ci			pdata->dvs_ctrl_mode_init[rid] = 1;
3183d0407baSopenharmony_ci			pdata->dvs_flag[mode] |= BIT(rid);
3193d0407baSopenharmony_ci
3203d0407baSopenharmony_ci			/* init dvs function, dvs-pin or start bit */
3213d0407baSopenharmony_ci			if (mode <= RK806_DVS_START3)
3223d0407baSopenharmony_ci				rk806_dvs_start_fun_init(rdev);
3233d0407baSopenharmony_ci			else if (mode <= RK806_DVS_PWRCTRL3)
3243d0407baSopenharmony_ci				rk806_dvs_pwrctrl_fun_init(rdev);
3253d0407baSopenharmony_ci			else if (mode <= RK806_DVS_START_PWRCTR3)
3263d0407baSopenharmony_ci				rk806_dvs_start_pwrctrl_fun_init(rdev);
3273d0407baSopenharmony_ci			return pdata->dvs_ctrl_mode[rid];
3283d0407baSopenharmony_ci		}
3293d0407baSopenharmony_ci	}
3303d0407baSopenharmony_ci
3313d0407baSopenharmony_ci	return pdata->dvs_ctrl_mode[rid];
3323d0407baSopenharmony_ci}
3333d0407baSopenharmony_ci
3343d0407baSopenharmony_cistatic int get_dvs_mode(struct regulator_dev *rdev)
3353d0407baSopenharmony_ci{
3363d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
3373d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
3383d0407baSopenharmony_ci
3393d0407baSopenharmony_ci	if (!pdata->support_dvs)
3403d0407baSopenharmony_ci		return RK806_DVS_NOT_SUPPORT;
3413d0407baSopenharmony_ci
3423d0407baSopenharmony_ci	if (pdata->dvs_ctrl_mode_init[rid] || pdata->regulator_init)
3433d0407baSopenharmony_ci		return pdata->dvs_ctrl_mode[rid];
3443d0407baSopenharmony_ci
3453d0407baSopenharmony_ci	return rk806_dvs_mode_init(rdev);
3463d0407baSopenharmony_ci}
3473d0407baSopenharmony_ci
3483d0407baSopenharmony_cistatic int get_gpio_id(int mode)
3493d0407baSopenharmony_ci{
3503d0407baSopenharmony_ci	int pid = -1;
3513d0407baSopenharmony_ci
3523d0407baSopenharmony_ci	if ((mode >= RK806_DVS_PWRCTRL1) && (mode <= RK806_DVS_PWRCTRL3))
3533d0407baSopenharmony_ci		pid = mode - RK806_DVS_PWRCTRL1;
3543d0407baSopenharmony_ci
3553d0407baSopenharmony_ci	return pid;
3563d0407baSopenharmony_ci}
3573d0407baSopenharmony_ci
3583d0407baSopenharmony_cistatic int rk806_get_reg_offset(int id)
3593d0407baSopenharmony_ci{
3603d0407baSopenharmony_ci	int reg_offset = 0;
3613d0407baSopenharmony_ci
3623d0407baSopenharmony_ci	if (id >= RK806_ID_DCDC1 && id <= RK806_ID_DCDC10)
3633d0407baSopenharmony_ci		reg_offset = RK806_DCDC_SLP_REG_OFFSET;
3643d0407baSopenharmony_ci	else if ((id >= RK806_ID_NLDO1 && id <= RK806_ID_NLDO4) ||
3653d0407baSopenharmony_ci		 (id == RK806_ID_NLDO5))
3663d0407baSopenharmony_ci		reg_offset = RK806_NLDO_SLP_REG_OFFSET;
3673d0407baSopenharmony_ci	else if (id >= RK806_ID_PLDO1 && id <= RK806_ID_PLDO6)
3683d0407baSopenharmony_ci		reg_offset = RK806_PLDO_SLP_REG_OFFSET;
3693d0407baSopenharmony_ci
3703d0407baSopenharmony_ci	return reg_offset;
3713d0407baSopenharmony_ci}
3723d0407baSopenharmony_ci
3733d0407baSopenharmony_cistatic int rk806_get_read_vsel_register(struct regulator_dev *rdev)
3743d0407baSopenharmony_ci{
3753d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
3763d0407baSopenharmony_ci	int level, vsel_reg, pid;
3773d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
3783d0407baSopenharmony_ci	int mode;
3793d0407baSopenharmony_ci
3803d0407baSopenharmony_ci	vsel_reg = rdev->desc->vsel_reg;
3813d0407baSopenharmony_ci	if (!pdata->support_dvs)
3823d0407baSopenharmony_ci		return vsel_reg;
3833d0407baSopenharmony_ci
3843d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
3853d0407baSopenharmony_ci	pid = get_gpio_id(mode);
3863d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
3873d0407baSopenharmony_ci		level = gpiod_get_value(pdata->dvs_gpios[pid]);
3883d0407baSopenharmony_ci		/* level == 0, the Output high level, the SLP_VSEL output */
3893d0407baSopenharmony_ci		if (level == 0)
3903d0407baSopenharmony_ci			vsel_reg = rdev->desc->vsel_reg + rk806_get_reg_offset(rid);
3913d0407baSopenharmony_ci	}
3923d0407baSopenharmony_ci
3933d0407baSopenharmony_ci	return vsel_reg;
3943d0407baSopenharmony_ci}
3953d0407baSopenharmony_ci
3963d0407baSopenharmony_cistatic int rk806_get_write_vsel_register(struct regulator_dev *rdev)
3973d0407baSopenharmony_ci{
3983d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
3993d0407baSopenharmony_ci	int level, vsel_reg, pid;
4003d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
4013d0407baSopenharmony_ci	int mode;
4023d0407baSopenharmony_ci
4033d0407baSopenharmony_ci	vsel_reg = rdev->desc->vsel_reg;
4043d0407baSopenharmony_ci	if (!pdata->support_dvs)
4053d0407baSopenharmony_ci		return vsel_reg;
4063d0407baSopenharmony_ci
4073d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
4083d0407baSopenharmony_ci	pid = get_gpio_id(mode);
4093d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
4103d0407baSopenharmony_ci		level = gpiod_get_value(pdata->dvs_gpios[pid]);
4113d0407baSopenharmony_ci		/* level == 1, output low level, the ON_VSEL output, next SLP_VSEL */
4123d0407baSopenharmony_ci		if (level == 1)
4133d0407baSopenharmony_ci			vsel_reg = rdev->desc->vsel_reg + rk806_get_reg_offset(rid);
4143d0407baSopenharmony_ci	}
4153d0407baSopenharmony_ci
4163d0407baSopenharmony_ci	return vsel_reg;
4173d0407baSopenharmony_ci}
4183d0407baSopenharmony_ci
4193d0407baSopenharmony_cistatic void rk806_do_gpio_dvs(struct regulator_dev *rdev)
4203d0407baSopenharmony_ci{
4213d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
4223d0407baSopenharmony_ci	char dvs_ctrl_name[10][32] = {
4233d0407baSopenharmony_ci					"dvs_default",
4243d0407baSopenharmony_ci					"start_dvs1_ctrl",
4253d0407baSopenharmony_ci					"start_dvs2_ctrl",
4263d0407baSopenharmony_ci					"start_dvs3_ctrl",
4273d0407baSopenharmony_ci					"dvs_pin1_ctrl",
4283d0407baSopenharmony_ci					"dvs_pin2_ctrl",
4293d0407baSopenharmony_ci					"dvs_pin3_ctrl",
4303d0407baSopenharmony_ci					"start_and_pwrctrl1",
4313d0407baSopenharmony_ci					"start_and_pwrctrl2",
4323d0407baSopenharmony_ci					"start_and_pwrctrl3"};
4333d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
4343d0407baSopenharmony_ci	int gpio_level, pid;
4353d0407baSopenharmony_ci	int mode, count;
4363d0407baSopenharmony_ci
4373d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
4383d0407baSopenharmony_ci	pdata->dvs_used[mode] |= BIT(rid);
4393d0407baSopenharmony_ci	count = get_count(pdata->dvs_used[mode]);
4403d0407baSopenharmony_ci
4413d0407baSopenharmony_ci	if ((pdata->dvs_used[mode] != pdata->dvs_flag[mode]) ||
4423d0407baSopenharmony_ci	    (count != pdata->dvs_count[mode]))
4433d0407baSopenharmony_ci		return;
4443d0407baSopenharmony_ci
4453d0407baSopenharmony_ci	pdata->dvs_used[mode] = 0;
4463d0407baSopenharmony_ci
4473d0407baSopenharmony_ci	pid = get_gpio_id(mode);
4483d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
4493d0407baSopenharmony_ci		gpio_level = gpiod_get_value(pdata->dvs_gpios[pid]);
4503d0407baSopenharmony_ci		if (gpio_level == 1)
4513d0407baSopenharmony_ci			gpiod_set_value(pdata->dvs_gpios[pid], 0);
4523d0407baSopenharmony_ci		else
4533d0407baSopenharmony_ci			gpiod_set_value(pdata->dvs_gpios[pid], 1);
4543d0407baSopenharmony_ci	}
4553d0407baSopenharmony_ci	REG_DBG("pin: name: %s, %s\n", dvs_ctrl_name[mode], rdev->desc->name);
4563d0407baSopenharmony_ci}
4573d0407baSopenharmony_ci
4583d0407baSopenharmony_cistatic void rk806_do_soft_dvs(struct regulator_dev *rdev)
4593d0407baSopenharmony_ci{
4603d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
4613d0407baSopenharmony_ci	char dvs_ctrl_name[10][32] = {
4623d0407baSopenharmony_ci					"dvs_default",
4633d0407baSopenharmony_ci					"start_dvs1_ctrl",
4643d0407baSopenharmony_ci					"start_dvs2_ctrl",
4653d0407baSopenharmony_ci					"start_dvs3_ctrl",
4663d0407baSopenharmony_ci					"dvs_pin1_ctrl",
4673d0407baSopenharmony_ci					"dvs_pin2_ctrl",
4683d0407baSopenharmony_ci					"dvs_pin3_ctrl",
4693d0407baSopenharmony_ci					"start_and_pwrctrl1",
4703d0407baSopenharmony_ci					"start_and_pwrctrl2",
4713d0407baSopenharmony_ci					"start_and_pwrctrl3"};
4723d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
4733d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
4743d0407baSopenharmony_ci	int soft_mode, count;
4753d0407baSopenharmony_ci	int offset;
4763d0407baSopenharmony_ci
4773d0407baSopenharmony_ci	soft_mode = get_dvs_mode(rdev);
4783d0407baSopenharmony_ci	pdata->dvs_used[soft_mode] |= BIT(rid);
4793d0407baSopenharmony_ci	count = get_count(pdata->dvs_used[soft_mode]);
4803d0407baSopenharmony_ci
4813d0407baSopenharmony_ci	if ((pdata->dvs_used[soft_mode] != pdata->dvs_flag[soft_mode]) ||
4823d0407baSopenharmony_ci	    (count != pdata->dvs_count[soft_mode]))
4833d0407baSopenharmony_ci		return;
4843d0407baSopenharmony_ci
4853d0407baSopenharmony_ci	pdata->dvs_used[soft_mode] = 0;
4863d0407baSopenharmony_ci
4873d0407baSopenharmony_ci	if (soft_mode < RK806_DVS_START_PWRCTR1)
4883d0407baSopenharmony_ci		offset = soft_mode - RK806_DVS_START1;
4893d0407baSopenharmony_ci	else
4903d0407baSopenharmony_ci		offset = soft_mode - RK806_DVS_START_PWRCTR1;
4913d0407baSopenharmony_ci
4923d0407baSopenharmony_ci	rk806_field_write(rk806, DVS_START1 + offset, 0x01);
4933d0407baSopenharmony_ci	REG_DBG("soft:%s, %s\n", dvs_ctrl_name[soft_mode], rdev->desc->name);
4943d0407baSopenharmony_ci}
4953d0407baSopenharmony_ci
4963d0407baSopenharmony_cistatic void rk806_regulator_sync_voltage(struct regulator_dev *rdev)
4973d0407baSopenharmony_ci{
4983d0407baSopenharmony_ci	int mode;
4993d0407baSopenharmony_ci
5003d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
5013d0407baSopenharmony_ci	if (mode == RK806_DVS_NOT_SUPPORT)
5023d0407baSopenharmony_ci		return;
5033d0407baSopenharmony_ci
5043d0407baSopenharmony_ci	if ((mode >= RK806_DVS_PWRCTRL1) && (mode <= RK806_DVS_PWRCTRL3))
5053d0407baSopenharmony_ci		rk806_do_gpio_dvs(rdev);
5063d0407baSopenharmony_ci	else
5073d0407baSopenharmony_ci		rk806_do_soft_dvs(rdev);
5083d0407baSopenharmony_ci}
5093d0407baSopenharmony_ci
5103d0407baSopenharmony_cistatic unsigned int rk806_regulator_of_map_mode(unsigned int mode)
5113d0407baSopenharmony_ci{
5123d0407baSopenharmony_ci	switch (mode) {
5133d0407baSopenharmony_ci	case 1:
5143d0407baSopenharmony_ci		return REGULATOR_MODE_FAST;
5153d0407baSopenharmony_ci	case 2:
5163d0407baSopenharmony_ci		return REGULATOR_MODE_NORMAL;
5173d0407baSopenharmony_ci	default:
5183d0407baSopenharmony_ci		return -EINVAL;
5193d0407baSopenharmony_ci	}
5203d0407baSopenharmony_ci}
5213d0407baSopenharmony_ci
5223d0407baSopenharmony_cistatic int rk806_set_suspend_enable_ctrl(struct regulator_dev *rdev,
5233d0407baSopenharmony_ci					 unsigned int en)
5243d0407baSopenharmony_ci{
5253d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
5263d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
5273d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
5283d0407baSopenharmony_ci	unsigned int val;
5293d0407baSopenharmony_ci
5303d0407baSopenharmony_ci	if (en)
5313d0407baSopenharmony_ci		val = 1;
5323d0407baSopenharmony_ci	else
5333d0407baSopenharmony_ci		val = 0;
5343d0407baSopenharmony_ci
5353d0407baSopenharmony_ci	if ((get_dvs_mode(rdev) < RK806_DVS_PWRCTRL1) ||
5363d0407baSopenharmony_ci	    (get_dvs_mode(rdev) > RK806_DVS_PWRCTRL3))
5373d0407baSopenharmony_ci		return rk806_field_write(rk806, pdata->dvs_field[rid].sleep_en, val);
5383d0407baSopenharmony_ci
5393d0407baSopenharmony_ci	pdata->sleep_mode[rid].sleep_en_val = val;
5403d0407baSopenharmony_ci
5413d0407baSopenharmony_ci	return 0;
5423d0407baSopenharmony_ci}
5433d0407baSopenharmony_ci
5443d0407baSopenharmony_cistatic int rk806_set_suspend_enable(struct regulator_dev *rdev)
5453d0407baSopenharmony_ci{
5463d0407baSopenharmony_ci	return rk806_set_suspend_enable_ctrl(rdev, 1);
5473d0407baSopenharmony_ci}
5483d0407baSopenharmony_ci
5493d0407baSopenharmony_cistatic int rk806_set_suspend_disable(struct regulator_dev *rdev)
5503d0407baSopenharmony_ci{
5513d0407baSopenharmony_ci	return rk806_set_suspend_enable_ctrl(rdev, 0);
5523d0407baSopenharmony_ci}
5533d0407baSopenharmony_ci
5543d0407baSopenharmony_cistatic int rk806_set_mode(struct regulator_dev *rdev, unsigned int mode)
5553d0407baSopenharmony_ci{
5563d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
5573d0407baSopenharmony_ci	int ctr_bit, reg;
5583d0407baSopenharmony_ci
5593d0407baSopenharmony_ci	if (rid > RK806_ID_DCDC10)
5603d0407baSopenharmony_ci		return 0;
5613d0407baSopenharmony_ci
5623d0407baSopenharmony_ci	reg = RK806_POWER_FPWM_EN0 + rid / 8;
5633d0407baSopenharmony_ci	ctr_bit = rid % 8;
5643d0407baSopenharmony_ci
5653d0407baSopenharmony_ci	switch (mode) {
5663d0407baSopenharmony_ci	case REGULATOR_MODE_FAST:
5673d0407baSopenharmony_ci		return regmap_update_bits(rdev->regmap, reg,
5683d0407baSopenharmony_ci					  PWM_MODE_MSK << ctr_bit,
5693d0407baSopenharmony_ci					  FPWM_MODE << ctr_bit);
5703d0407baSopenharmony_ci	case REGULATOR_MODE_NORMAL:
5713d0407baSopenharmony_ci		return regmap_update_bits(rdev->regmap, reg,
5723d0407baSopenharmony_ci					  PWM_MODE_MSK << ctr_bit,
5733d0407baSopenharmony_ci					  AUTO_PWM_MODE << ctr_bit);
5743d0407baSopenharmony_ci	default:
5753d0407baSopenharmony_ci		dev_err(&rdev->dev, "do not support this mode\n");
5763d0407baSopenharmony_ci		return -EINVAL;
5773d0407baSopenharmony_ci	}
5783d0407baSopenharmony_ci
5793d0407baSopenharmony_ci	return 0;
5803d0407baSopenharmony_ci}
5813d0407baSopenharmony_ci
5823d0407baSopenharmony_cistatic unsigned int rk806_get_mode(struct regulator_dev *rdev)
5833d0407baSopenharmony_ci{
5843d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
5853d0407baSopenharmony_ci	int ctr_bit, reg;
5863d0407baSopenharmony_ci	unsigned int val;
5873d0407baSopenharmony_ci	int err;
5883d0407baSopenharmony_ci
5893d0407baSopenharmony_ci	if (rid > RK806_ID_DCDC10)
5903d0407baSopenharmony_ci		return 0;
5913d0407baSopenharmony_ci
5923d0407baSopenharmony_ci	reg = RK806_POWER_FPWM_EN0 + rid / 8;
5933d0407baSopenharmony_ci	ctr_bit = rid % 8;
5943d0407baSopenharmony_ci
5953d0407baSopenharmony_ci	err = regmap_read(rdev->regmap, reg, &val);
5963d0407baSopenharmony_ci	if (err)
5973d0407baSopenharmony_ci		return err;
5983d0407baSopenharmony_ci
5993d0407baSopenharmony_ci	if ((val >> ctr_bit) & FPWM_MODE)
6003d0407baSopenharmony_ci		return REGULATOR_MODE_FAST;
6013d0407baSopenharmony_ci	else
6023d0407baSopenharmony_ci		return REGULATOR_MODE_NORMAL;
6033d0407baSopenharmony_ci}
6043d0407baSopenharmony_ci
6053d0407baSopenharmony_cistatic int rk806_regulator_sleep2dvs_mode(struct regulator_dev *rdev)
6063d0407baSopenharmony_ci{
6073d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
6083d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
6093d0407baSopenharmony_ci	int mode = get_dvs_mode(rdev);
6103d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
6113d0407baSopenharmony_ci	int pid = get_gpio_id(mode);
6123d0407baSopenharmony_ci	int gpio_level, j;
6133d0407baSopenharmony_ci
6143d0407baSopenharmony_ci	/* set slp_fun NULL*/
6153d0407baSopenharmony_ci	if (pdata->dvs_ctrl_mode[rid] == RK806_DVS_PWRCTRL1)
6163d0407baSopenharmony_ci		rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN);
6173d0407baSopenharmony_ci	else if (pdata->dvs_ctrl_mode[rid] == RK806_DVS_PWRCTRL2)
6183d0407baSopenharmony_ci		rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_DVS_FUN);
6193d0407baSopenharmony_ci	else if (pdata->dvs_ctrl_mode[rid] == RK806_DVS_PWRCTRL3)
6203d0407baSopenharmony_ci		rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_DVS_FUN);
6213d0407baSopenharmony_ci
6223d0407baSopenharmony_ci
6233d0407baSopenharmony_ci	/* 3.check the used count 1*/
6243d0407baSopenharmony_ci	pdata->dvs_used[mode] |= BIT(rid);
6253d0407baSopenharmony_ci	if (pdata->dvs_used[mode] != pdata->dvs_flag[mode])
6263d0407baSopenharmony_ci		return 0;
6273d0407baSopenharmony_ci
6283d0407baSopenharmony_ci	pdata->dvs_used[mode] = 0;
6293d0407baSopenharmony_ci	/* 5.clear the SLP_CTRL_SEL */
6303d0407baSopenharmony_ci	for (j = 0; j < RK806_ID_END; j++)
6313d0407baSopenharmony_ci		if (pdata->dvs_ctrl_mode[j] == mode)
6323d0407baSopenharmony_ci			rk806_field_write(rk806,
6333d0407baSopenharmony_ci					  pdata->dvs_field[j].vsel_ctrl_sel,
6343d0407baSopenharmony_ci					  pdata->dvs_ctrl_mode[j]);
6353d0407baSopenharmony_ci
6363d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
6373d0407baSopenharmony_ci		gpio_level = pdata->dvs_mode[rid].dvs_gpio_level[pid];
6383d0407baSopenharmony_ci		if (gpio_level == 1) {
6393d0407baSopenharmony_ci			gpiod_set_value(pdata->dvs_gpios[pid], 0);
6403d0407baSopenharmony_ci			rk806_field_write(rk806,
6413d0407baSopenharmony_ci					  pdata->dvs_field[rid].on_vsel,
6423d0407baSopenharmony_ci					  pdata->dvs_mode[rid].on_vsel_val);
6433d0407baSopenharmony_ci			rk806_field_write(rk806,
6443d0407baSopenharmony_ci					  pdata->dvs_field[rid].en_reg,
6453d0407baSopenharmony_ci					  pdata->dvs_mode[rid].en_reg_val | (pdata->dvs_field[rid].en_bit << 4));
6463d0407baSopenharmony_ci		}
6473d0407baSopenharmony_ci	}
6483d0407baSopenharmony_ci	return 0;
6493d0407baSopenharmony_ci}
6503d0407baSopenharmony_ci
6513d0407baSopenharmony_cistatic int rk806_regulator_resume(struct regulator_dev *rdev)
6523d0407baSopenharmony_ci{
6533d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
6543d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
6553d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
6563d0407baSopenharmony_ci	int j;
6573d0407baSopenharmony_ci
6583d0407baSopenharmony_ci	if (!pdata->support_dvs)
6593d0407baSopenharmony_ci		return 0;
6603d0407baSopenharmony_ci
6613d0407baSopenharmony_ci	if (rid == RK806_ID_DCDC1) {
6623d0407baSopenharmony_ci		for (j = 0; j < RK806_ID_END; j++) {
6633d0407baSopenharmony_ci			rk806_field_write(rk806,
6643d0407baSopenharmony_ci					  pdata->dvs_field[j].vsel_ctrl_sel,
6653d0407baSopenharmony_ci					  0x00);
6663d0407baSopenharmony_ci			rk806_field_write(rk806,
6673d0407baSopenharmony_ci					  pdata->dvs_field[j].sleep_vsel,
6683d0407baSopenharmony_ci					  pdata->dvs_mode[j].sleep_vsel_val);
6693d0407baSopenharmony_ci			rk806_field_write(rk806,
6703d0407baSopenharmony_ci					  pdata->dvs_field[j].sleep_en,
6713d0407baSopenharmony_ci					  pdata->dvs_mode[j].sleep_en_val);
6723d0407baSopenharmony_ci		}
6733d0407baSopenharmony_ci	}
6743d0407baSopenharmony_ci
6753d0407baSopenharmony_ci	if ((get_dvs_mode(rdev) >= RK806_DVS_PWRCTRL1) &&
6763d0407baSopenharmony_ci	    (get_dvs_mode(rdev) <= RK806_DVS_PWRCTRL3))
6773d0407baSopenharmony_ci		rk806_regulator_sleep2dvs_mode(rdev);
6783d0407baSopenharmony_ci	return 0;
6793d0407baSopenharmony_ci}
6803d0407baSopenharmony_ci
6813d0407baSopenharmony_cistatic int rk806_set_suspend_voltage_range(struct regulator_dev *rdev, int uv)
6823d0407baSopenharmony_ci{
6833d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
6843d0407baSopenharmony_ci	int sel = regulator_map_voltage_linear_range(rdev, uv, uv);
6853d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
6863d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
6873d0407baSopenharmony_ci	int reg_offset;
6883d0407baSopenharmony_ci	unsigned int reg;
6893d0407baSopenharmony_ci
6903d0407baSopenharmony_ci	if (sel < 0)
6913d0407baSopenharmony_ci		return -EINVAL;
6923d0407baSopenharmony_ci
6933d0407baSopenharmony_ci	reg_offset = rk806_get_reg_offset(rid);
6943d0407baSopenharmony_ci	reg = rdev->desc->vsel_reg + reg_offset;
6953d0407baSopenharmony_ci
6963d0407baSopenharmony_ci	return regmap_update_bits(rk806->regmap, reg,
6973d0407baSopenharmony_ci				  rdev->desc->vsel_mask,
6983d0407baSopenharmony_ci				  sel);
6993d0407baSopenharmony_ci}
7003d0407baSopenharmony_ci
7013d0407baSopenharmony_cistatic int rk806_get_voltage_sel_regmap(struct regulator_dev *rdev)
7023d0407baSopenharmony_ci{
7033d0407baSopenharmony_ci	unsigned int val;
7043d0407baSopenharmony_ci	int vsel_reg;
7053d0407baSopenharmony_ci	int ret;
7063d0407baSopenharmony_ci
7073d0407baSopenharmony_ci	vsel_reg = rk806_get_read_vsel_register(rdev);
7083d0407baSopenharmony_ci
7093d0407baSopenharmony_ci	ret = regmap_read(rdev->regmap, vsel_reg, &val);
7103d0407baSopenharmony_ci	if (ret != 0)
7113d0407baSopenharmony_ci		return ret;
7123d0407baSopenharmony_ci
7133d0407baSopenharmony_ci	val &= rdev->desc->vsel_mask;
7143d0407baSopenharmony_ci	val >>= ffs(rdev->desc->vsel_mask) - 1;
7153d0407baSopenharmony_ci
7163d0407baSopenharmony_ci	return val;
7173d0407baSopenharmony_ci}
7183d0407baSopenharmony_ci
7193d0407baSopenharmony_cistatic int rk806_set_voltage(struct regulator_dev *rdev,
7203d0407baSopenharmony_ci			     int req_min_uV, int req_max_uV,
7213d0407baSopenharmony_ci			     unsigned int *selector)
7223d0407baSopenharmony_ci{
7233d0407baSopenharmony_ci	int vsel_reg;
7243d0407baSopenharmony_ci	int mode;
7253d0407baSopenharmony_ci	int ret;
7263d0407baSopenharmony_ci	int sel;
7273d0407baSopenharmony_ci
7283d0407baSopenharmony_ci	ret = regulator_map_voltage_linear_range(rdev, req_min_uV, req_max_uV);
7293d0407baSopenharmony_ci	if (ret >= 0) {
7303d0407baSopenharmony_ci		*selector = ret;
7313d0407baSopenharmony_ci		sel = ret;
7323d0407baSopenharmony_ci	} else {
7333d0407baSopenharmony_ci		return -EINVAL;
7343d0407baSopenharmony_ci	}
7353d0407baSopenharmony_ci
7363d0407baSopenharmony_ci	vsel_reg = rk806_get_write_vsel_register(rdev);
7373d0407baSopenharmony_ci
7383d0407baSopenharmony_ci	sel <<= ffs(rdev->desc->vsel_mask) - 1;
7393d0407baSopenharmony_ci
7403d0407baSopenharmony_ci	ret = regmap_update_bits(rdev->regmap, vsel_reg,
7413d0407baSopenharmony_ci				 rdev->desc->vsel_mask, sel);
7423d0407baSopenharmony_ci
7433d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
7443d0407baSopenharmony_ci	if (mode == RK806_DVS_NOT_SUPPORT)
7453d0407baSopenharmony_ci		return ret;
7463d0407baSopenharmony_ci
7473d0407baSopenharmony_ci	if ((mode >= RK806_DVS_PWRCTRL1) &&
7483d0407baSopenharmony_ci	    (mode <= RK806_DVS_PWRCTRL3))
7493d0407baSopenharmony_ci		rk806_do_gpio_dvs(rdev);
7503d0407baSopenharmony_ci	else
7513d0407baSopenharmony_ci		rk806_do_soft_dvs(rdev);
7523d0407baSopenharmony_ci
7533d0407baSopenharmony_ci	return ret;
7543d0407baSopenharmony_ci}
7553d0407baSopenharmony_ci
7563d0407baSopenharmony_cistatic int rk806_regulator_is_enabled_regmap(struct regulator_dev *rdev)
7573d0407baSopenharmony_ci{
7583d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
7593d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
7603d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
7613d0407baSopenharmony_ci	int gpio_level, pid;
7623d0407baSopenharmony_ci	unsigned int val;
7633d0407baSopenharmony_ci	int mode;
7643d0407baSopenharmony_ci
7653d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
7663d0407baSopenharmony_ci	pid = get_gpio_id(mode);
7673d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
7683d0407baSopenharmony_ci		gpio_level = gpiod_get_value(pdata->dvs_gpios[pid]);
7693d0407baSopenharmony_ci		if (gpio_level == 0)
7703d0407baSopenharmony_ci			return rk806_field_read(rk806, pdata->dvs_field[rid].sleep_en);
7713d0407baSopenharmony_ci	}
7723d0407baSopenharmony_ci
7733d0407baSopenharmony_ci	val = rk806_field_read(rk806, pdata->dvs_field[rid].en_reg);
7743d0407baSopenharmony_ci	return (val & rdev->desc->enable_val) != 0;
7753d0407baSopenharmony_ci}
7763d0407baSopenharmony_ci
7773d0407baSopenharmony_cistatic int rk806_regulator_enable_regmap(struct regulator_dev *rdev)
7783d0407baSopenharmony_ci{
7793d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
7803d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
7813d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
7823d0407baSopenharmony_ci	int gpio_level, pid;
7833d0407baSopenharmony_ci	int mode;
7843d0407baSopenharmony_ci
7853d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
7863d0407baSopenharmony_ci	pid = get_gpio_id(mode);
7873d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
7883d0407baSopenharmony_ci		gpio_level = gpiod_get_value(pdata->dvs_gpios[pid]);
7893d0407baSopenharmony_ci		if (gpio_level == 0)
7903d0407baSopenharmony_ci			return rk806_field_write(rk806,
7913d0407baSopenharmony_ci						 pdata->dvs_field[rid].sleep_en,
7923d0407baSopenharmony_ci						 0x01);
7933d0407baSopenharmony_ci	}
7943d0407baSopenharmony_ci
7953d0407baSopenharmony_ci	return rk806_field_write(rk806,
7963d0407baSopenharmony_ci				 pdata->dvs_field[rid].en_reg,
7973d0407baSopenharmony_ci				 rdev->desc->enable_val);
7983d0407baSopenharmony_ci}
7993d0407baSopenharmony_ci
8003d0407baSopenharmony_cistatic int rk806_regulator_disable_regmap(struct regulator_dev *rdev)
8013d0407baSopenharmony_ci{
8023d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
8033d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
8043d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
8053d0407baSopenharmony_ci	int gpio_level, pid;
8063d0407baSopenharmony_ci	int mode;
8073d0407baSopenharmony_ci
8083d0407baSopenharmony_ci	mode = get_dvs_mode(rdev);
8093d0407baSopenharmony_ci	pid = get_gpio_id(mode);
8103d0407baSopenharmony_ci	if ((pid >= 0) && (pdata->dvs_gpios[pid] != NULL)) {
8113d0407baSopenharmony_ci		gpio_level = gpiod_get_value(pdata->dvs_gpios[pid]);
8123d0407baSopenharmony_ci		if (gpio_level == 0)
8133d0407baSopenharmony_ci			return rk806_field_write(rk806,
8143d0407baSopenharmony_ci						 pdata->dvs_field[rid].sleep_en,
8153d0407baSopenharmony_ci						 0x00);
8163d0407baSopenharmony_ci	}
8173d0407baSopenharmony_ci
8183d0407baSopenharmony_ci	return rk806_field_write(rk806,
8193d0407baSopenharmony_ci				 pdata->dvs_field[rid].en_reg,
8203d0407baSopenharmony_ci				 rdev->desc->disable_val);
8213d0407baSopenharmony_ci}
8223d0407baSopenharmony_ci
8233d0407baSopenharmony_cistatic int rk806_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
8243d0407baSopenharmony_ci{
8253d0407baSopenharmony_ci	unsigned int ramp_value = RK806_RAMP_RATE_2LSB_PER_1CLK;
8263d0407baSopenharmony_ci	struct rk806_regulator_data *pdata = rdev_get_drvdata(rdev);
8273d0407baSopenharmony_ci	struct rk806 *rk806 = pdata->rk806;
8283d0407baSopenharmony_ci	int rid = rdev_get_id(rdev);
8293d0407baSopenharmony_ci
8303d0407baSopenharmony_ci	if (rid <= RK806_ID_DCDC10) {
8313d0407baSopenharmony_ci		switch (ramp_delay) {
8323d0407baSopenharmony_ci		case 1 ... 390:
8333d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
8343d0407baSopenharmony_ci			break;
8353d0407baSopenharmony_ci		case 391 ... 961:
8363d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_13CLK;
8373d0407baSopenharmony_ci			break;
8383d0407baSopenharmony_ci		case 962 ... 1560:
8393d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_8CLK;
8403d0407baSopenharmony_ci			break;
8413d0407baSopenharmony_ci		case 1561 ... 3125:
8423d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_4CLK;
8433d0407baSopenharmony_ci			break;
8443d0407baSopenharmony_ci		case 3126 ... 6250:
8453d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_2CLK;
8463d0407baSopenharmony_ci			break;
8473d0407baSopenharmony_ci		case 6251 ... 12500:
8483d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_1CLK;
8493d0407baSopenharmony_ci			break;
8503d0407baSopenharmony_ci		case 12501 ... 25000:
8513d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_2LSB_PER_1CLK;
8523d0407baSopenharmony_ci			break;
8533d0407baSopenharmony_ci		case 25001 ... 50000: /* 50mV/us */
8543d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_4LSB_PER_1CLK;
8553d0407baSopenharmony_ci			break;
8563d0407baSopenharmony_ci		default:
8573d0407baSopenharmony_ci			pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
8583d0407baSopenharmony_ci				rdev->desc->name, ramp_delay);
8593d0407baSopenharmony_ci		}
8603d0407baSopenharmony_ci
8613d0407baSopenharmony_ci		rk806_field_write(rk806,
8623d0407baSopenharmony_ci				  rk806_buck_rate_config_field[rid][0],
8633d0407baSopenharmony_ci				  ramp_value & 0x03);
8643d0407baSopenharmony_ci		return rk806_field_write(rk806,
8653d0407baSopenharmony_ci					 rk806_buck_rate_config_field[rid][1],
8663d0407baSopenharmony_ci					 (ramp_value & 0x4) >> 2);
8673d0407baSopenharmony_ci	} else {
8683d0407baSopenharmony_ci		switch (ramp_delay) {
8693d0407baSopenharmony_ci		case 1 ... 780:
8703d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_32CLK;
8713d0407baSopenharmony_ci			break;
8723d0407baSopenharmony_ci		case 781 ... 1900:
8733d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_13CLK;
8743d0407baSopenharmony_ci			break;
8753d0407baSopenharmony_ci		case 1901 ... 3120:
8763d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_8CLK;
8773d0407baSopenharmony_ci			break;
8783d0407baSopenharmony_ci		case 3121 ... 6280:
8793d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_4CLK;
8803d0407baSopenharmony_ci			break;
8813d0407baSopenharmony_ci		case 6281 ... 12500:
8823d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_2CLK;
8833d0407baSopenharmony_ci			break;
8843d0407baSopenharmony_ci		case 12501 ... 25000:
8853d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_1LSB_PER_1CLK;
8863d0407baSopenharmony_ci			break;
8873d0407baSopenharmony_ci		case 25001 ... 50000:
8883d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_2LSB_PER_1CLK;
8893d0407baSopenharmony_ci			break;
8903d0407baSopenharmony_ci		case 50001 ... 100000:
8913d0407baSopenharmony_ci			ramp_value = RK806_RAMP_RATE_4LSB_PER_1CLK;
8923d0407baSopenharmony_ci			break;
8933d0407baSopenharmony_ci		default:
8943d0407baSopenharmony_ci			pr_warn("%s ramp_delay: %d not supported, setting 10000\n",
8953d0407baSopenharmony_ci				rdev->desc->name, ramp_delay);
8963d0407baSopenharmony_ci		}
8973d0407baSopenharmony_ci		return rk806_field_write(rk806, LDO_RATE, ramp_value);
8983d0407baSopenharmony_ci	}
8993d0407baSopenharmony_ci}
9003d0407baSopenharmony_ci
9013d0407baSopenharmony_cistatic const struct regulator_ops rk806_ops_dcdc = {
9023d0407baSopenharmony_ci	.list_voltage		= regulator_list_voltage_linear_range,
9033d0407baSopenharmony_ci	.map_voltage		= regulator_map_voltage_linear_range,
9043d0407baSopenharmony_ci
9053d0407baSopenharmony_ci	.get_voltage_sel	= rk806_get_voltage_sel_regmap,
9063d0407baSopenharmony_ci	.set_voltage		= rk806_set_voltage,
9073d0407baSopenharmony_ci	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
9083d0407baSopenharmony_ci	.set_mode		= rk806_set_mode,
9093d0407baSopenharmony_ci	.get_mode		= rk806_get_mode,
9103d0407baSopenharmony_ci
9113d0407baSopenharmony_ci	.enable			= rk806_regulator_enable_regmap,
9123d0407baSopenharmony_ci	.disable		= rk806_regulator_disable_regmap,
9133d0407baSopenharmony_ci	.is_enabled		= rk806_regulator_is_enabled_regmap,
9143d0407baSopenharmony_ci
9153d0407baSopenharmony_ci	.set_suspend_mode	= rk806_set_mode,
9163d0407baSopenharmony_ci	.set_ramp_delay		= rk806_set_ramp_delay,
9173d0407baSopenharmony_ci
9183d0407baSopenharmony_ci	.set_suspend_voltage	= rk806_set_suspend_voltage_range,
9193d0407baSopenharmony_ci	.resume			= rk806_regulator_resume,
9203d0407baSopenharmony_ci	.set_suspend_enable	= rk806_set_suspend_enable,
9213d0407baSopenharmony_ci	.set_suspend_disable	= rk806_set_suspend_disable,
9223d0407baSopenharmony_ci};
9233d0407baSopenharmony_ci
9243d0407baSopenharmony_cistatic const struct regulator_ops rk806_ops_ldo = {
9253d0407baSopenharmony_ci	.list_voltage		= regulator_list_voltage_linear_range,
9263d0407baSopenharmony_ci	.map_voltage		= regulator_map_voltage_linear_range,
9273d0407baSopenharmony_ci
9283d0407baSopenharmony_ci	.get_voltage_sel	= rk806_get_voltage_sel_regmap,
9293d0407baSopenharmony_ci	.set_voltage		= rk806_set_voltage,
9303d0407baSopenharmony_ci	.set_voltage_time_sel	= regulator_set_voltage_time_sel,
9313d0407baSopenharmony_ci
9323d0407baSopenharmony_ci	.enable			= rk806_regulator_enable_regmap,
9333d0407baSopenharmony_ci	.disable		= rk806_regulator_disable_regmap,
9343d0407baSopenharmony_ci	.is_enabled		= rk806_regulator_is_enabled_regmap,
9353d0407baSopenharmony_ci
9363d0407baSopenharmony_ci	.set_suspend_mode	= rk806_set_mode,
9373d0407baSopenharmony_ci	.set_ramp_delay		= rk806_set_ramp_delay,
9383d0407baSopenharmony_ci
9393d0407baSopenharmony_ci	.set_suspend_voltage	= rk806_set_suspend_voltage_range,
9403d0407baSopenharmony_ci	.resume			= rk806_regulator_resume,
9413d0407baSopenharmony_ci	.set_suspend_enable	= rk806_set_suspend_enable,
9423d0407baSopenharmony_ci	.set_suspend_disable	= rk806_set_suspend_disable,
9433d0407baSopenharmony_ci};
9443d0407baSopenharmony_ci
9453d0407baSopenharmony_ci#define RK806_REGULATOR(_name, _supply_name, _id, _ops,\
9463d0407baSopenharmony_ci			_n_voltages, _vr, _er, _lr, ctrl_bit)\
9473d0407baSopenharmony_ci[_id] = {\
9483d0407baSopenharmony_ci		.name = _name,\
9493d0407baSopenharmony_ci		.supply_name = _supply_name,\
9503d0407baSopenharmony_ci		.of_match = of_match_ptr(_name),\
9513d0407baSopenharmony_ci		.regulators_node = of_match_ptr("regulators"),\
9523d0407baSopenharmony_ci		.id = _id,\
9533d0407baSopenharmony_ci		.ops = &_ops,\
9543d0407baSopenharmony_ci		.type = REGULATOR_VOLTAGE,\
9553d0407baSopenharmony_ci		.n_voltages = _n_voltages,\
9563d0407baSopenharmony_ci		.linear_ranges = _lr,\
9573d0407baSopenharmony_ci		.n_linear_ranges = ARRAY_SIZE(_lr),\
9583d0407baSopenharmony_ci		.vsel_reg = _vr,\
9593d0407baSopenharmony_ci		.vsel_mask = 0xff,\
9603d0407baSopenharmony_ci		.enable_reg = _er,\
9613d0407baSopenharmony_ci		.enable_mask = ENABLE_MASK(ctrl_bit),\
9623d0407baSopenharmony_ci		.enable_val = ENABLE_MASK(ctrl_bit),\
9633d0407baSopenharmony_ci		.disable_val = DISABLE_VAL(ctrl_bit),\
9643d0407baSopenharmony_ci		.of_map_mode = rk806_regulator_of_map_mode,\
9653d0407baSopenharmony_ci		.owner = THIS_MODULE,\
9663d0407baSopenharmony_ci	}
9673d0407baSopenharmony_ci
9683d0407baSopenharmony_cistatic const struct regulator_desc rk806_regulators[] = {
9693d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG1", "vcc1", RK806_ID_DCDC1, rk806_ops_dcdc,
9703d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK1_ON_VSEL,
9713d0407baSopenharmony_ci			RK806_POWER_EN0, rk806_buck_voltage_ranges, 0),
9723d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG2", "vcc2", RK806_ID_DCDC2, rk806_ops_dcdc,
9733d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK2_ON_VSEL,
9743d0407baSopenharmony_ci			RK806_POWER_EN0, rk806_buck_voltage_ranges, 1),
9753d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG3", "vcc3", RK806_ID_DCDC3, rk806_ops_dcdc,
9763d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK3_ON_VSEL,
9773d0407baSopenharmony_ci			RK806_POWER_EN0, rk806_buck_voltage_ranges, 2),
9783d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG4", "vcc4", RK806_ID_DCDC4, rk806_ops_dcdc,
9793d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK4_ON_VSEL,
9803d0407baSopenharmony_ci			RK806_POWER_EN0, rk806_buck_voltage_ranges, 3),
9813d0407baSopenharmony_ci
9823d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG5", "vcc5", RK806_ID_DCDC5, rk806_ops_dcdc,
9833d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK5_ON_VSEL,
9843d0407baSopenharmony_ci			RK806_POWER_EN1, rk806_buck_voltage_ranges, 0),
9853d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG6", "vcc6", RK806_ID_DCDC6, rk806_ops_dcdc,
9863d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK6_ON_VSEL,
9873d0407baSopenharmony_ci			RK806_POWER_EN1, rk806_buck_voltage_ranges, 1),
9883d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG7", "vcc7", RK806_ID_DCDC7, rk806_ops_dcdc,
9893d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK7_ON_VSEL,
9903d0407baSopenharmony_ci			RK806_POWER_EN1, rk806_buck_voltage_ranges, 2),
9913d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG8", "vcc8", RK806_ID_DCDC8, rk806_ops_dcdc,
9923d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK8_ON_VSEL,
9933d0407baSopenharmony_ci			RK806_POWER_EN1, rk806_buck_voltage_ranges, 3),
9943d0407baSopenharmony_ci
9953d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG9", "vcc9", RK806_ID_DCDC9, rk806_ops_dcdc,
9963d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK9_ON_VSEL,
9973d0407baSopenharmony_ci			RK806_POWER_EN2, rk806_buck_voltage_ranges, 0),
9983d0407baSopenharmony_ci	RK806_REGULATOR("DCDC_REG10", "vcc10", RK806_ID_DCDC10, rk806_ops_dcdc,
9993d0407baSopenharmony_ci			RK806_BUCK_SEL_CNT, RK806_BUCK10_ON_VSEL,
10003d0407baSopenharmony_ci			RK806_POWER_EN2, rk806_buck_voltage_ranges, 1),
10013d0407baSopenharmony_ci
10023d0407baSopenharmony_ci	RK806_REGULATOR("NLDO_REG1", "vcc13", RK806_ID_NLDO1, rk806_ops_ldo,
10033d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_NLDO1_ON_VSEL,
10043d0407baSopenharmony_ci			RK806_POWER_EN3, rk806_ldo_voltage_ranges, 0),
10053d0407baSopenharmony_ci	RK806_REGULATOR("NLDO_REG2", "vcc13", RK806_ID_NLDO2, rk806_ops_ldo,
10063d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_NLDO2_ON_VSEL,
10073d0407baSopenharmony_ci			RK806_POWER_EN3, rk806_ldo_voltage_ranges, 1),
10083d0407baSopenharmony_ci	RK806_REGULATOR("NLDO_REG3", "vcc13", RK806_ID_NLDO3, rk806_ops_ldo,
10093d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_NLDO3_ON_VSEL,
10103d0407baSopenharmony_ci			RK806_POWER_EN3, rk806_ldo_voltage_ranges, 2),
10113d0407baSopenharmony_ci	RK806_REGULATOR("NLDO_REG4", "vcc14", RK806_ID_NLDO4, rk806_ops_ldo,
10123d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_NLDO4_ON_VSEL,
10133d0407baSopenharmony_ci			RK806_POWER_EN3, rk806_ldo_voltage_ranges, 3),
10143d0407baSopenharmony_ci
10153d0407baSopenharmony_ci	RK806_REGULATOR("NLDO_REG5", "vcc14", RK806_ID_NLDO5, rk806_ops_ldo,
10163d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_NLDO5_ON_VSEL,
10173d0407baSopenharmony_ci			RK806_POWER_EN5, rk806_ldo_voltage_ranges, 2),
10183d0407baSopenharmony_ci
10193d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG1", "vcc11", RK806_ID_PLDO1, rk806_ops_ldo,
10203d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO1_ON_VSEL,
10213d0407baSopenharmony_ci			RK806_POWER_EN4, rk806_ldo_voltage_ranges, 1),
10223d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG2", "vcc11", RK806_ID_PLDO2, rk806_ops_ldo,
10233d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO2_ON_VSEL,
10243d0407baSopenharmony_ci			RK806_POWER_EN4, rk806_ldo_voltage_ranges, 2),
10253d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG3", "vcc11", RK806_ID_PLDO3, rk806_ops_ldo,
10263d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO3_ON_VSEL,
10273d0407baSopenharmony_ci			RK806_POWER_EN4, rk806_ldo_voltage_ranges, 3),
10283d0407baSopenharmony_ci
10293d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG4", "vcc12", RK806_ID_PLDO4, rk806_ops_ldo,
10303d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO4_ON_VSEL,
10313d0407baSopenharmony_ci			RK806_POWER_EN5, rk806_ldo_voltage_ranges, 0),
10323d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG5", "vcc12", RK806_ID_PLDO5, rk806_ops_ldo,
10333d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO5_ON_VSEL,
10343d0407baSopenharmony_ci			RK806_POWER_EN5, rk806_ldo_voltage_ranges, 1),
10353d0407baSopenharmony_ci
10363d0407baSopenharmony_ci	RK806_REGULATOR("PLDO_REG6", "vcca", RK806_ID_PLDO6, rk806_ops_ldo,
10373d0407baSopenharmony_ci			RK806_LDO_SEL_CNT, RK806_PLDO6_ON_VSEL,
10383d0407baSopenharmony_ci			RK806_POWER_EN4, rk806_ldo_voltage_ranges, 0),
10393d0407baSopenharmony_ci};
10403d0407baSopenharmony_ci
10413d0407baSopenharmony_cistatic void rk806_regulator_dt_parse_pdata(struct rk806 *rk806,
10423d0407baSopenharmony_ci					   struct regmap *map,
10433d0407baSopenharmony_ci					   struct rk806_regulator_data *pdata)
10443d0407baSopenharmony_ci
10453d0407baSopenharmony_ci{
10463d0407baSopenharmony_ci	char dvs_ctrl_name[10][32] = {
10473d0407baSopenharmony_ci					"dvs_default",
10483d0407baSopenharmony_ci					"start_dvs1_ctrl",
10493d0407baSopenharmony_ci					"start_dvs2_ctrl",
10503d0407baSopenharmony_ci					"start_dvs3_ctrl",
10513d0407baSopenharmony_ci					"dvs_pin1_ctrl",
10523d0407baSopenharmony_ci					"dvs_pin2_ctrl",
10533d0407baSopenharmony_ci					"dvs_pin3_ctrl",
10543d0407baSopenharmony_ci					"start_and_pwrctrl1",
10553d0407baSopenharmony_ci					"start_and_pwrctrl2",
10563d0407baSopenharmony_ci					"start_and_pwrctrl3"};
10573d0407baSopenharmony_ci	char dvs_pin_name[3][30] = { "rk806,pmic-dvs-gpio1",
10583d0407baSopenharmony_ci				     "rk806,pmic-dvs-gpio2",
10593d0407baSopenharmony_ci				     "rk806,pmic-dvs-gpio3" };
10603d0407baSopenharmony_ci	struct device_node *np = rk806->dev->of_node;
10613d0407baSopenharmony_ci	struct device_node *dn;
10623d0407baSopenharmony_ci	int i, j;
10633d0407baSopenharmony_ci
10643d0407baSopenharmony_ci	pdata->support_dvs = 0;
10653d0407baSopenharmony_ci
10663d0407baSopenharmony_ci	for (i = 0; i < RK806_ID_END; i++) {
10673d0407baSopenharmony_ci		pdata->dvs_field[i] = rk806_dvs_fields[i];
10683d0407baSopenharmony_ci		pdata->dvs_ctrl_id[i] = start_dvs_id[i];
10693d0407baSopenharmony_ci		pdata->vsel_ctrl_id[i] = vsel_ctr_sel_id[i];
10703d0407baSopenharmony_ci	}
10713d0407baSopenharmony_ci
10723d0407baSopenharmony_ci	for (j = 1; j < RK806_DVS_END; j++) {
10733d0407baSopenharmony_ci		if (device_property_present(rk806->dev, dvs_ctrl_name[j])) {
10743d0407baSopenharmony_ci			REG_DBG("%s:\n", dvs_ctrl_name[j]);
10753d0407baSopenharmony_ci			for (i = 0;
10763d0407baSopenharmony_ci			     (dn = of_parse_phandle(np, dvs_ctrl_name[j], i));
10773d0407baSopenharmony_ci			     i++) {
10783d0407baSopenharmony_ci				REG_DBG("\t%s\n", dn->name);
10793d0407baSopenharmony_ci				pdata->support_dvs = 1;
10803d0407baSopenharmony_ci				pdata->dvs_dn[j][i] = dn;
10813d0407baSopenharmony_ci				pdata->dvs_count[j]++;
10823d0407baSopenharmony_ci
10833d0407baSopenharmony_ci				of_node_put(dn);
10843d0407baSopenharmony_ci				if (i >= RK806_ID_END)
10853d0407baSopenharmony_ci					break;
10863d0407baSopenharmony_ci			}
10873d0407baSopenharmony_ci		}
10883d0407baSopenharmony_ci	}
10893d0407baSopenharmony_ci	if (!pdata->support_dvs)
10903d0407baSopenharmony_ci		return;
10913d0407baSopenharmony_ci
10923d0407baSopenharmony_ci	for (i = 0; i < 3; i++) {
10933d0407baSopenharmony_ci		pdata->dvs_gpios[i] = devm_gpiod_get_optional(rk806->dev,
10943d0407baSopenharmony_ci							      dvs_pin_name[i],
10953d0407baSopenharmony_ci							      GPIOD_OUT_HIGH);
10963d0407baSopenharmony_ci		if (IS_ERR(pdata->dvs_gpios[i])) {
10973d0407baSopenharmony_ci			pdata->dvs_gpios[i] = NULL;
10983d0407baSopenharmony_ci			dev_info(rk806->dev, "Failed to get %s\n", dvs_pin_name[i]);
10993d0407baSopenharmony_ci		}
11003d0407baSopenharmony_ci	}
11013d0407baSopenharmony_ci}
11023d0407baSopenharmony_ci
11033d0407baSopenharmony_cistatic int rk806_regulator_probe(struct platform_device *pdev)
11043d0407baSopenharmony_ci{
11053d0407baSopenharmony_ci	struct rk806 *rk806 = dev_get_drvdata(pdev->dev.parent);
11063d0407baSopenharmony_ci	struct rk806_regulator_data *pdata;
11073d0407baSopenharmony_ci	struct regulator_config config = { };
11083d0407baSopenharmony_ci	struct regulator_dev *rdev;
11093d0407baSopenharmony_ci	int i;
11103d0407baSopenharmony_ci
11113d0407baSopenharmony_ci	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
11123d0407baSopenharmony_ci	if (!pdata)
11133d0407baSopenharmony_ci		return -ENOMEM;
11143d0407baSopenharmony_ci
11153d0407baSopenharmony_ci	rk806_regulator_dt_parse_pdata(rk806, rk806->regmap, pdata);
11163d0407baSopenharmony_ci
11173d0407baSopenharmony_ci	pdata->rk806 = rk806;
11183d0407baSopenharmony_ci	platform_set_drvdata(pdev, pdata);
11193d0407baSopenharmony_ci
11203d0407baSopenharmony_ci	config.dev = &pdev->dev;
11213d0407baSopenharmony_ci	config.driver_data = pdata;
11223d0407baSopenharmony_ci	config.dev->of_node = rk806->dev->of_node;
11233d0407baSopenharmony_ci	config.regmap = rk806->regmap;
11243d0407baSopenharmony_ci
11253d0407baSopenharmony_ci	for (i = 0; i < ARRAY_SIZE(rk806_regulators); i++) {
11263d0407baSopenharmony_ci		rdev = devm_regulator_register(&pdev->dev,
11273d0407baSopenharmony_ci					       &rk806_regulators[i],
11283d0407baSopenharmony_ci					       &config);
11293d0407baSopenharmony_ci		if (IS_ERR(rdev)) {
11303d0407baSopenharmony_ci			dev_err(rk806->dev, "failed to register %s regulator\n",
11313d0407baSopenharmony_ci				pdev->name);
11323d0407baSopenharmony_ci			return PTR_ERR(rdev);
11333d0407baSopenharmony_ci		}
11343d0407baSopenharmony_ci
11353d0407baSopenharmony_ci		rk806_regulator_sync_voltage(rdev);
11363d0407baSopenharmony_ci	}
11373d0407baSopenharmony_ci
11383d0407baSopenharmony_ci	pdata->regulator_init = 1;
11393d0407baSopenharmony_ci
11403d0407baSopenharmony_ci	return 0;
11413d0407baSopenharmony_ci}
11423d0407baSopenharmony_ci
11433d0407baSopenharmony_cistatic int __maybe_unused rk806_suspend(struct device *dev)
11443d0407baSopenharmony_ci{
11453d0407baSopenharmony_ci	struct rk806 *rk806 = dev_get_drvdata(dev->parent);
11463d0407baSopenharmony_ci	int i;
11473d0407baSopenharmony_ci
11483d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN);
11493d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL2_FUN, PWRCTRL_NULL_FUN);
11503d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL3_FUN, PWRCTRL_NULL_FUN);
11513d0407baSopenharmony_ci
11523d0407baSopenharmony_ci	for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++)
11533d0407baSopenharmony_ci		rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_NO_EFFECT);
11543d0407baSopenharmony_ci
11553d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_DVS_FUN);
11563d0407baSopenharmony_ci
11573d0407baSopenharmony_ci	for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++)
11583d0407baSopenharmony_ci		rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_PWRCTRL1);
11593d0407baSopenharmony_ci
11603d0407baSopenharmony_ci	return 0;
11613d0407baSopenharmony_ci}
11623d0407baSopenharmony_ci
11633d0407baSopenharmony_cistatic int __maybe_unused rk806_resume(struct device *dev)
11643d0407baSopenharmony_ci{
11653d0407baSopenharmony_ci	struct rk806 *rk806 = dev_get_drvdata(dev->parent);
11663d0407baSopenharmony_ci	int i;
11673d0407baSopenharmony_ci
11683d0407baSopenharmony_ci	for (i = RK806_ID_DCDC1; i < RK806_ID_END; i++)
11693d0407baSopenharmony_ci		rk806_field_write(rk806, BUCK1_VSEL_CTR_SEL + i, CTR_BY_NO_EFFECT);
11703d0407baSopenharmony_ci
11713d0407baSopenharmony_ci	rk806_field_write(rk806, PWRCTRL1_FUN, PWRCTRL_NULL_FUN);
11723d0407baSopenharmony_ci
11733d0407baSopenharmony_ci	return 0;
11743d0407baSopenharmony_ci}
11753d0407baSopenharmony_ciSIMPLE_DEV_PM_OPS(rk806_pm_ops, rk806_suspend, rk806_resume);
11763d0407baSopenharmony_ci
11773d0407baSopenharmony_cistatic void rk806_regulator_shutdown(struct platform_device *pdev)
11783d0407baSopenharmony_ci{
11793d0407baSopenharmony_ci	struct rk806 *rk806 = dev_get_drvdata(pdev->dev.parent);
11803d0407baSopenharmony_ci
11813d0407baSopenharmony_ci	if (system_state == SYSTEM_POWER_OFF)
11823d0407baSopenharmony_ci		if ((rk806->pins->p) && (rk806->pins->power_off))
11833d0407baSopenharmony_ci			pinctrl_select_state(rk806->pins->p, rk806->pins->power_off);
11843d0407baSopenharmony_ci
11853d0407baSopenharmony_ci	if (system_state == SYSTEM_RESTART)
11863d0407baSopenharmony_ci		if ((rk806->pins->p) && (rk806->pins->power_off))
11873d0407baSopenharmony_ci			pinctrl_select_state(rk806->pins->p, rk806->pins->reset);
11883d0407baSopenharmony_ci
11893d0407baSopenharmony_ci}
11903d0407baSopenharmony_ci
11913d0407baSopenharmony_cistatic const struct platform_device_id rk806_regulator_id_table[] = {
11923d0407baSopenharmony_ci	{ "rk806-regulator", },
11933d0407baSopenharmony_ci	{ /* sentinel */ }
11943d0407baSopenharmony_ci};
11953d0407baSopenharmony_ciMODULE_DEVICE_TABLE(platform, rk806_regulator_id_table);
11963d0407baSopenharmony_ci
11973d0407baSopenharmony_cistatic struct platform_driver rk806_regulator_driver = {
11983d0407baSopenharmony_ci	.driver = {
11993d0407baSopenharmony_ci		.name = "rk806-regulator",
12003d0407baSopenharmony_ci		.pm = &rk806_pm_ops,
12013d0407baSopenharmony_ci	},
12023d0407baSopenharmony_ci	.probe = rk806_regulator_probe,
12033d0407baSopenharmony_ci	.id_table = rk806_regulator_id_table,
12043d0407baSopenharmony_ci	.shutdown = rk806_regulator_shutdown,
12053d0407baSopenharmony_ci};
12063d0407baSopenharmony_cimodule_platform_driver(rk806_regulator_driver);
12073d0407baSopenharmony_ci
12083d0407baSopenharmony_ciMODULE_AUTHOR("Xu Shengfei <xsf@rock-chips.com>");
12093d0407baSopenharmony_ciMODULE_DESCRIPTION("rk806 voltage regulator driver");
12103d0407baSopenharmony_ciMODULE_LICENSE("GPL v2");
1211