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