/* * MAXIM max77812 Regulator driver * * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. * * Author: Venkat Reddy Talla * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed "as is" WITHOUT ANY WARRANTY of any kind, * whether express or implied; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. */ #include #include #include #include #include #include #include #include #define MAX77812_REG_RSET 0x00 #define MAX77812_REG_INT_SRC 0x01 #define MAX77812_REG_INT_SRC_M 0x02 #define MAX77812_REG_TOPSYS_INT 0x03 #define MAX77812_REG_TOPSYS_INT_M 0x04 #define MAX77812_REG_TOPSYS_STAT 0x05 #define MAX77812_REG_EN_CTRL 0x06 #define MAX77812_REG_STUP_DLY2 0x07 #define MAX77812_REG_STUP_DLY3 0x08 #define MAX77812_REG_STUP_DLY4 0x09 #define MAX77812_REG_SHDN_DLY1 0x0A #define MAX77812_REG_SHDN_DLY2 0x0B #define MAX77812_REG_SHDN_DLY3 0x0C #define MAX77812_REG_SHDN_DLY4 0x0D #define MAX77812_REG_WDTRSTB_DEB 0x0E #define MAX77812_REG_GPI_FUNC 0x0F #define MAX77812_REG_GPI_DEB1 0x10 #define MAX77812_REG_GPI_DEB2 0x11 #define MAX77812_REG_GPI_PD_CTRL 0x12 #define MAX77812_REG_PROT_CFG 0x13 #define MAX77812_REG_VERSION 0x14 #define MAX77812_REG_I2C_CFG 0x15 #define MAX77812_REG_BUCK_INT 0x20 #define MAX77812_REG_BUCK_INT_M 0x21 #define MAX77812_REG_BUCK_STAT 0x22 #define MAX77812_REG_M1_VOUT 0x23 #define MAX77812_REG_M2_VOUT 0x24 #define MAX77812_REG_M3_VOUT 0x25 #define MAX77812_REG_M4_VOUT 0x26 #define MAX77812_REG_M1_VOUT_D 0x27 #define MAX77812_REG_M2_VOUT_D 0x28 #define MAX77812_REG_M3_VOUT_D 0x29 #define MAX77812_REG_M4_VOUT_D 0x2A #define MAX77812_REG_M1_VOUT_S 0x2B #define MAX77812_REG_M2_VOUT_S 0x2C #define MAX77812_REG_M3_VOUT_S 0x2D #define MAX77812_REG_M4_VOUT_S 0x2E #define MAX77812_REG_M1_CFG 0x2F #define MAX77812_REG_M2_CFG 0x30 #define MAX77812_REG_M3_CFG 0x31 #define MAX77812_REG_M4_CFG 0x32 #define MAX77812_REG_GLB_CFG1 0x33 #define MAX77812_REG_GLB_CFG2 0x34 #define MAX77812_REG_GLB_CFG3 0x35 #define MAX77812_REG_GLB_CFG4 0x36 #define MAX77812_REG_GLB_CFG5 0x37 #define MAX77812_REG_GLB_CFG6 0x38 #define MAX77812_REG_GLB_CFG7 0x39 #define MAX77812_REG_GLB_CFG8 0x3A #define MAX77812_REG_PROT_ACCESS 0xFD #define MAX77812_REG_MAX 0xFE #define MAX77812_REG_EN_CTRL_MASK(n) BIT(n) #define MAX77812_START_SLEW_RATE_MASK 0x07 #define MAX77812_SHDN_SLEW_RATE_MASK 0x70 #define MAX77812_RAMPUP_SLEW_RATE_MASK 0x07 #define MAX77812_RAMPDOWN_SLEW_RATE_MASK 0x70 #define MAX77812_SLEW_RATE_SHIFT 4 #define MAX77812_OP_ACTIVE_DISCHARGE_MASK BIT(7) #define MAX77812_PEAK_CURRENT_LMT_MASK 0x70 #define MAX77812_SWITCH_FREQ_MASK 0x0C #define MAX77812_FORCED_PWM_MASK BIT(1) #define MAX77812_SLEW_RATE_CNTRL_MASK BIT(0) #define MAX77812_START_SHD_DELAY_MASK 0x1F #define MAX77812_VERSION_MASK 0x07 #define MAX77812_ES2_VERSION 0x04 #define MAX77812_QS_VERSION 0x05 #define MAX77812_VOUT_MASK 0xFF #define MAX77812_VOUT_N_VOLTAGE 0xFF #define MAX77812_VOUT_VMIN 250000 #define MAX77812_VOUT_VMAX 1525000 #define MAX77812_VOUT_STEP 5000 #define MAX77812_PHASE4_I2C_ADD 0x30 #define MAX77812_PHASE31_I2C_ADD 0x31 #define MAX77812_PHASE22_I2C_ADD 0x32 #define MAX77812_PHASE211_I2C_ADD 0x33 #define MAX77812_PHASE1_I2C_ADD 0x34 enum { MAX77812_REG_ID_M1, MAX77812_REG_ID_M2, MAX77812_REG_ID_M3, MAX77812_REG_ID_M4, MAX77812_ID_RG_MAX, }; static unsigned int slew_rate_table[] = { 1250, 2500, 5000, 10000, 20000, 40000, 60000, }; static unsigned int peak_current_limit[] = { 3000000, 3600000, 4200000, 4800000, 5400000, 6000000, 6000000, 7200000, }; struct max77812_reg_pdata { int peak_current_limit; int switching_freq; bool disable_active_discharge; bool delay_time_step_select; bool enable_forced_pwm; bool disable_slew_rate_cntrl; }; struct max77812_regulator { struct device *dev; struct regmap *rmap; struct regulator_desc *rdesc[MAX77812_ID_RG_MAX]; struct max77812_reg_pdata reg_pdata[MAX77812_ID_RG_MAX]; struct regulator_dev *rdev[MAX77812_ID_RG_MAX]; u32 ramp_up_slew_rate; u32 ramp_down_slew_rate; u32 shutdown_slew_rate; u32 softstart_slew_rate; }; static u8 max77802_slew_rate_to_reg(const unsigned int sr_limits[], u8 cnt, unsigned int slew_rate) { int i; for (i = 0; i < cnt; i++) { if (slew_rate <= sr_limits[i]) return i; } return cnt - 1; } static int max77812_reg_init(struct max77812_regulator *max77812) { u8 slew_rate = 0; u8 rampdelay = 0; u8 mask = 0; unsigned int val; int ret; if (max77812->softstart_slew_rate) { slew_rate = max77802_slew_rate_to_reg(slew_rate_table, ARRAY_SIZE(slew_rate_table), max77812->softstart_slew_rate); mask = MAX77812_START_SLEW_RATE_MASK; } if (max77812->shutdown_slew_rate) { rampdelay = max77802_slew_rate_to_reg(slew_rate_table, ARRAY_SIZE(slew_rate_table), max77812->shutdown_slew_rate); slew_rate |= (rampdelay << MAX77812_SLEW_RATE_SHIFT); mask |= MAX77812_SHDN_SLEW_RATE_MASK; } if (slew_rate && mask) { ret = regmap_update_bits(max77812->rmap, MAX77812_REG_GLB_CFG1, mask, slew_rate); if (ret < 0) { dev_err(max77812->dev, "slew rate cfg1 update failed %d\n", ret); return ret; } } slew_rate = 0; mask = 0; if (max77812->ramp_up_slew_rate) { slew_rate = max77802_slew_rate_to_reg(slew_rate_table, ARRAY_SIZE(slew_rate_table), max77812->ramp_up_slew_rate); mask = MAX77812_RAMPUP_SLEW_RATE_MASK; } if (max77812->ramp_down_slew_rate) { rampdelay = max77802_slew_rate_to_reg(slew_rate_table, ARRAY_SIZE(slew_rate_table), max77812->ramp_down_slew_rate); slew_rate |= (rampdelay << MAX77812_SLEW_RATE_SHIFT); mask |= MAX77812_RAMPDOWN_SLEW_RATE_MASK; } if (slew_rate && mask) { ret = regmap_update_bits(max77812->rmap, MAX77812_REG_GLB_CFG2, mask, slew_rate); if (ret < 0) { dev_err(max77812->dev, "slew rate cfg2 update failed %d\n", ret); return ret; } } ret = regmap_read(max77812->rmap, MAX77812_REG_VERSION, &val); if (ret < 0) { dev_err(max77812->dev, "version reg read failed:%d\n", ret); return ret; } /* Bit[2:0] = 100b -> ES2 Bit[2:0] = 101b -> QS version */ dev_info(max77812->dev, "MAX77812 Version OTP:0x%02X\n", val); if ((val & MAX77812_VERSION_MASK) == MAX77812_ES2_VERSION) { ret = regmap_write(max77812->rmap, MAX77812_REG_PROT_ACCESS, 0x5A); if (ret < 0) goto error; ret = regmap_read(max77812->rmap, MAX77812_REG_PROT_ACCESS, &val); if (ret < 0) goto error; if (val != 0x5A) { dev_err(max77812->dev, "prot register unlock failed\n"); return -EINVAL; } ret = regmap_write(max77812->rmap, MAX77812_REG_GLB_CFG5, 0x3E); if (ret < 0) goto error; ret = regmap_write(max77812->rmap, MAX77812_REG_GLB_CFG6, 0x90); if (ret < 0) goto error; ret = regmap_write(max77812->rmap, MAX77812_REG_GLB_CFG8, 0x3A); if (ret < 0) goto error; ret = regmap_write(max77812->rmap, MAX77812_REG_PROT_ACCESS, 0x0); if (ret < 0) goto error; ret = regmap_read(max77812->rmap, MAX77812_REG_PROT_ACCESS, &val); if (ret < 0) goto error; if (val) { dev_err(max77812->dev, "protect registers lock failed\n"); return -EINVAL; } } return 0; error: dev_err(max77812->dev, "protect register access failed %d\n", ret); return ret; } static int max77812_config_init(struct max77812_regulator *max77812, int id) { struct max77812_reg_pdata *rpdata = &max77812->reg_pdata[id]; u8 rail_config = 0; u8 mask = 0; u8 curnt_lim; u8 switch_freq; u8 reg_addr; int ret; if (rpdata->disable_active_discharge) { rail_config &= ~MAX77812_OP_ACTIVE_DISCHARGE_MASK; mask = MAX77812_OP_ACTIVE_DISCHARGE_MASK; } if (rpdata->peak_current_limit > 0) { curnt_lim = max77802_slew_rate_to_reg(peak_current_limit, ARRAY_SIZE(peak_current_limit), rpdata->peak_current_limit); rail_config |= (curnt_lim << 4); mask |= MAX77812_PEAK_CURRENT_LMT_MASK; } if (rpdata->switching_freq > 0) { if (rpdata->switching_freq == 2) switch_freq = 0; else if (rpdata->switching_freq == 3) switch_freq = 1; else if (rpdata->switching_freq == 4) switch_freq = 2; else switch_freq = 3; rail_config |= (switch_freq << 2); mask |= MAX77812_SWITCH_FREQ_MASK; } if (rpdata->enable_forced_pwm) { rail_config |= MAX77812_FORCED_PWM_MASK; mask |= MAX77812_FORCED_PWM_MASK; } if (rpdata->disable_slew_rate_cntrl) { rail_config &= ~MAX77812_SLEW_RATE_CNTRL_MASK; mask |= MAX77812_SLEW_RATE_CNTRL_MASK; } switch (id) { case MAX77812_REG_ID_M1: reg_addr = MAX77812_REG_M1_CFG; break; case MAX77812_REG_ID_M2: reg_addr = MAX77812_REG_M2_CFG; break; case MAX77812_REG_ID_M3: reg_addr = MAX77812_REG_M3_CFG; break; case MAX77812_REG_ID_M4: reg_addr = MAX77812_REG_M4_CFG; break; } if (rail_config && mask) { ret = regmap_update_bits(max77812->rmap, reg_addr, mask, rail_config); if (ret < 0) { dev_err(max77812->dev, "reg config update failed %d\n", ret); return ret; } } return 0; } static int max77812_of_parse_cb(struct device_node *np, const struct regulator_desc *desc, struct regulator_config *config) { struct max77812_regulator *max77812 = config->driver_data; struct max77812_reg_pdata *rpdata = &max77812->reg_pdata[desc->id]; u32 pval; int ret; rpdata->disable_active_discharge = of_property_read_bool(np, "maxim,disable-active-discharge"); ret = of_property_read_u32(np, "maxim,peak-current-limit-ua", &pval); rpdata->peak_current_limit = (!ret) ? pval : -1; ret = of_property_read_u32(np, "maxim,switching-frequency", &pval); rpdata->switching_freq = (!ret) ? pval : -1; rpdata->enable_forced_pwm = of_property_read_bool(np, "maxim,enable-forced-pwm-mode"); rpdata->disable_slew_rate_cntrl = of_property_read_bool(np, "maxim,disable-slew-rate-control"); return max77812_config_init(max77812, desc->id); } static struct regulator_ops max77812_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, }; #define MAX77812_REGULATOR_DESC(_id, _name, _en_bit) \ [MAX77812_REG_ID_##_id] = { \ .name = "max77812-"#_name, \ .of_match = of_match_ptr(#_name), \ .regulators_node = of_match_ptr("regulators"), \ .of_parse_cb = max77812_of_parse_cb, \ .supply_name = "vin", \ .id = MAX77812_REG_ID_##_id, \ .ops = &max77812_regulator_ops, \ .n_voltages = MAX77812_VOUT_N_VOLTAGE, \ .min_uV = MAX77812_VOUT_VMIN, \ .uV_step = MAX77812_VOUT_STEP, \ .enable_time = 500, \ .vsel_mask = MAX77812_VOUT_MASK, \ .vsel_reg = MAX77812_REG_##_id##_VOUT, \ .enable_reg = MAX77812_REG_EN_CTRL, \ .enable_mask = BIT(_en_bit), \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ } static struct regulator_desc max77812_regs_desc[MAX77812_ID_RG_MAX] = { MAX77812_REGULATOR_DESC(M1, m1vout, 0), MAX77812_REGULATOR_DESC(M2, m2vout, 2), MAX77812_REGULATOR_DESC(M3, m3vout, 4), MAX77812_REGULATOR_DESC(M4, m4vout, 6), }; static int max77812_reg_parse_dt(struct device *dev, struct max77812_regulator *max77812_regs) { struct device_node *np = dev->of_node; u32 pval; int ret; ret = of_property_read_u32(np, "maxim,ramp-up-slew-rate", &pval); if (!ret) max77812_regs->ramp_up_slew_rate = pval; ret = of_property_read_u32(np, "maxim,ramp-down-slew-rate", &pval); if (!ret) max77812_regs->ramp_down_slew_rate = pval; else max77812_regs->ramp_down_slew_rate = max77812_regs->ramp_up_slew_rate; ret = of_property_read_u32(np, "maxim,soft-start-slew-rate", &pval); if (!ret) max77812_regs->softstart_slew_rate = pval; ret = of_property_read_u32(np, "maxim,shutdown-slew-rate", &pval); if (!ret) max77812_regs->shutdown_slew_rate = pval; else max77812_regs->shutdown_slew_rate = max77812_regs->softstart_slew_rate; return 0; } static const struct regmap_config max77812_regmap_config = { .reg_bits = 8, .val_bits = 8, .max_register = MAX77812_REG_MAX - 1, .cache_type = REGCACHE_NONE, }; static int max77812_probe(struct i2c_client *client, const struct i2c_device_id *client_id) { struct device *dev = &client->dev; struct max77812_reg_pdata *rpdata; struct regulator_config config = { }; struct regulator_desc *max77812_rdesc[MAX77812_ID_RG_MAX]; struct max77812_regulator *max77812; unsigned short addr = client->addr; int id, max_regs; int ret; max77812 = devm_kzalloc(dev, sizeof(*max77812), GFP_KERNEL); if (!max77812) return -ENOMEM; ret = max77812_reg_parse_dt(dev, max77812); if (ret < 0) { dev_err(dev, "Reading data from DT failed: %d\n", ret); return ret; } max77812->rmap = devm_regmap_init_i2c(client, &max77812_regmap_config); if (IS_ERR(max77812->rmap)) { ret = PTR_ERR(max77812->rmap); dev_err(dev, "regmap init failed: %d\n", ret); return ret; } i2c_set_clientdata(client, max77812); max77812->dev = dev; ret = max77812_reg_init(max77812); if (ret < 0) { dev_err(dev, "max77812 Init failed: %d\n", ret); return ret; } switch (addr) { case MAX77812_PHASE4_I2C_ADD: max77812_rdesc[0] = &max77812_regs_desc[MAX77812_REG_ID_M1]; max_regs = 1; break; case MAX77812_PHASE31_I2C_ADD: max77812_rdesc[0] = &max77812_regs_desc[MAX77812_REG_ID_M1]; max77812_rdesc[1] = &max77812_regs_desc[MAX77812_REG_ID_M4]; max_regs = 2; break; case MAX77812_PHASE22_I2C_ADD: max77812_rdesc[0] = &max77812_regs_desc[MAX77812_REG_ID_M1]; max77812_rdesc[1] = &max77812_regs_desc[MAX77812_REG_ID_M3]; max_regs = 2; break; case MAX77812_PHASE211_I2C_ADD: max77812_rdesc[0] = &max77812_regs_desc[MAX77812_REG_ID_M1]; max77812_rdesc[1] = &max77812_regs_desc[MAX77812_REG_ID_M3]; max77812_rdesc[2] = &max77812_regs_desc[MAX77812_REG_ID_M4]; max_regs = 3; break; case MAX77812_PHASE1_I2C_ADD: max77812_rdesc[0] = &max77812_regs_desc[MAX77812_REG_ID_M1]; max77812_rdesc[1] = &max77812_regs_desc[MAX77812_REG_ID_M2]; max77812_rdesc[2] = &max77812_regs_desc[MAX77812_REG_ID_M3]; max77812_rdesc[3] = &max77812_regs_desc[MAX77812_REG_ID_M4]; max_regs = 4; break; default: dev_err(dev, "I2C address invalid: 0x%02x\n", addr); ret = -EINVAL; break; } for (id = 0; id < max_regs; ++id) { max77812->rdesc[id] = max77812_rdesc[id]; rpdata = &max77812->reg_pdata[id]; config.regmap = max77812->rmap; config.dev = dev; config.driver_data = max77812; max77812->rdev[id] = devm_regulator_register(dev, max77812->rdesc[id], &config); if (IS_ERR(max77812->rdev[id])) { ret = PTR_ERR(max77812->rdev[id]); dev_err(dev, "regulator %s register failed: %d\n", max77812->rdesc[id]->name, ret); return ret; } if (!max77812->rdev[id]->constraints->enable_time) max77812->rdev[id]->constraints->enable_time = max77812->softstart_slew_rate; if (!max77812->rdev[id]->constraints->ramp_delay) max77812->rdev[id]->constraints->ramp_delay = max77812->ramp_up_slew_rate; } return 0; } static const struct of_device_id max77812_of_match[] = { { .compatible = "maxim,max77812-regulator", }, {}, }; MODULE_DEVICE_TABLE(of, max77812_of_match); static const struct i2c_device_id max77812_id[] = { {.name = "max77812",}, {}, }; static struct i2c_driver max77812_i2c_driver = { .driver = { .name = "max77812", .owner = THIS_MODULE, .of_match_table = max77812_of_match, }, .probe = max77812_probe, .id_table = max77812_id, }; module_i2c_driver(max77812_i2c_driver); MODULE_DESCRIPTION("max77812 regulator driver"); MODULE_AUTHOR("Venkat Reddy Talla "); MODULE_LICENSE("GPL v2");