]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/regulator/tps65090-regulator.c
Merge tag 'for-v3.8' of git://git.infradead.org/users/cbou/linux-pstore
[karo-tx-linux.git] / drivers / regulator / tps65090-regulator.c
index 5f7f9311024eccaa7daf6160d93d16f3d31d4c16..41c391789c9790a59678dc1232bf0938e978a47e 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -31,17 +32,23 @@ struct tps65090_regulator {
        struct regulator_dev    *rdev;
 };
 
-static struct regulator_ops tps65090_ops = {
-       .enable = regulator_enable_regmap,
-       .disable = regulator_disable_regmap,
-       .is_enabled = regulator_is_enabled_regmap,
+static struct regulator_ops tps65090_ext_control_ops = {
+};
+
+static struct regulator_ops tps65090_reg_contol_ops = {
+       .enable         = regulator_enable_regmap,
+       .disable        = regulator_disable_regmap,
+       .is_enabled     = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops tps65090_ldo_ops = {
 };
 
 #define tps65090_REG_DESC(_id, _sname, _en_reg, _ops)  \
 {                                                      \
        .name = "TPS65090_RAILS"#_id,                   \
        .supply_name = _sname,                          \
-       .id = TPS65090_ID_##_id,                        \
+       .id = TPS65090_REGULATOR_##_id,                 \
        .ops = &_ops,                                   \
        .enable_reg = _en_reg,                          \
        .enable_mask = BIT(0),                          \
@@ -50,31 +57,33 @@ static struct regulator_ops tps65090_ops = {
 }
 
 static struct regulator_desc tps65090_regulator_desc[] = {
-       tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_ops),
-       tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_ops),
-       tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_ops),
-       tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_ops),
-       tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_ops),
-       tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_ops),
-       tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_ops),
-       tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_ops),
-       tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_ops),
-       tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_ops),
+       tps65090_REG_DESC(DCDC1, "vsys1",   0x0C, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(DCDC2, "vsys2",   0x0D, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(DCDC3, "vsys3",   0x0E, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET1,  "infet1",  0x0F, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET2,  "infet2",  0x10, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET3,  "infet3",  0x11, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET4,  "infet4",  0x12, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET5,  "infet5",  0x13, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET6,  "infet6",  0x14, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(FET7,  "infet7",  0x15, tps65090_reg_contol_ops),
+       tps65090_REG_DESC(LDO1,  "vsys_l1", 0,    tps65090_ldo_ops),
+       tps65090_REG_DESC(LDO2,  "vsys_l2", 0,    tps65090_ldo_ops),
 };
 
 static inline bool is_dcdc(int id)
 {
        switch (id) {
-       case TPS65090_ID_DCDC1:
-       case TPS65090_ID_DCDC2:
-       case TPS65090_ID_DCDC3:
+       case TPS65090_REGULATOR_DCDC1:
+       case TPS65090_REGULATOR_DCDC2:
+       case TPS65090_REGULATOR_DCDC3:
                return true;
        default:
                return false;
        }
 }
 
-static int __devinit tps65090_config_ext_control(
+static int tps65090_config_ext_control(
        struct tps65090_regulator *ri, bool enable)
 {
        int ret;
@@ -90,7 +99,7 @@ static int __devinit tps65090_config_ext_control(
        return ret;
 }
 
-static int __devinit tps65090_regulator_disable_ext_control(
+static int tps65090_regulator_disable_ext_control(
                struct tps65090_regulator *ri,
                struct tps65090_regulator_plat_data *tps_pdata)
 {
@@ -113,7 +122,23 @@ static int __devinit tps65090_regulator_disable_ext_control(
        return tps65090_config_ext_control(ri, false);
 }
 
-static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
+static void tps65090_configure_regulator_config(
+               struct tps65090_regulator_plat_data *tps_pdata,
+               struct regulator_config *config)
+{
+       if (gpio_is_valid(tps_pdata->gpio)) {
+               int gpio_flag = GPIOF_OUT_INIT_LOW;
+
+               if (tps_pdata->reg_init_data->constraints.always_on ||
+                               tps_pdata->reg_init_data->constraints.boot_on)
+                       gpio_flag = GPIOF_OUT_INIT_HIGH;
+
+               config->ena_gpio = tps_pdata->gpio;
+               config->ena_gpio_flags = gpio_flag;
+       }
+}
+
+static int tps65090_regulator_probe(struct platform_device *pdev)
 {
        struct tps65090 *tps65090_mfd = dev_get_drvdata(pdev->dev.parent);
        struct tps65090_regulator *ri = NULL;
@@ -133,14 +158,14 @@ static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       pmic = devm_kzalloc(&pdev->dev, TPS65090_ID_MAX * sizeof(*pmic),
+       pmic = devm_kzalloc(&pdev->dev, TPS65090_REGULATOR_MAX * sizeof(*pmic),
                        GFP_KERNEL);
        if (!pmic) {
                dev_err(&pdev->dev, "mem alloc for pmic failed\n");
                return -ENOMEM;
        }
 
-       for (num = 0; num < TPS65090_ID_MAX; num++) {
+       for (num = 0; num < TPS65090_REGULATOR_MAX; num++) {
                tps_pdata = tps65090_pdata->reg_pdata[num];
 
                ri = &pmic[num];
@@ -149,18 +174,24 @@ static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
 
                /*
                 * TPS5090 DCDC support the control from external digital input.
-                * It may be possible that during boot, the external control is
-                * enabled. Disabling external control for DCDC.
+                * Configure it as per platform data.
                 */
                if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data) {
-                       ret = tps65090_regulator_disable_ext_control(
+                       if (tps_pdata->enable_ext_control) {
+                               tps65090_configure_regulator_config(
+                                               tps_pdata, &config);
+                               ri->desc->ops = &tps65090_ext_control_ops;
+                       } else {
+                               ret = tps65090_regulator_disable_ext_control(
                                                ri, tps_pdata);
-                       if (ret < 0) {
-                               dev_err(&pdev->dev,
+                               if (ret < 0) {
+                                       dev_err(&pdev->dev,
                                                "failed disable ext control\n");
-                               goto scrub;
+                                       goto scrub;
+                               }
                        }
                }
+
                config.dev = &pdev->dev;
                config.driver_data = ri;
                config.regmap = tps65090_mfd->rmap;
@@ -177,6 +208,17 @@ static int __devinit tps65090_regulator_probe(struct platform_device *pdev)
                        goto scrub;
                }
                ri->rdev = rdev;
+
+               /* Enable external control if it is require */
+               if (tps_pdata && is_dcdc(num) && tps_pdata->reg_init_data &&
+                               tps_pdata->enable_ext_control) {
+                       ret = tps65090_config_ext_control(ri, true);
+                       if (ret < 0) {
+                               /* Increment num to get unregister rdev */
+                               num++;
+                               goto scrub;
+                       }
+               }
        }
 
        platform_set_drvdata(pdev, pmic);
@@ -190,13 +232,13 @@ scrub:
        return ret;
 }
 
-static int __devexit tps65090_regulator_remove(struct platform_device *pdev)
+static int tps65090_regulator_remove(struct platform_device *pdev)
 {
        struct tps65090_regulator *pmic = platform_get_drvdata(pdev);
        struct tps65090_regulator *ri;
        int num;
 
-       for (num = 0; num < TPS65090_ID_MAX; ++num) {
+       for (num = 0; num < TPS65090_REGULATOR_MAX; ++num) {
                ri = &pmic[num];
                regulator_unregister(ri->rdev);
        }
@@ -205,11 +247,11 @@ static int __devexit tps65090_regulator_remove(struct platform_device *pdev)
 
 static struct platform_driver tps65090_regulator_driver = {
        .driver = {
-               .name   = "tps65090-regulator",
+               .name   = "tps65090-pmic",
                .owner  = THIS_MODULE,
        },
        .probe          = tps65090_regulator_probe,
-       .remove         = __devexit_p(tps65090_regulator_remove),
+       .remove         = tps65090_regulator_remove,
 };
 
 static int __init tps65090_regulator_init(void)
@@ -227,3 +269,4 @@ module_exit(tps65090_regulator_exit);
 MODULE_DESCRIPTION("tps65090 regulator driver");
 MODULE_AUTHOR("Venu Byravarasu <vbyravarasu@nvidia.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:tps65090-pmic");