aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator
diff options
context:
space:
mode:
authorcodeworkx <codeworkx@cyanogenmod.com>2012-09-22 09:48:20 +0200
committercodeworkx <codeworkx@cyanogenmod.com>2012-09-22 14:02:16 +0200
commit2489007e7d740ccbc3e0a202914e243ad5178787 (patch)
treeb8e6380ea7b1da63474ad68a5dba997e01146043 /drivers/regulator
parent5f67568eb31e3a813c7c52461dcf66ade15fc2e7 (diff)
downloadkernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.gz
kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.tar.bz2
kernel_samsung_smdk4412-2489007e7d740ccbc3e0a202914e243ad5178787.zip
merge opensource jb u5
Change-Id: I1aaec157aa196f3448eff8636134fce89a814cf2
Diffstat (limited to 'drivers/regulator')
-rw-r--r--drivers/regulator/Kconfig18
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/core.c2
-rw-r--r--drivers/regulator/fixed.c4
-rw-r--r--drivers/regulator/lp8720.c471
-rw-r--r--drivers/regulator/max77686.c47
-rw-r--r--drivers/regulator/max77693.c5
-rw-r--r--drivers/regulator/max8952_grande.c258
-rw-r--r--drivers/regulator/s5m8767.c58
9 files changed, 839 insertions, 26 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 02868c07d85..e17e47b6c61 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -108,6 +108,15 @@ config REGULATOR_MAX8952
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_MAX8952_GRANDE
+ 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.
+ This driver uses MODE3 for Grande Project
+
config REGULATOR_MAX8997
tristate "Maxim 8997/8966 regulator"
depends on MFD_MAX8997
@@ -218,6 +227,15 @@ config REGULATOR_LP3972
Say Y here to support the voltage regulators and convertors
on National Semiconductors LP3972 PMIC
+config REGULATOR_LP8720
+ tristate "National Semiconductors LP8720 PMIC regulator driver"
+ depends on I2C
+ help
+ This driver controls a National Semiconductors LP8720 voltage
+ output regulator(the BUCKs and LDOs) via I2C bus. Say Y here
+ to support the voltage regulators and convertors on National
+ Semiconductors LP8720 PMIC
+
config REGULATOR_PCAP
tristate "PCAP2 regulator driver"
depends on EZX_PCAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 7f7be11c91f..d71b7930880 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -12,12 +12,14 @@ obj-$(CONFIG_REGULATOR_AD5398) += ad5398.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
obj-$(CONFIG_REGULATOR_LP3971) += lp3971.o
obj-$(CONFIG_REGULATOR_LP3972) += lp3972.o
+obj-$(CONFIG_REGULATOR_LP8720) += lp8720.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_MAX8952_GRANDE) += max8952_grande.o
obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX8698) += max8698.o
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index d3e38790906..5f1a08b48f2 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2704,8 +2704,8 @@ void regulator_unregister(struct regulator_dev *rdev)
list_del(&rdev->list);
if (rdev->supply)
sysfs_remove_link(&rdev->dev.kobj, "supply");
- device_unregister(&rdev->dev);
kfree(rdev->constraints);
+ device_unregister(&rdev->dev);
mutex_unlock(&regulator_list_mutex);
}
EXPORT_SYMBOL_GPL(regulator_unregister);
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 2fe9d99c9f2..153d35b9771 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -229,7 +229,11 @@ static int __init regulator_fixed_voltage_init(void)
{
return platform_driver_register(&regulator_fixed_voltage_driver);
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(regulator_fixed_voltage_init);
+#else
subsys_initcall(regulator_fixed_voltage_init);
+#endif
static void __exit regulator_fixed_voltage_exit(void)
{
diff --git a/drivers/regulator/lp8720.c b/drivers/regulator/lp8720.c
new file mode 100644
index 00000000000..cb667182b01
--- /dev/null
+++ b/drivers/regulator/lp8720.c
@@ -0,0 +1,471 @@
+/*
+ * Regulator driver for National Semiconductors LP8720 PMIC chip
+ *
+ * Based on lp3972.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/lp8720.h>
+#include <mach/gpio.h>
+#include <linux/slab.h>
+#include <plat/gpio-cfg.h>
+
+static const int ldo_output_enable_mask[] = {
+ LP8720_LDO1_EN,
+ LP8720_LDO2_EN,
+ LP8720_LDO3_EN,
+ LP8720_LDO4_EN,
+ LP8720_LDO5_EN,
+ LP8720_BUCK_V1_EN,
+ LP8720_BUCK_V2_EN,
+};
+
+static const int ldo_output_enable_addr[] = {
+ LP8720_LDO1_REG,
+ LP8720_LDO2_REG,
+ LP8720_LDO3_REG,
+ LP8720_LDO4_REG,
+ LP8720_LDO5_REG,
+ LP8720_BUCK_V1_REG,
+ LP8720_BUCK_V2_REG,
+};
+
+#define LP8720_LDO_OUTPUT_ENABLE_MASK(x) (ldo_output_enable_mask[x])
+#define LP8720_LDO_OUTPUT_ENABLE_REG(x) (ldo_output_enable_addr[x])
+
+
+static const int ldo1235_voltage_map[] = {
+ 1200, 1250, 1300, 1350, 1400, 1450, 1500, 1550,
+ 1600, 1650, 1700, 1750, 1800, 1850, 1900, 2000,
+ 2100, 2200, 2300, 2400, 2500, 2600, 2650, 2700,
+ 2750, 2800, 2850, 2900, 2950, 3000, 3100, 3300,
+};
+
+static const int ldo4_voltage_map[] = {
+ 800, 850, 900, 1000, 1100, 1200, 1250, 1300,
+ 1350, 1400, 1450, 1500, 1550, 1600, 1650, 1700,
+ 1750, 1800, 1850, 1900, 2000, 2100, 2200, 2300,
+ 2400, 2500, 2600, 2650, 2700, 2750, 2800, 2850,
+};
+
+static const int buck12_voltage_map[] = {
+ 0, 800, 850, 900, 950, 1000, 1050, 1100,
+ 1150, 1200, 1250, 1300, 1350, 1400, 1450, 1500,
+ 1550, 1600, 1650, 1700, 1750, 1800, 1850, 1900,
+ 1950, 2000, 2050, 2100, 2150, 2200, 2250, 2300,
+};
+
+static const int *ldo_voltage_map[] = {
+ ldo1235_voltage_map, /* LDO1 */
+ ldo1235_voltage_map, /* LDO2 */
+ ldo1235_voltage_map, /* LDO3 */
+ ldo4_voltage_map, /* LDO4 */
+ ldo1235_voltage_map, /* LDO5 */
+ buck12_voltage_map, /* BUCK_V1 */
+ buck12_voltage_map, /* BUCK_V2 */
+};
+
+#define LDO_VOL_VALUE_MAP(x) (ldo_voltage_map[(x - LP8720_LDO1)])
+#define LDO_VOL_MIN_IDX (0)
+#define LDO_VOL_MAX_IDX (31)
+
+static int lp8720_i2c_read(struct i2c_client *i2c, char reg, int count,
+ u8 *dest)
+{
+ u8 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 lp8720_i2c_write(struct i2c_client *i2c, u8 reg, int count,
+ const u8 value)
+{
+ u8 ret;
+
+ if (count != 1)
+ return -EIO;
+
+ ret = i2c_smbus_write_byte_data(i2c, reg, value);
+
+ return ret;
+}
+
+static u8 lp8720_reg_read(struct lp8720 *lp8720, u8 reg)
+{
+ u8 val = 0;
+
+ mutex_lock(&lp8720->io_lock);
+ lp8720_i2c_read(lp8720->i2c, reg, 1, &val);
+ dev_dbg(lp8720->dev, "reg read 0x%02x -> 0x%02x\n", (int)reg,
+ (unsigned)val & 0xff);
+ mutex_unlock(&lp8720->io_lock);
+
+ return val & 0xff;
+}
+
+
+static int lp8720_set_bits(struct lp8720 *lp8720, u8 reg, u16 mask, u16 val)
+{
+ u8 tmp;
+ int ret;
+
+ mutex_lock(&lp8720->io_lock);
+ ret = lp8720_i2c_read(lp8720->i2c, reg, 1, &tmp);
+ tmp = (tmp & ~mask) | val;
+ if (ret == 0) {
+ ret = lp8720_i2c_write(lp8720->i2c, reg, 1, tmp);
+ dev_dbg(lp8720->dev, "reg write 0x%02x -> 0x%02x\n", (int)reg,
+ (unsigned)val & 0xff);
+ }
+ mutex_unlock(&lp8720->io_lock);
+
+ return ret;
+}
+
+static int lp8720_ldo_is_enabled(struct regulator_dev *dev)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+ u16 mask = LP8720_LDO_OUTPUT_ENABLE_MASK(ldo);
+ u16 val;
+
+ val = lp8720_reg_read(lp8720, LP8720_ENABLE_REG);
+ dev_dbg(lp8720->dev, "%s, is_enabled ldo:%d, mask:0x%4x - %s\n",
+ __func__, ldo, mask,
+ !!(val & mask) ? "enabled" : "disabled");
+
+ return !!(val & mask);
+}
+
+static int lp8720_ldo_enable(struct regulator_dev *dev)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+ u16 mask = LP8720_LDO_OUTPUT_ENABLE_MASK(ldo);
+
+ dev_dbg(lp8720->dev, "%s, enable ldo:%d, mask:0x%4x\n",
+ __func__, ldo, mask);
+ return lp8720_set_bits(lp8720, LP8720_ENABLE_REG,
+ mask, mask);
+}
+
+static int lp8720_ldo_disable(struct regulator_dev *dev)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+ u16 mask = LP8720_LDO_OUTPUT_ENABLE_MASK(ldo);
+
+ dev_dbg(lp8720->dev, "%s, disable ldo:%d, mask:0x%4x\n",
+ __func__, ldo, mask);
+ return lp8720_set_bits(lp8720, LP8720_ENABLE_REG,
+ mask, 0);
+}
+
+static int lp8720_ldo_list_voltage(struct regulator_dev *dev, unsigned index)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+
+ if (ldo < 0 || ldo > ARRAY_SIZE(ldo_voltage_map)) {
+ dev_err(lp8720->dev, "[ldo = %d] is out of range\n", ldo);
+ return -EINVAL;
+ }
+ if (index < 0 || index > LDO_VOL_MAX_IDX) {
+ dev_err(lp8720->dev, "[index = %d] is out of range\n", index);
+ return -EINVAL;
+ }
+ return 1000 * LDO_VOL_VALUE_MAP(ldo)[index];
+}
+
+static int lp8720_ldo_get_voltage(struct regulator_dev *dev)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+ u16 val, reg;
+
+ reg = lp8720_reg_read(lp8720, LP8720_LDO_VOL_CONTR_REG(ldo));
+ val = reg & LP8720_LDOV_MASK;
+
+ return 1000 * LDO_VOL_VALUE_MAP(ldo)[val];
+}
+
+static int lp8720_ldo_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV,
+ unsigned int *selector)
+{
+ struct lp8720 *lp8720 = rdev_get_drvdata(dev);
+ int ldo = rdev_get_id(dev) - LP8720_LDO1;
+ int min_vol = min_uV / 1000, max_vol = max_uV / 1000;
+ const int *vol_map = LDO_VOL_VALUE_MAP(ldo);
+ u16 val;
+
+ if (min_vol < vol_map[LDO_VOL_MIN_IDX] ||
+ min_vol > vol_map[LDO_VOL_MAX_IDX]) {
+ dev_err(lp8720->dev, "[min_vol = %d] is out of range\n",
+ min_vol);
+ dev_err(lp8720->dev, "vol_map[%d] : %d, vol_map[%d] : %d\n",
+ LDO_VOL_MIN_IDX, vol_map[LDO_VOL_MIN_IDX],
+ LDO_VOL_MAX_IDX, vol_map[LDO_VOL_MAX_IDX]);
+ return -EINVAL;
+ }
+
+ for (val = LDO_VOL_MIN_IDX; val <= LDO_VOL_MAX_IDX; val++)
+ if (vol_map[val] >= min_vol)
+ break;
+
+ if (val > LDO_VOL_MAX_IDX || vol_map[val] > max_vol) {
+ dev_err(lp8720->dev, "[val = %d] is out of range\n", val);
+ return -EINVAL;
+ }
+
+ *selector = val;
+ dev_dbg(lp8720->dev, "%s, disable ldo:%d, val:0x%4x\n",
+ __func__, ldo, val);
+
+ return lp8720_set_bits(lp8720, LP8720_LDO_VOL_CONTR_REG(ldo),
+ LP8720_LDOV_MASK, val);
+}
+
+static struct regulator_ops lp8720_ldo_ops = {
+ .list_voltage = lp8720_ldo_list_voltage,
+ .is_enabled = lp8720_ldo_is_enabled,
+ .enable = lp8720_ldo_enable,
+ .disable = lp8720_ldo_disable,
+ .get_voltage = lp8720_ldo_get_voltage,
+ .set_voltage = lp8720_ldo_set_voltage,
+};
+
+static struct regulator_desc regulators[] = {
+ {
+ .name = "LDO1",
+ .id = LP8720_LDO1,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(ldo1235_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = LP8720_LDO2,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(ldo1235_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = LP8720_LDO3,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(ldo1235_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = LP8720_LDO4,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(ldo4_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO5",
+ .id = LP8720_LDO5,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(ldo1235_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK_V1",
+ .id = LP8720_BUCK_V1,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(buck12_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "BUCK_V2",
+ .id = LP8720_BUCK_V2,
+ .ops = &lp8720_ldo_ops,
+ .n_voltages = ARRAY_SIZE(buck12_voltage_map),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __devinit setup_regulators(struct lp8720 *lp8720,
+ struct lp8720_platform_data *pdata)
+{
+ int i, err;
+
+ lp8720->num_regulators = pdata->num_regulators;
+ lp8720->rdev = kcalloc(pdata->num_regulators,
+ sizeof(struct regulator_dev *), GFP_KERNEL);
+ if (!lp8720->rdev) {
+ err = -ENOMEM;
+ goto err_nomem;
+ }
+
+ /* Instantiate the regulators */
+ for (i = 0; i < pdata->num_regulators; i++) {
+ struct lp8720_regulator_subdev *reg = &pdata->regulators[i];
+ lp8720->rdev[i] = regulator_register(&regulators[reg->id],
+ lp8720->dev, reg->initdata, lp8720);
+ if (IS_ERR(lp8720->rdev[i])) {
+ err = PTR_ERR(lp8720->rdev[i]);
+ dev_err(lp8720->dev, "regulator init failed: %d\n",
+ err);
+ goto error;
+ }
+ }
+ return 0;
+error:
+ while (--i >= 0)
+ regulator_unregister(lp8720->rdev[i]);
+ kfree(lp8720->rdev);
+ lp8720->rdev = NULL;
+err_nomem:
+ return err;
+}
+
+static int __devinit lp8720_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct lp8720 *lp8720;
+ struct lp8720_platform_data *pdata = i2c->dev.platform_data;
+ int ret;
+ u8 readbyte = 0;
+ u8 enable = 0;
+
+ if (!pdata) {
+ dev_dbg(&i2c->dev, "No platform init data supplied\n");
+ return -ENODEV;
+ }
+
+ lp8720 = kzalloc(sizeof(struct lp8720), GFP_KERNEL);
+ if (!lp8720)
+ return -ENOMEM;
+
+ lp8720->i2c = i2c;
+ lp8720->dev = &i2c->dev;
+
+ mutex_init(&lp8720->io_lock);
+ ret = lp8720_i2c_read(i2c, 0x00, 1, &readbyte);
+ if (ret == 0 &&
+ readbyte != 0x05) {
+ ret = -ENODEV;
+ dev_err(&i2c->dev, "chip reported: [00h]= 0x%x\n", readbyte);
+ }
+ if (ret < 0) {
+ dev_err(&i2c->dev, "failed to detect device. ret = %d\n", ret);
+ goto err_detect;
+ }
+
+ ret = setup_regulators(lp8720, pdata);
+ if (ret < 0)
+ goto err_detect;
+
+ i2c_set_clientdata(i2c, lp8720);
+ ret = gpio_request(pdata->en_pin, pdata->name);
+ if (ret) {
+ printk(KERN_ERR "%s, ERROR [%s] - gpio_request(%d) failed\n",
+ __func__,
+ pdata->name,
+ pdata->en_pin);
+ }
+ s3c_gpio_cfgpin(pdata->en_pin, S3C_GPIO_OUTPUT);
+ s3c_gpio_setpull(pdata->en_pin, S3C_GPIO_PULL_NONE);
+ gpio_set_value(pdata->en_pin, 1);
+ if (!gpio_get_value(pdata->en_pin)) {
+ printk(KERN_ERR "%s, ERROR [%s] - gpio_get_value(%d) is %s\n",
+ __func__,
+ pdata->name,
+ pdata->en_pin,
+ gpio_get_value(pdata->en_pin) ? "HIGH" : "LOW");
+ }
+ if (!strncmp(pdata->name,
+ "lp8720_folder_pmic",
+ strlen("lp8720_folder_pmic"))) {
+ printk(KERN_DEBUG "%s, folder_pmic\n", __func__);
+ } else if (!strncmp(pdata->name,
+ "lp8720_sub_pmic",
+ strlen("lp8720_sub_pmic"))) {
+ lp8720_i2c_read(i2c, LP8720_ENABLE_REG, 1, &readbyte);
+ enable = readbyte & 0xC0;
+ lp8720_i2c_write(i2c, LP8720_ENABLE_REG, 1, enable);
+ lp8720_i2c_read(i2c, LP8720_ENABLE_REG, 1, &readbyte);
+ printk(KERN_DEBUG "%s, [%s] - ENABLE_REG : 0x%2x\n",
+ __func__, pdata->name, readbyte);
+ }
+
+ return 0;
+
+err_detect:
+ kfree(lp8720);
+ return ret;
+}
+
+static int __devexit lp8720_i2c_remove(struct i2c_client *i2c)
+{
+ struct lp8720 *lp8720 = i2c_get_clientdata(i2c);
+ struct lp8720_platform_data *pdata = i2c->dev.platform_data;
+ int i;
+
+ for (i = 0; i < lp8720->num_regulators; i++)
+ regulator_unregister(lp8720->rdev[i]);
+ kfree(lp8720->rdev);
+ kfree(lp8720);
+ gpio_free(pdata->en_pin);
+ return 0;
+}
+
+static const struct i2c_device_id lp8720_i2c_id[] = {
+ { "lp8720", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, lp8720_i2c_id);
+
+static struct i2c_driver lp8720_i2c_driver = {
+ .driver = {
+ .name = "lp8720",
+ .owner = THIS_MODULE,
+ },
+ .probe = lp8720_i2c_probe,
+ .remove = __devexit_p(lp8720_i2c_remove),
+ .id_table = lp8720_i2c_id,
+};
+
+static int __init lp8720_module_init(void)
+{
+ return i2c_add_driver(&lp8720_i2c_driver);
+}
+subsys_initcall(lp8720_module_init);
+
+static void __exit lp8720_module_exit(void)
+{
+ i2c_del_driver(&lp8720_i2c_driver);
+}
+module_exit(lp8720_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Axel Lin <axel.lin@gmail.com>");
+MODULE_DESCRIPTION("LP8720 PMIC driver");
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index ebb29548ab9..936afb1c16f 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -316,7 +316,7 @@ static int max77686_reg_enable(struct regulator_dev *rdev)
if (ret)
return ret;
- pr_info("%s: id=%d, pattern=%x\n",
+ printk(PMIC_DEBUG "%s: id=%d, pattern=%x\n",
__func__, rdev_get_id(rdev), pattern);
return max77686_update_reg(i2c, reg, pattern, mask);
@@ -332,7 +332,7 @@ static int max77686_reg_disable(struct regulator_dev *rdev)
if (ret)
return ret;
- pr_info("%s: id=%d, pattern=%x\n",
+ printk(PMIC_DEBUG "%s: id=%d, pattern=%x\n",
__func__, rdev_get_id(rdev), pattern);
return max77686_update_reg(i2c, reg, ~mask, mask);
@@ -401,7 +401,7 @@ static int max77686_get_voltage(struct regulator_dev *rdev)
val >>= shift;
val &= mask;
- pr_debug("%s: id=%d, val=%x\n",
+ printk(PMIC_REG_DEBUG "%s: id=%d, val=%x\n",
__func__, rid, val);
return max77686_list_voltage(rdev, val);
@@ -467,12 +467,19 @@ static int max77686_set_voltage(struct regulator_dev *rdev,
org = (org & mask) >> shift;
#if defined(CONFIG_MACH_M0) || defined(CONFIG_MACH_C1) || \
- defined(CONFIG_MACH_C1VZW) || defined(CONFIG_MACH_P4NOTE) || \
- defined(CONFIG_MACH_GC1)
+ defined(CONFIG_MACH_M3) || \
+ defined(CONFIG_MACH_P4NOTE) || \
+ defined(CONFIG_MACH_GC1) || defined(CONFIG_MACH_T0) || \
+ defined(CONFIG_MACH_GRANDE) || defined(CONFIG_MACH_IRON)
+#if !defined(CONFIG_MACH_T0_CHN_CU_DUOS) || \
+ !defined(CONFIG_MACH_T0_CHN_CMCC) || \
+ !defined(CONFIG_MACH_T0_CHN_OPEN_DUOS) || \
+ !defined(CONFIG_MACH_T0_CHN_CTC)
/* Test code for HDMI debug */
if (!gpio_get_value(GPIO_HDMI_EN))
#endif
- pr_debug("max77686: id=%d, org=%x, val=%x",
+#endif
+ printk(PMIC_REG_DEBUG "max77686: id=%d, org=%x, val=%x",
rdev_get_id(rdev), org, i);
ret = max77686_update_reg(i2c, reg, i << shift, mask << shift);
@@ -633,7 +640,7 @@ static int max77686_set_ramp_rate(struct i2c_client *i2c, int rate)
break;
}
- pr_debug("%s: ramp_delay=%d, data=0x%x\n", __func__, ramp_delay, data);
+ printk(PMIC_DEBUG "%s: ramp_delay=%d, data=0x%x\n", __func__, ramp_delay, data);
max77686_update_reg(i2c, MAX77686_REG_BUCK2CTRL1, data, 0xC0);
max77686_update_reg(i2c, MAX77686_REG_BUCK3CTRL1, data, 0xC0);
@@ -649,10 +656,10 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
struct regulator_dev **rdev;
struct max77686_data *max77686;
struct i2c_client *i2c;
- int i, ret, size;
+ int i, ret, size, err;
u8 data = 0;
- pr_info("%s\n", __func__);
+ printk(PMIC_DEBUG "%s\n", __func__);
if (!pdata) {
dev_err(pdev->dev.parent, "No platform init data supplied.\n");
@@ -682,7 +689,7 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
max77686_read_reg(i2c, MAX77686_REG_DEVICE_ID, &data);
max77686->device_id = (data & 0x7);
- pr_info("%s: DEVICE ID=0x%x\n", __func__, data);
+ printk(PMIC_DEBUG "%s: DEVICE ID=0x%x\n", __func__, data);
/*
* TODO
@@ -700,7 +707,11 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
if (gpio_is_valid(pdata->buck234_gpio_dvs[i].gpio)) {
max77686->buck234_gpios_dvs[i] =
pdata->buck234_gpio_dvs[i].gpio;
- gpio_request(pdata->buck234_gpio_dvs[i].gpio, buf);
+ err = gpio_request(
+ pdata->buck234_gpio_dvs[i].gpio, buf);
+ if (err)
+ pr_warn(
+ "failed to request MAX77686 DVS%d\n", i);
gpio_direction_output(pdata->buck234_gpio_dvs[i].gpio,
pdata->buck234_gpio_dvs[i].data);
} else {
@@ -714,7 +725,11 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
int data = (max77686->device_id <= MAX77686_DEVICE_PASS1) ? 1 : 0;
max77686->buck234_gpios_selb[i] =
pdata->buck234_gpio_selb[i];
- gpio_request(pdata->buck234_gpio_selb[i], buf);
+ err = gpio_request(
+ pdata->buck234_gpio_selb[i], buf);
+ if (err)
+ pr_warn(
+ "failed to request MAX77686 SELB%d\n", i);
gpio_direction_output(pdata->buck234_gpio_selb[i], data);
} else {
dev_info(&pdev->dev, "GPIO %s ignored (%d)\n",
@@ -776,7 +791,7 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
regulators[id].n_voltages =
(desc->max - desc->min) / desc->step + 1;
- pr_info("%s: desc=%p, id=%d, n_vol=%d, max=%d, min=%d, step=%d\n",
+ printk(PMIC_DEBUG "%s: desc=%p, id=%d, n_vol=%d, max=%d, min=%d, step=%d\n",
__func__, desc, id, regulators[id].n_voltages,
desc->max, desc->min, desc->step);
}
@@ -852,11 +867,15 @@ static struct platform_driver max77686_pmic_driver = {
static int __init max77686_pmic_init(void)
{
- pr_info("%s\n", __func__);
+ printk(PMIC_DEBUG "%s\n", __func__);
return platform_driver_register(&max77686_pmic_driver);
}
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(max77686_pmic_init);
+#else
subsys_initcall(max77686_pmic_init);
+#endif
static void __exit max77686_pmic_cleanup(void)
{
diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c
index bcbdd3ad42c..5293ea03c2b 100644
--- a/drivers/regulator/max77693.c
+++ b/drivers/regulator/max77693.c
@@ -559,8 +559,11 @@ static int __init max77693_pmic_init(void)
{
return platform_driver_register(&max77693_pmic_driver);
}
-
+#ifdef CONFIG_FAST_RESUME
+beforeresume_initcall(max77693_pmic_init);
+#else
subsys_initcall(max77693_pmic_init);
+#endif
static void __exit max77693_pmic_cleanup(void)
{
diff --git a/drivers/regulator/max8952_grande.c b/drivers/regulator/max8952_grande.c
new file mode 100644
index 00000000000..dad8a8e3b5e
--- /dev/null
+++ b/drivers/regulator/max8952_grande.c
@@ -0,0 +1,258 @@
+/*
+ * 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, unsigned *selector)
+{
+ 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_vid1)) {
+ /* 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);
+ *selector = vid;
+ 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;
+ int readbyte;
+
+ 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_write_reg(max8952, MAX8952_REG_MODE3, 0x2B);
+ readbyte = max8952_read_reg(max8952, MAX8952_REG_MODE3);
+ printk(KERN_DEBUG "%s, readbyte : 0x%2x\n", __func__, readbyte);
+
+ 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;
+
+ kfree(max8952);
+ return 0;
+}
+
+static const struct i2c_device_id max8952_ids[] = {
+ { "max8952_grande", 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_grande",
+ },
+ .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/s5m8767.c b/drivers/regulator/s5m8767.c
index 2690b4c29d5..da85667d4e3 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -21,6 +21,7 @@
#include <linux/regulator/machine.h>
#include <linux/mfd/s5m87xx/s5m-core.h>
#include <linux/mfd/s5m87xx/s5m-pmic.h>
+#include <linux/sched.h>
struct s5m8767_info {
struct device *dev;
@@ -28,7 +29,9 @@ struct s5m8767_info {
int num_regulators;
struct regulator_dev **rdev;
struct s5m_opmode_data *opmode_data;
+ struct delayed_work set_buchg;
+ u8 device_id;
int ramp_delay;
bool buck2_ramp;
bool buck3_ramp;
@@ -190,9 +193,9 @@ unsigned int s5m8767_opmode_reg[][3] = {
{0x3, 0x1, 0x1},
{0x3, 0x1, 0x1}, /* BUCK9 */
/* 32KHZ */
- {0x1, 0x1, 0x1},
- {0x2, 0x2, 0x2},
- {0x4, 0x4, 0x4},
+ {0x1, 0x0, 0x0},
+ {0x1, 0x0, 0x0},
+ {0x1, 0x0, 0x0},
};
static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, int *pmic_en)
@@ -222,7 +225,8 @@ static int s5m8767_get_register(struct regulator_dev *rdev, int *reg, int *pmic_
break;
case S5M8767_AP_EN32KHZ ... S5M8767_BT_EN32KHZ:
*reg = S5M8767_REG_CTRL1;
- break;
+ *pmic_en = 0x01 << (reg_id - S5M8767_AP_EN32KHZ);
+ return 0;
default:
return -EINVAL;
}
@@ -392,15 +396,15 @@ static int s5m8767_get_voltage_sel(struct regulator_dev *rdev)
mask = 0x3f;
break;
case S5M8767_BUCK2:
- if(s5m8767->buck2_gpiodvs)
+ if (s5m8767->buck2_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
case S5M8767_BUCK3:
- if(s5m8767->buck3_gpiodvs)
+ if (s5m8767->buck3_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
case S5M8767_BUCK4:
- if(s5m8767->buck4_gpiodvs)
+ if (s5m8767->buck4_gpiodvs)
reg += s5m8767->buck_gpioindex;
break;
}
@@ -475,7 +479,12 @@ static int s5m8767_set_voltage(struct regulator_dev *rdev,
s5m_reg_read(i2c, reg, &val);
val = val & mask;
- ret = s5m_reg_update(i2c, reg, i, mask);
+ if (s5m8767->device_id == 4 && reg == S5M8767_REG_BUCK1CTRL2)
+ ret = s5m_reg_update(i2c, reg, (i >= 0x40) ? \
+ (0x3F) : (i), mask);
+ else
+ ret = s5m_reg_update(i2c, reg, i, mask);
+
*selector = i;
if (val < i) {
@@ -536,8 +545,7 @@ static int s5m8767_set_voltage_buck(struct regulator_dev *rdev,
if (s5m8767->buck2_gpiodvs) {
while (s5m8767->buck2_vol[i] != new_val)
i++;
- }
- else
+ } else
return s5m8767_set_voltage(rdev, min_uV, max_uV, selector);
break;
case S5M8767_BUCK3:
@@ -682,6 +690,20 @@ static struct regulator_desc regulators[] = {
},
};
+static void s5m_set_buchg(struct work_struct *work)
+{
+ struct s5m8767_info *s5m8767;
+ u8 val;
+ val = 0x4f; /* set for BUCHG 100uA */
+
+ s5m8767 = container_of(work, struct s5m8767_info, set_buchg.work);
+
+ s5m_reg_write(s5m8767->iodev->i2c, S5M8767_REG_BUCHG, val);
+
+ s5m_reg_read(s5m8767->iodev->i2c, S5M8767_REG_BUCHG, &val);
+ pr_info("%s set S5M8767_REG_BUCHG = 0x%02x\n", __func__, val);
+}
+
static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
{
struct s5m87xx_dev *iodev = dev_get_drvdata(pdev->dev.parent);
@@ -731,6 +753,17 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
s5m8767->opmode_data = pdata->opmode_data;
+ s5m_reg_read(i2c, S5M8767_REG_ID, &s5m8767->device_id);
+ printk(KERN_DEBUG "%s: PMIC DEVICE ID=> 0x%x\n",
+ __func__, s5m8767->device_id);
+
+ buck_init = s5m8767_convert_voltage(&buck_voltage_val1,
+ pdata->buck1_init,
+ pdata->buck1_init +
+ buck_voltage_val1.step);
+
+ s5m_reg_write(i2c, S5M8767_REG_BUCK1DVS2, buck_init);
+
buck_init = s5m8767_convert_voltage(&buck_voltage_val2,
pdata->buck2_init,
pdata->buck2_init +
@@ -855,6 +888,8 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
gpio_direction_output(pdata->buck_ds[1], 0x0);
/* DS4 GPIO */
gpio_direction_output(pdata->buck_ds[2], 0x0);
+ /* BUCK1 DVS2 Enable */
+ s5m_reg_update(i2c, S5M8767_REG_BUCK1CTRL1, 0x02, 0x02);
if (pdata->buck2_gpiodvs) {
if (pdata->buck3_gpiodvs || pdata->buck4_gpiodvs) {
@@ -968,6 +1003,9 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
}
}
+ INIT_DELAYED_WORK_DEFERRABLE(&s5m8767->set_buchg, s5m_set_buchg);
+ schedule_delayed_work(&s5m8767->set_buchg, msecs_to_jiffies(40000));
+
return 0;
err:
for (i = 0; i < s5m8767->num_regulators; i++)