sky2: disable ASF on Yukon Supreme
[safe/jmp/linux-2.6] / drivers / regulator / twl-regulator.c
index 8e1b68a..7e67485 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/err.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/driver.h>
 #include <linux/regulator/machine.h>
@@ -40,6 +41,12 @@ struct twlreg_info {
        u8                      table_len;
        const u16               *table;
 
+       /* regulator specific turn-on delay */
+       u16                     delay;
+
+       /* State REMAP default configuration */
+       u8                      remap;
+
        /* chip constraints on regulator behavior */
        u16                     min_mV;
 
@@ -52,27 +59,38 @@ struct twlreg_info {
  * The first three registers of all power resource banks help hardware to
  * manage the various resource groups.
  */
+/* Common offset in TWL4030/6030 */
 #define VREG_GRP               0
+/* TWL4030 register offsets */
 #define VREG_TYPE              1
 #define VREG_REMAP             2
 #define VREG_DEDICATED         3       /* LDO control */
-
+/* TWL6030 register offsets */
+#define VREG_TRANS             1
+#define VREG_STATE             2
+#define VREG_VOLTAGE           3
+/* TWL6030 Misc register offsets */
+#define VREG_BC_ALL            1
+#define VREG_BC_REF            2
+#define VREG_BC_PROC           3
+#define VREG_BC_CLK_RST                4
 
 static inline int
-twlreg_read(struct twlreg_info *info, unsigned offset)
+twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset)
 {
        u8 value;
        int status;
 
-       status = twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER,
+       status = twl_i2c_read_u8(slave_subgp,
                        &value, info->base + offset);
        return (status < 0) ? status : value;
 }
 
 static inline int
-twlreg_write(struct twlreg_info *info, unsigned offset, u8 value)
+twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset,
+                                                u8 value)
 {
-       return twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER,
+       return twl_i2c_write_u8(slave_subgp,
                        value, info->base + offset);
 }
 
@@ -82,17 +100,22 @@ twlreg_write(struct twlreg_info *info, unsigned offset, u8 value)
 
 static int twlreg_grp(struct regulator_dev *rdev)
 {
-       return twlreg_read(rdev_get_drvdata(rdev), VREG_GRP);
+       return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER,
+                                                                VREG_GRP);
 }
 
 /*
  * Enable/disable regulators by joining/leaving the P1 (processor) group.
  * We assume nobody else is updating the DEV_GRP registers.
  */
-
-#define P3_GRP         BIT(7)          /* "peripherals" */
-#define P2_GRP         BIT(6)          /* secondary processor, modem, etc */
-#define P1_GRP         BIT(5)          /* CPU/Linux */
+/* definition for 4030 family */
+#define P3_GRP_4030    BIT(7)          /* "peripherals" */
+#define P2_GRP_4030    BIT(6)          /* secondary processor, modem, etc */
+#define P1_GRP_4030    BIT(5)          /* CPU/Linux */
+/* definition for 6030 family */
+#define P3_GRP_6030    BIT(2)          /* secondary processor, modem, etc */
+#define P2_GRP_6030    BIT(1)          /* "peripherals" */
+#define P1_GRP_6030    BIT(0)          /* CPU/Linux */
 
 static int twlreg_is_enabled(struct regulator_dev *rdev)
 {
@@ -101,20 +124,33 @@ static int twlreg_is_enabled(struct regulator_dev *rdev)
        if (state < 0)
                return state;
 
-       return (state & P1_GRP) != 0;
+       if (twl_class_is_4030())
+               state &= P1_GRP_4030;
+       else
+               state &= P1_GRP_6030;
+       return state;
 }
 
 static int twlreg_enable(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
+       int                     ret;
 
-       grp = twlreg_read(info, VREG_GRP);
+       grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
        if (grp < 0)
                return grp;
 
-       grp |= P1_GRP;
-       return twlreg_write(info, VREG_GRP, grp);
+       if (twl_class_is_4030())
+               grp |= P1_GRP_4030;
+       else
+               grp |= P1_GRP_6030;
+
+       ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
+
+       udelay(info->delay);
+
+       return ret;
 }
 
 static int twlreg_disable(struct regulator_dev *rdev)
@@ -122,18 +158,25 @@ static int twlreg_disable(struct regulator_dev *rdev)
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
        int                     grp;
 
-       grp = twlreg_read(info, VREG_GRP);
+       grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP);
        if (grp < 0)
                return grp;
 
