162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 NXP 462306a36Sopenharmony_ci * Copyright (C) 2019 Boundary Devices 562306a36Sopenharmony_ci * Copyright (C) 2020 Amarula Solutions(India) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/err.h> 1062306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/regmap.h> 1462306a36Sopenharmony_ci#include <linux/regulator/driver.h> 1562306a36Sopenharmony_ci#include <linux/regulator/machine.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* registers */ 1862306a36Sopenharmony_ci#define PF8X00_DEVICEID 0x00 1962306a36Sopenharmony_ci#define PF8X00_REVID 0x01 2062306a36Sopenharmony_ci#define PF8X00_EMREV 0x02 2162306a36Sopenharmony_ci#define PF8X00_PROGID 0x03 2262306a36Sopenharmony_ci#define PF8X00_IMS_INT 0x04 2362306a36Sopenharmony_ci#define PF8X00_IMS_THERM 0x07 2462306a36Sopenharmony_ci#define PF8X00_SW_MODE_INT 0x0a 2562306a36Sopenharmony_ci#define PF8X00_SW_MODE_MASK 0x0b 2662306a36Sopenharmony_ci#define PF8X00_IMS_SW_ILIM 0x12 2762306a36Sopenharmony_ci#define PF8X00_IMS_LDO_ILIM 0x15 2862306a36Sopenharmony_ci#define PF8X00_IMS_SW_UV 0x18 2962306a36Sopenharmony_ci#define PF8X00_IMS_SW_OV 0x1b 3062306a36Sopenharmony_ci#define PF8X00_IMS_LDO_UV 0x1e 3162306a36Sopenharmony_ci#define PF8X00_IMS_LDO_OV 0x21 3262306a36Sopenharmony_ci#define PF8X00_IMS_PWRON 0x24 3362306a36Sopenharmony_ci#define PF8X00_SYS_INT 0x27 3462306a36Sopenharmony_ci#define PF8X00_HARD_FAULT 0x29 3562306a36Sopenharmony_ci#define PF8X00_FSOB_FLAGS 0x2a 3662306a36Sopenharmony_ci#define PF8X00_FSOB_SELECT 0x2b 3762306a36Sopenharmony_ci#define PF8X00_ABIST_OV1 0x2c 3862306a36Sopenharmony_ci#define PF8X00_ABIST_OV2 0x2d 3962306a36Sopenharmony_ci#define PF8X00_ABIST_UV1 0x2e 4062306a36Sopenharmony_ci#define PF8X00_ABIST_UV2 0x2f 4162306a36Sopenharmony_ci#define PF8X00_TEST_FLAGS 0x30 4262306a36Sopenharmony_ci#define PF8X00_ABIST_RUN 0x31 4362306a36Sopenharmony_ci#define PF8X00_RANDOM_GEN 0x33 4462306a36Sopenharmony_ci#define PF8X00_RANDOM_CHK 0x34 4562306a36Sopenharmony_ci#define PF8X00_VMONEN1 0x35 4662306a36Sopenharmony_ci#define PF8X00_VMONEN2 0x36 4762306a36Sopenharmony_ci#define PF8X00_CTRL1 0x37 4862306a36Sopenharmony_ci#define PF8X00_CTRL2 0x38 4962306a36Sopenharmony_ci#define PF8X00_CTRL3 0x39 5062306a36Sopenharmony_ci#define PF8X00_PWRUP_CTRL 0x3a 5162306a36Sopenharmony_ci#define PF8X00_RESETBMCU 0x3c 5262306a36Sopenharmony_ci#define PF8X00_PGOOD 0x3d 5362306a36Sopenharmony_ci#define PF8X00_PWRDN_DLY1 0x3e 5462306a36Sopenharmony_ci#define PF8X00_PWRDN_DLY2 0x3f 5562306a36Sopenharmony_ci#define PF8X00_FREQ_CTRL 0x40 5662306a36Sopenharmony_ci#define PF8X00_COINCELL_CTRL 0x41 5762306a36Sopenharmony_ci#define PF8X00_PWRON 0x42 5862306a36Sopenharmony_ci#define PF8X00_WD_CONFIG 0x43 5962306a36Sopenharmony_ci#define PF8X00_WD_CLEAR 0x44 6062306a36Sopenharmony_ci#define PF8X00_WD_EXPIRE 0x45 6162306a36Sopenharmony_ci#define PF8X00_WD_COUNTER 0x46 6262306a36Sopenharmony_ci#define PF8X00_FAULT_COUNTER 0x47 6362306a36Sopenharmony_ci#define PF8X00_FSAFE_COUNTER 0x48 6462306a36Sopenharmony_ci#define PF8X00_FAULT_TIMER 0x49 6562306a36Sopenharmony_ci#define PF8X00_AMUX 0x4a 6662306a36Sopenharmony_ci#define PF8X00_SW1_CONFIG1 0x4d 6762306a36Sopenharmony_ci#define PF8X00_LDO1_CONFIG1 0x85 6862306a36Sopenharmony_ci#define PF8X00_VSNVS_CONFIG1 0x9d 6962306a36Sopenharmony_ci#define PF8X00_PAGE_SELECT 0x9f 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* regulators */ 7262306a36Sopenharmony_cienum pf8x00_regulators { 7362306a36Sopenharmony_ci PF8X00_LDO1, 7462306a36Sopenharmony_ci PF8X00_LDO2, 7562306a36Sopenharmony_ci PF8X00_LDO3, 7662306a36Sopenharmony_ci PF8X00_LDO4, 7762306a36Sopenharmony_ci PF8X00_BUCK1, 7862306a36Sopenharmony_ci PF8X00_BUCK2, 7962306a36Sopenharmony_ci PF8X00_BUCK3, 8062306a36Sopenharmony_ci PF8X00_BUCK4, 8162306a36Sopenharmony_ci PF8X00_BUCK5, 8262306a36Sopenharmony_ci PF8X00_BUCK6, 8362306a36Sopenharmony_ci PF8X00_BUCK7, 8462306a36Sopenharmony_ci PF8X00_VSNVS, 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci PF8X00_MAX_REGULATORS, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cienum pf8x00_buck_states { 9062306a36Sopenharmony_ci SW_CONFIG1, 9162306a36Sopenharmony_ci SW_CONFIG2, 9262306a36Sopenharmony_ci SW_PWRUP, 9362306a36Sopenharmony_ci SW_MODE1, 9462306a36Sopenharmony_ci SW_RUN_VOLT, 9562306a36Sopenharmony_ci SW_STBY_VOLT, 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci#define PF8X00_SW_BASE(i) (8 * (i - PF8X00_BUCK1) + PF8X00_SW1_CONFIG1) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cienum pf8x00_ldo_states { 10062306a36Sopenharmony_ci LDO_CONFIG1, 10162306a36Sopenharmony_ci LDO_CONFIG2, 10262306a36Sopenharmony_ci LDO_PWRUP, 10362306a36Sopenharmony_ci LDO_RUN_VOLT, 10462306a36Sopenharmony_ci LDO_STBY_VOLT, 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci#define PF8X00_LDO_BASE(i) (6 * (i - PF8X00_LDO1) + PF8X00_LDO1_CONFIG1) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cienum swxilim_bits { 10962306a36Sopenharmony_ci SWXILIM_2100_MA, 11062306a36Sopenharmony_ci SWXILIM_2600_MA, 11162306a36Sopenharmony_ci SWXILIM_3000_MA, 11262306a36Sopenharmony_ci SWXILIM_4500_MA, 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci#define PF8X00_SWXILIM_SHIFT 3 11562306a36Sopenharmony_ci#define PF8X00_SWXILIM_MASK GENMASK(4, 3) 11662306a36Sopenharmony_ci#define PF8X00_SWXPHASE_MASK GENMASK(2, 0) 11762306a36Sopenharmony_ci#define PF8X00_SWXPHASE_SHIFT 7 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cienum pf8x00_devid { 12062306a36Sopenharmony_ci PF8100 = 0x0, 12162306a36Sopenharmony_ci PF8121A = BIT(1), 12262306a36Sopenharmony_ci PF8200 = BIT(3), 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci#define PF8X00_FAM BIT(6) 12562306a36Sopenharmony_ci#define PF8X00_DEVICE_FAM_MASK GENMASK(7, 4) 12662306a36Sopenharmony_ci#define PF8X00_DEVICE_ID_MASK GENMASK(3, 0) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistruct pf8x00_regulator_data { 12962306a36Sopenharmony_ci struct regulator_desc desc; 13062306a36Sopenharmony_ci unsigned int suspend_enable_reg; 13162306a36Sopenharmony_ci unsigned int suspend_enable_mask; 13262306a36Sopenharmony_ci unsigned int suspend_voltage_reg; 13362306a36Sopenharmony_ci unsigned int suspend_voltage_cache; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistruct pf8x00_chip { 13762306a36Sopenharmony_ci struct regmap *regmap; 13862306a36Sopenharmony_ci struct device *dev; 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct regmap_config pf8x00_regmap_config = { 14262306a36Sopenharmony_ci .reg_bits = 8, 14362306a36Sopenharmony_ci .val_bits = 8, 14462306a36Sopenharmony_ci .max_register = PF8X00_PAGE_SELECT, 14562306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* VLDOx output: 1.5V to 5.0V */ 14962306a36Sopenharmony_cistatic const int pf8x00_ldo_voltages[] = { 15062306a36Sopenharmony_ci 1500000, 1600000, 1800000, 1850000, 2150000, 2500000, 2800000, 3000000, 15162306a36Sopenharmony_ci 3100000, 3150000, 3200000, 3300000, 3350000, 1650000, 1700000, 5000000, 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci/* Output: 2.1A to 4.5A */ 15562306a36Sopenharmony_cistatic const unsigned int pf8x00_sw_current_table[] = { 15662306a36Sopenharmony_ci 2100000, 2600000, 3000000, 4500000, 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* Output: 0.4V to 1.8V */ 16062306a36Sopenharmony_ci#define PF8XOO_SW1_6_VOLTAGE_NUM 0xB2 16162306a36Sopenharmony_cistatic const struct linear_range pf8x00_sw1_to_6_voltages[] = { 16262306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(400000, 0x00, 0xB0, 6250), 16362306a36Sopenharmony_ci REGULATOR_LINEAR_RANGE(1800000, 0xB1, 0xB1, 0), 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* Output: 1.0V to 4.1V */ 16762306a36Sopenharmony_cistatic const int pf8x00_sw7_voltages[] = { 16862306a36Sopenharmony_ci 1000000, 1100000, 1200000, 1250000, 1300000, 1350000, 1500000, 1600000, 16962306a36Sopenharmony_ci 1800000, 1850000, 2000000, 2100000, 2150000, 2250000, 2300000, 2400000, 17062306a36Sopenharmony_ci 2500000, 2800000, 3150000, 3200000, 3250000, 3300000, 3350000, 3400000, 17162306a36Sopenharmony_ci 3500000, 3800000, 4000000, 4100000, 4100000, 4100000, 4100000, 4100000, 17262306a36Sopenharmony_ci}; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Output: 1.8V, 3.0V, or 3.3V */ 17562306a36Sopenharmony_cistatic const int pf8x00_vsnvs_voltages[] = { 17662306a36Sopenharmony_ci 0, 1800000, 3000000, 3300000, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void swxilim_select(struct pf8x00_chip *chip, int id, int ilim) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci u8 ilim_sel; 18262306a36Sopenharmony_ci u8 reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci switch (ilim) { 18562306a36Sopenharmony_ci case 2100: 18662306a36Sopenharmony_ci ilim_sel = SWXILIM_2100_MA; 18762306a36Sopenharmony_ci break; 18862306a36Sopenharmony_ci case 2600: 18962306a36Sopenharmony_ci ilim_sel = SWXILIM_2600_MA; 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci case 3000: 19262306a36Sopenharmony_ci ilim_sel = SWXILIM_3000_MA; 19362306a36Sopenharmony_ci break; 19462306a36Sopenharmony_ci case 4500: 19562306a36Sopenharmony_ci ilim_sel = SWXILIM_4500_MA; 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci default: 19862306a36Sopenharmony_ci ilim_sel = SWXILIM_2100_MA; 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci regmap_update_bits(chip->regmap, reg, 20362306a36Sopenharmony_ci PF8X00_SWXILIM_MASK, 20462306a36Sopenharmony_ci ilim_sel << PF8X00_SWXILIM_SHIFT); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void handle_ilim_property(struct device_node *np, 20862306a36Sopenharmony_ci const struct regulator_desc *desc, 20962306a36Sopenharmony_ci struct regulator_config *config) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct pf8x00_chip *chip = config->driver_data; 21262306a36Sopenharmony_ci int ret; 21362306a36Sopenharmony_ci int val; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) { 21662306a36Sopenharmony_ci ret = of_property_read_u32(np, "nxp,ilim-ma", &val); 21762306a36Sopenharmony_ci if (ret) { 21862306a36Sopenharmony_ci dev_dbg(chip->dev, "unspecified ilim for BUCK%d, use value stored in OTP\n", 21962306a36Sopenharmony_ci desc->id - PF8X00_LDO4); 22062306a36Sopenharmony_ci return; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci dev_warn(chip->dev, "nxp,ilim-ma is deprecated, please use regulator-max-microamp\n"); 22462306a36Sopenharmony_ci swxilim_select(chip, desc->id, val); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci } else 22762306a36Sopenharmony_ci dev_warn(chip->dev, "nxp,ilim-ma used with incorrect regulator (%d)\n", desc->id); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic void handle_shift_property(struct device_node *np, 23162306a36Sopenharmony_ci const struct regulator_desc *desc, 23262306a36Sopenharmony_ci struct regulator_config *config) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci unsigned char id = desc->id - PF8X00_LDO4; 23562306a36Sopenharmony_ci unsigned char reg = PF8X00_SW_BASE(id) + SW_CONFIG2; 23662306a36Sopenharmony_ci struct pf8x00_chip *chip = config->driver_data; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci int phase; 23962306a36Sopenharmony_ci int val; 24062306a36Sopenharmony_ci int ret; 24162306a36Sopenharmony_ci if ((desc->id >= PF8X00_BUCK1) && (desc->id <= PF8X00_BUCK7)) { 24262306a36Sopenharmony_ci ret = of_property_read_u32(np, "nxp,phase-shift", &val); 24362306a36Sopenharmony_ci if (ret) { 24462306a36Sopenharmony_ci dev_dbg(chip->dev, 24562306a36Sopenharmony_ci "unspecified phase-shift for BUCK%d, using OTP configuration\n", 24662306a36Sopenharmony_ci id); 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (val < 0 || val > 315 || val % 45 != 0) { 25162306a36Sopenharmony_ci dev_warn(config->dev, 25262306a36Sopenharmony_ci "invalid phase_shift %d for BUCK%d, using OTP configuration\n", 25362306a36Sopenharmony_ci val, id); 25462306a36Sopenharmony_ci return; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci phase = val / 45; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (phase >= 1) 26062306a36Sopenharmony_ci phase -= 1; 26162306a36Sopenharmony_ci else 26262306a36Sopenharmony_ci phase = PF8X00_SWXPHASE_SHIFT; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci regmap_update_bits(chip->regmap, reg, 26562306a36Sopenharmony_ci PF8X00_SWXPHASE_MASK, 26662306a36Sopenharmony_ci phase); 26762306a36Sopenharmony_ci } else 26862306a36Sopenharmony_ci dev_warn(chip->dev, "nxp,phase-shift used with incorrect regulator (%d)\n", id); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic int pf8x00_of_parse_cb(struct device_node *np, 27362306a36Sopenharmony_ci const struct regulator_desc *desc, 27462306a36Sopenharmony_ci struct regulator_config *config) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci handle_ilim_property(np, desc, config); 27862306a36Sopenharmony_ci handle_shift_property(np, desc, config); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int pf8x00_suspend_enable(struct regulator_dev *rdev) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev); 28662306a36Sopenharmony_ci struct regmap *rmap = rdev_get_regmap(rdev); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return regmap_update_bits(rmap, regl->suspend_enable_reg, 28962306a36Sopenharmony_ci regl->suspend_enable_mask, 29062306a36Sopenharmony_ci regl->suspend_enable_mask); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int pf8x00_suspend_disable(struct regulator_dev *rdev) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev); 29662306a36Sopenharmony_ci struct regmap *rmap = rdev_get_regmap(rdev); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci return regmap_update_bits(rmap, regl->suspend_enable_reg, 29962306a36Sopenharmony_ci regl->suspend_enable_mask, 0); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int pf8x00_set_suspend_voltage(struct regulator_dev *rdev, int uV) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct pf8x00_regulator_data *regl = rdev_get_drvdata(rdev); 30562306a36Sopenharmony_ci int ret; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (regl->suspend_voltage_cache == uV) 30862306a36Sopenharmony_ci return 0; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci ret = regulator_map_voltage_iterate(rdev, uV, uV); 31162306a36Sopenharmony_ci if (ret < 0) { 31262306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "failed to map %i uV\n", uV); 31362306a36Sopenharmony_ci return ret; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci dev_dbg(rdev_get_dev(rdev), "uV: %i, reg: 0x%x, msk: 0x%x, val: 0x%x\n", 31762306a36Sopenharmony_ci uV, regl->suspend_voltage_reg, regl->desc.vsel_mask, ret); 31862306a36Sopenharmony_ci ret = regmap_update_bits(rdev->regmap, regl->suspend_voltage_reg, 31962306a36Sopenharmony_ci regl->desc.vsel_mask, ret); 32062306a36Sopenharmony_ci if (ret < 0) { 32162306a36Sopenharmony_ci dev_err(rdev_get_dev(rdev), "failed to set %i uV\n", uV); 32262306a36Sopenharmony_ci return ret; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci regl->suspend_voltage_cache = uV; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic const struct regulator_ops pf8x00_ldo_ops = { 33162306a36Sopenharmony_ci .enable = regulator_enable_regmap, 33262306a36Sopenharmony_ci .disable = regulator_disable_regmap, 33362306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 33462306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 33562306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 33662306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 33762306a36Sopenharmony_ci .set_suspend_enable = pf8x00_suspend_enable, 33862306a36Sopenharmony_ci .set_suspend_disable = pf8x00_suspend_disable, 33962306a36Sopenharmony_ci .set_suspend_voltage = pf8x00_set_suspend_voltage, 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic const struct regulator_ops pf8x00_buck1_6_ops = { 34462306a36Sopenharmony_ci .enable = regulator_enable_regmap, 34562306a36Sopenharmony_ci .disable = regulator_disable_regmap, 34662306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 34762306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_linear_range, 34862306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 34962306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 35062306a36Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 35162306a36Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 35262306a36Sopenharmony_ci .set_suspend_enable = pf8x00_suspend_enable, 35362306a36Sopenharmony_ci .set_suspend_disable = pf8x00_suspend_disable, 35462306a36Sopenharmony_ci .set_suspend_voltage = pf8x00_set_suspend_voltage, 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic const struct regulator_ops pf8x00_buck7_ops = { 35862306a36Sopenharmony_ci .enable = regulator_enable_regmap, 35962306a36Sopenharmony_ci .disable = regulator_disable_regmap, 36062306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 36162306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 36262306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 36362306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 36462306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 36562306a36Sopenharmony_ci .get_current_limit = regulator_get_current_limit_regmap, 36662306a36Sopenharmony_ci .set_current_limit = regulator_set_current_limit_regmap, 36762306a36Sopenharmony_ci .set_suspend_enable = pf8x00_suspend_enable, 36862306a36Sopenharmony_ci .set_suspend_disable = pf8x00_suspend_disable, 36962306a36Sopenharmony_ci}; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic const struct regulator_ops pf8x00_vsnvs_ops = { 37262306a36Sopenharmony_ci .enable = regulator_enable_regmap, 37362306a36Sopenharmony_ci .disable = regulator_disable_regmap, 37462306a36Sopenharmony_ci .is_enabled = regulator_is_enabled_regmap, 37562306a36Sopenharmony_ci .list_voltage = regulator_list_voltage_table, 37662306a36Sopenharmony_ci .map_voltage = regulator_map_voltage_ascend, 37762306a36Sopenharmony_ci .set_voltage_sel = regulator_set_voltage_sel_regmap, 37862306a36Sopenharmony_ci .get_voltage_sel = regulator_get_voltage_sel_regmap, 37962306a36Sopenharmony_ci}; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci#define PF8X00LDO(_id, _name, base, voltages) \ 38262306a36Sopenharmony_ci [PF8X00_LDO ## _id] = { \ 38362306a36Sopenharmony_ci .desc = { \ 38462306a36Sopenharmony_ci .name = _name, \ 38562306a36Sopenharmony_ci .of_match = _name, \ 38662306a36Sopenharmony_ci .regulators_node = "regulators", \ 38762306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(voltages), \ 38862306a36Sopenharmony_ci .ops = &pf8x00_ldo_ops, \ 38962306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 39062306a36Sopenharmony_ci .id = PF8X00_LDO ## _id, \ 39162306a36Sopenharmony_ci .owner = THIS_MODULE, \ 39262306a36Sopenharmony_ci .volt_table = voltages, \ 39362306a36Sopenharmony_ci .vsel_reg = (base) + LDO_RUN_VOLT, \ 39462306a36Sopenharmony_ci .vsel_mask = 0xff, \ 39562306a36Sopenharmony_ci .enable_reg = (base) + LDO_CONFIG2, \ 39662306a36Sopenharmony_ci .enable_val = 0x2, \ 39762306a36Sopenharmony_ci .disable_val = 0x0, \ 39862306a36Sopenharmony_ci .enable_mask = 2, \ 39962306a36Sopenharmony_ci }, \ 40062306a36Sopenharmony_ci .suspend_enable_reg = (base) + LDO_CONFIG2, \ 40162306a36Sopenharmony_ci .suspend_enable_mask = 1, \ 40262306a36Sopenharmony_ci .suspend_voltage_reg = (base) + LDO_STBY_VOLT, \ 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci#define PF8X00BUCK(_id, _name, base, voltages) \ 40662306a36Sopenharmony_ci [PF8X00_BUCK ## _id] = { \ 40762306a36Sopenharmony_ci .desc = { \ 40862306a36Sopenharmony_ci .name = _name, \ 40962306a36Sopenharmony_ci .of_match = _name, \ 41062306a36Sopenharmony_ci .regulators_node = "regulators", \ 41162306a36Sopenharmony_ci .of_parse_cb = pf8x00_of_parse_cb, \ 41262306a36Sopenharmony_ci .n_voltages = PF8XOO_SW1_6_VOLTAGE_NUM, \ 41362306a36Sopenharmony_ci .ops = &pf8x00_buck1_6_ops, \ 41462306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 41562306a36Sopenharmony_ci .id = PF8X00_BUCK ## _id, \ 41662306a36Sopenharmony_ci .owner = THIS_MODULE, \ 41762306a36Sopenharmony_ci .ramp_delay = 19000, \ 41862306a36Sopenharmony_ci .linear_ranges = pf8x00_sw1_to_6_voltages, \ 41962306a36Sopenharmony_ci .n_linear_ranges = \ 42062306a36Sopenharmony_ci ARRAY_SIZE(pf8x00_sw1_to_6_voltages), \ 42162306a36Sopenharmony_ci .vsel_reg = (base) + SW_RUN_VOLT, \ 42262306a36Sopenharmony_ci .vsel_mask = 0xff, \ 42362306a36Sopenharmony_ci .curr_table = pf8x00_sw_current_table, \ 42462306a36Sopenharmony_ci .n_current_limits = \ 42562306a36Sopenharmony_ci ARRAY_SIZE(pf8x00_sw_current_table), \ 42662306a36Sopenharmony_ci .csel_reg = (base) + SW_CONFIG2, \ 42762306a36Sopenharmony_ci .csel_mask = PF8X00_SWXILIM_MASK, \ 42862306a36Sopenharmony_ci .enable_reg = (base) + SW_MODE1, \ 42962306a36Sopenharmony_ci .enable_val = 0x3, \ 43062306a36Sopenharmony_ci .disable_val = 0x0, \ 43162306a36Sopenharmony_ci .enable_mask = 0x3, \ 43262306a36Sopenharmony_ci .enable_time = 500, \ 43362306a36Sopenharmony_ci }, \ 43462306a36Sopenharmony_ci .suspend_enable_reg = (base) + SW_MODE1, \ 43562306a36Sopenharmony_ci .suspend_enable_mask = 0xc, \ 43662306a36Sopenharmony_ci .suspend_voltage_reg = (base) + SW_STBY_VOLT, \ 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci#define PF8X00BUCK7(_name, base, voltages) \ 44062306a36Sopenharmony_ci [PF8X00_BUCK7] = { \ 44162306a36Sopenharmony_ci .desc = { \ 44262306a36Sopenharmony_ci .name = _name, \ 44362306a36Sopenharmony_ci .of_match = _name, \ 44462306a36Sopenharmony_ci .regulators_node = "regulators", \ 44562306a36Sopenharmony_ci .of_parse_cb = pf8x00_of_parse_cb, \ 44662306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(voltages), \ 44762306a36Sopenharmony_ci .ops = &pf8x00_buck7_ops, \ 44862306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 44962306a36Sopenharmony_ci .id = PF8X00_BUCK7, \ 45062306a36Sopenharmony_ci .owner = THIS_MODULE, \ 45162306a36Sopenharmony_ci .ramp_delay = 19000, \ 45262306a36Sopenharmony_ci .volt_table = voltages, \ 45362306a36Sopenharmony_ci .vsel_reg = (base) + SW_RUN_VOLT, \ 45462306a36Sopenharmony_ci .vsel_mask = 0xff, \ 45562306a36Sopenharmony_ci .curr_table = pf8x00_sw_current_table, \ 45662306a36Sopenharmony_ci .n_current_limits = \ 45762306a36Sopenharmony_ci ARRAY_SIZE(pf8x00_sw_current_table), \ 45862306a36Sopenharmony_ci .csel_reg = (base) + SW_CONFIG2, \ 45962306a36Sopenharmony_ci .csel_mask = PF8X00_SWXILIM_MASK, \ 46062306a36Sopenharmony_ci .enable_reg = (base) + SW_MODE1, \ 46162306a36Sopenharmony_ci .enable_val = 0x3, \ 46262306a36Sopenharmony_ci .disable_val = 0x0, \ 46362306a36Sopenharmony_ci .enable_mask = 0x3, \ 46462306a36Sopenharmony_ci .enable_time = 500, \ 46562306a36Sopenharmony_ci }, \ 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci#define PF8X00VSNVS(_name, base, voltages) \ 47062306a36Sopenharmony_ci [PF8X00_VSNVS] = { \ 47162306a36Sopenharmony_ci .desc = { \ 47262306a36Sopenharmony_ci .name = _name, \ 47362306a36Sopenharmony_ci .of_match = _name, \ 47462306a36Sopenharmony_ci .regulators_node = "regulators", \ 47562306a36Sopenharmony_ci .n_voltages = ARRAY_SIZE(voltages), \ 47662306a36Sopenharmony_ci .ops = &pf8x00_vsnvs_ops, \ 47762306a36Sopenharmony_ci .type = REGULATOR_VOLTAGE, \ 47862306a36Sopenharmony_ci .id = PF8X00_VSNVS, \ 47962306a36Sopenharmony_ci .owner = THIS_MODULE, \ 48062306a36Sopenharmony_ci .volt_table = voltages, \ 48162306a36Sopenharmony_ci .vsel_reg = (base), \ 48262306a36Sopenharmony_ci .vsel_mask = 0x3, \ 48362306a36Sopenharmony_ci }, \ 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic struct pf8x00_regulator_data pf8x00_regs_data[PF8X00_MAX_REGULATORS] = { 48762306a36Sopenharmony_ci PF8X00LDO(1, "ldo1", PF8X00_LDO_BASE(PF8X00_LDO1), pf8x00_ldo_voltages), 48862306a36Sopenharmony_ci PF8X00LDO(2, "ldo2", PF8X00_LDO_BASE(PF8X00_LDO2), pf8x00_ldo_voltages), 48962306a36Sopenharmony_ci PF8X00LDO(3, "ldo3", PF8X00_LDO_BASE(PF8X00_LDO3), pf8x00_ldo_voltages), 49062306a36Sopenharmony_ci PF8X00LDO(4, "ldo4", PF8X00_LDO_BASE(PF8X00_LDO4), pf8x00_ldo_voltages), 49162306a36Sopenharmony_ci PF8X00BUCK(1, "buck1", PF8X00_SW_BASE(PF8X00_BUCK1), pf8x00_sw1_to_6_voltages), 49262306a36Sopenharmony_ci PF8X00BUCK(2, "buck2", PF8X00_SW_BASE(PF8X00_BUCK2), pf8x00_sw1_to_6_voltages), 49362306a36Sopenharmony_ci PF8X00BUCK(3, "buck3", PF8X00_SW_BASE(PF8X00_BUCK3), pf8x00_sw1_to_6_voltages), 49462306a36Sopenharmony_ci PF8X00BUCK(4, "buck4", PF8X00_SW_BASE(PF8X00_BUCK4), pf8x00_sw1_to_6_voltages), 49562306a36Sopenharmony_ci PF8X00BUCK(5, "buck5", PF8X00_SW_BASE(PF8X00_BUCK5), pf8x00_sw1_to_6_voltages), 49662306a36Sopenharmony_ci PF8X00BUCK(6, "buck6", PF8X00_SW_BASE(PF8X00_BUCK6), pf8x00_sw1_to_6_voltages), 49762306a36Sopenharmony_ci PF8X00BUCK7("buck7", PF8X00_SW_BASE(PF8X00_BUCK7), pf8x00_sw7_voltages), 49862306a36Sopenharmony_ci PF8X00VSNVS("vsnvs", PF8X00_VSNVS_CONFIG1, pf8x00_vsnvs_voltages), 49962306a36Sopenharmony_ci}; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int pf8x00_identify(struct pf8x00_chip *chip) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unsigned int value; 50462306a36Sopenharmony_ci u8 dev_fam, dev_id; 50562306a36Sopenharmony_ci const char *name = NULL; 50662306a36Sopenharmony_ci int ret; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ret = regmap_read(chip->regmap, PF8X00_DEVICEID, &value); 50962306a36Sopenharmony_ci if (ret) { 51062306a36Sopenharmony_ci dev_err(chip->dev, "failed to read chip family\n"); 51162306a36Sopenharmony_ci return ret; 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci dev_fam = value & PF8X00_DEVICE_FAM_MASK; 51562306a36Sopenharmony_ci switch (dev_fam) { 51662306a36Sopenharmony_ci case PF8X00_FAM: 51762306a36Sopenharmony_ci break; 51862306a36Sopenharmony_ci default: 51962306a36Sopenharmony_ci dev_err(chip->dev, 52062306a36Sopenharmony_ci "Chip 0x%x is not from PF8X00 family\n", dev_fam); 52162306a36Sopenharmony_ci return ret; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci dev_id = value & PF8X00_DEVICE_ID_MASK; 52562306a36Sopenharmony_ci switch (dev_id) { 52662306a36Sopenharmony_ci case PF8100: 52762306a36Sopenharmony_ci name = "PF8100"; 52862306a36Sopenharmony_ci break; 52962306a36Sopenharmony_ci case PF8121A: 53062306a36Sopenharmony_ci name = "PF8121A"; 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case PF8200: 53362306a36Sopenharmony_ci name = "PF8200"; 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci default: 53662306a36Sopenharmony_ci dev_err(chip->dev, "Unknown pf8x00 device id 0x%x\n", dev_id); 53762306a36Sopenharmony_ci return -ENODEV; 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dev_info(chip->dev, "%s PMIC found.\n", name); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic int pf8x00_i2c_probe(struct i2c_client *client) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct regulator_config config = { NULL, }; 54862306a36Sopenharmony_ci struct pf8x00_chip *chip; 54962306a36Sopenharmony_ci int id; 55062306a36Sopenharmony_ci int ret; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); 55362306a36Sopenharmony_ci if (!chip) 55462306a36Sopenharmony_ci return -ENOMEM; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci i2c_set_clientdata(client, chip); 55762306a36Sopenharmony_ci chip->dev = &client->dev; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci chip->regmap = devm_regmap_init_i2c(client, &pf8x00_regmap_config); 56062306a36Sopenharmony_ci if (IS_ERR(chip->regmap)) { 56162306a36Sopenharmony_ci ret = PTR_ERR(chip->regmap); 56262306a36Sopenharmony_ci dev_err(&client->dev, 56362306a36Sopenharmony_ci "regmap allocation failed with err %d\n", ret); 56462306a36Sopenharmony_ci return ret; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci ret = pf8x00_identify(chip); 56862306a36Sopenharmony_ci if (ret) 56962306a36Sopenharmony_ci return ret; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci for (id = 0; id < ARRAY_SIZE(pf8x00_regs_data); id++) { 57262306a36Sopenharmony_ci struct pf8x00_regulator_data *data = &pf8x00_regs_data[id]; 57362306a36Sopenharmony_ci struct regulator_dev *rdev; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci config.dev = chip->dev; 57662306a36Sopenharmony_ci config.driver_data = data; 57762306a36Sopenharmony_ci config.regmap = chip->regmap; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci rdev = devm_regulator_register(&client->dev, &data->desc, &config); 58062306a36Sopenharmony_ci if (IS_ERR(rdev)) { 58162306a36Sopenharmony_ci dev_err(&client->dev, 58262306a36Sopenharmony_ci "failed to register %s regulator\n", data->desc.name); 58362306a36Sopenharmony_ci return PTR_ERR(rdev); 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci return 0; 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic const struct of_device_id pf8x00_dt_ids[] = { 59162306a36Sopenharmony_ci { .compatible = "nxp,pf8100",}, 59262306a36Sopenharmony_ci { .compatible = "nxp,pf8121a",}, 59362306a36Sopenharmony_ci { .compatible = "nxp,pf8200",}, 59462306a36Sopenharmony_ci { } 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pf8x00_dt_ids); 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic const struct i2c_device_id pf8x00_i2c_id[] = { 59962306a36Sopenharmony_ci { "pf8100", 0 }, 60062306a36Sopenharmony_ci { "pf8121a", 0 }, 60162306a36Sopenharmony_ci { "pf8200", 0 }, 60262306a36Sopenharmony_ci {}, 60362306a36Sopenharmony_ci}; 60462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, pf8x00_i2c_id); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic struct i2c_driver pf8x00_regulator_driver = { 60762306a36Sopenharmony_ci .id_table = pf8x00_i2c_id, 60862306a36Sopenharmony_ci .driver = { 60962306a36Sopenharmony_ci .name = "pf8x00", 61062306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 61162306a36Sopenharmony_ci .of_match_table = pf8x00_dt_ids, 61262306a36Sopenharmony_ci }, 61362306a36Sopenharmony_ci .probe = pf8x00_i2c_probe, 61462306a36Sopenharmony_ci}; 61562306a36Sopenharmony_cimodule_i2c_driver(pf8x00_regulator_driver); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ciMODULE_AUTHOR("Jagan Teki <jagan@amarulasolutions.com>"); 61862306a36Sopenharmony_ciMODULE_AUTHOR("Troy Kisky <troy.kisky@boundarydevices.com>"); 61962306a36Sopenharmony_ciMODULE_DESCRIPTION("Regulator Driver for NXP's PF8100/PF8121A/PF8200 PMIC"); 62062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 621