diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/Kconfig | 15 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 5 | ||||
-rw-r--r-- | drivers/regulator/ab8500.c | 86 | ||||
-rw-r--r-- | drivers/regulator/core.c | 87 | ||||
-rw-r--r-- | drivers/regulator/dummy.h | 4 | ||||
-rw-r--r-- | drivers/regulator/lp3972.c | 660 | ||||
-rw-r--r-- | drivers/regulator/max8952.c | 366 | ||||
-rw-r--r-- | drivers/regulator/max8998.c | 270 | ||||
-rw-r--r-- | drivers/regulator/mc13783-regulator.c | 4 | ||||
-rw-r--r-- | drivers/regulator/tps6586x-regulator.c | 33 | ||||
-rw-r--r-- | drivers/regulator/twl-regulator.c | 6 |
11 files changed, 1433 insertions, 103 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 172951bf23a..dd30e883d4a 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -100,6 +100,14 @@ config REGULATOR_MAX8925 help Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. +config REGULATOR_MAX8952 + tristate "Maxim MAX8952 Power Management IC" + depends on I2C + help + This driver controls a Maxim 8952 voltage output regulator + via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS + modes ranging from 0.77V to 1.40V by 0.01V steps. + config REGULATOR_MAX8998 tristate "Maxim 8998 voltage regulator" depends on MFD_MAX8998 @@ -164,6 +172,13 @@ config REGULATOR_LP3971 Say Y here to support the voltage regulators and convertors on National Semiconductors LP3971 PMIC +config REGULATOR_LP3972 + tristate "National Semiconductors LP3972 PMIC regulator driver" + depends on I2C + help + Say Y here to support the voltage regulators and convertors + on National Semiconductors LP3972 PMIC + config REGULATOR_PCAP tristate "PCAP2 regulator driver" depends on EZX_PCAP diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8285fd832e1..bff81573678 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -3,20 +3,21 @@ # -obj-$(CONFIG_REGULATOR) += core.o +obj-$(CONFIG_REGULATOR) += core.o dummy.o obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o -obj-$(CONFIG_REGULATOR_DUMMY) += dummy.o obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o +obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o +obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o diff --git a/drivers/regulator/ab8500.c b/drivers/regulator/ab8500.c index 28c7ae67cec..db6b70f2051 100644 --- a/drivers/regulator/ab8500.c +++ b/drivers/regulator/ab8500.c @@ -21,6 +21,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/mfd/ab8500.h> +#include <linux/mfd/abx500.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> #include <linux/regulator/ab8500.h> @@ -33,9 +34,11 @@ * @max_uV: maximum voltage (for variable voltage supplies) * @min_uV: minimum voltage (for variable voltage supplies) * @fixed_uV: typical voltage (for fixed voltage supplies) + * @update_bank: bank to control on/off * @update_reg: register to control on/off * @mask: mask to enable/disable regulator * @enable: bits to enable the regulator in normal(high power) mode + * @voltage_bank: bank to control regulator voltage * @voltage_reg: register to control regulator voltage * @voltage_mask: mask to control regulator voltage * @supported_voltages: supported voltage table @@ -49,11 +52,13 @@ struct ab8500_regulator_info { int max_uV; int min_uV; int fixed_uV; - int update_reg; - int mask; - int enable; - int voltage_reg; - int voltage_mask; + u8 update_bank; + u8 update_reg; + u8 mask; + u8 enable; + u8 voltage_bank; + u8 voltage_reg; + u8 voltage_mask; int const *supported_voltages; int voltages_len; }; @@ -97,8 +102,8 @@ static int ab8500_regulator_enable(struct regulator_dev *rdev) if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_set_bits(info->ab8500, info->update_reg, - info->mask, info->enable); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, info->mask, info->enable); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set enable bits for regulator\n"); @@ -114,8 +119,8 @@ static int ab8500_regulator_disable(struct regulator_dev *rdev) if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_set_bits(info->ab8500, info->update_reg, - info->mask, 0x0); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->update_bank, info->update_reg, info->mask, 0x0); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set disable bits for regulator\n"); @@ -126,19 +131,21 @@ static int ab8500_regulator_is_enabled(struct regulator_dev *rdev) { int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 value; regulator_id = rdev_get_id(rdev); if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_read(info->ab8500, info->update_reg); + ret = abx500_get_register_interruptible(info->dev, + info->update_bank, info->update_reg, &value); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read 0x%x register\n", info->update_reg); return ret; } - if (ret & info->mask) + if (value & info->mask) return true; else return false; @@ -165,14 +172,16 @@ static int ab8500_list_voltage(struct regulator_dev *rdev, unsigned selector) static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) { - int regulator_id, ret, val; + int regulator_id, ret; struct ab8500_regulator_info *info = rdev_get_drvdata(rdev); + u8 value; regulator_id = rdev_get_id(rdev); if (regulator_id >= AB8500_NUM_REGULATORS) return -EINVAL; - ret = ab8500_read(info->ab8500, info->voltage_reg); + ret = abx500_get_register_interruptible(info->dev, info->voltage_bank, + info->voltage_reg, &value); if (ret < 0) { dev_err(rdev_get_dev(rdev), "couldn't read voltage reg for regulator\n"); @@ -180,11 +189,11 @@ static int ab8500_regulator_get_voltage(struct regulator_dev *rdev) } /* vintcore has a different layout */ - val = ret & info->voltage_mask; + value &= info->voltage_mask; if (regulator_id == AB8500_LDO_INTCORE) - ret = info->supported_voltages[val >> 0x3]; + ret = info->supported_voltages[value >> 0x3]; else - ret = info->supported_voltages[val]; + ret = info->supported_voltages[value]; return ret; } @@ -224,8 +233,9 @@ static int ab8500_regulator_set_voltage(struct regulator_dev *rdev, } /* set the registers for the request */ - ret = ab8500_set_bits(info->ab8500, info->voltage_reg, - info->voltage_mask, ret); + ret = abx500_mask_and_set_register_interruptible(info->dev, + info->voltage_bank, info->voltage_reg, + info->voltage_mask, (u8)ret); if (ret < 0) dev_err(rdev_get_dev(rdev), "couldn't set voltage reg for regulator\n"); @@ -262,9 +272,9 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .list_voltage = ab8500_list_voltage, }; -#define AB8500_LDO(_id, min, max, reg, reg_mask, reg_enable, \ - volt_reg, volt_mask, voltages, \ - len_volts) \ +#define AB8500_LDO(_id, min, max, bank, reg, reg_mask, \ + reg_enable, volt_bank, volt_reg, volt_mask, \ + voltages, len_volts) \ { \ .desc = { \ .name = "LDO-" #_id, \ @@ -275,9 +285,11 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { }, \ .min_uV = (min) * 1000, \ .max_uV = (max) * 1000, \ + .update_bank = bank, \ .update_reg = reg, \ .mask = reg_mask, \ .enable = reg_enable, \ + .voltage_bank = volt_bank, \ .voltage_reg = volt_reg, \ .voltage_mask = volt_mask, \ .supported_voltages = voltages, \ @@ -285,8 +297,8 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .fixed_uV = 0, \ } -#define AB8500_FIXED_LDO(_id, fixed, reg, reg_mask, \ - reg_enable) \ +#define AB8500_FIXED_LDO(_id, fixed, bank, reg, \ + reg_mask, reg_enable) \ { \ .desc = { \ .name = "LDO-" #_id, \ @@ -296,6 +308,7 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { .owner = THIS_MODULE, \ }, \ .fixed_uV = fixed * 1000, \ + .update_bank = bank, \ .update_reg = reg, \ .mask = reg_mask, \ .enable = reg_enable, \ @@ -304,28 +317,29 @@ static struct regulator_ops ab8500_ldo_fixed_ops = { static struct ab8500_regulator_info ab8500_regulator_info[] = { /* * Variable Voltage LDOs - * name, min uV, max uV, ctrl reg, reg mask, enable mask, - * volt ctrl reg, volt ctrl mask, volt table, num supported volts + * name, min uV, max uV, ctrl bank, ctrl reg, reg mask, enable mask, + * volt ctrl bank, volt ctrl reg, volt ctrl mask, volt table, + * num supported volts */ - AB8500_LDO(AUX1, 1100, 3300, 0x0409, 0x3, 0x1, 0x041f, 0xf, + AB8500_LDO(AUX1, 1100, 3300, 0x04, 0x09, 0x3, 0x1, 0x04, 0x1f, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX2, 1100, 3300, 0x0409, 0xc, 0x4, 0x0420, 0xf, + AB8500_LDO(AUX2, 1100, 3300, 0x04, 0x09, 0xc, 0x4, 0x04, 0x20, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(AUX3, 1100, 3300, 0x040a, 0x3, 0x1, 0x0421, 0xf, + AB8500_LDO(AUX3, 1100, 3300, 0x04, 0x0a, 0x3, 0x1, 0x04, 0x21, 0xf, ldo_vauxn_voltages, ARRAY_SIZE(ldo_vauxn_voltages)), - AB8500_LDO(INTCORE, 1100, 3300, 0x0380, 0x4, 0x4, 0x0380, 0x38, + AB8500_LDO(INTCORE, 1100, 3300, 0x03, 0x80, 0x4, 0x4, 0x03, 0x80, 0x38, ldo_vintcore_voltages, ARRAY_SIZE(ldo_vintcore_voltages)), /* * Fixed Voltage LDOs - * name, o/p uV, ctrl reg, enable, disable + * name, o/p uV, ctrl bank, ctrl reg, enable, disable */ - AB8500_FIXED_LDO(TVOUT, 2000, 0x0380, 0x2, 0x2), - AB8500_FIXED_LDO(AUDIO, 2000, 0x0383, 0x2, 0x2), - AB8500_FIXED_LDO(ANAMIC1, 2050, 0x0383, 0x4, 0x4), - AB8500_FIXED_LDO(ANAMIC2, 2050, 0x0383, 0x8, 0x8), - AB8500_FIXED_LDO(DMIC, 1800, 0x0383, 0x10, 0x10), - AB8500_FIXED_LDO(ANA, 1200, 0x0383, 0xc, 0x4), + AB8500_FIXED_LDO(TVOUT, 2000, 0x03, 0x80, 0x2, 0x2), + AB8500_FIXED_LDO(AUDIO, 2000, 0x03, 0x83, 0x2, 0x2), + AB8500_FIXED_LDO(ANAMIC1, 2050, 0x03, 0x83, 0x4, 0x4), + AB8500_FIXED_LDO(ANAMIC2, 2050, 0x03, 0x83, 0x8, 0x8), + AB8500_FIXED_LDO(DMIC, 1800, 0x03, 0x83, 0x10, 0x10), + AB8500_FIXED_LDO(ANA, 1200, 0x03, 0x83, 0xc, 0x4), }; static inline struct ab8500_regulator_info *find_regulator_info(int id) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index cc8b337b911..ba521f0f0fa 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -33,6 +33,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); static int has_full_constraints; +static bool board_wants_dummy_regulator; /* * struct regulator_map @@ -63,7 +64,8 @@ struct regulator { }; static int _regulator_is_enabled(struct regulator_dev *rdev); -static int _regulator_disable(struct regulator_dev *rdev); +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr); static int _regulator_get_voltage(struct regulator_dev *rdev); static int _regulator_get_current_limit(struct regulator_dev *rdev); static unsigned int _regulator_get_mode(struct regulator_dev *rdev); @@ -909,7 +911,7 @@ out: } /** - * set_consumer_device_supply: Bind a regulator to a symbolic supply + * set_consumer_device_supply - Bind a regulator to a symbolic supply * @rdev: regulator source * @consumer_dev: device the supply applies to * @consumer_dev_name: dev_name() string for device supply applies to @@ -1050,7 +1052,6 @@ static struct regulator *create_regulator(struct regulator_dev *rdev, printk(KERN_WARNING "%s: could not add device link %s err %d\n", __func__, dev->kobj.name, err); - device_remove_file(dev, ®ulator->dev_attr); goto link_name_err; } } @@ -1108,6 +1109,11 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, } } + if (board_wants_dummy_regulator) { + rdev = dummy_regulator_rdev; + goto found; + } + #ifdef CONFIG_REGULATOR_DUMMY if (!devname) devname = "deviceless"; @@ -1261,13 +1267,17 @@ static int _regulator_enable(struct regulator_dev *rdev) { int ret, delay; - /* do we need to enable the supply regulator first */ - if (rdev->supply) { - ret = _regulator_enable(rdev->supply); - if (ret < 0) { - printk(KERN_ERR "%s: failed to enable %s: %d\n", - __func__, rdev_get_name(rdev), ret); - return ret; + if (rdev->use_count == 0) { + /* do we need to enable the supply regulator first */ + if (rdev->supply) { + mutex_lock(&rdev->supply->mutex); + ret = _regulator_enable(rdev->supply); + mutex_unlock(&rdev->supply->mutex); + if (ret < 0) { + printk(KERN_ERR "%s: failed to enable %s: %d\n", + __func__, rdev_get_name(rdev), ret); + return ret; + } } } @@ -1306,10 +1316,12 @@ static int _regulator_enable(struct regulator_dev *rdev) if (ret < 0) return ret; - if (delay >= 1000) + if (delay >= 1000) { mdelay(delay / 1000); - else if (delay) + udelay(delay % 1000); + } else if (delay) { udelay(delay); + } } else if (ret < 0) { printk(KERN_ERR "%s: is_enabled() failed for %s: %d\n", @@ -1348,9 +1360,11 @@ int regulator_enable(struct regulator *regulator) EXPORT_SYMBOL_GPL(regulator_enable); /* locks held by regulator_disable() */ -static int _regulator_disable(struct regulator_dev *rdev) +static int _regulator_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; + *supply_rdev_ptr = NULL; if (WARN(rdev->use_count <= 0, "unbalanced disables for %s\n", @@ -1376,8 +1390,7 @@ static int _regulator_disable(struct regulator_dev *rdev) } /* decrease our supplies ref count and disable if required */ - if (rdev->supply) - _regulator_disable(rdev->supply); + *supply_rdev_ptr = rdev->supply; rdev->use_count = 0; } else if (rdev->use_count > 1) { @@ -1407,17 +1420,29 @@ static int _regulator_disable(struct regulator_dev *rdev) int regulator_disable(struct regulator *regulator) { struct regulator_dev *rdev = regulator->rdev; + struct regulator_dev *supply_rdev = NULL; int ret = 0; mutex_lock(&rdev->mutex); - ret = _regulator_disable(rdev); + ret = _regulator_disable(rdev, &supply_rdev); mutex_unlock(&rdev->mutex); + + /* decrease our supplies ref count and disable if required */ + while (supply_rdev != NULL) { + rdev = supply_rdev; + + mutex_lock(&rdev->mutex); + _regulator_disable(rdev, &supply_rdev); + mutex_unlock(&rdev->mutex); + } + return ret; } EXPORT_SYMBOL_GPL(regulator_disable); /* locks held by regulator_force_disable() */ -static int _regulator_force_disable(struct regulator_dev *rdev) +static int _regulator_force_disable(struct regulator_dev *rdev, + struct regulator_dev **supply_rdev_ptr) { int ret = 0; @@ -1436,8 +1461,7 @@ static int _regulator_force_disable(struct regulator_dev *rdev) } /* decrease our supplies ref count and disable if required */ - if (rdev->supply) - _regulator_disable(rdev->supply); + *supply_rdev_ptr = rdev->supply; rdev->use_count = 0; return ret; @@ -1454,12 +1478,17 @@ static int _regulator_force_disable(struct regulator_dev *rdev) */ int regulator_force_disable(struct regulator *regulator) { + struct regulator_dev *supply_rdev = NULL; int ret; mutex_lock(®ulator->rdev->mutex); regulator->uA_load = 0; - ret = _regulator_force_disable(regulator->rdev); + ret = _regulator_force_disable(regulator->rdev, &supply_rdev); mutex_unlock(®ulator->rdev->mutex); + + if (supply_rdev) + regulator_disable(get_device_regulator(rdev_get_dev(supply_rdev))); + return ret; } EXPORT_SYMBOL_GPL(regulator_force_disable); @@ -2323,6 +2352,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (init_data->supply_regulator && init_data->supply_regulator_dev) { dev_err(dev, "Supply regulator specified by both name and dev\n"); + ret = -EINVAL; goto scrub; } @@ -2341,6 +2371,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, if (!found) { dev_err(dev, "Failed to find supply %s\n", init_data->supply_regulator); + ret = -ENODEV; goto scrub; } @@ -2463,6 +2494,22 @@ void regulator_has_full_constraints(void) EXPORT_SYMBOL_GPL(regulator_has_full_constraints); /** + * regulator_use_dummy_regulator - Provide a dummy regulator when none is found + * + * Calling this function will cause the regulator API to provide a + * dummy regulator to consumers if no physical regulator is found, + * allowing most consumers to proceed as though a regulator were + * configured. This allows systems such as those with software + * controllable regulators for the CPU core only to be brought up more + * readily. + */ +void regulator_use_dummy_regulator(void) +{ + board_wants_dummy_regulator = true; +} +EXPORT_SYMBOL_GPL(regulator_use_dummy_regulator); + +/** * rdev_get_drvdata - get rdev regulator driver data * @rdev: regulator * diff --git a/drivers/regulator/dummy.h b/drivers/regulator/dummy.h index 3921c0e2424..97a11b7e888 100644 --- a/drivers/regulator/dummy.h +++ b/drivers/regulator/dummy.h @@ -22,10 +22,6 @@ struct regulator_dev; extern struct regulator_dev *dummy_regulator_rdev; -#ifdef CONFIG_REGULATOR_DUMMY void __init regulator_dummy_init(void); -#else -static inline void regulator_dummy_init(void) { } -#endif #endif diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c new file mode 100644 index 00000000000..e07062fd0b4 --- /dev/null +++ b/drivers/regulator/lp3972.c @@ -0,0 +1,660 @@ +/* + * Regulator driver for National Semiconductors LP3972 PMIC chip + * + * Based on lp3971.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/bug.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/lp3972.h> +#include <linux/slab.h> + +struct lp3972 { + struct device *dev; + struct mutex io_lock; + struct i2c_client *i2c; + int num_regulators; + struct regulator_dev **rdev; +}; + +/* LP3972 Control Registers */ +#define LP3972_SCR_REG 0x07 +#define LP3972_OVER1_REG 0x10 +#define LP3972_OVSR1_REG 0x11 +#define LP3972_OVER2_REG 0x12 +#define LP3972_OVSR2_REG 0x13 +#define LP3972_VCC1_REG 0x20 +#define LP3972_ADTV1_REG 0x23 +#define LP3972_ADTV2_REG 0x24 +#define LP3972_AVRC_REG 0x25 +#define LP3972_CDTC1_REG 0x26 +#define LP3972_CDTC2_REG 0x27 +#define LP3972_SDTV1_REG 0x29 +#define LP3972_SDTV2_REG 0x2A +#define LP3972_MDTV1_REG 0x32 +#define LP3972_MDTV2_REG 0x33 +#define LP3972_L2VCR_REG 0x39 +#define LP3972_L34VCR_REG 0x3A +#define LP3972_SCR1_REG 0x80 +#define LP3972_SCR2_REG 0x81 +#define LP3972_OEN3_REG 0x82 +#define LP3972_OSR3_REG 0x83 +#define LP3972_LOER4_REG 0x84 +#define LP3972_B2TV_REG 0x85 +#define LP3972_B3TV_REG 0x86 +#define LP3972_B32RC_REG 0x87 +#define LP3972_ISRA_REG 0x88 +#define LP3972_BCCR_REG 0x89 +#define LP3972_II1RR_REG 0x8E +#define LP3972_II2RR_REG 0x8F + +#define LP3972_SYS_CONTROL1_REG LP3972_SCR1_REG +/* System control register 1 initial value, + * bits 5, 6 and 7 are EPROM programmable */ +#define SYS_CONTROL1_INIT_VAL 0x02 +#define SYS_CONTROL1_INIT_MASK 0x1F + +#define LP3972_VOL_CHANGE_REG LP3972_VCC1_REG +#define LP3972_VOL_CHANGE_FLAG_GO 0x01 +#define LP3972_VOL_CHANGE_FLAG_MASK 0x03 + +/* LDO output enable mask */ +#define LP3972_OEN3_L1EN BIT(0) +#define LP3972_OVER2_LDO2_EN BIT(2) +#define LP3972_OVER2_LDO3_EN BIT(3) +#define LP3972_OVER2_LDO4_EN BIT(4) +#define LP3972_OVER1_S_EN BIT(2) + +static const int ldo1_voltage_map[] = { + 1700, 1725, 1750, 1775, 1800, 1825, 1850, 1875, + 1900, 1925, 1950, 1975, 2000, +}; + +static const int ldo23_voltage_map[] = { + 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, + 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, +}; + +static const int ldo4_voltage_map[] = { + 1000, 1050, 1100, 1150, 1200, 1250, 1300, 1350, + 1400, 1500, 1800, 1900, 2500, 2800, 3000, 3300, +}; + +static const int ldo5_voltage_map[] = { + 0, 0, 0, 0, 0, 850, 875, 900, + 925, 950, 975, 1000, 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +}; + +static const int buck1_voltage_map[] = { + 725, 750, 775, 800, 825, 850, 875, 900, + 925, 950, 975, 1000, 1025, 1050, 1075, 1100, + 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, + 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, +}; + +static const int buck23_voltage_map[] = { + 0, 800, 850, 900, 950, 1000, 1050, 1100, + 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500, + 1550, 1600, 1650, 1700, 1800, 1900, 2500, 2800, + 3000, 3300, +}; + +static const int *ldo_voltage_map[] = { + ldo1_voltage_map, + ldo23_voltage_map, + ldo23_voltage_map, + ldo4_voltage_map, + ldo5_voltage_map, +}; + +static const int *buck_voltage_map[] = { + buck1_voltage_map, + buck23_voltage_map, + buck23_voltage_map, +}; + +static const int ldo_output_enable_mask[] = { + LP3972_OEN3_L1EN, + LP3972_OVER2_LDO2_EN, + LP3972_OVER2_LDO3_EN, + LP3972_OVER2_LDO4_EN, + LP3972_OVER1_S_EN, +}; + +static const int ldo_output_enable_addr[] = { + LP3972_OEN3_REG, + LP3972_OVER2_REG, + LP3972_OVER2_REG, + LP3972_OVER2_REG, + LP3972_OVER1_REG, +}; + +static const int ldo_vol_ctl_addr[] = { + LP3972_MDTV1_REG, + LP3972_L2VCR_REG, + LP3972_L34VCR_REG, + LP3972_L34VCR_REG, + LP3972_SDTV1_REG, +}; + +static const int buck_vol_enable_addr[] = { + LP3972_OVER1_REG, + LP3972_OEN3_REG, + LP3972_OEN3_REG, +}; + +static const int buck_base_addr[] = { + LP3972_ADTV1_REG, + LP3972_B2TV_REG, + LP3972_B3TV_REG, +}; + +#define LP3972_LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[x]) +#define LP3972_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x]) +#define LP3972_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x]) + +/* LDO voltage control registers shift: + LP3972_LDO1 -> 0, LP3972_LDO2 -> 4 + LP3972_LDO3 -> 0, LP3972_LDO4 -> 4 + LP3972_LDO5 -> 0 +*/ +#define LP3972_LDO_VOL_CONTR_SHIFT(x) (((x) & 1) << 2) +#define LP3972_LDO_VOL_CONTR_REG(x) (ldo_vol_ctl_addr[x]) +#define LP3972_LDO_VOL_CHANGE_SHIFT(x) ((x) ? 4 : 6) + +#define LP3972_LDO_VOL_MASK(x) (((x) % 4) ? 0x0f : 0x1f) +#define LP3972_LDO_VOL_MIN_IDX(x) (((x) == 4) ? 0x05 : 0x00) +#define LP3972_LDO_VOL_MAX_IDX(x) ((x) ? (((x) == 4) ? 0x1f : 0x0f) : 0x0c) + +#define LP3972_BUCK_VOL_VALUE_MAP(x) (buck_voltage_map[x]) +#define LP3972_BUCK_VOL_ENABLE_REG(x) (buck_vol_enable_addr[x]) +#define LP3972_BUCK_VOL1_REG(x) (buck_base_addr[x]) +#define LP3972_BUCK_VOL_MASK 0x1f +#define LP3972_BUCK_VOL_MIN_IDX(x) ((x) ? 0x01 : 0x00) +#define LP3972_BUCK_VOL_MAX_IDX(x) ((x) ? 0x19 : 0x1f) + +static int lp3972_i2c_read(struct i2c_client *i2c, char reg, int count, + u16 *dest) +{ + int ret; + + if (count != 1) + return -EIO; + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + return ret; + + *dest = ret; + return 0; +} + +static int lp3972_i2c_write(struct i2c_client *i2c, char reg, int count, + const u16 *src) +{ + if (count != 1) + return -EIO; + return i2c_smbus_write_byte_data(i2c, reg, *src); +} + +static u8 lp3972_reg_read(struct lp3972 *lp3972, u8 reg) +{ + u16 val = 0; + + mutex_lock(&lp3972->io_lock); + + lp3972_i2c_read(lp3972->i2c, reg, 1, &val); + + dev_dbg(lp3972->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val & 0xff); + + mutex_unlock(&lp3972->io_lock); + + return val & 0xff; +} + +static int lp3972_set_bits(struct lp3972 *lp3972, u8 reg, u16 mask, u16 val) +{ + u16 tmp; + int ret; + + mutex_lock(&lp3972->io_lock); + + ret = lp3972_i2c_read(lp3972->i2c, reg, 1, &tmp); + tmp = (tmp & ~mask) | val; + if (ret == 0) { + ret = lp3972_i2c_write(lp3972->i2c, reg, 1, &tmp); + dev_dbg(lp3972->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg, + (unsigned)val & 0xff); + } + mutex_unlock(&lp3972->io_lock); + + return ret; +} + +static int lp3972_ldo_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int ldo = rdev_get_id(dev) - LP3972_LDO1; + return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[index]; +} + +static int lp3972_ldo_is_enabled(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + u16 val; + + val = lp3972_reg_read(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo)); + return !!(val & mask); +} + +static int lp3972_ldo_enable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + + return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), + mask, mask); +} + +static int lp3972_ldo_disable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_OUTPUT_ENABLE_MASK(ldo); + + return lp3972_set_bits(lp3972, LP3972_LDO_OUTPUT_ENABLE_REG(ldo), + mask, 0); +} + +static int lp3972_ldo_get_voltage(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + u16 mask = LP3972_LDO_VOL_MASK(ldo); + u16 val, reg; + + reg = lp3972_reg_read(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo)); + val = (reg >> LP3972_LDO_VOL_CONTR_SHIFT(ldo)) & mask; + + return 1000 * LP3972_LDO_VOL_VALUE_MAP(ldo)[val]; +} + +static int lp3972_ldo_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int ldo = rdev_get_id(dev) - LP3972_LDO1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = LP3972_LDO_VOL_VALUE_MAP(ldo); + u16 val; + int shift, ret; + + if (min_vol < vol_map[LP3972_LDO_VOL_MIN_IDX(ldo)] || + min_vol > vol_map[LP3972_LDO_VOL_MAX_IDX(ldo)]) + return -EINVAL; + + for (val = LP3972_LDO_VOL_MIN_IDX(ldo); + val <= LP3972_LDO_VOL_MAX_IDX(ldo); val++) + if (vol_map[val] >= min_vol) + break; + + if (val > LP3972_LDO_VOL_MAX_IDX(ldo) || vol_map[val] > max_vol) + return -EINVAL; + + shift = LP3972_LDO_VOL_CONTR_SHIFT(ldo); + ret = lp3972_set_bits(lp3972, LP3972_LDO_VOL_CONTR_REG(ldo), + LP3972_LDO_VOL_MASK(ldo) << shift, val << shift); + + if (ret) + return ret; + + /* + * LDO1 and LDO5 support voltage control by either target voltage1 + * or target voltage2 register. + * We use target voltage1 register for LDO1 and LDO5 in this driver. + * We need to update voltage change control register(0x20) to enable + * LDO1 and LDO5 to change to their programmed target values. + */ + switch (ldo) { + case LP3972_LDO1: + case LP3972_LDO5: + shift = LP3972_LDO_VOL_CHANGE_SHIFT(ldo); + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK << shift, + LP3972_VOL_CHANGE_FLAG_GO << shift); + if (ret) + return ret; + + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK << shift, 0); + break; + } + + return ret; +} + +static struct regulator_ops lp3972_ldo_ops = { + .list_voltage = lp3972_ldo_list_voltage, + .is_enabled = lp3972_ldo_is_enabled, + .enable = lp3972_ldo_enable, + .disable = lp3972_ldo_disable, + .get_voltage = lp3972_ldo_get_voltage, + .set_voltage = lp3972_ldo_set_voltage, +}; + +static int lp3972_dcdc_list_voltage(struct regulator_dev *dev, unsigned index) +{ + int buck = rdev_get_id(dev) - LP3972_DCDC1; + return 1000 * buck_voltage_map[buck][index]; +} + +static int lp3972_dcdc_is_enabled(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_reg_read(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck)); + return !!(val & mask); +} + +static int lp3972_dcdc_enable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), + mask, mask); + return val; +} + +static int lp3972_dcdc_disable(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 mask = 1 << (buck * 2); + u16 val; + + val = lp3972_set_bits(lp3972, LP3972_BUCK_VOL_ENABLE_REG(buck), + mask, 0); + return val; +} + +static int lp3972_dcdc_get_voltage(struct regulator_dev *dev) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + u16 reg; + int val; + + reg = lp3972_reg_read(lp3972, LP3972_BUCK_VOL1_REG(buck)); + reg &= LP3972_BUCK_VOL_MASK; + if (reg <= LP3972_BUCK_VOL_MAX_IDX(buck)) + val = 1000 * buck_voltage_map[buck][reg]; + else { + val = 0; + dev_warn(&dev->dev, "chip reported incorrect voltage value." + " reg = %d\n", reg); + } + + return val; +} + +static int lp3972_dcdc_set_voltage(struct regulator_dev *dev, + int min_uV, int max_uV) +{ + struct lp3972 *lp3972 = rdev_get_drvdata(dev); + int buck = rdev_get_id(dev) - LP3972_DCDC1; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const int *vol_map = buck_voltage_map[buck]; + u16 val; + int ret; + + if (min_vol < vol_map[LP3972_BUCK_VOL_MIN_IDX(buck)] || + min_vol > vol_map[LP3972_BUCK_VOL_MAX_IDX(buck)]) + return -EINVAL; + + for (val = LP3972_BUCK_VOL_MIN_IDX(buck); + val <= LP3972_BUCK_VOL_MAX_IDX(buck); val++) + if (vol_map[val] >= min_vol) + break; + + if (val > LP3972_BUCK_VOL_MAX_IDX(buck) || + vol_map[val] > max_vol) + return -EINVAL; + + ret = lp3972_set_bits(lp3972, LP3972_BUCK_VOL1_REG(buck), + LP3972_BUCK_VOL_MASK, val); + if (ret) + return ret; + + if (buck != 0) + return ret; + + ret = lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK, LP3972_VOL_CHANGE_FLAG_GO); + if (ret) + return ret; + + return lp3972_set_bits(lp3972, LP3972_VOL_CHANGE_REG, + LP3972_VOL_CHANGE_FLAG_MASK, 0); +} + +static struct regulator_ops lp3972_dcdc_ops = { + .list_voltage = lp3972_dcdc_list_voltage, + .is_enabled = lp3972_dcdc_is_enabled, + .enable = lp3972_dcdc_enable, + .disable = lp3972_dcdc_disable, + .get_voltage = lp3972_dcdc_get_voltage, + .set_voltage = lp3972_dcdc_set_voltage, +}; + +static struct regulator_desc regulators[] = { + { + .name = "LDO1", + .id = LP3972_LDO1, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo1_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO2", + .id = LP3972_LDO2, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO3", + .id = LP3972_LDO3, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO4", + .id = LP3972_LDO4, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo4_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "LDO5", + .id = LP3972_LDO5, + .ops = &lp3972_ldo_ops, + .n_voltages = ARRAY_SIZE(ldo5_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC1", + .id = LP3972_DCDC1, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck1_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC2", + .id = LP3972_DCDC2, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, + { + .name = "DCDC3", + .id = LP3972_DCDC3, + .ops = &lp3972_dcdc_ops, + .n_voltages = ARRAY_SIZE(buck23_voltage_map), + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + }, +}; + +static int __devinit setup_regulators(struct lp3972 *lp3972, + struct lp3972_platform_data *pdata) +{ + int i, err; + + lp3972->num_regulators = pdata->num_regulators; + lp3972->rdev = kcalloc(pdata->num_regulators, + sizeof(struct regulator_dev *), GFP_KERNEL); + if (!lp3972->rdev) { + err = -ENOMEM; + goto err_nomem; + } + + /* Instantiate the regulators */ + for (i = 0; i < pdata->num_regulators; i++) { + struct lp3972_regulator_subdev *reg = &pdata->regulators[i]; + lp3972->rdev[i] = regulator_register(®ulators[reg->id], + lp3972->dev, reg->initdata, lp3972); + + if (IS_ERR(lp3972->rdev[i])) { + err = PTR_ERR(lp3972->rdev[i]); + dev_err(lp3972->dev, "regulator init failed: %d\n", + err); + goto error; + } + } + + return 0; +error: + while (--i >= 0) + regulator_unregister(lp3972->rdev[i]); + kfree(lp3972->rdev); + lp3972->rdev = NULL; +err_nomem: + return err; +} + +static int __devinit lp3972_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct lp3972 *lp3972; + struct lp3972_platform_data *pdata = i2c->dev.platform_data; + int ret; + u16 val; + + if (!pdata) { + dev_dbg(&i2c->dev, "No platform init data supplied\n"); + return -ENODEV; + } + + lp3972 = kzalloc(sizeof(struct lp3972), GFP_KERNEL); + if (!lp3972) + return -ENOMEM; + + lp3972->i2c = i2c; + lp3972->dev = &i2c->dev; + + mutex_init(&lp3972->io_lock); + + /* Detect LP3972 */ + ret = lp3972_i2c_read(i2c, LP3972_SYS_CONTROL1_REG, 1, &val); + if (ret == 0 && + (val & SYS_CONTROL1_INIT_MASK) != SYS_CONTROL1_INIT_VAL) { + ret = -ENODEV; + dev_err(&i2c->dev, "chip reported: val = 0x%x\n", val); + } + if (ret < 0) { + dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret); + goto err_detect; + } + + ret = setup_regulators(lp3972, pdata); + if (ret < 0) + goto err_detect; + + i2c_set_clientdata(i2c, lp3972); + return 0; + +err_detect: + kfree(lp3972); + return ret; +} + +static int __devexit lp3972_i2c_remove(struct i2c_client *i2c) +{ + struct lp3972 *lp3972 = i2c_get_clientdata(i2c); + int i; + + for (i = 0; i < lp3972->num_regulators; i++) + regulator_unregister(lp3972->rdev[i]); + kfree(lp3972->rdev); + kfree(lp3972); + + return 0; +} + +static const struct i2c_device_id lp3972_i2c_id[] = { + { "lp3972", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); + +static struct i2c_driver lp3972_i2c_driver = { + .driver = { + .name = "lp3972", + .owner = THIS_MODULE, + }, + .probe = lp3972_i2c_probe, + .remove = __devexit_p(lp3972_i2c_remove), + .id_table = lp3972_i2c_id, +}; + +static int __init lp3972_module_init(void) +{ + return i2c_add_driver(&lp3972_i2c_driver); +} +subsys_initcall(lp3972_module_init); + +static void __exit lp3972_module_exit(void) +{ + i2c_del_driver(&lp3972_i2c_driver); +} +module_exit(lp3972_module_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>"); +MODULE_DESCRIPTION("LP3972 PMIC driver"); diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c new file mode 100644 index 00000000000..0d5dda4fd91 --- /dev/null +++ b/drivers/regulator/max8952.c @@ -0,0 +1,366 @@ +/* + * max8952.c - Voltage and current regulation for the Maxim 8952 + * + * Copyright (C) 2010 Samsung Electronics + * MyungJoo Ham <myungjoo.ham@samsung.com> + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/max8952.h> +#include <linux/mutex.h> +#include <linux/gpio.h> +#include <linux/io.h> +#include <linux/slab.h> + +/* Registers */ +enum { + MAX8952_REG_MODE0, + MAX8952_REG_MODE1, + MAX8952_REG_MODE2, + MAX8952_REG_MODE3, + MAX8952_REG_CONTROL, + MAX8952_REG_SYNC, + MAX8952_REG_RAMP, + MAX8952_REG_CHIP_ID1, + MAX8952_REG_CHIP_ID2, +}; + +struct max8952_data { + struct i2c_client *client; + struct device *dev; + struct mutex mutex; + struct max8952_platform_data *pdata; + struct regulator_dev *rdev; + + bool vid0; + bool vid1; + bool en; +}; + +static int max8952_read_reg(struct max8952_data *max8952, u8 reg) +{ + int ret = i2c_smbus_read_byte_data(max8952->client, reg); + if (ret > 0) + ret &= 0xff; + + return ret; +} + +static int max8952_write_reg(struct max8952_data *max8952, + u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(max8952->client, reg, value); +} + +static int max8952_voltage(struct max8952_data *max8952, u8 mode) +{ + return (max8952->pdata->dvs_mode[mode] * 10 + 770) * 1000; +} + +static int max8952_list_voltage(struct regulator_dev *rdev, + unsigned int selector) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + if (rdev_get_id(rdev) != 0) + return -EINVAL; + + return max8952_voltage(max8952, selector); +} + +static int max8952_is_enabled(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + return max8952->en; +} + +static int max8952_enable(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + /* If not valid, assume "ALWAYS_HIGH" */ + if (gpio_is_valid(max8952->pdata->gpio_en)) + gpio_set_value(max8952->pdata->gpio_en, 1); + + max8952->en = true; + return 0; +} + +static int max8952_disable(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + + /* If not valid, assume "ALWAYS_HIGH" -> not permitted */ + if (gpio_is_valid(max8952->pdata->gpio_en)) + gpio_set_value(max8952->pdata->gpio_en, 0); + else + return -EPERM; + + max8952->en = false; + return 0; +} + +static int max8952_get_voltage(struct regulator_dev *rdev) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + u8 vid = 0; + + if (max8952->vid0) + vid += 1; + if (max8952->vid1) + vid += 2; + + return max8952_voltage(max8952, vid); +} + +static int max8952_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct max8952_data *max8952 = rdev_get_drvdata(rdev); + s8 vid = -1, i; + + if (!gpio_is_valid(max8952->pdata->gpio_vid0) || + !gpio_is_valid(max8952->pdata->gpio_vid0)) { + /* DVS not supported */ + return -EPERM; + } + + for (i = 0; i < MAX8952_NUM_DVS_MODE; i++) { + int volt = max8952_voltage(max8952, i); + + /* Set the voltage as low as possible within the range */ + if (volt <= max_uV && volt >= min_uV) + if (vid == -1 || max8952_voltage(max8952, vid) > volt) + vid = i; + } + + if (vid >= 0 && vid < MAX8952_NUM_DVS_MODE) { + max8952->vid0 = (vid % 2 == 1); + max8952->vid1 = (((vid >> 1) % 2) == 1); + gpio_set_value(max8952->pdata->gpio_vid0, max8952->vid0); + gpio_set_value(max8952->pdata->gpio_vid1, max8952->vid1); + } else + return -EINVAL; + + return 0; +} + +static struct regulator_ops max8952_ops = { + .list_voltage = max8952_list_voltage, + .is_enabled = max8952_is_enabled, + .enable = max8952_enable, + .disable = max8952_disable, + .get_voltage = max8952_get_voltage, + .set_voltage = max8952_set_voltage, + .set_suspend_disable = max8952_disable, +}; + +static struct regulator_desc regulator = { + .name = "MAX8952_VOUT", + .id = 0, + .n_voltages = MAX8952_NUM_DVS_MODE, + .ops = &max8952_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, +}; + +static int __devinit max8952_pmic_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct max8952_platform_data *pdata = client->dev.platform_data; + struct max8952_data *max8952; + + int ret = 0, err = 0; + + if (!pdata) { + dev_err(&client->dev, "Require the platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) + return -EIO; + + max8952 = kzalloc(sizeof(struct max8952_data), GFP_KERNEL); + if (!max8952) + return -ENOMEM; + + max8952->client = client; + max8952->dev = &client->dev; + max8952->pdata = pdata; + mutex_init(&max8952->mutex); + + max8952->rdev = regulator_register(®ulator, max8952->dev, + &pdata->reg_data, max8952); + + if (IS_ERR(max8952->rdev)) { + ret = PTR_ERR(max8952->rdev); + dev_err(max8952->dev, "regulator init failed (%d)\n", ret); + goto err_reg; + } + + max8952->en = !!(pdata->reg_data.constraints.boot_on); + max8952->vid0 = (pdata->default_mode % 2) == 1; + max8952->vid1 = ((pdata->default_mode >> 1) % 2) == 1; + + if (gpio_is_valid(pdata->gpio_en)) { + if (!gpio_request(pdata->gpio_en, "MAX8952 EN")) + gpio_direction_output(pdata->gpio_en, max8952->en); + else + err = 1; + } else + err = 2; + + if (err) { + dev_info(max8952->dev, "EN gpio invalid: assume that EN" + "is always High\n"); + max8952->en = 1; + pdata->gpio_en = -1; /* Mark invalid */ + } + + err = 0; + + if (gpio_is_valid(pdata->gpio_vid0) && + gpio_is_valid(pdata->gpio_vid1)) { + if (!gpio_request(pdata->gpio_vid0, "MAX8952 VID0")) + gpio_direction_output(pdata->gpio_vid0, + (pdata->default_mode) % 2); + else + err = 1; + + if (!gpio_request(pdata->gpio_vid1, "MAX8952 VID1")) + gpio_direction_output(pdata->gpio_vid1, + (pdata->default_mode >> 1) % 2); + else { + if (!err) + gpio_free(pdata->gpio_vid0); + err = 2; + } + + } else + err = 3; + + if (err) { + dev_warn(max8952->dev, "VID0/1 gpio invalid: " + "DVS not avilable.\n"); + max8952->vid0 = 0; + max8952->vid1 = 0; + /* Mark invalid */ + pdata->gpio_vid0 = -1; + pdata->gpio_vid1 = -1; + + /* Disable Pulldown of EN only */ + max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x60); + + dev_err(max8952->dev, "DVS modes disabled because VID0 and VID1" + " do not have proper controls.\n"); + } else { + /* + * Disable Pulldown on EN, VID0, VID1 to reduce + * leakage current of MAX8952 assuming that MAX8952 + * is turned on (EN==1). Note that without having VID0/1 + * properly connected, turning pulldown off can be + * problematic. Thus, turn this off only when they are + * controllable by GPIO. + */ + max8952_write_reg(max8952, MAX8952_REG_CONTROL, 0x0); + } + + max8952_write_reg(max8952, MAX8952_REG_MODE0, + (max8952_read_reg(max8952, + MAX8952_REG_MODE0) & 0xC0) | + (pdata->dvs_mode[0] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE1, + (max8952_read_reg(max8952, + MAX8952_REG_MODE1) & 0xC0) | + (pdata->dvs_mode[1] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE2, + (max8952_read_reg(max8952, + MAX8952_REG_MODE2) & 0xC0) | + (pdata->dvs_mode[2] & 0x3F)); + max8952_write_reg(max8952, MAX8952_REG_MODE3, + (max8952_read_reg(max8952, + MAX8952_REG_MODE3) & 0xC0) | + (pdata->dvs_mode[3] & 0x3F)); + + max8952_write_reg(max8952, MAX8952_REG_SYNC, + (max8952_read_reg(max8952, MAX8952_REG_SYNC) & 0x3F) | + ((pdata->sync_freq & 0x3) << 6)); + max8952_write_reg(max8952, MAX8952_REG_RAMP, + (max8952_read_reg(max8952, MAX8952_REG_RAMP) & 0x1F) | + ((pdata->ramp_speed & 0x7) << 5)); + + i2c_set_clientdata(client, max8952); + + return 0; + +err_reg: + kfree(max8952); + return ret; +} + +static int __devexit max8952_pmic_remove(struct i2c_client *client) +{ + struct max8952_data *max8952 = i2c_get_clientdata(client); + struct max8952_platform_data *pdata = max8952->pdata; + struct regulator_dev *rdev = max8952->rdev; + + regulator_unregister(rdev); + + gpio_free(pdata->gpio_vid0); + gpio_free(pdata->gpio_vid1); + gpio_free(pdata->gpio_en); + + kfree(max8952); + return 0; +} + +static const struct i2c_device_id max8952_ids[] = { + { "max8952", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, max8952_ids); + +static struct i2c_driver max8952_pmic_driver = { + .probe = max8952_pmic_probe, + .remove = __devexit_p(max8952_pmic_remove), + .driver = { + .name = "max8952", + }, + .id_table = max8952_ids, +}; + +static int __init max8952_pmic_init(void) +{ + return i2c_add_driver(&max8952_pmic_driver); +} +subsys_initcall(max8952_pmic_init); + +static void __exit max8952_pmic_exit(void) +{ + i2c_del_driver(&max8952_pmic_driver); +} +module_exit(max8952_pmic_exit); + +MODULE_DESCRIPTION("MAXIM 8952 voltage regulator driver"); +MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c index a1baf1fbe00..5c20756db60 100644 --- a/drivers/regulator/max8998.c +++ b/drivers/regulator/max8998.c @@ -39,6 +39,11 @@ struct max8998_data { struct max8998_dev *iodev; int num_regulators; struct regulator_dev **rdev; + u8 buck1_vol[4]; /* voltages for selection */ + u8 buck2_vol[2]; + unsigned int buck1_idx; /* index to last changed voltage */ + /* value in a set */ + unsigned int buck2_idx; }; struct voltage_map_desc { @@ -173,6 +178,7 @@ static int max8998_get_enable_register(struct regulator_dev *rdev, static int max8998_ldo_is_enabled(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int ret, reg, shift = 8; u8 val; @@ -180,7 +186,7 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - ret = max8998_read_reg(max8998->iodev, reg, &val); + ret = max8998_read_reg(i2c, reg, &val); if (ret) return ret; @@ -190,31 +196,34 @@ static int max8998_ldo_is_enabled(struct regulator_dev *rdev) static int max8998_ldo_enable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 8, ret; ret = max8998_get_enable_register(rdev, ®, &shift); if (ret) return ret; - return max8998_update_reg(max8998->iodev, reg, 1<<shift, 1<<shift); + return max8998_update_reg(i2c, reg, 1<<shift, 1<<shift); } static int max8998_ldo_disable(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 8, ret; ret = max8998_get_enable_register(rdev, ®, &shift); if (ret) return ret; - return max8998_update_reg(max8998->iodev, reg, 0, 1<<shift); + return max8998_update_reg(i2c, reg, 0, 1<<shift); } static int max8998_get_voltage_register(struct regulator_dev *rdev, int *_reg, int *_shift, int *_mask) { int ldo = max8998_get_ldo(rdev); + struct max8998_data *max8998 = rdev_get_drvdata(rdev); int reg, shift = 0, mask = 0xff; switch (ldo) { @@ -251,10 +260,10 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev, reg = MAX8998_REG_LDO12 + (ldo - MAX8998_LDO12); break; case MAX8998_BUCK1: - reg = MAX8998_REG_BUCK1_DVSARM1; + reg = MAX8998_REG_BUCK1_VOLTAGE1 + max8998->buck1_idx; break; case MAX8998_BUCK2: - reg = MAX8998_REG_BUCK2_DVSINT1; + reg = MAX8998_REG_BUCK2_VOLTAGE1 + max8998->buck2_idx; break; case MAX8998_BUCK3: reg = MAX8998_REG_BUCK3; @@ -276,6 +285,7 @@ static int max8998_get_voltage_register(struct regulator_dev *rdev, static int max8998_get_voltage(struct regulator_dev *rdev) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int reg, shift = 0, mask, ret; u8 val; @@ -283,7 +293,7 @@ static int max8998_get_voltage(struct regulator_dev *rdev) if (ret) return ret; - ret = max8998_read_reg(max8998->iodev, reg, &val); + ret = max8998_read_reg(i2c, reg, &val); if (ret) return ret; @@ -293,18 +303,16 @@ static int max8998_get_voltage(struct regulator_dev *rdev) return max8998_list_voltage(rdev, val); } -static int max8998_set_voltage(struct regulator_dev *rdev, +static int max8998_set_voltage_ldo(struct regulator_dev *rdev, int min_uV, int max_uV) { struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct i2c_client *i2c = max8998->iodev->i2c; int min_vol = min_uV / 1000, max_vol = max_uV / 1000; - int previous_vol = 0; const struct voltage_map_desc *desc; int ldo = max8998_get_ldo(rdev); int reg, shift = 0, mask, ret; int i = 0; - u8 val; - bool en_ramp = false; if (ldo >= ARRAY_SIZE(ldo_voltage_map)) return -EINVAL; @@ -327,24 +335,155 @@ static int max8998_set_voltage(struct regulator_dev *rdev, if (ret) return ret; - /* wait for RAMP_UP_DELAY if rdev is BUCK1/2 and - * ENRAMP is ON */ - if (ldo == MAX8998_BUCK1 || ldo == MAX8998_BUCK2) { - max8998_read_reg(max8998->iodev, MAX8998_REG_ONOFF4, &val); - if (val & (1 << 4)) { - en_ramp = true; - previous_vol = max8998_get_voltage(rdev); - } + ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + + return ret; +} + +static inline void buck1_gpio_set(int gpio1, int gpio2, int v) +{ + gpio_set_value(gpio1, v & 0x1); + gpio_set_value(gpio2, (v >> 1) & 0x1); +} + +static inline void buck2_gpio_set(int gpio, int v) +{ + gpio_set_value(gpio, v & 0x1); +} + +static int max8998_set_voltage_buck(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct max8998_data *max8998 = rdev_get_drvdata(rdev); + struct max8998_platform_data *pdata = + dev_get_platdata(max8998->iodev->dev); + struct i2c_client *i2c = max8998->iodev->i2c; + int min_vol = min_uV / 1000, max_vol = max_uV / 1000; + const struct voltage_map_desc *desc; + int buck = max8998_get_ldo(rdev); + int reg, shift = 0, mask, ret; + int difference = 0, i = 0, j = 0, previous_vol = 0; + u8 val = 0; + static u8 buck1_last_val; + + if (buck >= ARRAY_SIZE(ldo_voltage_map)) + return -EINVAL; + + desc = ldo_voltage_map[buck]; + + if (desc == NULL) + return -EINVAL; + + if (max_vol < desc->min || min_vol > desc->max) + return -EINVAL; + + while (desc->min + desc->step*i < min_vol && + desc->min + desc->step*i < desc->max) + i++; + + if (desc->min + desc->step*i > max_vol) + return -EINVAL; + + ret = max8998_get_voltage_register(rdev, ®, &shift, &mask); + if (ret) + return ret; + + previous_vol = max8998_get_voltage(rdev); + + /* Check if voltage needs to be changed */ + /* if previous_voltage equal new voltage, return */ + if (previous_vol == max8998_list_voltage(rdev, i)) { + dev_dbg(max8998->dev, "No voltage change, old:%d, new:%d\n", + previous_vol, max8998_list_voltage(rdev, i)); + return ret; } - ret = max8998_update_reg(max8998->iodev, reg, i<<shift, mask<<shift); + switch (buck) { + case MAX8998_BUCK1: + dev_dbg(max8998->dev, + "BUCK1, i:%d, buck1_vol1:%d, buck1_vol2:%d\n\ + buck1_vol3:%d, buck1_vol4:%d\n", + i, max8998->buck1_vol[0], max8998->buck1_vol[1], + max8998->buck1_vol[2], max8998->buck1_vol[3]); + + if (gpio_is_valid(pdata->buck1_set1) && + gpio_is_valid(pdata->buck1_set2)) { + + /* check if requested voltage */ + /* value is already defined */ + for (j = 0; j < ARRAY_SIZE(max8998->buck1_vol); j++) { + if (max8998->buck1_vol[j] == i) { + max8998->buck1_idx = j; + buck1_gpio_set(pdata->buck1_set1, + pdata->buck1_set2, j); + goto buck1_exit; + } + } + + /* no predefine regulator found */ + max8998->buck1_idx = (buck1_last_val % 2) + 2; + dev_dbg(max8998->dev, "max8998->buck1_idx:%d\n", + max8998->buck1_idx); + max8998->buck1_vol[max8998->buck1_idx] = i; + ret = max8998_get_voltage_register(rdev, ®, + &shift, + &mask); + ret = max8998_write_reg(i2c, reg, i); + buck1_gpio_set(pdata->buck1_set1, + pdata->buck1_set2, max8998->buck1_idx); + buck1_last_val++; +buck1_exit: + dev_dbg(max8998->dev, "%s: SET1:%d, SET2:%d\n", + i2c->name, gpio_get_value(pdata->buck1_set1), + gpio_get_value(pdata->buck1_set2)); + break; + } else { + ret = max8998_write_reg(i2c, reg, i); + } + break; + + case MAX8998_BUCK2: + dev_dbg(max8998->dev, + "BUCK2, i:%d buck2_vol1:%d, buck2_vol2:%d\n" + , i, max8998->buck2_vol[0], max8998->buck2_vol[1]); + if (gpio_is_valid(pdata->buck2_set3)) { + if (max8998->buck2_vol[0] == i) { + max8998->buck1_idx = 0; + buck2_gpio_set(pdata->buck2_set3, 0); + } else { + max8998->buck1_idx = 1; + ret = max8998_get_voltage_register(rdev, ®, + &shift, + &mask); + ret = max8998_write_reg(i2c, reg, i); + max8998->buck2_vol[1] = i; + buck2_gpio_set(pdata->buck2_set3, 1); + } + dev_dbg(max8998->dev, "%s: SET3:%d\n", i2c->name, + gpio_get_value(pdata->buck2_set3)); + } else { + ret = max8998_write_reg(i2c, reg, i); + } + break; - if (en_ramp == true) { - int difference = desc->min + desc->step*i - previous_vol/1000; - if (difference > 0) - udelay(difference / ((val & 0x0f) + 1)); + case MAX8998_BUCK3: + case MAX8998_BUCK4: + ret = max8998_update_reg(i2c, reg, i<<shift, mask<<shift); + break; } + /* Voltage stabilization */ + max8998_read_reg(i2c, MAX8998_REG_ONOFF4, &val); + + /* lp3974 hasn't got ENRAMP bit - ramp is assumed as true */ + /* MAX8998 has ENRAMP bit implemented, so test it*/ + if (max8998->iodev->type == TYPE_MAX8998 && !(val & MAX8998_ENRAMP)) + return ret; + + difference = desc->min + desc->step*i - previous_vol/1000; + if (difference > 0) + udelay(difference / ((val & 0x0f) + 1)); + return ret; } @@ -354,7 +493,7 @@ static struct regulator_ops max8998_ldo_ops = { .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage = max8998_get_voltage, - .set_voltage = max8998_set_voltage, + .set_voltage = max8998_set_voltage_ldo, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, }; @@ -365,7 +504,7 @@ static struct regulator_ops max8998_buck_ops = { .enable = max8998_ldo_enable, .disable = max8998_ldo_disable, .get_voltage = max8998_get_voltage, - .set_voltage = max8998_set_voltage, + .set_voltage = max8998_set_voltage_buck, .set_suspend_enable = max8998_ldo_enable, .set_suspend_disable = max8998_ldo_disable, }; @@ -538,6 +677,7 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) struct max8998_platform_data *pdata = dev_get_platdata(iodev->dev); struct regulator_dev **rdev; struct max8998_data *max8998; + struct i2c_client *i2c; int i, ret, size; if (!pdata) { @@ -561,6 +701,86 @@ static __devinit int max8998_pmic_probe(struct platform_device *pdev) max8998->iodev = iodev; max8998->num_regulators = pdata->num_regulators; platform_set_drvdata(pdev, max8998); + i2c = max8998->iodev->i2c; + + /* NOTE: */ + /* For unused GPIO NOT marked as -1 (thereof equal to 0) WARN_ON */ + /* will be displayed */ + + /* Check if MAX8998 voltage selection GPIOs are defined */ + if (gpio_is_valid(pdata->buck1_set1) && + gpio_is_valid(pdata->buck1_set2)) { + /* Check if SET1 is not equal to 0 */ + if (!pdata->buck1_set1) { + printk(KERN_ERR "MAX8998 SET1 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck1_set1); + return -EIO; + } + /* Check if SET2 is not equal to 0 */ + if (!pdata->buck1_set2) { + printk(KERN_ERR "MAX8998 SET2 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck1_set2); + return -EIO; + } + + gpio_request(pdata->buck1_set1, "MAX8998 BUCK1_SET1"); + gpio_direction_output(pdata->buck1_set1, + max8998->buck1_idx & 0x1); + + + gpio_request(pdata->buck1_set2, "MAX8998 BUCK1_SET2"); + gpio_direction_output(pdata->buck1_set2, + (max8998->buck1_idx >> 1) & 0x1); + /* Set predefined value for BUCK1 register 1 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck1_max_voltage1 / 1000)) + i++; + printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); + max8998->buck1_vol[0] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE1, i); + + /* Set predefined value for BUCK1 register 2 */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck1_max_voltage2 / 1000)) + i++; + + max8998->buck1_vol[1] = i; + printk(KERN_ERR "i:%d, buck1_idx:%d\n", i, max8998->buck1_idx); + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK1_VOLTAGE2, i) + + ret; + if (ret) + return ret; + + } + + if (gpio_is_valid(pdata->buck2_set3)) { + /* Check if SET3 is not equal to 0 */ + if (!pdata->buck2_set3) { + printk(KERN_ERR "MAX8998 SET3 GPIO defined as 0 !\n"); + WARN_ON(!pdata->buck2_set3); + return -EIO; + } + gpio_request(pdata->buck2_set3, "MAX8998 BUCK2_SET3"); + gpio_direction_output(pdata->buck2_set3, + max8998->buck2_idx & 0x1); + + /* BUCK2 - set preset default voltage value to buck2_vol[0] */ + i = 0; + while (buck12_voltage_map_desc.min + + buck12_voltage_map_desc.step*i + != (pdata->buck2_max_voltage / 1000)) + i++; + printk(KERN_ERR "i:%d, buck2_idx:%d\n", i, max8998->buck2_idx); + max8998->buck2_vol[0] = i; + ret = max8998_write_reg(i2c, MAX8998_REG_BUCK2_VOLTAGE1, i); + if (ret) + return ret; + + } for (i = 0; i < pdata->num_regulators; i++) { const struct voltage_map_desc *desc; diff --git a/drivers/regulator/mc13783-regulator.c b/drivers/regulator/mc13783-regulator.c index 4597d508a22..ecd99f59dba 100644 --- a/drivers/regulator/mc13783-regulator.c +++ b/drivers/regulator/mc13783-regulator.c @@ -465,8 +465,8 @@ static struct regulator_ops mc13783_fixed_regulator_ops = { .get_voltage = mc13783_fixed_regulator_get_voltage, }; -int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, - u32 val) +static int mc13783_powermisc_rmw(struct mc13783_regulator_priv *priv, u32 mask, + u32 val) { struct mc13783 *mc13783 = priv->mc13783; int ret; diff --git a/drivers/regulator/tps6586x-regulator.c b/drivers/regulator/tps6586x-regulator.c index 51237fbb1bb..6d20b0454a1 100644 --- a/drivers/regulator/tps6586x-regulator.c +++ b/drivers/regulator/tps6586x-regulator.c @@ -231,8 +231,7 @@ static int tps6586x_dvm_voltages[] = { }; #define TPS6586X_REGULATOR(_id, vdata, _ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ -{ \ + ereg0, ebit0, ereg1, ebit1) \ .desc = { \ .name = "REG-" #_id, \ .ops = &tps6586x_regulator_##_ops, \ @@ -248,18 +247,26 @@ static int tps6586x_dvm_voltages[] = { .enable_bit[0] = (ebit0), \ .enable_reg[1] = TPS6586X_SUPPLY##ereg1, \ .enable_bit[1] = (ebit1), \ - .voltages = tps6586x_##vdata##_voltages, \ -} + .voltages = tps6586x_##vdata##_voltages, + +#define TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ + .go_reg = TPS6586X_##goreg, \ + .go_bit = (gobit), #define TPS6586X_LDO(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1) \ +{ \ TPS6586X_REGULATOR(_id, vdata, ldo_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, 0, 0) + ereg0, ebit0, ereg1, ebit1) \ +} #define TPS6586X_DVM(_id, vdata, vreg, shift, nbits, \ ereg0, ebit0, ereg1, ebit1, goreg, gobit) \ +{ \ TPS6586X_REGULATOR(_id, vdata, dvm_ops, vreg, shift, nbits, \ - ereg0, ebit0, ereg1, ebit1, goreg, gobit) + ereg0, ebit0, ereg1, ebit1) \ + TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit) \ +} static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(LDO_0, ldo, SUPPLYV1, 5, 3, ENC, 0, END, 0), @@ -267,11 +274,11 @@ static struct tps6586x_regulator tps6586x_regulator[] = { TPS6586X_LDO(LDO_5, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6), TPS6586X_LDO(LDO_6, ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4), TPS6586X_LDO(LDO_7, ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5), - TPS6586X_LDO(LDO_8, ldo, SUPPLYV1, 5, 3, ENC, 6, END, 6), + TPS6586X_LDO(LDO_8, ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6), TPS6586X_LDO(LDO_9, ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7), - TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, ENE, 7, ENE, 7), + TPS6586X_LDO(LDO_RTC, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7), TPS6586X_LDO(LDO_1, dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1), - TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 1, END, 1), + TPS6586X_LDO(SM_2, sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7), TPS6586X_DVM(LDO_2, dvm, LDO2BV1, 0, 5, ENA, 3, ENB, 3, VCC2, 6), TPS6586X_DVM(LDO_4, ldo4, LDO4V1, 0, 5, ENC, 3, END, 3, VCC1, 6), @@ -290,6 +297,10 @@ static inline int tps6586x_regulator_preinit(struct device *parent, uint8_t val1, val2; int ret; + if (ri->enable_reg[0] == ri->enable_reg[1] && + ri->enable_bit[0] == ri->enable_bit[1]) + return 0; + ret = tps6586x_read(parent, ri->enable_reg[0], &val1); if (ret) return ret; @@ -298,14 +309,14 @@ static inline int tps6586x_regulator_preinit(struct device *parent, if (ret) return ret; - if (!(val2 & ri->enable_bit[1])) + if (!(val2 & (1 << ri->enable_bit[1]))) return 0; /* * The regulator is on, but it's enabled with the bit we don't * want to use, so we switch the enable bits */ - if (!(val1 & ri->enable_bit[0])) { + if (!(val1 & (1 << ri->enable_bit[0]))) { ret = tps6586x_set_bits(parent, ri->enable_reg[0], 1 << ri->enable_bit[0]); if (ret) diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 7e5892efc43..a57262a4fa6 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -219,12 +219,12 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode) return -EACCES; status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message >> 8, 0x15 /* PB_WORD_MSB */ ); - if (status >= 0) + message >> 8, TWL4030_PM_MASTER_PB_WORD_MSB); + if (status < 0) return status; return twl_i2c_write_u8(TWL_MODULE_PM_MASTER, - message, 0x16 /* PB_WORD_LSB */ ); + message & 0xff, TWL4030_PM_MASTER_PB_WORD_LSB); } /*----------------------------------------------------------------------*/ |