-       grp &= ~P1_GRP;
-       return twlreg_write(info, VREG_GRP, grp);
+       if (twl_class_is_4030())
+               grp &= ~(P1_GRP_4030 | P2_GRP_4030 | P3_GRP_4030);
+       else
+               grp &= ~(P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030);
+
+       return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_GRP, grp);
 }
 
 static int twlreg_get_status(struct regulator_dev *rdev)
 {
        int     state = twlreg_grp(rdev);
 
+       if (twl_class_is_6030())
+               return 0; /* FIXME return for 6030 regulator */
+
        if (state < 0)
                return state;
        state &= 0x0f;
@@ -152,6 +195,9 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
        unsigned                message;
        int                     status;
 
+       if (twl_class_is_6030())
+               return 0; /* FIXME return for 6030 regulator */
+
        /* We can only set the mode through state machine commands... */
        switch (mode) {
        case REGULATOR_MODE_NORMAL:
@@ -168,7 +214,7 @@ static int twlreg_set_mode(struct regulator_dev *rdev, unsigned mode)
        status = twlreg_grp(rdev);
        if (status < 0)
                return status;
-       if (!(status & (P3_GRP | P2_GRP | P1_GRP)))
+       if (!(status & (P3_GRP_4030 | P2_GRP_4030 | P1_GRP_4030)))
                return -EACCES;
 
        status = twl_i2c_write_u8(TWL_MODULE_PM_MASTER,
@@ -260,7 +306,41 @@ static const u16 VSIM_VSEL_table[] = {
 static const u16 VDAC_VSEL_table[] = {
        1200, 1300, 1800, 1800,
 };
-
+static const u16 VDD1_VSEL_table[] = {
+       800, 1450,
+};
+static const u16 VDD2_VSEL_table[] = {
+       800, 1450, 1500,
+};
+static const u16 VIO_VSEL_table[] = {
+       1800, 1850,
+};
+static const u16 VINTANA2_VSEL_table[] = {
+       2500, 2750,
+};
+static const u16 VAUX1_6030_VSEL_table[] = {
+       1000, 1300, 1800, 2500,
+       2800, 2900, 3000, 3000,
+};
+static const u16 VAUX2_6030_VSEL_table[] = {
+       1200, 1800, 2500, 2750,
+       2800, 2800, 2800, 2800,
+};
+static const u16 VAUX3_6030_VSEL_table[] = {
+       1000, 1200, 1300, 1800,
+       2500, 2800, 3000, 3000,
+};
+static const u16 VMMC_VSEL_table[] = {
+       1200, 1800, 2800, 2900,
+       3000, 3000, 3000, 3000,
+};
+static const u16 VPP_VSEL_table[] = {
+       1800, 1900, 2000, 2100,
+       2200, 2300, 2400, 2500,
+};
+static const u16 VUSIM_VSEL_table[] = {
+       1200, 1800, 2500, 2900,
+};
 
 static int twlldo_list_voltage(struct regulator_dev *rdev, unsigned index)
 {
@@ -288,7 +368,8 @@ twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
 
                /* use the first in-range value */
                if (min_uV <= uV && uV <= max_uV)
-                       return twlreg_write(info, VREG_DEDICATED, vsel);
+                       return twlreg_write(info, TWL_MODULE_PM_RECEIVER,
+                                                       VREG_VOLTAGE, vsel);
        }
 
        return -EDOM;
@@ -297,7 +378,8 @@ twlldo_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV)
 static int twlldo_get_voltage(struct regulator_dev *rdev)
 {
        struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int                     vsel = twlreg_read(info, VREG_DEDICATED);
+       int             vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER,
+                                                               VREG_VOLTAGE);
 
        if (vsel < 0)
                return vsel;
@@ -356,16 +438,30 @@ static struct regulator_ops twlfixed_ops = {
 
 /*----------------------------------------------------------------------*/
 
-#define TWL4030_ADJUSTABLE_LDO(label, offset, num) \
-               TWL_ADJUSTABLE_LDO(label, offset, num, TWL4030)
-#define TWL4030_FIXED_LDO(label, offset, mVolts, num) \
-               TWL_FIXED_LDO(label, offset, mVolts, num, TWL4030)
-
-#define TWL_ADJUSTABLE_LDO(label, offset, num, family) { \
+#define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
+               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf, TWL4030)
+#define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf) \
+               TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf, TWL4030)
+#define TWL6030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf) \
+               TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, \
+                       remap_conf, TWL6030)
+#define TWL6030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf) \
+               TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \
+                       remap_conf, TWL6030)
+
+#define TWL_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf, \
+               family) { \
        .base = offset, \
        .id = num, \
        .table_len = ARRAY_SIZE(label##_VSEL_table), \
        .table = label##_VSEL_table, \
+       .delay = turnon_delay, \
+       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = family##_REG_##label, \
@@ -376,10 +472,13 @@ static struct regulator_ops twlfixed_ops = {
                }, \
        }
 
-#define TWL_FIXED_LDO(label, offset, mVolts, num, family) { \
+#define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
+               family) { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
+       .delay = turnon_delay, \
+       .remap = remap_conf, \
        .desc = { \
                .name = #label, \
                .id = family##_REG_##label, \
@@ -395,31 +494,41 @@ static struct regulator_ops twlfixed_ops = {
  * software control over them after boot.
  */
 static struct twlreg_info twl_regs[] = {
-       TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1),
-       TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2),
-       TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2),
-       TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3),
-       TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4),
-       TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5),
-       TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6),
-       /*
-       TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7),
-       */
-       TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8),
-       TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9),
-       TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10),
-       /*
-       TWL4030_ADJUSTABLE_LDO(VINTANA1, 0x3f, 11),
-       TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12),
-       TWL4030_ADJUSTABLE_LDO(VINTDIG, 0x47, 13),
-       TWL4030_SMPS(VIO, 0x4b, 14),
-       TWL4030_SMPS(VDD1, 0x55, 15),
-       TWL4030_SMPS(VDD2, 0x63, 16),
-        */
-       TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17),
-       TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18),
-       TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19),
+       TWL4030_ADJUSTABLE_LDO(VAUX1, 0x17, 1, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX2_4030, 0x1b, 2, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX2, 0x1b, 2, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX3, 0x1f, 3, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VAUX4, 0x23, 4, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VMMC1, 0x27, 5, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VMMC2, 0x2b, 6, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VPLL1, 0x2f, 7, 100, 0x00),
+       TWL4030_ADJUSTABLE_LDO(VPLL2, 0x33, 8, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VSIM, 0x37, 9, 100, 0x00),
+       TWL4030_ADJUSTABLE_LDO(VDAC, 0x3b, 10, 100, 0x08),
+       TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08),
+       TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VDD1, 0x55, 15, 1000, 0x08),
+       TWL4030_ADJUSTABLE_LDO(VDD2, 0x63, 16, 1000, 0x08),
+       TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08),
+       TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08),
+       TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08),
        /* VUSBCP is managed *only* by the USB subchip */
