162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// max77802.c - Regulator driver for the Maxim 77802 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2013-2014 Google, Inc 662306a36Sopenharmony_ci// Simon Glass <sjg@chromium.org> 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Copyright (C) 2012 Samsung Electronics 962306a36Sopenharmony_ci// Chiwoong Byun <woong.byun@samsung.com> 1062306a36Sopenharmony_ci// Jonghwa Lee <jonghwa3.lee@samsung.com> 1162306a36Sopenharmony_ci// 1262306a36Sopenharmony_ci// This driver is based on max8997.c 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/bug.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/regulator/driver.h> 2162306a36Sopenharmony_ci#include <linux/regulator/machine.h> 2262306a36Sopenharmony_ci#include <linux/regulator/of_regulator.h> 2362306a36Sopenharmony_ci#include <linux/mfd/max77686.h> 2462306a36Sopenharmony_ci#include <linux/mfd/max77686-private.h> 2562306a36Sopenharmony_ci#include <dt-bindings/regulator/maxim,max77802.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* Default ramp delay in case it is not manually set */ 2862306a36Sopenharmony_ci#define MAX77802_RAMP_DELAY 100000 /* uV/us */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define MAX77802_OPMODE_SHIFT_LDO 6 3162306a36Sopenharmony_ci#define MAX77802_OPMODE_BUCK234_SHIFT 4 3262306a36Sopenharmony_ci#define MAX77802_OPMODE_MASK 0x3 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define MAX77802_VSEL_MASK 0x3F 3562306a36Sopenharmony_ci#define MAX77802_DVS_VSEL_MASK 0xFF 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define MAX77802_RAMP_RATE_MASK_2BIT 0xC0 3862306a36Sopenharmony_ci#define MAX77802_RAMP_RATE_SHIFT_2BIT 6 3962306a36Sopenharmony_ci#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0 4062306a36Sopenharmony_ci#define MAX77802_RAMP_RATE_SHIFT_4BIT 4 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define MAX77802_STATUS_OFF 0x0 4362306a36Sopenharmony_ci#define MAX77802_OFF_PWRREQ 0x1 4462306a36Sopenharmony_ci#define MAX77802_LP_PWRREQ 0x2 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const unsigned int max77802_buck234_ramp_table[] = { 4762306a36Sopenharmony_ci 12500, 4862306a36Sopenharmony_ci 25000, 4962306a36Sopenharmony_ci 50000, 5062306a36Sopenharmony_ci 100000, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic const unsigned int max77802_buck16_ramp_table[] = { 5462306a36Sopenharmony_ci 1000, 2000, 3030, 4000, 5562306a36Sopenharmony_ci 5000, 5880, 7140, 8330, 5662306a36Sopenharmony_ci 9090, 10000, 11110, 12500, 5762306a36Sopenharmony_ci 16670, 25000, 50000, 100000, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistruct max77802_regulator_prv { 6162306a36Sopenharmony_ci /* Array indexed by regulator id */ 6262306a36Sopenharmony_ci unsigned int opmode[MAX77802_REG_MAX]; 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic inline unsigned int max77802_map_mode(unsigned int mode) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci return mode == MAX77802_OPMODE_NORMAL ? 6862306a36Sopenharmony_ci REGULATOR_MODE_NORMAL : REGULATOR_MODE_STANDBY; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic int max77802_get_opmode_shift(int id) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 && 7462306a36Sopenharmony_ci id <= MAX77802_BUCK10)) 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (id >= MAX77802_BUCK2 && id <= MAX77802_BUCK4) 7862306a36Sopenharmony_ci return MAX77802_OPMODE_BUCK234_SHIFT; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (id >= MAX77802_LDO1 && id <= MAX77802_LDO35) 8162306a36Sopenharmony_ci return MAX77802_OPMODE_SHIFT_LDO; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return -EINVAL; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/** 8762306a36Sopenharmony_ci * max77802_set_suspend_disable - Disable the regulator during system suspend 8862306a36Sopenharmony_ci * @rdev: regulator to mark as disabled 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * All regulators expect LDO 1, 3, 20 and 21 support OFF by PWRREQ. 9162306a36Sopenharmony_ci * Configure the regulator so the PMIC will turn it OFF during system suspend. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_cistatic int max77802_set_suspend_disable(struct regulator_dev *rdev) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci unsigned int val = MAX77802_OFF_PWRREQ; 9662306a36Sopenharmony_ci struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); 9762306a36Sopenharmony_ci unsigned int id = rdev_get_id(rdev); 9862306a36Sopenharmony_ci int shift = max77802_get_opmode_shift(id); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) 10162306a36Sopenharmony_ci return -EINVAL; 10262306a36Sopenharmony_ci max77802->opmode[id] = val; 10362306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 10462306a36Sopenharmony_ci rdev->desc->enable_mask, val << shift); 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Some LDOs support Low Power Mode while the system is running. 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * LDOs 1, 3, 20, 21. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_cistatic int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); 11562306a36Sopenharmony_ci unsigned int id = rdev_get_id(rdev); 11662306a36Sopenharmony_ci unsigned int val; 11762306a36Sopenharmony_ci int shift = max77802_get_opmode_shift(id); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci switch (mode) { 12062306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 12162306a36Sopenharmony_ci val = MAX77802_OPMODE_LP; /* ON in Low Power Mode */ 12262306a36Sopenharmony_ci break; 12362306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 12462306a36Sopenharmony_ci val = MAX77802_OPMODE_NORMAL; /* ON in Normal Mode */ 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci default: 12762306a36Sopenharmony_ci dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", 12862306a36Sopenharmony_ci rdev->desc->name, mode); 12962306a36Sopenharmony_ci return -EINVAL; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) 13362306a36Sopenharmony_ci return -EINVAL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci max77802->opmode[id] = val; 13662306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 13762306a36Sopenharmony_ci rdev->desc->enable_mask, val << shift); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic unsigned max77802_get_mode(struct regulator_dev *rdev) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); 14362306a36Sopenharmony_ci unsigned int id = rdev_get_id(rdev); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci return max77802_map_mode(max77802->opmode[id]); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/** 15162306a36Sopenharmony_ci * max77802_set_suspend_mode - set regulator opmode when the system is suspended 15262306a36Sopenharmony_ci * @rdev: regulator to change mode 15362306a36Sopenharmony_ci * @mode: operating mode to be set 15462306a36Sopenharmony_ci * 15562306a36Sopenharmony_ci * Will set the operating mode for the regulators during system suspend. 15662306a36Sopenharmony_ci * This function is valid for the three different enable control logics: 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Enable Control Logic1 by PWRREQ (BUCK 2-4 and LDOs 2, 4-19, 22-35) 15962306a36Sopenharmony_ci * Enable Control Logic2 by PWRREQ (LDOs 1, 20, 21) 16062306a36Sopenharmony_ci * Enable Control Logic3 by PWRREQ (LDO 3) 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * If setting the regulator mode fails, the function only warns but does 16362306a36Sopenharmony_ci * not return an error code to avoid the regulator core to stop setting 16462306a36Sopenharmony_ci * the operating mode for the remaining regulators. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic int max77802_set_suspend_mode(struct regulator_dev *rdev, 16762306a36Sopenharmony_ci unsigned int mode) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); 17062306a36Sopenharmony_ci unsigned int id = rdev_get_id(rdev); 17162306a36Sopenharmony_ci unsigned int val; 17262306a36Sopenharmony_ci int shift = max77802_get_opmode_shift(id); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) 17562306a36Sopenharmony_ci return -EINVAL; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* 17862306a36Sopenharmony_ci * If the regulator has been disabled for suspend 17962306a36Sopenharmony_ci * then is invalid to try setting a suspend mode. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_ci if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) { 18262306a36Sopenharmony_ci dev_warn(&rdev->dev, "%s: is disabled, mode: 0x%x not set\n", 18362306a36Sopenharmony_ci rdev->desc->name, mode); 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci switch (mode) { 18862306a36Sopenharmony_ci case REGULATOR_MODE_STANDBY: 18962306a36Sopenharmony_ci /* 19062306a36Sopenharmony_ci * If the regulator opmode is normal then enable 19162306a36Sopenharmony_ci * ON in Low Power Mode by PWRREQ. If the mode is 19262306a36Sopenharmony_ci * already Low Power then no action is required. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ci if (max77802->opmode[id] == MAX77802_OPMODE_NORMAL) 19562306a36Sopenharmony_ci val = MAX77802_LP_PWRREQ; 19662306a36Sopenharmony_ci else 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci case REGULATOR_MODE_NORMAL: 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * If the regulator operating mode is Low Power then 20262306a36Sopenharmony_ci * normal is not a valid opmode in suspend. If the 20362306a36Sopenharmony_ci * mode is already normal then no action is required. 20462306a36Sopenharmony_ci */ 20562306a36Sopenharmony_ci if (max77802->opmode[id] == MAX77802_OPMODE_LP) 20662306a36Sopenharmony_ci dev_warn(&rdev->dev, "%s: in Low Power: 0x%x invalid\n", 20762306a36Sopenharmony_ci rdev->desc->name, mode); 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci default: 21062306a36Sopenharmony_ci dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n", 21162306a36Sopenharmony_ci rdev->desc->name, mode); 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 21662306a36Sopenharmony_ci rdev->desc->enable_mask, val << shift); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int max77802_enable(struct regulator_dev *rdev) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev); 22262306a36Sopenharmony_ci unsigned int id = rdev_get_id(rdev); 22362306a36Sopenharmony_ci int shift = max77802_get_opmode_shift(id); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (WARN_ON_ONCE(id >= ARRAY_SIZE(max77802->opmode))) 22662306a36Sopenharmony_ci return -EINVAL; 22762306a36Sopenharmony_ci if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) 22862306a36Sopenharmony_ci max77802->opmode[id] = MAX77802_OPMODE_NORMAL; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, 23162306a36Sopenharmony_ci rdev->desc->enable_mask, 23262306a36Sopenharmony_ci max77802->opmode[id] << shift); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* 23662306a36Sopenharmony_ci * LDOs 2, 4-19, 22-35 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_cistatic const struct regulator_ops max77802_ldo_ops_logic1 = { 23962306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 24062306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 24162306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 24262306a36Sopenharmony_ci .enable = max77802_enable, 24362306a36Sopenharmony_ci .disable = regulator_disable_regmap, 24462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 24562306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 24662306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 24762306a36Sopenharmony_ci .set_suspend_disable = max77802_set_suspend_disable, 24862306a36Sopenharmony_ci .set_suspend_mode = max77802_set_suspend_mode, 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci/* 25262306a36Sopenharmony_ci * LDOs 1, 20, 21, 3 25362306a36Sopenharmony_ci */ 25462306a36Sopenharmony_cistatic const struct regulator_ops max77802_ldo_ops_logic2 = { 25562306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 25662306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 25762306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 25862306a36Sopenharmony_ci .enable = max77802_enable, 25962306a36Sopenharmony_ci .disable = regulator_disable_regmap, 26062306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 26162306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 26262306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 26362306a36Sopenharmony_ci .set_mode = max77802_set_mode, 26462306a36Sopenharmony_ci .get_mode = max77802_get_mode, 26562306a36Sopenharmony_ci .set_suspend_mode = max77802_set_suspend_mode, 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* BUCKS 1, 6 */ 26962306a36Sopenharmony_cistatic const struct regulator_ops max77802_buck_16_dvs_ops = { 27062306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 27162306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 27262306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 27362306a36Sopenharmony_ci .enable = max77802_enable, 27462306a36Sopenharmony_ci .disable = regulator_disable_regmap, 27562306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 27662306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 27762306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 27862306a36Sopenharmony_ci .set_ramp_delay = regulator_set_ramp_delay_regmap, 27962306a36Sopenharmony_ci .set_suspend_disable = max77802_set_suspend_disable, 28062306a36Sopenharmony_ci}; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/* BUCKs 2-4 */ 28362306a36Sopenharmony_cistatic const struct regulator_ops max77802_buck_234_ops = { 28462306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 28562306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 28662306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 28762306a36Sopenharmony_ci .enable = max77802_enable, 28862306a36Sopenharmony_ci .disable = regulator_disable_regmap, 28962306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 29062306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 29162306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 29262306a36Sopenharmony_ci .set_ramp_delay = regulator_set_ramp_delay_regmap, 29362306a36Sopenharmony_ci .set_suspend_disable = max77802_set_suspend_disable, 29462306a36Sopenharmony_ci .set_suspend_mode = max77802_set_suspend_mode, 29562306a36Sopenharmony_ci}; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* BUCKs 5, 7-10 */ 29862306a36Sopenharmony_cistatic const struct regulator_ops max77802_buck_dvs_ops = { 29962306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear, 30062306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_linear, 30162306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 30262306a36Sopenharmony_ci .enable = max77802_enable, 30362306a36Sopenharmony_ci .disable = regulator_disable_regmap, 30462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 30562306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 30662306a36Sopenharmony_ci .set_voltage_time_sel = regulator_set_voltage_time_sel, 30762306a36Sopenharmony_ci .set_suspend_disable = max77802_set_suspend_disable, 30862306a36Sopenharmony_ci}; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */ 31162306a36Sopenharmony_ci#define regulator_77802_desc_p_ldo(num, supply, log) { \ 31262306a36Sopenharmony_ci .name = "LDO"#num, \ 31362306a36Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 31462306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 31562306a36Sopenharmony_ci .id = MAX77802_LDO##num, \ 31662306a36Sopenharmony_ci .supply_name = "inl"#supply, \ 31762306a36Sopenharmony_ci .ops = &max77802_ldo_ops_logic##log, \ 31862306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 31962306a36Sopenharmony_ci .owner = THIS_MODULE, \ 32062306a36Sopenharmony_ci .min_uV = 800000, \ 32162306a36Sopenharmony_ci .uV_step = 50000, \ 32262306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 32362306a36Sopenharmony_ci .n_voltages = 1 << 6, \ 32462306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ 32562306a36Sopenharmony_ci .vsel_mask = MAX77802_VSEL_MASK, \ 32662306a36Sopenharmony_ci .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ 32762306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ 32862306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */ 33262306a36Sopenharmony_ci#define regulator_77802_desc_n_ldo(num, supply, log) { \ 33362306a36Sopenharmony_ci .name = "LDO"#num, \ 33462306a36Sopenharmony_ci .of_match = of_match_ptr("LDO"#num), \ 33562306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 33662306a36Sopenharmony_ci .id = MAX77802_LDO##num, \ 33762306a36Sopenharmony_ci .supply_name = "inl"#supply, \ 33862306a36Sopenharmony_ci .ops = &max77802_ldo_ops_logic##log, \ 33962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 34062306a36Sopenharmony_ci .owner = THIS_MODULE, \ 34162306a36Sopenharmony_ci .min_uV = 800000, \ 34262306a36Sopenharmony_ci .uV_step = 25000, \ 34362306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 34462306a36Sopenharmony_ci .n_voltages = 1 << 6, \ 34562306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ 34662306a36Sopenharmony_ci .vsel_mask = MAX77802_VSEL_MASK, \ 34762306a36Sopenharmony_ci .enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \ 34862306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \ 34962306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* BUCKs 1, 6 */ 35362306a36Sopenharmony_ci#define regulator_77802_desc_16_buck(num) { \ 35462306a36Sopenharmony_ci .name = "BUCK"#num, \ 35562306a36Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 35662306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 35762306a36Sopenharmony_ci .id = MAX77802_BUCK##num, \ 35862306a36Sopenharmony_ci .supply_name = "inb"#num, \ 35962306a36Sopenharmony_ci .ops = &max77802_buck_16_dvs_ops, \ 36062306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 36162306a36Sopenharmony_ci .owner = THIS_MODULE, \ 36262306a36Sopenharmony_ci .min_uV = 612500, \ 36362306a36Sopenharmony_ci .uV_step = 6250, \ 36462306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 36562306a36Sopenharmony_ci .n_voltages = 1 << 8, \ 36662306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ 36762306a36Sopenharmony_ci .vsel_mask = MAX77802_DVS_VSEL_MASK, \ 36862306a36Sopenharmony_ci .enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \ 36962306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK, \ 37062306a36Sopenharmony_ci .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL, \ 37162306a36Sopenharmony_ci .ramp_mask = MAX77802_RAMP_RATE_MASK_4BIT, \ 37262306a36Sopenharmony_ci .ramp_delay_table = max77802_buck16_ramp_table, \ 37362306a36Sopenharmony_ci .n_ramp_values = ARRAY_SIZE(max77802_buck16_ramp_table), \ 37462306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* BUCKS 2-4 */ 37862306a36Sopenharmony_ci#define regulator_77802_desc_234_buck(num) { \ 37962306a36Sopenharmony_ci .name = "BUCK"#num, \ 38062306a36Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 38162306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 38262306a36Sopenharmony_ci .id = MAX77802_BUCK##num, \ 38362306a36Sopenharmony_ci .supply_name = "inb"#num, \ 38462306a36Sopenharmony_ci .ops = &max77802_buck_234_ops, \ 38562306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 38662306a36Sopenharmony_ci .owner = THIS_MODULE, \ 38762306a36Sopenharmony_ci .min_uV = 600000, \ 38862306a36Sopenharmony_ci .uV_step = 6250, \ 38962306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 39062306a36Sopenharmony_ci .n_voltages = 0x91, \ 39162306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_BUCK ## num ## DVS1, \ 39262306a36Sopenharmony_ci .vsel_mask = MAX77802_DVS_VSEL_MASK, \ 39362306a36Sopenharmony_ci .enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ 39462306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK << \ 39562306a36Sopenharmony_ci MAX77802_OPMODE_BUCK234_SHIFT, \ 39662306a36Sopenharmony_ci .ramp_reg = MAX77802_REG_BUCK ## num ## CTRL1, \ 39762306a36Sopenharmony_ci .ramp_mask = MAX77802_RAMP_RATE_MASK_2BIT, \ 39862306a36Sopenharmony_ci .ramp_delay_table = max77802_buck234_ramp_table, \ 39962306a36Sopenharmony_ci .n_ramp_values = ARRAY_SIZE(max77802_buck234_ramp_table), \ 40062306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/* BUCK 5 */ 40462306a36Sopenharmony_ci#define regulator_77802_desc_buck5(num) { \ 40562306a36Sopenharmony_ci .name = "BUCK"#num, \ 40662306a36Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 40762306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 40862306a36Sopenharmony_ci .id = MAX77802_BUCK##num, \ 40962306a36Sopenharmony_ci .supply_name = "inb"#num, \ 41062306a36Sopenharmony_ci .ops = &max77802_buck_dvs_ops, \ 41162306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 41262306a36Sopenharmony_ci .owner = THIS_MODULE, \ 41362306a36Sopenharmony_ci .min_uV = 750000, \ 41462306a36Sopenharmony_ci .uV_step = 50000, \ 41562306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 41662306a36Sopenharmony_ci .n_voltages = 1 << 6, \ 41762306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_BUCK5OUT, \ 41862306a36Sopenharmony_ci .vsel_mask = MAX77802_VSEL_MASK, \ 41962306a36Sopenharmony_ci .enable_reg = MAX77802_REG_BUCK5CTRL, \ 42062306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK, \ 42162306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci/* BUCKs 7-10 */ 42562306a36Sopenharmony_ci#define regulator_77802_desc_buck7_10(num) { \ 42662306a36Sopenharmony_ci .name = "BUCK"#num, \ 42762306a36Sopenharmony_ci .of_match = of_match_ptr("BUCK"#num), \ 42862306a36Sopenharmony_ci .regulators_node = of_match_ptr("regulators"), \ 42962306a36Sopenharmony_ci .id = MAX77802_BUCK##num, \ 43062306a36Sopenharmony_ci .supply_name = "inb"#num, \ 43162306a36Sopenharmony_ci .ops = &max77802_buck_dvs_ops, \ 43262306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 43362306a36Sopenharmony_ci .owner = THIS_MODULE, \ 43462306a36Sopenharmony_ci .min_uV = 750000, \ 43562306a36Sopenharmony_ci .uV_step = 50000, \ 43662306a36Sopenharmony_ci .ramp_delay = MAX77802_RAMP_DELAY, \ 43762306a36Sopenharmony_ci .n_voltages = 1 << 6, \ 43862306a36Sopenharmony_ci .vsel_reg = MAX77802_REG_BUCK7OUT + (num - 7) * 3, \ 43962306a36Sopenharmony_ci .vsel_mask = MAX77802_VSEL_MASK, \ 44062306a36Sopenharmony_ci .enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \ 44162306a36Sopenharmony_ci .enable_mask = MAX77802_OPMODE_MASK, \ 44262306a36Sopenharmony_ci .of_map_mode = max77802_map_mode, \ 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic const struct regulator_desc regulators[] = { 44662306a36Sopenharmony_ci regulator_77802_desc_16_buck(1), 44762306a36Sopenharmony_ci regulator_77802_desc_234_buck(2), 44862306a36Sopenharmony_ci regulator_77802_desc_234_buck(3), 44962306a36Sopenharmony_ci regulator_77802_desc_234_buck(4), 45062306a36Sopenharmony_ci regulator_77802_desc_buck5(5), 45162306a36Sopenharmony_ci regulator_77802_desc_16_buck(6), 45262306a36Sopenharmony_ci regulator_77802_desc_buck7_10(7), 45362306a36Sopenharmony_ci regulator_77802_desc_buck7_10(8), 45462306a36Sopenharmony_ci regulator_77802_desc_buck7_10(9), 45562306a36Sopenharmony_ci regulator_77802_desc_buck7_10(10), 45662306a36Sopenharmony_ci regulator_77802_desc_n_ldo(1, 10, 2), 45762306a36Sopenharmony_ci regulator_77802_desc_n_ldo(2, 10, 1), 45862306a36Sopenharmony_ci regulator_77802_desc_p_ldo(3, 3, 2), 45962306a36Sopenharmony_ci regulator_77802_desc_p_ldo(4, 6, 1), 46062306a36Sopenharmony_ci regulator_77802_desc_p_ldo(5, 3, 1), 46162306a36Sopenharmony_ci regulator_77802_desc_p_ldo(6, 3, 1), 46262306a36Sopenharmony_ci regulator_77802_desc_p_ldo(7, 3, 1), 46362306a36Sopenharmony_ci regulator_77802_desc_n_ldo(8, 1, 1), 46462306a36Sopenharmony_ci regulator_77802_desc_p_ldo(9, 5, 1), 46562306a36Sopenharmony_ci regulator_77802_desc_p_ldo(10, 4, 1), 46662306a36Sopenharmony_ci regulator_77802_desc_p_ldo(11, 4, 1), 46762306a36Sopenharmony_ci regulator_77802_desc_p_ldo(12, 9, 1), 46862306a36Sopenharmony_ci regulator_77802_desc_p_ldo(13, 4, 1), 46962306a36Sopenharmony_ci regulator_77802_desc_p_ldo(14, 4, 1), 47062306a36Sopenharmony_ci regulator_77802_desc_n_ldo(15, 1, 1), 47162306a36Sopenharmony_ci regulator_77802_desc_n_ldo(17, 2, 1), 47262306a36Sopenharmony_ci regulator_77802_desc_p_ldo(18, 7, 1), 47362306a36Sopenharmony_ci regulator_77802_desc_p_ldo(19, 5, 1), 47462306a36Sopenharmony_ci regulator_77802_desc_p_ldo(20, 7, 2), 47562306a36Sopenharmony_ci regulator_77802_desc_p_ldo(21, 6, 2), 47662306a36Sopenharmony_ci regulator_77802_desc_p_ldo(23, 9, 1), 47762306a36Sopenharmony_ci regulator_77802_desc_p_ldo(24, 6, 1), 47862306a36Sopenharmony_ci regulator_77802_desc_p_ldo(25, 9, 1), 47962306a36Sopenharmony_ci regulator_77802_desc_p_ldo(26, 9, 1), 48062306a36Sopenharmony_ci regulator_77802_desc_n_ldo(27, 2, 1), 48162306a36Sopenharmony_ci regulator_77802_desc_p_ldo(28, 7, 1), 48262306a36Sopenharmony_ci regulator_77802_desc_p_ldo(29, 7, 1), 48362306a36Sopenharmony_ci regulator_77802_desc_n_ldo(30, 2, 1), 48462306a36Sopenharmony_ci regulator_77802_desc_p_ldo(32, 9, 1), 48562306a36Sopenharmony_ci regulator_77802_desc_p_ldo(33, 6, 1), 48662306a36Sopenharmony_ci regulator_77802_desc_p_ldo(34, 9, 1), 48762306a36Sopenharmony_ci regulator_77802_desc_n_ldo(35, 2, 1), 48862306a36Sopenharmony_ci}; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int max77802_pmic_probe(struct platform_device *pdev) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent); 49362306a36Sopenharmony_ci struct max77802_regulator_prv *max77802; 49462306a36Sopenharmony_ci int i, val; 49562306a36Sopenharmony_ci struct regulator_config config = { }; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci max77802 = devm_kzalloc(&pdev->dev, 49862306a36Sopenharmony_ci sizeof(struct max77802_regulator_prv), 49962306a36Sopenharmony_ci GFP_KERNEL); 50062306a36Sopenharmony_ci if (!max77802) 50162306a36Sopenharmony_ci return -ENOMEM; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci config.dev = iodev->dev; 50462306a36Sopenharmony_ci config.regmap = iodev->regmap; 50562306a36Sopenharmony_ci config.driver_data = max77802; 50662306a36Sopenharmony_ci platform_set_drvdata(pdev, max77802); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci for (i = 0; i < MAX77802_REG_MAX; i++) { 50962306a36Sopenharmony_ci struct regulator_dev *rdev; 51062306a36Sopenharmony_ci unsigned int id = regulators[i].id; 51162306a36Sopenharmony_ci int shift = max77802_get_opmode_shift(id); 51262306a36Sopenharmony_ci int ret; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val); 51562306a36Sopenharmony_ci if (ret < 0) { 51662306a36Sopenharmony_ci dev_warn(&pdev->dev, 51762306a36Sopenharmony_ci "cannot read current mode for %d\n", i); 51862306a36Sopenharmony_ci val = MAX77802_OPMODE_NORMAL; 51962306a36Sopenharmony_ci } else { 52062306a36Sopenharmony_ci val = val >> shift & MAX77802_OPMODE_MASK; 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* 52462306a36Sopenharmony_ci * If the regulator is disabled and the system warm rebooted, 52562306a36Sopenharmony_ci * the hardware reports OFF as the regulator operating mode. 52662306a36Sopenharmony_ci * Default to operating mode NORMAL in that case. 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_ci if (id < ARRAY_SIZE(max77802->opmode)) { 52962306a36Sopenharmony_ci if (val == MAX77802_STATUS_OFF) 53062306a36Sopenharmony_ci max77802->opmode[id] = MAX77802_OPMODE_NORMAL; 53162306a36Sopenharmony_ci else 53262306a36Sopenharmony_ci max77802->opmode[id] = val; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci rdev = devm_regulator_register(&pdev->dev, 53662306a36Sopenharmony_ci ®ulators[i], &config); 53762306a36Sopenharmony_ci if (IS_ERR(rdev)) { 53862306a36Sopenharmony_ci ret = PTR_ERR(rdev); 53962306a36Sopenharmony_ci dev_err(&pdev->dev, 54062306a36Sopenharmony_ci "regulator init failed for %d: %d\n", i, ret); 54162306a36Sopenharmony_ci return ret; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic const struct platform_device_id max77802_pmic_id[] = { 54962306a36Sopenharmony_ci {"max77802-pmic", 0}, 55062306a36Sopenharmony_ci { }, 55162306a36Sopenharmony_ci}; 55262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, max77802_pmic_id); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic struct platform_driver max77802_pmic_driver = { 55562306a36Sopenharmony_ci .driver = { 55662306a36Sopenharmony_ci .name = "max77802-pmic", 55762306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 55862306a36Sopenharmony_ci }, 55962306a36Sopenharmony_ci .probe = max77802_pmic_probe, 56062306a36Sopenharmony_ci .id_table = max77802_pmic_id, 56162306a36Sopenharmony_ci}; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_cimodule_platform_driver(max77802_pmic_driver); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciMODULE_DESCRIPTION("MAXIM 77802 Regulator Driver"); 56662306a36Sopenharmony_ciMODULE_AUTHOR("Simon Glass <sjg@chromium.org>"); 56762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 568