/* * drivers/regulator/max77660-regulator.c * Maxim LDO and Buck regulators driver * * Copyright 2011-2012 Maxim Integrated Products, Inc. * Copyright (C) 2011-2012 NVIDIA Corporation * * 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. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define DVFS_BASE_VOLTAGE_UV 600000 #define DVFS_VOLTAGE_STEP_UV 6250 enum { VOLT_REG = 0, /* XX_VOUT */ CFG_REG, /* XX_CNFG */ FPS_REG, /* XX_FPS */ PWR_MODE_REG /* XX_PWR_MODE */ }; struct max77660_register { u8 addr; }; struct max77660_regulator_info { u8 id; u8 type; u32 min_uV; u32 max_uV; u32 step_uV; struct max77660_register regs[4]; /* volt, cfg, fps, pwrmode */ struct regulator_desc desc; u8 volt_mask; u8 power_mode_mask; u8 power_mode_shift; int enable_bit; }; struct max77660_regulator { struct max77660_regulator_info *rinfo; struct regulator_dev *rdev; struct device *dev; struct max77660_regulator_platform_data *pdata; u32 regulator_mode; u8 power_mode; enum max77660_regulator_fps_src fps_src; u8 val[4]; /* volt, cfg, fps, power mode */ int safe_down_uV; /* for stable down scaling */ int external_flags; }; #define fps_src_name(fps_src) \ (fps_src == FPS_SRC_0 ? "FPS_SRC_0" : \ fps_src == FPS_SRC_1 ? "FPS_SRC_1" : \ fps_src == FPS_SRC_2 ? "FPS_SRC_2" : \ fps_src == FPS_SRC_3 ? "FPS_SRC_3" : \ fps_src == FPS_SRC_4 ? "FPS_SRC_4" : \ fps_src == FPS_SRC_5 ? "FPS_SRC_5" : \ fps_src == FPS_SRC_6 ? "FPS_SRC_6" : "FPS_SRC_NONE") static struct max77660_register fps_cfg_regs[] = { { .addr = MAX77660_REG_CNFG_FPS_AP_OFF, }, { .addr = MAX77660_REG_CNFG_FPS_AP_SLP, }, { .addr = MAX77660_REG_CNFG_FPS_6, }, }; static inline struct device *to_max77660_chip(struct max77660_regulator *reg) { return reg->dev->parent; } static int max77660_regulator_set_fps(struct max77660_regulator *reg) { struct max77660_regulator_platform_data *pdata = reg->pdata; struct max77660_regulator_info *rinfo = reg->rinfo; u8 val; u8 mask; int ret; if ((rinfo->regs[FPS_REG].addr == MAX77660_REG_FPS_NONE) || (reg->fps_src == pdata->fps_src)) return 0; /* FPS SRC setting */ switch (pdata->fps_src) { case FPS_SRC_0: case FPS_SRC_1: case FPS_SRC_2: case FPS_SRC_3: case FPS_SRC_4: case FPS_SRC_5: case FPS_SRC_6: val = pdata->fps_src << MAX77660_FPS_SRC_SHIFT; mask = MAX77660_FPS_SRC_MASK; break; case FPS_SRC_NONE: val = MAX77660_FPS_SRC_MASK | MAX77660_FPS_PU_PERIOD_MASK | MAX77660_FPS_PD_PERIOD_MASK; mask = MAX77660_FPS_SRC_MASK | MAX77660_FPS_PU_PERIOD_MASK | MAX77660_FPS_PD_PERIOD_MASK; goto reg_update; case FPS_SRC_DEF: return 0; default: return -EINVAL; } /* FPS power up period setting */ if (pdata->fps_pu_period != FPS_POWER_PERIOD_DEF) { val |= (pdata->fps_pu_period << MAX77660_FPS_PU_PERIOD_SHIFT); mask |= MAX77660_FPS_PU_PERIOD_MASK; } /* FPS power down period setting */ if (pdata->fps_pd_period != FPS_POWER_PERIOD_DEF) { val |= (pdata->fps_pd_period << MAX77660_FPS_PD_PERIOD_SHIFT); mask |= MAX77660_FPS_PD_PERIOD_MASK; } reg_update: ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[FPS_REG].addr, val, mask); if (ret < 0) return ret; reg->fps_src = pdata->fps_src; return 0; } static int max77660_regulator_set_fps_cfg(struct max77660_regulator *reg, struct max77660_regulator_fps_cfg *fps_cfg) { u8 val = 0, mask = 0; int ret = 0; if ((reg->fps_src < FPS_SRC_0) || (reg->fps_src >= FPS_SRC_NONE)) return -EINVAL; if ((reg->fps_src >= FPS_SRC_0) && (reg->fps_src <= FPS_SRC_5)) { if (fps_cfg->tu_ap_off != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->tu_ap_off << MAX77660_FPS_AP_OFF_TU_SHIFT); mask |= MAX77660_FPS_AP_OFF_TU_MASK; } if (fps_cfg->td_ap_off != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->tu_ap_off << MAX77660_FPS_AP_OFF_TD_SHIFT); mask |= MAX77660_FPS_AP_OFF_TD_MASK; } ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, fps_cfg_regs[0].addr, val, mask); mask = 0; val = 0; if (fps_cfg->tu_ap_slp != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->tu_ap_off << MAX77660_FPS_AP_SLP_TU_SHIFT); mask |= MAX77660_FPS_AP_SLP_TU_MASK; } if (fps_cfg->td_ap_slp != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->tu_ap_off << MAX77660_FPS_AP_SLP_TD_SHIFT); mask |= MAX77660_FPS_AP_SLP_TD_MASK; } ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, fps_cfg_regs[1].addr, val, mask); } if (reg->fps_src == FPS_SRC_6) { if (fps_cfg->tu_fps_6 != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->tu_fps_6 << MAX77660_FPS_6_TU_SHIFT); mask |= MAX77660_FPS_6_TU_MASK; } if (fps_cfg->tu_fps_6 != FPS_TIME_PERIOD_DEF) { val |= (fps_cfg->td_ap_off << MAX77660_FPS_6_TD_SHIFT); mask |= MAX77660_FPS_AP_SLP_TD_MASK; } ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, fps_cfg_regs[2].addr, val, mask); } return ret; } static int max77660_regulator_set_fps_cfgs(struct max77660_regulator *reg, struct max77660_regulator_fps_cfg *fps_cfgs, int num_fps_cfgs) { int i, ret; static int fps_cfg_init; if (fps_cfg_init) return 0; for (i = 0; i < num_fps_cfgs; i++) { ret = max77660_regulator_set_fps_cfg(reg, &fps_cfgs[i]); if (ret < 0) return ret; } fps_cfg_init = 1; return 0; } static int max77660_regulator_set_power_mode(struct max77660_regulator *reg, u8 power_mode) { struct max77660_regulator_info *rinfo = reg->rinfo; u8 mask = rinfo->power_mode_mask; u8 shift = rinfo->power_mode_shift; int ret = 0; if (rinfo->type == REGULATOR_TYPE_SW) return 0; ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[PWR_MODE_REG].addr, power_mode << shift, mask); if (ret < 0) return ret; reg->power_mode = power_mode; return ret; } static u8 max77660_regulator_get_power_mode(struct max77660_regulator *reg) { struct max77660_regulator_info *rinfo = reg->rinfo; u8 mask = rinfo->power_mode_mask; u8 shift = rinfo->power_mode_shift; int ret; u8 val; if (rinfo->type == REGULATOR_TYPE_SW) return 0; ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[PWR_MODE_REG].addr, &val); if (ret < 0) return ret; reg->power_mode = (val & mask) >> shift; return reg->power_mode; } static int max77660_regulator_do_set_voltage(struct max77660_regulator *reg, int min_uV, int max_uV) { struct max77660_regulator_info *rinfo = reg->rinfo; u8 addr = rinfo->regs[VOLT_REG].addr; u8 mask = rinfo->volt_mask; u8 val; int old_uV, new_uV, safe_uV; int i, steps = 1; int ret = 0; if (min_uV < rinfo->min_uV || max_uV > rinfo->max_uV) return -EDOM; ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, addr, &val); if (ret < 0) return ret; old_uV = (val & mask) * rinfo->step_uV + rinfo->min_uV; if ((old_uV > min_uV) && (reg->safe_down_uV >= rinfo->step_uV)) { steps = DIV_ROUND_UP(old_uV - min_uV, reg->safe_down_uV); safe_uV = -reg->safe_down_uV; } if (steps == 1) { val = (min_uV - rinfo->min_uV) / rinfo->step_uV; ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, addr, val, mask); } else { for (i = 0; i < steps; i++) { if (abs(min_uV - old_uV) > abs(safe_uV)) new_uV = old_uV + safe_uV; else new_uV = min_uV; dev_dbg(®->rdev->dev, "do_set_voltage: name=%s, %d/%d, old_uV=%d, new_uV=%d\n", reg->rdev->desc->name, i + 1, steps, old_uV, new_uV); val = (new_uV - rinfo->min_uV) / rinfo->step_uV; ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, addr, val, mask); if (ret < 0) return ret; old_uV = new_uV; } } return ret; } static int max77660_regulator_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, unsigned *selector) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); dev_dbg(&rdev->dev, "set_voltage: name=%s, min_uV=%d, max_uV=%d\n", rdev->desc->name, min_uV, max_uV); return max77660_regulator_do_set_voltage(reg, min_uV, max_uV); } static int max77660_regulator_get_voltage(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_info *rinfo = reg->rinfo; int volt, ret; u8 val; ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[VOLT_REG].addr, &val); if (ret < 0) return ret; volt = (val & rinfo->volt_mask) * rinfo->step_uV + rinfo->min_uV; dev_dbg(&rdev->dev, "get_voltage: name=%s, volt=%d, val=0x%02x\n", rdev->desc->name, volt, val); return volt; } static int max77660_regulator_mask_ext_control(struct device *dev) { u8 mask; int ret; mask = GLBLCNFG5_EN1_MASK_MASK | GLBLCNFG5_EN5_MASK_MASK | GLBLCNFG5_EN1_FPS6_MASK_MASK; ret = max77660_reg_update(dev->parent, MAX77660_PWR_SLAVE, MAX77660_REG_GLOBAL_CFG5, mask, mask); if (ret < 0) { dev_err(dev, "GLOBAL_CFG5 update failed: %d\n", ret); return ret; } mask = GLBLCNFG7_EN4_MASK_MASK | GLBLCNFG7_EN3_MASK_MASK | GLBLCNFG7_EN2_MASK_MASK; ret = max77660_reg_update(dev->parent, MAX77660_PWR_SLAVE, MAX77660_REG_GLOBAL_CFG7, mask, mask); if (ret < 0) { dev_err(dev, "GLOBAL_CFG7 update failed: %d\n", ret); return ret; } return 0; } static int max77660_regulator_unmask_ext_control(struct device *dev, unsigned ext_control) { u8 mask_cfg7 = 0; u8 mask_cfg5 = 0; int ret; if ((ext_control & MAX77660_EXT_ENABLE_EN1) || (ext_control & MAX77660_EXT_ENABLE_EN2)) { mask_cfg5 |= GLBLCNFG5_EN1_MASK_MASK; mask_cfg7 |= GLBLCNFG7_EN2_MASK_MASK; } if (ext_control & MAX77660_EXT_ENABLE_EN3) mask_cfg7 |= GLBLCNFG7_EN3_MASK_MASK; if (ext_control & MAX77660_EXT_ENABLE_EN4) mask_cfg7 |= GLBLCNFG7_EN4_MASK_MASK; if (ext_control & MAX77660_EXT_ENABLE_EN5) mask_cfg5 |= GLBLCNFG5_EN5_MASK_MASK; if (ext_control & MAX77660_EXT_ENABLE_EN1FPS6) mask_cfg5 |= GLBLCNFG5_EN1_FPS6_MASK_MASK; if (mask_cfg5) { ret = max77660_reg_update(dev->parent, MAX77660_PWR_SLAVE, MAX77660_REG_GLOBAL_CFG5, 0, mask_cfg5); if (ret < 0) { dev_err(dev, "GLOBAL_CFG5 update failed: %d\n", ret); return ret; } } if (mask_cfg7) { ret = max77660_reg_update(dev->parent, MAX77660_PWR_SLAVE, MAX77660_REG_GLOBAL_CFG7, 0, mask_cfg7); if (ret < 0) { dev_err(dev, "GLOBAL_CFG7 update failed: %d\n", ret); return ret; } } return 0; } static int max77660_regulator_enable(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_info *rinfo = reg->rinfo; struct max77660_regulator_platform_data *pdata = reg->pdata; int power_mode = (pdata->flags & GLPM_ENABLE) ? POWER_MODE_GLPM : POWER_MODE_NORMAL; if (reg->external_flags & MAX77660_EXTERNAL_ENABLE) return 0; /* ES 1.1 suggest to keep BUCK3 and BUCK5 in GLPM */ if (max77660_is_es_1_1(reg->dev)) if (reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK3 || reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK5) max77660_regulator_set_power_mode(reg, POWER_MODE_GLPM); if (reg->fps_src != FPS_SRC_NONE) { dev_dbg(&rdev->dev, "enable: Regulator %s using %s\n", rdev->desc->name, fps_src_name(reg->fps_src)); return 0; } /* N-Channel LDOs don't support Low-Power mode. */ if ((rinfo->type != REGULATOR_TYPE_LDO_N) && (reg->regulator_mode == REGULATOR_MODE_STANDBY)) power_mode = POWER_MODE_LPM; return max77660_regulator_set_power_mode(reg, power_mode); } static int max77660_regulator_disable(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); int power_mode = POWER_MODE_DISABLE; if (reg->external_flags & MAX77660_EXTERNAL_ENABLE) return 0; if (reg->fps_src != FPS_SRC_NONE) { dev_dbg(&rdev->dev, "disable: Regulator %s using %s\n", rdev->desc->name, fps_src_name(reg->fps_src)); return 0; } return max77660_regulator_set_power_mode(reg, power_mode); } static int max77660_regulator_is_enabled(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); int ret = 1; if (reg->external_flags & MAX77660_EXTERNAL_ENABLE) return 1; if (reg->fps_src != FPS_SRC_NONE) { dev_dbg(&rdev->dev, "is_enable: Regulator %s using %s\n", rdev->desc->name, fps_src_name(reg->fps_src)); return 1; } if (max77660_regulator_get_power_mode(reg) == POWER_MODE_DISABLE) ret = 0; return ret; } static int max77660_regulator_set_mode(struct regulator_dev *rdev, unsigned int mode) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_platform_data *pdata = reg->pdata; struct max77660_regulator_info *rinfo = reg->rinfo; u8 power_mode; u8 mask; u8 val = 0; int ret; if ((mode == REGULATOR_MODE_NORMAL) || (mode == REGULATOR_MODE_FAST)) power_mode = (pdata->flags & GLPM_ENABLE) ? POWER_MODE_GLPM : POWER_MODE_NORMAL; else if (mode == REGULATOR_MODE_STANDBY) { /* N-Channel LDOs don't support Low-Power mode. */ power_mode = (rinfo->type != REGULATOR_TYPE_LDO_N) ? POWER_MODE_LPM : POWER_MODE_NORMAL; } else return -EINVAL; if (reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK6 || reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK7) { mask = MAX77660_BUCK6_7_CNFG_FPWM_MASK; switch (mode) { case REGULATOR_MODE_FAST: val = 0; break; case REGULATOR_MODE_NORMAL: val = 1 << MAX77660_BUCK6_7_CNFG_FPWM_SHIFT; break; } ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[CFG_REG].addr, mask, val); if (ret < 0) return ret; } ret = max77660_regulator_set_power_mode(reg, power_mode); if (!ret) reg->regulator_mode = mode; return ret; } static unsigned int max77660_regulator_get_mode(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); return reg->regulator_mode; } static int max77660_switch_enable(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_info *rinfo = reg->rinfo; int idx, ret; if (rinfo->id == MAX77660_REGULATOR_ID_SW4) return 0; idx = rinfo->enable_bit; ret = max77660_reg_set_bits(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[VOLT_REG].addr, 1 << idx); return ret; } static int max77660_switch_disable(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_info *rinfo = reg->rinfo; int idx, ret; if (rinfo->id == MAX77660_REGULATOR_ID_SW4) return 0; idx = rinfo->enable_bit; ret = max77660_reg_clr_bits(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[VOLT_REG].addr, 1 << idx); return ret; } static int max77660_switch_is_enabled(struct regulator_dev *rdev) { struct max77660_regulator *reg = rdev_get_drvdata(rdev); struct max77660_regulator_info *rinfo = reg->rinfo; int idx, ret; u8 val = 0; if (rinfo->id == MAX77660_REGULATOR_ID_SW4) return 1; idx = rinfo->enable_bit; ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[VOLT_REG].addr, &val); return !!(val & (1 << idx)); } static int max77660_reg_enable_time(struct regulator_dev *dev) { return 500; } static struct regulator_ops max77660_regulator_ops = { .set_voltage = max77660_regulator_set_voltage, .get_voltage = max77660_regulator_get_voltage, .enable_time = max77660_reg_enable_time, .enable = max77660_regulator_enable, .disable = max77660_regulator_disable, .is_enabled = max77660_regulator_is_enabled, .set_mode = max77660_regulator_set_mode, .get_mode = max77660_regulator_get_mode, }; static struct regulator_ops max77660_sw_ops = { .enable = max77660_switch_enable, .disable = max77660_switch_disable, .enable_time = max77660_reg_enable_time, .is_enabled = max77660_switch_is_enabled, }; static int max77660_regulator_preinit(struct max77660_regulator *reg) { struct max77660_regulator_platform_data *pdata = reg->pdata; struct max77660_regulator_info *rinfo = reg->rinfo; u8 idx; u8 val, mask; int ret; int addr; /* Unmask extern control */ if (pdata->flags & MAX77660_EXTERNAL_ENABLE) { ret = max77660_regulator_unmask_ext_control(reg->dev, pdata->flags); if (ret < 0) { dev_err(reg->dev, "Unmasking ext control failed: %d\n", ret); return ret; } } /* Update Power Mode register mask and offset */ if (rinfo->type == REGULATOR_TYPE_BUCK) { idx = reg->rinfo->id - MAX77660_REGULATOR_ID_BUCK1; /* 4 Bucks Pwr Mode in 1 register */ reg->rinfo->regs[PWR_MODE_REG].addr = MAX77660_REG_BUCK_PWR_MODE1 + (idx/4); reg->rinfo->power_mode_shift = (idx%4)*2 ; reg->rinfo->power_mode_mask = reg->rinfo->power_mode_mask << (reg->rinfo->power_mode_shift); } if ((rinfo->type == REGULATOR_TYPE_LDO_N) || (rinfo->type == REGULATOR_TYPE_LDO_P)) { idx = reg->rinfo->id - MAX77660_REGULATOR_ID_LDO1; /* 4 LDOs Pwr Mode in 1 register */ reg->rinfo->regs[PWR_MODE_REG].addr = MAX77660_REG_LDO_PWR_MODE1 + + (idx/4); reg->rinfo->power_mode_shift = (idx%4)*2 ; reg->rinfo->power_mode_mask = reg->rinfo->power_mode_mask << (reg->rinfo->power_mode_shift); } /* Update FPS source */ if (rinfo->regs[FPS_REG].addr == MAX77660_REG_FPS_NONE) reg->fps_src = FPS_SRC_NONE; else reg->fps_src = (reg->val[FPS_REG] & MAX77660_FPS_SRC_MASK) >> MAX77660_FPS_SRC_SHIFT; dev_dbg(reg->dev, "preinit: initial fps_src=%s\n", fps_src_name(reg->fps_src)); /* Update power mode */ max77660_regulator_get_power_mode(reg); /* Check Chip Identification */ ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, MAX77660_REG_CID5, &val); if (ret < 0) { dev_err(reg->dev, "preinit: Failed to get register 0x%x\n", MAX77660_REG_CID5); return ret; } /* Set FPS */ ret = max77660_regulator_set_fps_cfgs(reg, pdata->fps_cfgs, pdata->num_fps_cfgs); if (ret < 0) { dev_err(reg->dev, "preinit: Failed to set FPSCFG\n"); return ret; } /* N-Channel LDOs don't support Low-Power mode. */ if ((rinfo->type == REGULATOR_TYPE_LDO_N) && (pdata->flags & GLPM_ENABLE)) pdata->flags &= ~GLPM_ENABLE; /* To prevent power rail turn-off when change FPS source, * it must set power mode to NORMAL before change FPS source to NONE * from SRC_0, SRC_1 and SRC_2. */ if ((reg->fps_src != FPS_SRC_NONE) && (pdata->fps_src == FPS_SRC_NONE) && (reg->power_mode != POWER_MODE_NORMAL)) { val = (pdata->flags & GLPM_ENABLE) ? POWER_MODE_GLPM : POWER_MODE_NORMAL; ret = max77660_regulator_set_power_mode(reg, val); if (ret < 0) { dev_err(reg->dev, "preinit: Failed to set power mode to POWER_MODE_NORMAL\n"); return ret; } } if (reg->rinfo->id == MAX77660_REGULATOR_ID_LDO15 || reg->rinfo->id == MAX77660_REGULATOR_ID_LDO16) { mask = 0; addr = (reg->rinfo->id == MAX77660_REGULATOR_ID_LDO15) ? MAX77660_REG_SIM_SIM1CNFG1 : MAX77660_REG_SIM_SIM2CNFG1; ret = max77660_reg_read(to_max77660_chip(reg), MAX77660_PWR_SLAVE, addr, &val); if (ret < 0) { dev_err(reg->dev, "preinit: Failed to get register 0x%x\n", addr); } mask |= SIM_SIM1_2_CNFG1_BATREM_EN_MASK | SIM_SIM1_2_CNFG1_SIM1DBCNT_MASK; val &= ~(SIM_SIM1_2_CNFG1_SIM1DBCNT_MASK); val |= SIM_SIM1_2_DBCNT; /* FIXME: if BAT remove is considered */ val &= ~(1 << SIM_SIM1_2_CNFG1_BATREM_EN_SHIFT); max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, addr, val, mask); max77660_regulator_set_power_mode(reg, POWER_MODE_NORMAL); } ret = max77660_regulator_set_fps(reg); if (ret < 0) { dev_err(reg->dev, "preinit: Failed to set FPS\n"); return ret; } /* * ES 1.0 errata suggest to keep BUCK3 and BUCK5 in FPWM mode */ if (max77660_is_es_1_0(reg->dev)) if (reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK3 || reg->rinfo->id == MAX77660_REGULATOR_ID_BUCK5) pdata->flags |= SD_FORCED_PWM_MODE; if (rinfo->type == REGULATOR_TYPE_BUCK) { val = 0; mask = 0; if ((reg->rinfo->id >= MAX77660_REGULATOR_ID_BUCK1) && (reg->rinfo->id <= MAX77660_REGULATOR_ID_BUCK5)) { mask |= MAX77660_BUCK1_5_CNFG_FPWM_MASK; if (pdata->flags & SD_FORCED_PWM_MODE) val |= MAX77660_BUCK1_5_CNFG_FPWM_MASK; mask |= MAX77660_BUCK1_5_CNFG_FSRADE_MASK; if (pdata->flags & SD_FSRADE_DISABLE) val |= MAX77660_BUCK1_5_CNFG_FSRADE_MASK; mask |= MAX77660_BUCK1_5_CNFG_DVFS_EN_MASK; if (pdata->flags & DISABLE_DVFS) val &= ~MAX77660_BUCK1_5_CNFG_DVFS_EN_MASK; } else if ((reg->rinfo->id >= MAX77660_REGULATOR_ID_BUCK6) && (reg->rinfo->id <= MAX77660_REGULATOR_ID_BUCK7)) { mask |= MAX77660_BUCK6_7_CNFG_FPWM_MASK; /* ES 1.1 suggest to remove all BUCKS from FPWM */ if ((pdata->flags & SD_FORCED_PWM_MODE) && !(max77660_is_es_1_1(reg->dev))) val |= MAX77660_BUCK6_7_CNFG_FPWM_MASK; } ret = max77660_reg_update(to_max77660_chip(reg), MAX77660_PWR_SLAVE, rinfo->regs[CFG_REG].addr, val, mask); if (ret < 0) { dev_err(reg->dev, "%s:Failed to set register 0x%x\n", __func__, rinfo->regs[CFG_REG].addr); return ret; } } return 0; } #define REGULATOR_BUCK(_id, _volt_mask, _fps_reg, _min_uV, _max_uV, _step_uV) \ [MAX77660_REGULATOR_ID_##_id] = { \ .id = MAX77660_REGULATOR_ID_##_id, \ .type = REGULATOR_TYPE_BUCK, \ .volt_mask = MAX77660_##_volt_mask##_VOLT_MASK, \ .regs = { \ [VOLT_REG] = { \ .addr = MAX77660_REG_##_id##_VOUT, \ }, \ [CFG_REG] = { \ .addr = MAX77660_REG_##_id##_CNFG, \ }, \ [FPS_REG] = { \ .addr = MAX77660_REG_FPS_##_id, \ }, \ }, \ .min_uV = _min_uV, \ .max_uV = _max_uV, \ .step_uV = _step_uV, \ .power_mode_mask = MAX77660_BUCK_POWER_MODE_MASK, \ .power_mode_shift = MAX77660_BUCK_POWER_MODE_SHIFT, \ .desc = { \ .name = max77660_rails(_id), \ .id = MAX77660_REGULATOR_ID_##_id, \ .ops = &max77660_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } #define REGULATOR_LDO(_id, _type, _min_uV, _max_uV, _step_uV) \ [MAX77660_REGULATOR_ID_##_id] = { \ .id = MAX77660_REGULATOR_ID_##_id, \ .type = REGULATOR_TYPE_LDO_##_type, \ .volt_mask = MAX77660_LDO_VOLT_MASK, \ .regs = { \ [VOLT_REG] = { \ .addr = MAX77660_REG_##_id##_CNFG, \ }, \ [CFG_REG] = { \ .addr = MAX77660_REG_##_id##_CNFG, \ }, \ [FPS_REG] = { \ .addr = MAX77660_REG_FPS_##_id, \ }, \ }, \ .min_uV = _min_uV, \ .max_uV = _max_uV, \ .step_uV = _step_uV, \ .power_mode_mask = MAX77660_LDO_POWER_MODE_MASK, \ .power_mode_shift = MAX77660_LDO_POWER_MODE_SHIFT, \ .desc = { \ .name = max77660_rails(_id), \ .id = MAX77660_REGULATOR_ID_##_id, \ .ops = &max77660_regulator_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } #define REGULATOR_SW(_id, _enable_bit) \ [MAX77660_REGULATOR_ID_##_id] = { \ .id = MAX77660_REGULATOR_ID_##_id, \ .type = REGULATOR_TYPE_SW, \ .volt_mask = 0, \ .enable_bit = _enable_bit, \ .regs = { \ [VOLT_REG] = { \ .addr = MAX77660_REG_SW_EN, \ }, \ [CFG_REG] = { \ .addr = MAX77660_REG_##_id##_CNFG, \ }, \ [FPS_REG] = { \ .addr = MAX77660_REG_FPS_NONE, \ }, \ }, \ .desc = { \ .name = max77660_rails(_id), \ .id = MAX77660_REGULATOR_ID_##_id, \ .ops = &max77660_sw_ops, \ .type = REGULATOR_VOLTAGE, \ .owner = THIS_MODULE, \ }, \ } static struct max77660_regulator_info max77660_regs_info[MAX77660_REGULATOR_ID_NR] = { REGULATOR_BUCK(BUCK1, SDX, BUCK1, 600000, 1500000, 6250), REGULATOR_BUCK(BUCK2, SDX, BUCK2, 600000, 1500000, 6250), REGULATOR_BUCK(BUCK3, SDX, BUCK3, 600000, 3787500, 12500), REGULATOR_BUCK(BUCK4, SDX, BUCK4, 600000, 1500000, 6250), REGULATOR_BUCK(BUCK5, SDX, BUCK5, 600000, 3787500, 12500), REGULATOR_BUCK(BUCK6, SD1, BUCK6, 1000000, 4150000, 50000), REGULATOR_BUCK(BUCK7, SD1, BUCK7, 1000000, 4150000, 50000), REGULATOR_LDO(LDO1, N, 600000, 2175000, 25000), REGULATOR_LDO(LDO2, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO3, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO4, P, 800000, 3950000, 12500), REGULATOR_LDO(LDO5, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO6, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO7, N, 600000, 2175000, 25000), REGULATOR_LDO(LDO8, N, 600000, 2175000, 25000), REGULATOR_LDO(LDO9, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO10, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO11, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO12, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO13, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO14, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO15, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO16, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO17, P, 800000, 3950000, 50000), REGULATOR_LDO(LDO18, P, 800000, 3950000, 50000), REGULATOR_SW(SW1, 0), REGULATOR_SW(SW2, 1), REGULATOR_SW(SW3, 2), REGULATOR_SW(SW4, -1), REGULATOR_SW(SW5, 3), }; static ssize_t max77660_show_dvfs_data(struct device *dev, struct device_attribute *attr, char *buf) { struct max77660_platform_data *pdata = dev_get_platdata(dev->parent); struct max77660_pwm_dvfs_init_data *dvfs_pd = &pdata->dvfs_pd; int count = 0; if (!dvfs_pd->en_pwm) return 0; count += sprintf(buf+count, "base_voltage:%d\n", dvfs_pd->base_voltage_uV); count += sprintf(buf+count, "step_size:%d\n", dvfs_pd->step_voltage_uV); count += sprintf(buf+count, "max_voltage:%d\n", dvfs_pd->max_voltage_uV); count += sprintf(buf+count, "default_voltage:%d\n", dvfs_pd->default_voltage_uV); return count; } static DEVICE_ATTR(dvfs_data, 0444, max77660_show_dvfs_data, NULL); static int max77660_pwm_dvfs_init(struct device *max77660_pmic_dev, struct max77660_platform_data *pdata) { u8 val = 0; int ret; struct device *parent = max77660_pmic_dev->parent; struct max77660_pwm_dvfs_init_data *dvfs_pd = &pdata->dvfs_pd; if (!dvfs_pd->en_pwm) return 0; ret = max77660_reg_update(parent, MAX77660_PWR_SLAVE, MAX77660_REG_BUCK4_CNFG, 1 << MAX77660_BUCK4_DVFS_EN_SHIFT, MAX77660_BUCK4_DVFS_EN_MASK); if (ret < 0) return ret; /* VSR gets reset after DVFS_EN changes from 0 to 1 */ val = DIV_ROUND_UP((dvfs_pd->default_voltage_uV - DVFS_BASE_VOLTAGE_UV), DVFS_VOLTAGE_STEP_UV); ret = max77660_reg_write(parent, MAX77660_PWR_SLAVE, MAX77660_REG_BUCK4_VSR, val); if (ret < 0) return ret; val = (1 << MAX77660_BUCK4_DVFS_PWMEN_SHIFT); switch (dvfs_pd->step_voltage_uV) { case 12500: val |= 0x1; break; case 25000: val |= 0x2; break; } ret = max77660_reg_write(parent, MAX77660_PWR_SLAVE, MAX77660_REG_BUCK4_DVFS_CNFG, val); if (ret < 0) return ret; val = DIV_ROUND_UP((dvfs_pd->base_voltage_uV - DVFS_BASE_VOLTAGE_UV), DVFS_VOLTAGE_STEP_UV); ret = max77660_reg_write(parent, MAX77660_PWR_SLAVE, MAX77660_REG_BUCK4_VBR, val); if (ret < 0) return ret; val = DIV_ROUND_UP((dvfs_pd->max_voltage_uV - DVFS_BASE_VOLTAGE_UV), DVFS_VOLTAGE_STEP_UV); ret = max77660_reg_write(parent, MAX77660_PWR_SLAVE, MAX77660_REG_BUCK4_MVR, val); if (ret < 0) return ret; ret = device_create_file(max77660_pmic_dev, &dev_attr_dvfs_data); if (ret) dev_warn(max77660_pmic_dev, "Can't register dvfs sysfs attribute\n"); ret = sysfs_create_link(kernel_kobj, &(max77660_pmic_dev->kobj), "pmic"); if (ret) dev_warn(max77660_pmic_dev, "Can't create sysfs link\n"); return ret; } static int max77660_regulator_probe(struct platform_device *pdev) { struct max77660_platform_data *pdata = dev_get_platdata(pdev->dev.parent); struct regulator_desc *rdesc; struct max77660_regulator *reg; struct max77660_regulator *max_regs; struct regulator_config config = { }; int ret = 0; int id; int reg_id; if (!pdata) { dev_err(&pdev->dev, "No Platform data\n"); return -ENODEV; } max_regs = devm_kzalloc(&pdev->dev, MAX77660_REGULATOR_ID_NR * sizeof(*max_regs), GFP_KERNEL); if (!max_regs) { dev_err(&pdev->dev, "mem alloc for reg failed\n"); return -ENOMEM; } platform_set_drvdata(pdev, max_regs); ret = max77660_regulator_mask_ext_control(&pdev->dev); if (ret < 0) { dev_err(&pdev->dev, "Masking ext control failed, %d\n", ret); return ret; } for (id = 0; id < MAX77660_REGULATOR_ID_NR; ++id) { struct max77660_regulator_platform_data *reg_pdata; struct regulator_init_data *reg_init_data = NULL; reg_pdata = pdata->regulator_pdata[id]; reg_id = id; reg = &max_regs[id]; rdesc = &max77660_regs_info[reg_id].desc; reg->rinfo = &max77660_regs_info[reg_id]; reg->dev = &pdev->dev; reg->pdata = reg_pdata; if (reg_pdata) reg_init_data = reg_pdata->reg_init_data; reg->regulator_mode = REGULATOR_MODE_NORMAL; reg->power_mode = POWER_MODE_NORMAL; dev_dbg(&pdev->dev, "probe: name=%s\n", rdesc->name); if (reg_pdata) { ret = max77660_regulator_preinit(reg); if (ret < 0) { dev_err(&pdev->dev, "Preinit regulator %s failed: %d\n", rdesc->name, ret); goto clean_exit; } } /* ES1.0 errata: Clear active discharge for LDO1 */ if (max77660_is_es_1_0(&pdev->dev) && (id == MAX77660_REGULATOR_ID_LDO1)) { ret = max77660_reg_clr_bits(to_max77660_chip(reg), MAX77660_PWR_SLAVE, MAX77660_REG_LDO1_CNFG, MAX77660_LDO1_18_CNFG_ADE_MASK); if (ret < 0) { dev_err(&pdev->dev, "LDO1_CNFG update failed: %d\n", ret); goto clean_exit; } } config.dev = &pdev->dev; config.init_data = reg_init_data; config.driver_data = reg; reg->rdev = regulator_register(rdesc, &config); if (IS_ERR(reg->rdev)) { ret = PTR_ERR(reg->rdev); dev_err(&pdev->dev, "regulator %s register failed: %d\n", rdesc->name, ret); goto clean_exit; } if (reg_pdata && (reg_pdata->flags & MAX77660_EXTERNAL_ENABLE)) { reg->external_flags = reg_pdata->flags; ret = max77660_regulator_set_power_mode(reg, POWER_MODE_DISABLE); if (ret < 0) { dev_err(&pdev->dev, "power mode config for regulator %s failed, %d\n", rdesc->name, ret); goto clean_exit; } } } ret = max77660_pwm_dvfs_init(&pdev->dev, pdata); if (ret) dev_err(&pdev->dev, "Failed to initialize BUCK4 dvfs"); return 0; clean_exit: while (--id >= 0) { reg = &max_regs[id]; if (reg->dev) regulator_unregister(reg->rdev); } return ret; } static int max77660_regulator_remove(struct platform_device *pdev) { struct max77660_regulator *max_regs = platform_get_drvdata(pdev); struct max77660_regulator *reg; int reg_count = MAX77660_REGULATOR_ID_NR; while (--reg_count >= 0) { reg = &max_regs[reg_count]; if (reg->dev) regulator_unregister(reg->rdev); } return 0; } static struct platform_driver max77660_regulator_driver = { .probe = max77660_regulator_probe, .remove = max77660_regulator_remove, .driver = { .name = "max77660-pmic", .owner = THIS_MODULE, }, }; static int __init max77660_regulator_init(void) { return platform_driver_register(&max77660_regulator_driver); } subsys_initcall(max77660_regulator_init); static void __exit max77660_reg_exit(void) { platform_driver_unregister(&max77660_regulator_driver); } module_exit(max77660_reg_exit); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MAX77660 Regulator Driver"); MODULE_VERSION("1.0"); MODULE_AUTHOR("Maxim Integrated"); MODULE_ALIAS("platform:max77660-regulator");