162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Device driver for regulators in Hi6421 IC 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) <2011-2014> HiSilicon Technologies Co., Ltd. 662306a36Sopenharmony_ci// http://www.hisilicon.com 762306a36Sopenharmony_ci// Copyright (c) <2013-2014> Linaro Ltd. 862306a36Sopenharmony_ci// https://www.linaro.org 962306a36Sopenharmony_ci// 1062306a36Sopenharmony_ci// Author: Guodong Xu <guodong.xu@linaro.org> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/device.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/err.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/regmap.h> 1962306a36Sopenharmony_ci#include <linux/regulator/driver.h> 2062306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2162306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2262306a36Sopenharmony_ci#include <linux/mfd/hi6421-pmic.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* 2562306a36Sopenharmony_ci * struct hi6421_regulator_pdata - Hi6421 regulator data of platform device 2662306a36Sopenharmony_ci * @lock: mutex to serialize regulator enable 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_cistruct hi6421_regulator_pdata { 2962306a36Sopenharmony_ci struct mutex lock; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * struct hi6421_regulator_info - hi6421 regulator information 3462306a36Sopenharmony_ci * @desc: regulator description 3562306a36Sopenharmony_ci * @mode_mask: ECO mode bitmask of LDOs; for BUCKs, this masks sleep 3662306a36Sopenharmony_ci * @eco_microamp: eco mode load upper limit (in uA), valid for LDOs only 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistruct hi6421_regulator_info { 3962306a36Sopenharmony_ci struct regulator_desc desc; 4062306a36Sopenharmony_ci u8 mode_mask; 4162306a36Sopenharmony_ci u32 eco_microamp; 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* HI6421 regulators */ 4562306a36Sopenharmony_cienum hi6421_regulator_id { 4662306a36Sopenharmony_ci HI6421_LDO0, 4762306a36Sopenharmony_ci HI6421_LDO1, 4862306a36Sopenharmony_ci HI6421_LDO2, 4962306a36Sopenharmony_ci HI6421_LDO3, 5062306a36Sopenharmony_ci HI6421_LDO4, 5162306a36Sopenharmony_ci HI6421_LDO5, 5262306a36Sopenharmony_ci HI6421_LDO6, 5362306a36Sopenharmony_ci HI6421_LDO7, 5462306a36Sopenharmony_ci HI6421_LDO8, 5562306a36Sopenharmony_ci HI6421_LDO9, 5662306a36Sopenharmony_ci HI6421_LDO10, 5762306a36Sopenharmony_ci HI6421_LDO11, 5862306a36Sopenharmony_ci HI6421_LDO12, 5962306a36Sopenharmony_ci HI6421_LDO13, 6062306a36Sopenharmony_ci HI6421_LDO14, 6162306a36Sopenharmony_ci HI6421_LDO15, 6262306a36Sopenharmony_ci HI6421_LDO16, 6362306a36Sopenharmony_ci HI6421_LDO17, 6462306a36Sopenharmony_ci HI6421_LDO18, 6562306a36Sopenharmony_ci HI6421_LDO19, 6662306a36Sopenharmony_ci HI6421_LDO20, 6762306a36Sopenharmony_ci HI6421_LDOAUDIO, 6862306a36Sopenharmony_ci HI6421_BUCK0, 6962306a36Sopenharmony_ci HI6421_BUCK1, 7062306a36Sopenharmony_ci HI6421_BUCK2, 7162306a36Sopenharmony_ci HI6421_BUCK3, 7262306a36Sopenharmony_ci HI6421_BUCK4, 7362306a36Sopenharmony_ci HI6421_BUCK5, 7462306a36Sopenharmony_ci HI6421_NUM_REGULATORS, 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* LDO 0, 4~7, 9~14, 16~20 have same voltage table. */ 7862306a36Sopenharmony_cistatic const unsigned int ldo_0_voltages[] = { 7962306a36Sopenharmony_ci 1500000, 1800000, 2400000, 2500000, 8062306a36Sopenharmony_ci 2600000, 2700000, 2850000, 3000000, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci/* LDO 8, 15 have same voltage table. */ 8462306a36Sopenharmony_cistatic const unsigned int ldo_8_voltages[] = { 8562306a36Sopenharmony_ci 1500000, 1800000, 2400000, 2600000, 8662306a36Sopenharmony_ci 2700000, 2850000, 3000000, 3300000, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* Ranges are sorted in ascending order. */ 9062306a36Sopenharmony_cistatic const struct linear_range ldo_audio_volt_range[] = { 9162306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(2800000, 0, 3, 50000), 9262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(3000000, 4, 7, 100000), 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic const unsigned int buck_3_voltages[] = { 9662306a36Sopenharmony_ci 950000, 1050000, 1100000, 1117000, 9762306a36Sopenharmony_ci 1134000, 1150000, 1167000, 1200000, 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic const unsigned int buck_4_voltages[] = { 10162306a36Sopenharmony_ci 1150000, 1200000, 1250000, 1350000, 10262306a36Sopenharmony_ci 1700000, 1800000, 1900000, 2000000, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic const unsigned int buck_5_voltages[] = { 10662306a36Sopenharmony_ci 1150000, 1200000, 1250000, 1350000, 10762306a36Sopenharmony_ci 1600000, 1700000, 1800000, 1900000, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_ops; 11162306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_ops; 11262306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_range_ops; 11362306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck012_ops; 11462306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck345_ops; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci#define HI6421_LDO_ENABLE_TIME (350) 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * _id - LDO id name string 11962306a36Sopenharmony_ci * _match - of match name string 12062306a36Sopenharmony_ci * v_table - voltage table 12162306a36Sopenharmony_ci * vreg - voltage select register 12262306a36Sopenharmony_ci * vmask - voltage select mask 12362306a36Sopenharmony_ci * ereg - enable register 12462306a36Sopenharmony_ci * emask - enable mask 12562306a36Sopenharmony_ci * odelay - off/on delay time in uS 12662306a36Sopenharmony_ci * ecomask - eco mode mask 12762306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_ci#define HI6421_LDO(_id, _match, v_table, vreg, vmask, ereg, emask, \ 13062306a36Sopenharmony_ci odelay, ecomask, ecoamp) \ 13162306a36Sopenharmony_ci [HI6421_##_id] = { \ 13262306a36Sopenharmony_ci .desc = { \ 13362306a36Sopenharmony_ci .name = #_id, \ 13462306a36Sopenharmony_ci .of_match = #_match, \ 13562306a36Sopenharmony_ci .regulators_node = "regulators", \ 13662306a36Sopenharmony_ci .ops = &hi6421_ldo_ops, \ 13762306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 13862306a36Sopenharmony_ci .id = HI6421_##_id, \ 13962306a36Sopenharmony_ci .owner = THIS_MODULE, \ 14062306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(v_table), \ 14162306a36Sopenharmony_ci .volt_table = v_table, \ 14262306a36Sopenharmony_ci .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ 14362306a36Sopenharmony_ci .vsel_mask = vmask, \ 14462306a36Sopenharmony_ci .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ 14562306a36Sopenharmony_ci .enable_mask = emask, \ 14662306a36Sopenharmony_ci .enable_time = HI6421_LDO_ENABLE_TIME, \ 14762306a36Sopenharmony_ci .off_on_delay = odelay, \ 14862306a36Sopenharmony_ci }, \ 14962306a36Sopenharmony_ci .mode_mask = ecomask, \ 15062306a36Sopenharmony_ci .eco_microamp = ecoamp, \ 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* HI6421 LDO1~3 are linear voltage regulators at fixed uV_step 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * _id - LDO id name string 15662306a36Sopenharmony_ci * _match - of match name string 15762306a36Sopenharmony_ci * _min_uV - minimum voltage supported in uV 15862306a36Sopenharmony_ci * n_volt - number of votages available 15962306a36Sopenharmony_ci * vstep - voltage increase in each linear step in uV 16062306a36Sopenharmony_ci * vreg - voltage select register 16162306a36Sopenharmony_ci * vmask - voltage select mask 16262306a36Sopenharmony_ci * ereg - enable register 16362306a36Sopenharmony_ci * emask - enable mask 16462306a36Sopenharmony_ci * odelay - off/on delay time in uS 16562306a36Sopenharmony_ci * ecomask - eco mode mask 16662306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci#define HI6421_LDO_LINEAR(_id, _match, _min_uV, n_volt, vstep, vreg, vmask,\ 16962306a36Sopenharmony_ci ereg, emask, odelay, ecomask, ecoamp) \ 17062306a36Sopenharmony_ci [HI6421_##_id] = { \ 17162306a36Sopenharmony_ci .desc = { \ 17262306a36Sopenharmony_ci .name = #_id, \ 17362306a36Sopenharmony_ci .of_match = #_match, \ 17462306a36Sopenharmony_ci .regulators_node = "regulators", \ 17562306a36Sopenharmony_ci .ops = &hi6421_ldo_linear_ops, \ 17662306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 17762306a36Sopenharmony_ci .id = HI6421_##_id, \ 17862306a36Sopenharmony_ci .owner = THIS_MODULE, \ 17962306a36Sopenharmony_ci .min_uV = _min_uV, \ 18062306a36Sopenharmony_ci .n_voltages = n_volt, \ 18162306a36Sopenharmony_ci .uV_step = vstep, \ 18262306a36Sopenharmony_ci .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ 18362306a36Sopenharmony_ci .vsel_mask = vmask, \ 18462306a36Sopenharmony_ci .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ 18562306a36Sopenharmony_ci .enable_mask = emask, \ 18662306a36Sopenharmony_ci .enable_time = HI6421_LDO_ENABLE_TIME, \ 18762306a36Sopenharmony_ci .off_on_delay = odelay, \ 18862306a36Sopenharmony_ci }, \ 18962306a36Sopenharmony_ci .mode_mask = ecomask, \ 19062306a36Sopenharmony_ci .eco_microamp = ecoamp, \ 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* HI6421 LDOAUDIO is a linear voltage regulator with two 4-step ranges 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * _id - LDO id name string 19662306a36Sopenharmony_ci * _match - of match name string 19762306a36Sopenharmony_ci * n_volt - number of votages available 19862306a36Sopenharmony_ci * volt_ranges - array of linear_range 19962306a36Sopenharmony_ci * vstep - voltage increase in each linear step in uV 20062306a36Sopenharmony_ci * vreg - voltage select register 20162306a36Sopenharmony_ci * vmask - voltage select mask 20262306a36Sopenharmony_ci * ereg - enable register 20362306a36Sopenharmony_ci * emask - enable mask 20462306a36Sopenharmony_ci * odelay - off/on delay time in uS 20562306a36Sopenharmony_ci * ecomask - eco mode mask 20662306a36Sopenharmony_ci * ecoamp - eco mode load uppler limit in uA 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci#define HI6421_LDO_LINEAR_RANGE(_id, _match, n_volt, volt_ranges, vreg, vmask,\ 20962306a36Sopenharmony_ci ereg, emask, odelay, ecomask, ecoamp) \ 21062306a36Sopenharmony_ci [HI6421_##_id] = { \ 21162306a36Sopenharmony_ci .desc = { \ 21262306a36Sopenharmony_ci .name = #_id, \ 21362306a36Sopenharmony_ci .of_match = #_match, \ 21462306a36Sopenharmony_ci .regulators_node = "regulators", \ 21562306a36Sopenharmony_ci .ops = &hi6421_ldo_linear_range_ops, \ 21662306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 21762306a36Sopenharmony_ci .id = HI6421_##_id, \ 21862306a36Sopenharmony_ci .owner = THIS_MODULE, \ 21962306a36Sopenharmony_ci .n_voltages = n_volt, \ 22062306a36Sopenharmony_ci .linear_ranges = volt_ranges, \ 22162306a36Sopenharmony_ci .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ 22262306a36Sopenharmony_ci .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ 22362306a36Sopenharmony_ci .vsel_mask = vmask, \ 22462306a36Sopenharmony_ci .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ 22562306a36Sopenharmony_ci .enable_mask = emask, \ 22662306a36Sopenharmony_ci .enable_time = HI6421_LDO_ENABLE_TIME, \ 22762306a36Sopenharmony_ci .off_on_delay = odelay, \ 22862306a36Sopenharmony_ci }, \ 22962306a36Sopenharmony_ci .mode_mask = ecomask, \ 23062306a36Sopenharmony_ci .eco_microamp = ecoamp, \ 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* HI6421 BUCK0/1/2 are linear voltage regulators at fixed uV_step 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * _id - BUCK0/1/2 id name string 23662306a36Sopenharmony_ci * _match - of match name string 23762306a36Sopenharmony_ci * vreg - voltage select register 23862306a36Sopenharmony_ci * vmask - voltage select mask 23962306a36Sopenharmony_ci * ereg - enable register 24062306a36Sopenharmony_ci * emask - enable mask 24162306a36Sopenharmony_ci * sleepmask - mask of sleep mode 24262306a36Sopenharmony_ci * etime - enable time 24362306a36Sopenharmony_ci * odelay - off/on delay time in uS 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci#define HI6421_BUCK012(_id, _match, vreg, vmask, ereg, emask, sleepmask,\ 24662306a36Sopenharmony_ci etime, odelay) \ 24762306a36Sopenharmony_ci [HI6421_##_id] = { \ 24862306a36Sopenharmony_ci .desc = { \ 24962306a36Sopenharmony_ci .name = #_id, \ 25062306a36Sopenharmony_ci .of_match = #_match, \ 25162306a36Sopenharmony_ci .regulators_node = "regulators", \ 25262306a36Sopenharmony_ci .ops = &hi6421_buck012_ops, \ 25362306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 25462306a36Sopenharmony_ci .id = HI6421_##_id, \ 25562306a36Sopenharmony_ci .owner = THIS_MODULE, \ 25662306a36Sopenharmony_ci .min_uV = 700000, \ 25762306a36Sopenharmony_ci .n_voltages = 128, \ 25862306a36Sopenharmony_ci .uV_step = 7086, \ 25962306a36Sopenharmony_ci .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ 26062306a36Sopenharmony_ci .vsel_mask = vmask, \ 26162306a36Sopenharmony_ci .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ 26262306a36Sopenharmony_ci .enable_mask = emask, \ 26362306a36Sopenharmony_ci .enable_time = etime, \ 26462306a36Sopenharmony_ci .off_on_delay = odelay, \ 26562306a36Sopenharmony_ci }, \ 26662306a36Sopenharmony_ci .mode_mask = sleepmask, \ 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* HI6421 BUCK3/4/5 share similar configurations as LDOs, with exception 27062306a36Sopenharmony_ci * that it supports SLEEP mode, so has different .ops. 27162306a36Sopenharmony_ci * 27262306a36Sopenharmony_ci * _id - LDO id name string 27362306a36Sopenharmony_ci * _match - of match name string 27462306a36Sopenharmony_ci * v_table - voltage table 27562306a36Sopenharmony_ci * vreg - voltage select register 27662306a36Sopenharmony_ci * vmask - voltage select mask 27762306a36Sopenharmony_ci * ereg - enable register 27862306a36Sopenharmony_ci * emask - enable mask 27962306a36Sopenharmony_ci * odelay - off/on delay time in uS 28062306a36Sopenharmony_ci * sleepmask - mask of sleep mode 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci#define HI6421_BUCK345(_id, _match, v_table, vreg, vmask, ereg, emask, \ 28362306a36Sopenharmony_ci odelay, sleepmask) \ 28462306a36Sopenharmony_ci [HI6421_##_id] = { \ 28562306a36Sopenharmony_ci .desc = { \ 28662306a36Sopenharmony_ci .name = #_id, \ 28762306a36Sopenharmony_ci .of_match = #_match, \ 28862306a36Sopenharmony_ci .regulators_node = "regulators", \ 28962306a36Sopenharmony_ci .ops = &hi6421_buck345_ops, \ 29062306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 29162306a36Sopenharmony_ci .id = HI6421_##_id, \ 29262306a36Sopenharmony_ci .owner = THIS_MODULE, \ 29362306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(v_table), \ 29462306a36Sopenharmony_ci .volt_table = v_table, \ 29562306a36Sopenharmony_ci .vsel_reg = HI6421_REG_TO_BUS_ADDR(vreg), \ 29662306a36Sopenharmony_ci .vsel_mask = vmask, \ 29762306a36Sopenharmony_ci .enable_reg = HI6421_REG_TO_BUS_ADDR(ereg), \ 29862306a36Sopenharmony_ci .enable_mask = emask, \ 29962306a36Sopenharmony_ci .enable_time = HI6421_LDO_ENABLE_TIME, \ 30062306a36Sopenharmony_ci .off_on_delay = odelay, \ 30162306a36Sopenharmony_ci }, \ 30262306a36Sopenharmony_ci .mode_mask = sleepmask, \ 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/* HI6421 regulator information */ 30662306a36Sopenharmony_cistatic struct hi6421_regulator_info 30762306a36Sopenharmony_ci hi6421_regulator_info[HI6421_NUM_REGULATORS] = { 30862306a36Sopenharmony_ci HI6421_LDO(LDO0, hi6421_vout0, ldo_0_voltages, 0x20, 0x07, 0x20, 0x10, 30962306a36Sopenharmony_ci 10000, 0x20, 8000), 31062306a36Sopenharmony_ci HI6421_LDO_LINEAR(LDO1, hi6421_vout1, 1700000, 4, 100000, 0x21, 0x03, 31162306a36Sopenharmony_ci 0x21, 0x10, 10000, 0x20, 5000), 31262306a36Sopenharmony_ci HI6421_LDO_LINEAR(LDO2, hi6421_vout2, 1050000, 8, 50000, 0x22, 0x07, 31362306a36Sopenharmony_ci 0x22, 0x10, 20000, 0x20, 8000), 31462306a36Sopenharmony_ci HI6421_LDO_LINEAR(LDO3, hi6421_vout3, 1050000, 8, 50000, 0x23, 0x07, 31562306a36Sopenharmony_ci 0x23, 0x10, 20000, 0x20, 8000), 31662306a36Sopenharmony_ci HI6421_LDO(LDO4, hi6421_vout4, ldo_0_voltages, 0x24, 0x07, 0x24, 0x10, 31762306a36Sopenharmony_ci 20000, 0x20, 8000), 31862306a36Sopenharmony_ci HI6421_LDO(LDO5, hi6421_vout5, ldo_0_voltages, 0x25, 0x07, 0x25, 0x10, 31962306a36Sopenharmony_ci 20000, 0x20, 8000), 32062306a36Sopenharmony_ci HI6421_LDO(LDO6, hi6421_vout6, ldo_0_voltages, 0x26, 0x07, 0x26, 0x10, 32162306a36Sopenharmony_ci 20000, 0x20, 8000), 32262306a36Sopenharmony_ci HI6421_LDO(LDO7, hi6421_vout7, ldo_0_voltages, 0x27, 0x07, 0x27, 0x10, 32362306a36Sopenharmony_ci 20000, 0x20, 5000), 32462306a36Sopenharmony_ci HI6421_LDO(LDO8, hi6421_vout8, ldo_8_voltages, 0x28, 0x07, 0x28, 0x10, 32562306a36Sopenharmony_ci 20000, 0x20, 8000), 32662306a36Sopenharmony_ci HI6421_LDO(LDO9, hi6421_vout9, ldo_0_voltages, 0x29, 0x07, 0x29, 0x10, 32762306a36Sopenharmony_ci 40000, 0x20, 8000), 32862306a36Sopenharmony_ci HI6421_LDO(LDO10, hi6421_vout10, ldo_0_voltages, 0x2a, 0x07, 0x2a, 0x10, 32962306a36Sopenharmony_ci 40000, 0x20, 8000), 33062306a36Sopenharmony_ci HI6421_LDO(LDO11, hi6421_vout11, ldo_0_voltages, 0x2b, 0x07, 0x2b, 0x10, 33162306a36Sopenharmony_ci 40000, 0x20, 8000), 33262306a36Sopenharmony_ci HI6421_LDO(LDO12, hi6421_vout12, ldo_0_voltages, 0x2c, 0x07, 0x2c, 0x10, 33362306a36Sopenharmony_ci 40000, 0x20, 8000), 33462306a36Sopenharmony_ci HI6421_LDO(LDO13, hi6421_vout13, ldo_0_voltages, 0x2d, 0x07, 0x2d, 0x10, 33562306a36Sopenharmony_ci 40000, 0x20, 8000), 33662306a36Sopenharmony_ci HI6421_LDO(LDO14, hi6421_vout14, ldo_0_voltages, 0x2e, 0x07, 0x2e, 0x10, 33762306a36Sopenharmony_ci 40000, 0x20, 8000), 33862306a36Sopenharmony_ci HI6421_LDO(LDO15, hi6421_vout15, ldo_8_voltages, 0x2f, 0x07, 0x2f, 0x10, 33962306a36Sopenharmony_ci 40000, 0x20, 8000), 34062306a36Sopenharmony_ci HI6421_LDO(LDO16, hi6421_vout16, ldo_0_voltages, 0x30, 0x07, 0x30, 0x10, 34162306a36Sopenharmony_ci 40000, 0x20, 8000), 34262306a36Sopenharmony_ci HI6421_LDO(LDO17, hi6421_vout17, ldo_0_voltages, 0x31, 0x07, 0x31, 0x10, 34362306a36Sopenharmony_ci 40000, 0x20, 8000), 34462306a36Sopenharmony_ci HI6421_LDO(LDO18, hi6421_vout18, ldo_0_voltages, 0x32, 0x07, 0x32, 0x10, 34562306a36Sopenharmony_ci 40000, 0x20, 8000), 34662306a36Sopenharmony_ci HI6421_LDO(LDO19, hi6421_vout19, ldo_0_voltages, 0x33, 0x07, 0x33, 0x10, 34762306a36Sopenharmony_ci 40000, 0x20, 8000), 34862306a36Sopenharmony_ci HI6421_LDO(LDO20, hi6421_vout20, ldo_0_voltages, 0x34, 0x07, 0x34, 0x10, 34962306a36Sopenharmony_ci 40000, 0x20, 8000), 35062306a36Sopenharmony_ci HI6421_LDO_LINEAR_RANGE(LDOAUDIO, hi6421_vout_audio, 8, 35162306a36Sopenharmony_ci ldo_audio_volt_range, 0x36, 0x70, 0x36, 0x01, 35262306a36Sopenharmony_ci 40000, 0x02, 5000), 35362306a36Sopenharmony_ci HI6421_BUCK012(BUCK0, hi6421_buck0, 0x0d, 0x7f, 0x0c, 0x01, 0x10, 400, 35462306a36Sopenharmony_ci 20000), 35562306a36Sopenharmony_ci HI6421_BUCK012(BUCK1, hi6421_buck1, 0x0f, 0x7f, 0x0e, 0x01, 0x10, 400, 35662306a36Sopenharmony_ci 20000), 35762306a36Sopenharmony_ci HI6421_BUCK012(BUCK2, hi6421_buck2, 0x11, 0x7f, 0x10, 0x01, 0x10, 350, 35862306a36Sopenharmony_ci 100), 35962306a36Sopenharmony_ci HI6421_BUCK345(BUCK3, hi6421_buck3, buck_3_voltages, 0x13, 0x07, 0x12, 36062306a36Sopenharmony_ci 0x01, 20000, 0x10), 36162306a36Sopenharmony_ci HI6421_BUCK345(BUCK4, hi6421_buck4, buck_4_voltages, 0x15, 0x07, 0x14, 36262306a36Sopenharmony_ci 0x01, 20000, 0x10), 36362306a36Sopenharmony_ci HI6421_BUCK345(BUCK5, hi6421_buck5, buck_5_voltages, 0x17, 0x07, 0x16, 36462306a36Sopenharmony_ci 0x01, 20000, 0x10), 36562306a36Sopenharmony_ci}; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_cistatic int hi6421_regulator_enable(struct regulator_dev *rdev) 36862306a36Sopenharmony_ci{ 36962306a36Sopenharmony_ci struct hi6421_regulator_pdata *pdata = rdev_get_drvdata(rdev); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* hi6421 spec requires regulator enablement must be serialized: 37262306a36Sopenharmony_ci * - Because when BUCK, LDO switching from off to on, it will have 37362306a36Sopenharmony_ci * a huge instantaneous current; so you can not turn on two or 37462306a36Sopenharmony_ci * more LDO or BUCKs simultaneously, or it may burn the chip. 37562306a36Sopenharmony_ci */ 37662306a36Sopenharmony_ci mutex_lock(&pdata->lock); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci /* call regulator regmap helper */ 37962306a36Sopenharmony_ci regulator_enable_regmap(rdev); 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci mutex_unlock(&pdata->lock); 38262306a36Sopenharmony_ci return 0; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic unsigned int hi6421_regulator_ldo_get_mode(struct regulator_dev *rdev) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci struct hi6421_regulator_info *info; 38862306a36Sopenharmony_ci unsigned int reg_val; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci info = container_of(rdev->desc, struct hi6421_regulator_info, desc); 39162306a36Sopenharmony_ci regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); 39262306a36Sopenharmony_ci if (reg_val & info->mode_mask) 39362306a36Sopenharmony_ci return REGULATOR_MODE_IDLE; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic unsigned int hi6421_regulator_buck_get_mode(struct regulator_dev *rdev) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct hi6421_regulator_info *info; 40162306a36Sopenharmony_ci unsigned int reg_val; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci info = container_of(rdev->desc, struct hi6421_regulator_info, desc); 40462306a36Sopenharmony_ci regmap_read(rdev->regmap, rdev->desc->enable_reg, ®_val); 40562306a36Sopenharmony_ci if (reg_val & info->mode_mask) 40662306a36Sopenharmony_ci return REGULATOR_MODE_STANDBY; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int hi6421_regulator_ldo_set_mode(struct regulator_dev *rdev, 41262306a36Sopenharmony_ci unsigned int mode) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct hi6421_regulator_info *info; 41562306a36Sopenharmony_ci unsigned int new_mode; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci info = container_of(rdev->desc, struct hi6421_regulator_info, desc); 41862306a36Sopenharmony_ci switch (mode) { 41962306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 42062306a36Sopenharmony_ci new_mode = 0; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case REGULATOR_MODE_IDLE: 42362306a36Sopenharmony_ci new_mode = info->mode_mask; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci default: 42662306a36Sopenharmony_ci return -EINVAL; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* set mode */ 43062306a36Sopenharmony_ci regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 43162306a36Sopenharmony_ci info->mode_mask, new_mode); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return 0; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int hi6421_regulator_buck_set_mode(struct regulator_dev *rdev, 43762306a36Sopenharmony_ci unsigned int mode) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct hi6421_regulator_info *info; 44062306a36Sopenharmony_ci unsigned int new_mode; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci info = container_of(rdev->desc, struct hi6421_regulator_info, desc); 44362306a36Sopenharmony_ci switch (mode) { 44462306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 44562306a36Sopenharmony_ci new_mode = 0; 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 44862306a36Sopenharmony_ci new_mode = info->mode_mask; 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci default: 45162306a36Sopenharmony_ci return -EINVAL; 45262306a36Sopenharmony_ci } 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* set mode */ 45562306a36Sopenharmony_ci regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 45662306a36Sopenharmony_ci info->mode_mask, new_mode); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic unsigned int 46262306a36Sopenharmony_cihi6421_regulator_ldo_get_optimum_mode(struct regulator_dev *rdev, 46362306a36Sopenharmony_ci int input_uV, int output_uV, int load_uA) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci struct hi6421_regulator_info *info; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci info = container_of(rdev->desc, struct hi6421_regulator_info, desc); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (load_uA > info->eco_microamp) 47062306a36Sopenharmony_ci return REGULATOR_MODE_NORMAL; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return REGULATOR_MODE_IDLE; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_ops = { 47662306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 47762306a36Sopenharmony_ci .enable = hi6421_regulator_enable, 47862306a36Sopenharmony_ci .disable = regulator_disable_regmap, 47962306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 48062306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 48162306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 48262306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 48362306a36Sopenharmony_ci .get_mode = hi6421_regulator_ldo_get_mode, 48462306a36Sopenharmony_ci .set_mode = hi6421_regulator_ldo_set_mode, 48562306a36Sopenharmony_ci .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, 48662306a36Sopenharmony_ci}; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_ops = { 48962306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 49062306a36Sopenharmony_ci .enable = hi6421_regulator_enable, 49162306a36Sopenharmony_ci .disable = regulator_disable_regmap, 49262306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 49362306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 49462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 49562306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 49662306a36Sopenharmony_ci .get_mode = hi6421_regulator_ldo_get_mode, 49762306a36Sopenharmony_ci .set_mode = hi6421_regulator_ldo_set_mode, 49862306a36Sopenharmony_ci .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic const struct regulator_ops hi6421_ldo_linear_range_ops = { 50262306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 50362306a36Sopenharmony_ci .enable = hi6421_regulator_enable, 50462306a36Sopenharmony_ci .disable = regulator_disable_regmap, 50562306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 50662306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear_range, 50762306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 50862306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 50962306a36Sopenharmony_ci .get_mode = hi6421_regulator_ldo_get_mode, 51062306a36Sopenharmony_ci .set_mode = hi6421_regulator_ldo_set_mode, 51162306a36Sopenharmony_ci .get_optimum_mode = hi6421_regulator_ldo_get_optimum_mode, 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck012_ops = { 51562306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 51662306a36Sopenharmony_ci .enable = hi6421_regulator_enable, 51762306a36Sopenharmony_ci .disable = regulator_disable_regmap, 51862306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 51962306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 52062306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 52162306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 52262306a36Sopenharmony_ci .get_mode = hi6421_regulator_buck_get_mode, 52362306a36Sopenharmony_ci .set_mode = hi6421_regulator_buck_set_mode, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic const struct regulator_ops hi6421_buck345_ops = { 52762306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 52862306a36Sopenharmony_ci .enable = hi6421_regulator_enable, 52962306a36Sopenharmony_ci .disable = regulator_disable_regmap, 53062306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 53162306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 53262306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 53362306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 53462306a36Sopenharmony_ci .get_mode = hi6421_regulator_buck_get_mode, 53562306a36Sopenharmony_ci .set_mode = hi6421_regulator_buck_set_mode, 53662306a36Sopenharmony_ci}; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic int hi6421_regulator_probe(struct platform_device *pdev) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct hi6421_pmic *pmic = dev_get_drvdata(pdev->dev.parent); 54162306a36Sopenharmony_ci struct hi6421_regulator_pdata *pdata; 54262306a36Sopenharmony_ci struct hi6421_regulator_info *info; 54362306a36Sopenharmony_ci struct regulator_config config = { }; 54462306a36Sopenharmony_ci struct regulator_dev *rdev; 54562306a36Sopenharmony_ci int i; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); 54862306a36Sopenharmony_ci if (!pdata) 54962306a36Sopenharmony_ci return -ENOMEM; 55062306a36Sopenharmony_ci mutex_init(&pdata->lock); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hi6421_regulator_info); i++) { 55362306a36Sopenharmony_ci /* assign per-regulator data */ 55462306a36Sopenharmony_ci info = &hi6421_regulator_info[i]; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci config.dev = pdev->dev.parent; 55762306a36Sopenharmony_ci config.driver_data = pdata; 55862306a36Sopenharmony_ci config.regmap = pmic->regmap; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, &info->desc, 56162306a36Sopenharmony_ci &config); 56262306a36Sopenharmony_ci if (IS_ERR(rdev)) { 56362306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register regulator %s\n", 56462306a36Sopenharmony_ci info->desc.name); 56562306a36Sopenharmony_ci return PTR_ERR(rdev); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cistatic const struct platform_device_id hi6421_regulator_table[] = { 57362306a36Sopenharmony_ci { .name = "hi6421-regulator" }, 57462306a36Sopenharmony_ci {}, 57562306a36Sopenharmony_ci}; 57662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, hi6421_regulator_table); 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic struct platform_driver hi6421_regulator_driver = { 57962306a36Sopenharmony_ci .id_table = hi6421_regulator_table, 58062306a36Sopenharmony_ci .driver = { 58162306a36Sopenharmony_ci .name = "hi6421-regulator", 58262306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 58362306a36Sopenharmony_ci }, 58462306a36Sopenharmony_ci .probe = hi6421_regulator_probe, 58562306a36Sopenharmony_ci}; 58662306a36Sopenharmony_cimodule_platform_driver(hi6421_regulator_driver); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ciMODULE_AUTHOR("Guodong Xu <guodong.xu@linaro.org>"); 58962306a36Sopenharmony_ciMODULE_DESCRIPTION("Hi6421 regulator driver"); 59062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 591