| /* |
| * driver/regulator/tps80031-regulator.c |
| * |
| * Regulator driver for TI TPS80031 |
| * |
| * Copyright (C) 2011 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. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/delay.h> |
| #include <linux/init.h> |
| #include <linux/err.h> |
| #include <linux/slab.h> |
| #include <linux/platform_device.h> |
| #include <linux/regulator/driver.h> |
| #include <linux/regulator/machine.h> |
| #include <linux/regulator/tps80031-regulator.h> |
| #include <linux/mfd/tps80031.h> |
| |
| /* Flags for DCDC Voltage reading */ |
| #define DCDC_OFFSET_EN BIT(0) |
| #define DCDC_EXTENDED_EN BIT(1) |
| #define TRACK_MODE_ENABLE BIT(2) |
| |
| #define SMPS_MULTOFFSET_VIO BIT(1) |
| #define SMPS_MULTOFFSET_SMPS1 BIT(3) |
| #define SMPS_MULTOFFSET_SMPS2 BIT(4) |
| #define SMPS_MULTOFFSET_SMPS3 BIT(6) |
| #define SMPS_MULTOFFSET_SMPS4 BIT(0) |
| |
| #define PMC_SMPS_OFFSET_ADD 0xE0 |
| #define PMC_SMPS_MULT_ADD 0xE3 |
| |
| #define STATE_OFF 0x00 |
| #define STATE_ON 0x01 |
| #define STATE_MASK 0x03 |
| |
| #define TRANS_SLEEP_OFF 0x00 |
| #define TRANS_SLEEP_ON 0x04 |
| #define TRANS_SLEEP_MASK 0x0C |
| |
| #define SMPS_CMD_MASK 0xC0 |
| #define SMPS_VSEL_MASK 0x3F |
| #define LDO_VSEL_MASK 0x1F |
| |
| #define TPS80031_MISC2_ADD 0xE5 |
| #define MISC2_LDOUSB_IN_VSYS 0x10 |
| #define MISC2_LDOUSB_IN_PMID 0x08 |
| #define MISC2_LDOUSB_IN_MASK 0x18 |
| |
| #define MISC2_LDO3_SEL_VIB_VAL BIT(0) |
| #define MISC2_LDO3_SEL_VIB_MASK 0x1 |
| |
| #define CHARGERUSB_CTRL3_ADD 0xEA |
| #define BOOST_HW_PWR_EN BIT(5) |
| #define BOOST_HW_PWR_EN_MASK BIT(5) |
| |
| #define CHARGERUSB_CTRL1_ADD 0xE8 |
| #define OPA_MODE_EN BIT(6) |
| #define OPA_MODE_EN_MASK BIT(6) |
| |
| #define USB_VBUS_CTRL_SET 0x04 |
| #define USB_VBUS_CTRL_CLR 0x05 |
| #define VBUS_DISCHRG 0x20 |
| |
| #define EXT_PWR_REQ (PWR_REQ_INPUT_PREQ1 | PWR_REQ_INPUT_PREQ2 | \ |
| PWR_REQ_INPUT_PREQ3) |
| |
| struct tps80031_regulator { |
| |
| /* Regulator register address.*/ |
| u8 trans_reg; |
| u8 state_reg; |
| u8 force_reg; |
| u8 volt_reg; |
| u8 volt_id; |
| uint8_t trans_reg_cache; |
| uint8_t state_reg_cache; |
| uint8_t force_reg_cache; |
| uint8_t volt_reg_cache; |
| |
| /* twl resource ID, for resource control state machine */ |
| u8 id; |
| |
| /* chip constraints on regulator behavior */ |
| u16 min_mV; |
| u16 max_mV; |
| |
| /* regulator specific turn-on delay */ |
| int delay; |
| |
| u8 flags; |
| unsigned int platform_flags; |
| unsigned int ext_ctrl_flag; |
| |
| /* used by regulator core */ |
| struct regulator_desc desc; |
| |
| /* Device */ |
| struct device *dev; |
| |
| /*Power request bits */ |
| int preq_bit; |
| }; |
| |
| static inline struct device *to_tps80031_dev(struct regulator_dev *rdev) |
| { |
| return rdev_get_dev(rdev)->parent->parent; |
| } |
| |
| static int tps80031_regulator_enable_time(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| |
| return ri->delay; |
| } |
| |
| static u8 tps80031_get_smps_offset(struct device *parent) |
| { |
| u8 value; |
| int ret; |
| |
| ret = tps80031_read(parent, SLAVE_ID1, PMC_SMPS_OFFSET_ADD, &value); |
| if (ret < 0) { |
| dev_err(parent, "Error in reading smps offset register\n"); |
| return 0; |
| } |
| return value; |
| } |
| |
| static u8 tps80031_get_smps_mult(struct device *parent) |
| { |
| u8 value; |
| int ret; |
| |
| ret = tps80031_read(parent, SLAVE_ID1, PMC_SMPS_MULT_ADD, &value); |
| if (ret < 0) { |
| dev_err(parent, "Error in reading smps mult register\n"); |
| return 0; |
| } |
| return value; |
| } |
| |
| static int tps80031_reg_is_enabled(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| |
| if (ri->ext_ctrl_flag & EXT_PWR_REQ) |
| return true; |
| return ((ri->state_reg_cache & STATE_MASK) == STATE_ON); |
| } |
| |
| static int tps80031_reg_enable(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| int ret; |
| uint8_t reg_val; |
| |
| if (ri->ext_ctrl_flag & EXT_PWR_REQ) |
| return 0; |
| |
| reg_val = (ri->state_reg_cache & ~STATE_MASK) | |
| (STATE_ON & STATE_MASK); |
| ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); |
| if (ret < 0) { |
| dev_err(&rdev->dev, "Error in writing the STATE register\n"); |
| return ret; |
| } |
| ri->state_reg_cache = reg_val; |
| udelay(ri->delay); |
| return ret; |
| } |
| |
| static int tps80031_reg_disable(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| int ret; |
| uint8_t reg_val; |
| |
| if (ri->ext_ctrl_flag & EXT_PWR_REQ) |
| return 0; |
| |
| reg_val = (ri->state_reg_cache & ~STATE_MASK) | |
| (STATE_OFF & STATE_MASK); |
| ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); |
| if (ret < 0) |
| dev_err(&rdev->dev, "Error in writing the STATE register\n"); |
| else |
| ri->state_reg_cache = reg_val; |
| return ret; |
| } |
| |
| /* |
| * DCDC status and control |
| */ |
| static int tps80031dcdc_list_voltage(struct regulator_dev *rdev, unsigned index) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| int voltage = 0; |
| |
| switch (ri->flags) { |
| case 0: |
| if (index == 0) |
| voltage = 0; |
| else if (index < 58) |
| voltage = (607700 + (12660 * (index - 1))); |
| else if (index == 58) |
| voltage = 1350 * 1000; |
| else if (index == 59) |
| voltage = 1500 * 1000; |
| else if (index == 60) |
| voltage = 1800 * 1000; |
| else if (index == 61) |
| voltage = 1900 * 1000; |
| else if (index == 62) |
| voltage = 2100 * 1000; |
| break; |
| |
| case DCDC_OFFSET_EN: |
| if (index == 0) |
| voltage = 0; |
| else if (index < 58) |
| voltage = (700000 + (12500 * (index - 1))); |
| else if (index == 58) |
| voltage = 1350 * 1000; |
| else if (index == 59) |
| voltage = 1500 * 1000; |
| else if (index == 60) |
| voltage = 1800 * 1000; |
| else if (index == 61) |
| voltage = 1900 * 1000; |
| else if (index == 62) |
| voltage = 2100 * 1000; |
| break; |
| |
| case DCDC_EXTENDED_EN: |
| if (index == 0) |
| voltage = 0; |
| else if (index < 58) |
| voltage = (1852000 + (38600 * (index - 1))); |
| else if (index == 58) |
| voltage = 2084 * 1000; |
| else if (index == 59) |
| voltage = 2315 * 1000; |
| else if (index == 60) |
| voltage = 2778 * 1000; |
| else if (index == 61) |
| voltage = 2932 * 1000; |
| else if (index == 62) |
| voltage = 3241 * 1000; |
| break; |
| |
| case DCDC_OFFSET_EN|DCDC_EXTENDED_EN: |
| if (index == 0) |
| voltage = 0; |
| else if (index < 58) |
| voltage = (2161000 + (38600 * (index - 1))); |
| else if (index == 58) |
| voltage = 4167 * 1000; |
| else if (index == 59) |
| voltage = 2315 * 1000; |
| else if (index == 60) |
| voltage = 2778 * 1000; |
| else if (index == 61) |
| voltage = 2932 * 1000; |
| else if (index == 62) |
| voltage = 3241 * 1000; |
| break; |
| } |
| |
| return voltage; |
| } |
| |
| static int __tps80031_dcdc_set_voltage(struct device *parent, |
| struct tps80031_regulator *ri, |
| int min_uV, int max_uV, |
| unsigned *selector) |
| { |
| int vsel = 0; |
| int ret; |
| |
| switch (ri->flags) { |
| case 0: |
| if (min_uV == 0) |
| vsel = 0; |
| else if ((min_uV >= 607700) && (min_uV <= 1300000)) { |
| int cal_volt; |
| vsel = (10 * (min_uV - 607700)) / 1266; |
| if (vsel % 100) |
| vsel += 100; |
| vsel /= 100; |
| vsel++; |
| cal_volt = (607700 + (12660 * (vsel - 1))); |
| if (cal_volt > max_uV) |
| return -EINVAL; |
| } else if ((min_uV > 1900000) && (max_uV >= 2100000)) |
| vsel = 62; |
| else if ((min_uV > 1800000) && (max_uV >= 1900000)) |
| vsel = 61; |
| else if ((min_uV > 1500000) && (max_uV >= 1800000)) |
| vsel = 60; |
| else if ((min_uV > 1350000) && (max_uV >= 1500000)) |
| vsel = 59; |
| else if ((min_uV > 1300000) && (max_uV >= 1350000)) |
| vsel = 58; |
| else |
| return -EINVAL; |
| break; |
| |
| case DCDC_OFFSET_EN: |
| if (min_uV == 0) |
| vsel = 0; |
| else if ((min_uV >= 700000) && (min_uV <= 1420000)) { |
| int cal_volt; |
| vsel = (min_uV - 700000) / 125; |
| if (vsel % 100) |
| vsel += 100; |
| vsel /= 100; |
| vsel++; |
| cal_volt = (700000 + (12500 * (vsel - 1))); |
| if (cal_volt > max_uV) |
| return -EINVAL; |
| } else if ((min_uV > 1900000) && (max_uV >= 2100000)) |
| vsel = 62; |
| else if ((min_uV > 1800000) && (max_uV >= 1900000)) |
| vsel = 61; |
| else if ((min_uV > 1500000) && (max_uV >= 1800000)) |
| vsel = 60; |
| else if ((min_uV > 1350000) && (max_uV >= 1500000)) |
| vsel = 59; |
| else if ((min_uV > 1300000) && (max_uV >= 1350000)) |
| vsel = 58; |
| else |
| return -EINVAL; |
| break; |
| |
| case DCDC_EXTENDED_EN: |
| if (min_uV == 0) |
| vsel = 0; |
| else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { |
| vsel = (min_uV - 1852000) / 386; |
| if (vsel % 100) |
| vsel += 100; |
| vsel++; |
| } |
| break; |
| |
| case DCDC_OFFSET_EN|DCDC_EXTENDED_EN: |
| if (min_uV == 0) |
| vsel = 0; |
| else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { |
| vsel = (min_uV - 2161000) / 386; |
| if (vsel % 100) |
| vsel += 100; |
| vsel /= 100; |
| vsel++; |
| } |
| break; |
| } |
| |
| if (selector) |
| *selector = vsel; |
| |
| if (ri->force_reg) { |
| if (((ri->force_reg_cache >> 6) & 0x3) == 0) { |
| ret = tps80031_write(parent, ri->volt_id, |
| ri->force_reg, vsel); |
| if (ret < 0) |
| dev_err(ri->dev, "Error in writing the " |
| "force register\n"); |
| else |
| ri->force_reg_cache = vsel; |
| return ret; |
| } |
| } |
| ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); |
| if (ret < 0) |
| dev_err(ri->dev, "Error in writing the Voltage register\n"); |
| else |
| ri->volt_reg_cache = vsel; |
| return ret; |
| } |
| |
| static int tps80031dcdc_set_voltage(struct regulator_dev *rdev, |
| int min_uV, int max_uV, unsigned *selector) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| return __tps80031_dcdc_set_voltage(parent, ri, min_uV, max_uV, |
| selector); |
| } |
| |
| static int tps80031dcdc_get_voltage(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| uint8_t vsel = 0; |
| int voltage = 0; |
| |
| if (ri->force_reg) { |
| vsel = ri->force_reg_cache; |
| if ((vsel & SMPS_CMD_MASK) == 0) |
| goto decode; |
| } |
| |
| vsel = ri->volt_reg_cache; |
| |
| decode: |
| vsel &= SMPS_VSEL_MASK; |
| |
| switch (ri->flags) { |
| case 0: |
| if (vsel == 0) |
| voltage = 0; |
| else if (vsel < 58) |
| voltage = (607700 + (12660 * (vsel - 1))); |
| else if (vsel == 58) |
| voltage = 1350 * 1000; |
| else if (vsel == 59) |
| voltage = 1500 * 1000; |
| else if (vsel == 60) |
| voltage = 1800 * 1000; |
| else if (vsel == 61) |
| voltage = 1900 * 1000; |
| else if (vsel == 62) |
| voltage = 2100 * 1000; |
| break; |
| |
| case DCDC_OFFSET_EN: |
| if (vsel == 0) |
| voltage = 0; |
| else if (vsel < 58) |
| voltage = (700000 + (12500 * (vsel - 1))); |
| else if (vsel == 58) |
| voltage = 1350 * 1000; |
| else if (vsel == 59) |
| voltage = 1500 * 1000; |
| else if (vsel == 60) |
| voltage = 1800 * 1000; |
| else if (vsel == 61) |
| voltage = 1900 * 1000; |
| else if (vsel == 62) |
| voltage = 2100 * 1000; |
| break; |
| |
| case DCDC_EXTENDED_EN: |
| if (vsel == 0) |
| voltage = 0; |
| else if (vsel < 58) |
| voltage = (1852000 + (38600 * (vsel - 1))); |
| else if (vsel == 58) |
| voltage = 2084 * 1000; |
| else if (vsel == 59) |
| voltage = 2315 * 1000; |
| else if (vsel == 60) |
| voltage = 2778 * 1000; |
| else if (vsel == 61) |
| voltage = 2932 * 1000; |
| else if (vsel == 62) |
| voltage = 3241 * 1000; |
| break; |
| |
| case DCDC_EXTENDED_EN|DCDC_OFFSET_EN: |
| if (vsel == 0) |
| voltage = 0; |
| else if (vsel < 58) |
| voltage = (2161000 + (38600 * (vsel - 1))); |
| else if (vsel == 58) |
| voltage = 4167 * 1000; |
| else if (vsel == 59) |
| voltage = 2315 * 1000; |
| else if (vsel == 60) |
| voltage = 2778 * 1000; |
| else if (vsel == 61) |
| voltage = 2932 * 1000; |
| else if (vsel == 62) |
| voltage = 3241 * 1000; |
| break; |
| } |
| |
| return voltage; |
| } |
| |
| static int tps80031ldo_list_voltage(struct regulator_dev *rdev, unsigned index) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| |
| if (index == 0) |
| return 0; |
| |
| if ((ri->desc.id == TPS80031_ID_LDO2) && |
| (ri->flags & TRACK_MODE_ENABLE)) |
| return (ri->min_mV + (((index - 1) * 125))/10) * 1000; |
| |
| return (ri->min_mV + ((index - 1) * 100)) * 1000; |
| } |
| |
| static int __tps80031_ldo2_set_voltage_track_mode(struct device *parent, |
| struct tps80031_regulator *ri, int min_uV, int max_uV) |
| { |
| int vsel = 0; |
| int ret; |
| int nvsel; |
| |
| if (min_uV < 600000) { |
| vsel = 0; |
| } else if ((min_uV >= 600000) && (max_uV <= 1300000)) { |
| vsel = (min_uV - 600000) / 125; |
| if (vsel % 100) |
| vsel += 100; |
| vsel /= 100; |
| vsel++; |
| } else { |
| return -EINVAL; |
| } |
| |
| /* Check for valid setting for TPS80031 or TPS80032-ES1.0 */ |
| if ((tps80031_get_chip_info(parent) == TPS80031) || |
| ((tps80031_get_chip_info(parent) == TPS80032) && |
| (tps80031_get_pmu_version(parent) == 0x0))) { |
| nvsel = vsel & 0x1F; |
| if ((nvsel == 0x0) || (nvsel >= 0x19 && nvsel <= 0x1F)) { |
| dev_err(ri->dev, "Invalid value for track mode LDO2 " |
| "configuration for TPS8003x PMU\n"); |
| return -EINVAL; |
| } |
| } |
| |
| ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); |
| if (ret < 0) |
| dev_err(ri->dev, "Error in writing the Voltage register\n"); |
| else |
| ri->volt_reg_cache = vsel; |
| return ret; |
| } |
| |
| |
| static int __tps80031_ldo_set_voltage(struct device *parent, |
| struct tps80031_regulator *ri, |
| int min_uV, int max_uV, |
| unsigned *selector) |
| { |
| int vsel; |
| int ret; |
| |
| if ((min_uV/1000 < ri->min_mV) || (max_uV/1000 > ri->max_mV)) |
| return -EDOM; |
| |
| if ((ri->desc.id == TPS80031_ID_LDO2) && |
| (ri->flags & TRACK_MODE_ENABLE)) |
| return __tps80031_ldo2_set_voltage_track_mode(parent, ri, |
| min_uV, max_uV); |
| |
| /* |
| * Use the below formula to calculate vsel |
| * mV = 1000mv + 100mv * (vsel - 1) |
| */ |
| vsel = (min_uV/1000 - 1000)/100 + 1; |
| if (selector) |
| *selector = vsel; |
| ret = tps80031_write(parent, ri->volt_id, ri->volt_reg, vsel); |
| if (ret < 0) |
| dev_err(ri->dev, "Error in writing the Voltage register\n"); |
| else |
| ri->volt_reg_cache = vsel; |
| return ret; |
| } |
| |
| static int tps80031ldo_set_voltage(struct regulator_dev *rdev, |
| int min_uV, int max_uV, unsigned *selector) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| |
| return __tps80031_ldo_set_voltage(parent, ri, min_uV, max_uV, |
| selector); |
| } |
| |
| static int tps80031ldo_get_voltage(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| uint8_t vsel; |
| |
| |
| if ((ri->desc.id == TPS80031_ID_LDO2) && |
| (ri->flags & TRACK_MODE_ENABLE)) { |
| vsel = ri->volt_reg_cache & 0x3F; |
| return (ri->min_mV + (((vsel - 1) * 125))/10) * 1000; |
| } |
| |
| vsel = ri->volt_reg_cache & LDO_VSEL_MASK; |
| /* |
| * Use the below formula to calculate vsel |
| * mV = 1000mv + 100mv * (vsel - 1) |
| */ |
| return (1000 + (100 * (vsel - 1))) * 1000; |
| } |
| |
| /* VBUS */ |
| static int tps80031_vbus_enable_time(struct regulator_dev *rdev) |
| { |
| /* Enable and settling time for vbus is 3ms */ |
| return 3000; |
| } |
| static int tps80031_vbus_is_enabled(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| uint8_t ctrl1, ctrl3; |
| int ret; |
| |
| if (ri->platform_flags & VBUS_SW_ONLY) { |
| ret = tps80031_read(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL1_ADD, &ctrl1); |
| if (!ret) |
| ret = tps80031_read(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL3_ADD, &ctrl3); |
| if (ret < 0) { |
| dev_err(&rdev->dev, "Error in reading control reg\n"); |
| return ret; |
| } |
| if ((ctrl1 & OPA_MODE_EN) && (ctrl3 & BOOST_HW_PWR_EN)) |
| return 1; |
| return 0; |
| } else { |
| return -EIO; |
| } |
| } |
| |
| static int tps80031_vbus_enable(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| int ret; |
| |
| if (ri->platform_flags & VBUS_SW_ONLY) { |
| ret = tps80031_set_bits(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL1_ADD, OPA_MODE_EN); |
| if (!ret) |
| ret = tps80031_set_bits(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL3_ADD, BOOST_HW_PWR_EN); |
| if (ret < 0) { |
| dev_err(&rdev->dev, "Error in reading control reg\n"); |
| return ret; |
| } |
| udelay(ri->delay); |
| return ret; |
| } |
| dev_err(&rdev->dev, "%s() is not supported with flag 0x%08x\n", |
| __func__, ri->platform_flags); |
| return -EIO; |
| } |
| |
| static int tps80031_vbus_disable(struct regulator_dev *rdev) |
| { |
| struct tps80031_regulator *ri = rdev_get_drvdata(rdev); |
| struct device *parent = to_tps80031_dev(rdev); |
| int ret = 0; |
| |
| if (ri->platform_flags & VBUS_SW_ONLY) { |
| |
| if (ri->platform_flags & VBUS_DISCHRG_EN_PDN) |
| ret = tps80031_write(parent, SLAVE_ID2, |
| USB_VBUS_CTRL_SET, VBUS_DISCHRG); |
| if (!ret) |
| ret = tps80031_clr_bits(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL1_ADD, OPA_MODE_EN); |
| if (!ret) |
| ret = tps80031_clr_bits(parent, SLAVE_ID2, |
| CHARGERUSB_CTRL3_ADD, BOOST_HW_PWR_EN); |
| if (!ret) |
| mdelay((ri->delay + 999)/1000); |
| |
| if (ri->platform_flags & VBUS_DISCHRG_EN_PDN) |
| tps80031_write(parent, SLAVE_ID2, |
| USB_VBUS_CTRL_CLR, VBUS_DISCHRG); |
| |
| if (ret < 0) |
| dev_err(&rdev->dev, "Error in reading control reg\n"); |
| return ret; |
| } |
| dev_err(&rdev->dev, "%s() is not supported with flag 0x%08x\n", |
| __func__, ri->platform_flags); |
| return -EIO; |
| } |
| |
| static int tps80031vbus_get_voltage(struct regulator_dev *rdev) |
| { |
| int ret; |
| ret = tps80031_vbus_is_enabled(rdev); |
| if (ret > 0) |
| return 5000000; |
| return ret; |
| } |
| |
| static struct regulator_ops tps80031dcdc_ops = { |
| .list_voltage = tps80031dcdc_list_voltage, |
| .set_voltage = tps80031dcdc_set_voltage, |
| .get_voltage = tps80031dcdc_get_voltage, |
| .enable = tps80031_reg_enable, |
| .disable = tps80031_reg_disable, |
| .is_enabled = tps80031_reg_is_enabled, |
| .enable_time = tps80031_regulator_enable_time, |
| }; |
| |
| static struct regulator_ops tps80031ldo_ops = { |
| .list_voltage = tps80031ldo_list_voltage, |
| .set_voltage = tps80031ldo_set_voltage, |
| .get_voltage = tps80031ldo_get_voltage, |
| .enable = tps80031_reg_enable, |
| .disable = tps80031_reg_disable, |
| .is_enabled = tps80031_reg_is_enabled, |
| .enable_time = tps80031_regulator_enable_time, |
| }; |
| |
| static struct regulator_ops tps80031vbus_ops = { |
| .get_voltage = tps80031vbus_get_voltage, |
| .enable = tps80031_vbus_enable, |
| .disable = tps80031_vbus_disable, |
| .is_enabled = tps80031_vbus_is_enabled, |
| .enable_time = tps80031_vbus_enable_time, |
| }; |
| |
| #define TPS80031_REG(_id, _trans_reg, _state_reg, _force_reg, _volt_reg, \ |
| _volt_id, min_mVolts, max_mVolts, _ops, _n_volt, _delay, \ |
| _preq_bit) \ |
| { \ |
| .trans_reg = _trans_reg, \ |
| .state_reg = _state_reg, \ |
| .force_reg = _force_reg, \ |
| .volt_reg = _volt_reg, \ |
| .volt_id = _volt_id, \ |
| .id = TPS80031_ID_##_id, \ |
| .min_mV = min_mVolts, \ |
| .max_mV = max_mVolts, \ |
| .desc = { \ |
| .name = tps80031_rails(_id), \ |
| .id = TPS80031_ID_##_id, \ |
| .n_voltages = _n_volt, \ |
| .ops = &_ops, \ |
| .type = REGULATOR_VOLTAGE, \ |
| .owner = THIS_MODULE, \ |
| }, \ |
| .delay = _delay, \ |
| .preq_bit = _preq_bit, \ |
| } |
| |
| static struct tps80031_regulator tps80031_regulator[] = { |
| TPS80031_REG(VIO, 0x47, 0x48, 0x49, 0x4A, SLAVE_ID0, 600, 2100, |
| tps80031dcdc_ops, 63, 500, 4), |
| TPS80031_REG(SMPS1, 0x53, 0x54, 0x55, 0x56, SLAVE_ID0, 600, 2100, |
| tps80031dcdc_ops, 63, 500, 0), |
| TPS80031_REG(SMPS2, 0x59, 0x5A, 0x5B, 0x5C, SLAVE_ID0, 600, 2100, |
| tps80031dcdc_ops, 63, 500, 1), |
| TPS80031_REG(SMPS3, 0x65, 0x66, 0x00, 0x68, SLAVE_ID1, 600, 2100, |
| tps80031dcdc_ops, 63, 500, 2), |
| TPS80031_REG(SMPS4, 0x41, 0x42, 0x00, 0x44, SLAVE_ID1, 600, 2100, |
| tps80031dcdc_ops, 63, 500, 3), |
| |
| TPS80031_REG(LDO1, 0x9D, 0x9E, 0x00, 0x9F, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 8), |
| TPS80031_REG(LDO2, 0x85, 0x86, 0x00, 0x87, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 9), |
| TPS80031_REG(LDO3, 0x8D, 0x8E, 0x00, 0x8F, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 10), |
| TPS80031_REG(LDO4, 0x89, 0x8A, 0x00, 0x8B, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 11), |
| TPS80031_REG(LDO5, 0x99, 0x9A, 0x00, 0x9B, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 12), |
| TPS80031_REG(LDO6, 0x91, 0x92, 0x00, 0x93, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 13), |
| TPS80031_REG(LDO7, 0xA5, 0xA6, 0x00, 0xA7, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 14), |
| TPS80031_REG(LDOUSB, 0xA1, 0xA2, 0x00, 0xA3, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 5), |
| TPS80031_REG(LDOLN, 0x95, 0x96, 0x00, 0x97, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, 15), |
| TPS80031_REG(VANA, 0x81, 0x82, 0x00, 0x83, SLAVE_ID1, 1000, 3300, |
| tps80031ldo_ops, 25, 500, -1), |
| TPS80031_REG(VBUS, 0x0, 0x0, 0x00, 0x0, SLAVE_ID1, 0, 5000, |
| tps80031vbus_ops, 2, 200000, -1), |
| }; |
| |
| static int tps80031_power_req_config(struct device *parent, |
| struct tps80031_regulator *ri, |
| struct tps80031_regulator_platform_data *tps80031_pdata) |
| { |
| int ret; |
| uint8_t reg_val; |
| |
| if (ri->preq_bit < 0) |
| return 0; |
| |
| ret = tps80031_ext_power_req_config(parent, ri->ext_ctrl_flag, |
| ri->preq_bit, ri->state_reg, ri->trans_reg); |
| if (!ret) |
| ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg, |
| &ri->trans_reg_cache); |
| |
| if (!ret && ri->state_reg) |
| ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg, |
| &ri->state_reg_cache); |
| if (ret < 0) { |
| dev_err(ri->dev, "%s() fails\n", __func__); |
| return ret; |
| } |
| |
| if (tps80031_pdata->ext_ctrl_flag & |
| (PWR_OFF_ON_SLEEP | PWR_ON_ON_SLEEP)) { |
| reg_val = (ri->trans_reg_cache & ~0xC); |
| if (tps80031_pdata->ext_ctrl_flag & PWR_ON_ON_SLEEP) |
| reg_val |= 0x4; |
| |
| ret = tps80031_write(parent, SLAVE_ID1, ri->trans_reg, |
| reg_val); |
| if (ret < 0) |
| dev_err(ri->dev, "Not able to write reg 0x%02x\n", |
| ri->trans_reg); |
| else |
| ri->trans_reg_cache = reg_val; |
| } |
| return ret; |
| } |
| |
| static int tps80031_regulator_preinit(struct device *parent, |
| struct tps80031_regulator *ri, |
| struct tps80031_regulator_platform_data *tps80031_pdata) |
| { |
| int ret = 0; |
| uint8_t reg_val; |
| |
| if (ri->desc.id == TPS80031_ID_LDOUSB) { |
| if (ri->platform_flags & USBLDO_INPUT_VSYS) |
| ret = tps80031_update(parent, SLAVE_ID1, |
| TPS80031_MISC2_ADD, |
| MISC2_LDOUSB_IN_VSYS, MISC2_LDOUSB_IN_MASK); |
| if (ri->platform_flags & USBLDO_INPUT_PMID) |
| ret = tps80031_update(parent, SLAVE_ID1, |
| TPS80031_MISC2_ADD, |
| MISC2_LDOUSB_IN_PMID, MISC2_LDOUSB_IN_MASK); |
| if (ret < 0) { |
| dev_err(ri->dev, "Not able to configure the rail " |
| "LDOUSB as per platform data error %d\n", ret); |
| return ret; |
| } |
| } |
| |
| if (ri->desc.id == TPS80031_ID_LDO3) { |
| if (ri->platform_flags & LDO3_OUTPUT_VIB) |
| ret = tps80031_update(parent, SLAVE_ID1, |
| TPS80031_MISC2_ADD, |
| MISC2_LDO3_SEL_VIB_VAL, |
| MISC2_LDO3_SEL_VIB_MASK); |
| if (ret < 0) { |
| dev_err(ri->dev, "Not able to configure the rail " |
| "LDO3 as per platform data error %d\n", ret); |
| return ret; |
| } |
| } |
| |
| if (!tps80031_pdata->init_apply) |
| return 0; |
| |
| if (tps80031_pdata->init_uV >= 0) { |
| switch (ri->desc.id) { |
| case TPS80031_ID_VIO: |
| case TPS80031_ID_SMPS1: |
| case TPS80031_ID_SMPS2: |
| case TPS80031_ID_SMPS3: |
| case TPS80031_ID_SMPS4: |
| ret = __tps80031_dcdc_set_voltage(parent, ri, |
| tps80031_pdata->init_uV, |
| tps80031_pdata->init_uV, 0); |
| break; |
| |
| case TPS80031_ID_LDO1: |
| case TPS80031_ID_LDO2: |
| case TPS80031_ID_LDO3: |
| case TPS80031_ID_LDO4: |
| case TPS80031_ID_LDO5: |
| case TPS80031_ID_LDO6: |
| case TPS80031_ID_LDO7: |
| case TPS80031_ID_LDOUSB: |
| case TPS80031_ID_LDOLN: |
| case TPS80031_ID_VANA: |
| ret = __tps80031_ldo_set_voltage(parent, ri, |
| tps80031_pdata->init_uV, |
| tps80031_pdata->init_uV, 0); |
| break; |
| default: |
| ret = -EINVAL; |
| break; |
| } |
| |
| if (ret < 0) { |
| dev_err(ri->dev, "Not able to initialize voltage %d " |
| "for rail %d err %d\n", tps80031_pdata->init_uV, |
| ri->desc.id, ret); |
| return ret; |
| } |
| } |
| |
| if (tps80031_pdata->init_enable) |
| reg_val = (ri->state_reg_cache & ~STATE_MASK) | |
| (STATE_ON & STATE_MASK); |
| else |
| reg_val = (ri->state_reg_cache & ~STATE_MASK) | |
| (STATE_OFF & STATE_MASK); |
| |
| ret = tps80031_write(parent, SLAVE_ID1, ri->state_reg, reg_val); |
| if (ret < 0) |
| dev_err(ri->dev, "Not able to %s rail %d err %d\n", |
| (tps80031_pdata->init_enable) ? "enable" : "disable", |
| ri->desc.id, ret); |
| else |
| ri->state_reg_cache = reg_val; |
| return ret; |
| } |
| |
| static inline struct tps80031_regulator *find_regulator_info(int id) |
| { |
| struct tps80031_regulator *ri; |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(tps80031_regulator); i++) { |
| ri = &tps80031_regulator[i]; |
| if (ri->desc.id == id) |
| return ri; |
| } |
| return NULL; |
| } |
| static void check_smps_mode_mult(struct device *parent, |
| struct tps80031_regulator *ri) |
| { |
| int mult_offset; |
| switch (ri->desc.id) { |
| case TPS80031_ID_VIO: |
| mult_offset = SMPS_MULTOFFSET_VIO; |
| break; |
| case TPS80031_ID_SMPS1: |
| mult_offset = SMPS_MULTOFFSET_SMPS1; |
| break; |
| case TPS80031_ID_SMPS2: |
| mult_offset = SMPS_MULTOFFSET_SMPS2; |
| break; |
| case TPS80031_ID_SMPS3: |
| mult_offset = SMPS_MULTOFFSET_SMPS3; |
| break; |
| case TPS80031_ID_SMPS4: |
| mult_offset = SMPS_MULTOFFSET_SMPS4; |
| break; |
| case TPS80031_ID_LDO2: |
| ri->flags = (tps80031_get_smps_mult(parent) & (1 << 5)) ? |
| TRACK_MODE_ENABLE : 0; |
| /* TRACK mode the ldo2 varies from 600mV to 1300mV */ |
| if (ri->flags & TRACK_MODE_ENABLE) { |
| ri->min_mV = 600; |
| ri->max_mV = 1300; |
| ri->desc.n_voltages = 57; |
| } |
| return; |
| default: |
| return; |
| } |
| |
| ri->flags = (tps80031_get_smps_offset(parent) & mult_offset) ? |
| DCDC_OFFSET_EN : 0; |
| ri->flags |= (tps80031_get_smps_mult(parent) & mult_offset) ? |
| DCDC_EXTENDED_EN : 0; |
| return; |
| } |
| |
| static inline int tps80031_cache_regulator_register(struct device *parent, |
| struct tps80031_regulator *ri) |
| { |
| int ret; |
| |
| ret = tps80031_read(parent, SLAVE_ID1, ri->trans_reg, |
| &ri->trans_reg_cache); |
| if (!ret && ri->state_reg) |
| ret = tps80031_read(parent, SLAVE_ID1, ri->state_reg, |
| &ri->state_reg_cache); |
| if (!ret && ri->force_reg) |
| ret = tps80031_read(parent, ri->volt_id, ri->force_reg, |
| &ri->force_reg_cache); |
| if (!ret && ri->volt_reg) |
| ret = tps80031_read(parent, ri->volt_id, ri->volt_reg, |
| &ri->volt_reg_cache); |
| return ret; |
| } |
| |
| static int __devinit tps80031_regulator_probe(struct platform_device *pdev) |
| { |
| struct tps80031_regulator *ri = NULL; |
| struct regulator_dev *rdev; |
| struct tps80031_regulator_platform_data *tps_pdata; |
| int id = pdev->id; |
| int err; |
| |
| dev_dbg(&pdev->dev, "Probing reulator %d\n", id); |
| |
| ri = find_regulator_info(id); |
| if (ri == NULL) { |
| dev_err(&pdev->dev, "invalid regulator ID specified\n"); |
| return -EINVAL; |
| } |
| tps_pdata = pdev->dev.platform_data; |
| ri->dev = &pdev->dev; |
| if (tps_pdata->delay_us > 0) |
| ri->delay = tps_pdata->delay_us; |
| |
| check_smps_mode_mult(pdev->dev.parent, ri); |
| ri->platform_flags = tps_pdata->flags; |
| ri->ext_ctrl_flag = tps_pdata->ext_ctrl_flag; |
| |
| err = tps80031_cache_regulator_register(pdev->dev.parent, ri); |
| if (err) { |
| dev_err(&pdev->dev, "Register access for caching is failed\n"); |
| return err; |
| } |
| err = tps80031_regulator_preinit(pdev->dev.parent, ri, tps_pdata); |
| if (err) |
| return err; |
| |
| err = tps80031_power_req_config(pdev->dev.parent, ri, tps_pdata); |
| if (err) |
| return err; |
| |
| rdev = regulator_register(&ri->desc, &pdev->dev, |
| &tps_pdata->regulator, ri); |
| if (IS_ERR_OR_NULL(rdev)) { |
| dev_err(&pdev->dev, "failed to register regulator %s\n", |
| ri->desc.name); |
| return PTR_ERR(rdev); |
| } |
| |
| platform_set_drvdata(pdev, rdev); |
| |
| return 0; |
| } |
| |
| static int __devexit tps80031_regulator_remove(struct platform_device *pdev) |
| { |
| struct regulator_dev *rdev = platform_get_drvdata(pdev); |
| |
| regulator_unregister(rdev); |
| return 0; |
| } |
| |
| static struct platform_driver tps80031_regulator_driver = { |
| .driver = { |
| .name = "tps80031-regulator", |
| .owner = THIS_MODULE, |
| }, |
| .probe = tps80031_regulator_probe, |
| .remove = __devexit_p(tps80031_regulator_remove), |
| }; |
| |
| static int __init tps80031_regulator_init(void) |
| { |
| return platform_driver_register(&tps80031_regulator_driver); |
| } |
| subsys_initcall(tps80031_regulator_init); |
| |
| static void __exit tps80031_regulator_exit(void) |
| { |
| platform_driver_unregister(&tps80031_regulator_driver); |
| } |
| module_exit(tps80031_regulator_exit); |
| |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("Regulator Driver for TI TPS80031 PMIC"); |
| MODULE_ALIAS("platform:tps80031-regulator"); |