regulator: twl4030: add support for external voltage get/set
authorTero Kristo <t-kristo@ti.com>
Thu, 16 Feb 2012 10:27:52 +0000 (12:27 +0200)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Sun, 11 Mar 2012 20:08:45 +0000 (20:08 +0000)
This is needed for SMPS regulators, which use the OMAP voltage
processor for voltage get/set functions instead of the normal I2C
channel. For this purpose, regulator_init_data->driver_data contents
are expanded, it is now a struct which contains function pointers
for the set/get voltage operations, a data pointer for these, and
the previously used features bitmask.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Samuel Ortiz <sameo@linux.intel.com> [for the MFD part]
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
drivers/mfd/twl-core.c
drivers/regulator/twl-regulator.c
include/linux/i2c/twl.h

index e04e04ddc15e41f933b2a58de5f3bc8d28e86c25..fae5f76d6ccb6a9243ed69717bb8f0eeb56826cf 100644 (file)
@@ -619,6 +619,8 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
                unsigned num_consumers, unsigned long features)
 {
        unsigned sub_chip_id;
+       struct twl_regulator_driver_data drv_data;
+
        /* regulator framework demands init_data ... */
        if (!pdata)
                return NULL;
@@ -628,7 +630,19 @@ add_regulator_linked(int num, struct regulator_init_data *pdata,
                pdata->num_consumer_supplies = num_consumers;
        }
 
-       pdata->driver_data = (void *)features;
+       if (pdata->driver_data) {
+               /* If we have existing drv_data, just add the flags */
+               struct twl_regulator_driver_data *tmp;
+               tmp = pdata->driver_data;
+               tmp->features |= features;
+       } else {
+               /* add new driver data struct, used only during init */
+               drv_data.features = features;
+               drv_data.set_voltage = NULL;
+               drv_data.get_voltage = NULL;
+               drv_data.data = NULL;
+               pdata->driver_data = &drv_data;
+       }
 
        /* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
        sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
index e5d22234215706f4b055bececb0137266152e4db..7ff8bb22d569bfc602195253984a3b9f941168a1 100644 (file)
@@ -58,6 +58,16 @@ struct twlreg_info {
 
        /* chip specific features */
        unsigned long           features;
+
+       /*
+        * optional override functions for voltage set/get
+        * these are currently only used for SMPS regulators
+        */
+       int                     (*get_voltage)(void *data);
+       int                     (*set_voltage)(void *data, int target_uV);
+
+       /* data passed from board for external get/set voltage */
+       void                    *data;
 };
 
 
@@ -522,15 +532,25 @@ twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
        struct twlreg_info *info = rdev_get_drvdata(rdev);
        int vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
 
-       twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030,
-               vsel);
+       if (info->set_voltage) {
+               return info->set_voltage(info->data, min_uV);
+       } else {
+               twlreg_write(info, TWL_MODULE_PM_RECEIVER,
+                       VREG_VOLTAGE_SMPS_4030, vsel);
+       }
+
        return 0;
 }
 
 static int twl4030smps_get_voltage(struct regulator_dev *rdev)
 {
        struct twlreg_info *info = rdev_get_drvdata(rdev);
-       int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+       int vsel;
+
+       if (info->get_voltage)
+               return info->get_voltage(info->data);
+
+       vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
                VREG_VOLTAGE_SMPS_4030);
 
        return vsel * 12500 + 600000;
@@ -1060,6 +1080,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        struct regulator_init_data      *initdata;
        struct regulation_constraints   *c;
        struct regulator_dev            *rdev;
+       struct twl_regulator_driver_data        *drvdata;
 
        for (i = 0, info = NULL; i < ARRAY_SIZE(twl_regs); i++) {
                if (twl_regs[i].desc.id != pdev->id)
@@ -1074,8 +1095,16 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        if (!initdata)
                return -EINVAL;
 
-       /* copy the features into regulator data */
-       info->features = (unsigned long)initdata->driver_data;
+       drvdata = initdata->driver_data;
+
+       if (!drvdata)
+               return -EINVAL;
+
+       /* copy the driver data into regulator data */
+       info->features = drvdata->features;
+       info->data = drvdata->data;
+       info->set_voltage = drvdata->set_voltage;
+       info->get_voltage = drvdata->get_voltage;
 
        /* Constrain board-specific capabilities according to what
         * this driver and the chip itself can actually do.
index 78d3465251d6cd8e38e47903622cd0e3bad9e42d..08a82d314f24f65b6ae6bc1890a2bba923bb25cc 100644 (file)
@@ -749,6 +749,13 @@ struct twl4030_platform_data {
        struct regulator_init_data              *vio6025;
 };
 
+struct twl_regulator_driver_data {
+       int             (*set_voltage)(void *data, int target_uV);
+       int             (*get_voltage)(void *data);
+       void            *data;
+       unsigned long   features;
+};
+
 /*----------------------------------------------------------------------*/
 
 int twl4030_sih_setup(int module);