+
+       /* 6030 REG with base as PMC Slave Misc : 0x0030 */
+       /* Turnon-delay and remap configuration values for 6030 are not
+          verified since the specification is not public */
+       TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 2, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 3, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 4, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 5, 0, 0x08),
+       TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 7, 0, 0x08),
+       TWL6030_FIXED_LDO(VANA, 0x50, 2100, 15, 0, 0x08),
+       TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 16, 0, 0x08),
+       TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0, 0x08),
+       TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0, 0x08)
 };
 
 static int twlreg_probe(struct platform_device *pdev)
@@ -451,6 +560,19 @@ static int twlreg_probe(struct platform_device *pdev)
        c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE
                                | REGULATOR_CHANGE_MODE
                                | REGULATOR_CHANGE_STATUS;
+       switch (pdev->id) {
+       case TWL4030_REG_VIO:
+       case TWL4030_REG_VDD1:
+       case TWL4030_REG_VDD2:
+       case TWL4030_REG_VPLL1:
+       case TWL4030_REG_VINTANA1:
+       case TWL4030_REG_VINTANA2:
+       case TWL4030_REG_VINTDIG:
+               c->always_on = true;
+               break;
+       default:
+               break;
+       }
 
        rdev = regulator_register(&info->desc, &pdev->dev, initdata, info);
        if (IS_ERR(rdev)) {
@@ -460,6 +582,9 @@ static int twlreg_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, rdev);
 
+       twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP,
+                                               info->remap);
+
        /* NOTE:  many regulators support short-circuit IRQs (presentable
         * as REGULATOR_OVER_CURRENT notifications?) configured via:
         *  - SC_CONFIG