]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
regulator: s5m8767a: Support AP watchdog reset operation
authorSangbeom Kim <sbkim73@samsung.com>
Mon, 18 Jun 2012 00:49:20 +0000 (09:49 +0900)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Tue, 19 Jun 2012 11:06:32 +0000 (12:06 +0100)
The S5M8767A can't know status of ap reset.
So, After AP watchdog reset, AP can't boot normally.

Problem can be happened like below condition.
- AP Bootable lowest voltage(vdd_arm): 0.9v
- AP DVFS voltage table: 0.8v, 0.9v, 1.0v
- During AP works on lowest voltage(0.8V), watchdog reset is asserted
- AP can't boot, because vdd arm is still 0.8v

Solution
- Basic concept:
  After ap watchdog reset, GPIO configuration is changed by default value
- S5M8767A has function of voltage control with gpio (8 levels with 3 gpios)
- Set bootable voltage on level 0 -> can work with default gpio configuration
- In the probing, Change voltage control level from level 0 to level 1
- Execute normal dvfs operation on level 1
- After watchdog reset, ap gpio is set by default value
- PMIC operation mode is changed by ap reset (level1 -> level0)
- Regardless of previous vdd_arm voltage, AP always can be booted.

Signed-off-by: Sangbeom Kim <sbkim73@samsung.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
drivers/regulator/s5m8767.c
include/linux/mfd/s5m87xx/s5m-core.h

index a4a3c7eefd1f3a5cd3b176c6ff7e466d5f768eda..fd89574c405ccdd00f37191382677025139c2847 100644 (file)
@@ -41,6 +41,7 @@ struct s5m8767_info {
        u8 buck3_vol[8];
        u8 buck4_vol[8];
        int buck_gpios[3];
+       int buck_ds[3];
        int buck_gpioindex;
 };
 
@@ -283,17 +284,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg)
                reg = S5M8767_REG_BUCK1CTRL2;
                break;
        case S5M8767_BUCK2:
-               reg = S5M8767_REG_BUCK2DVS1;
+               reg = S5M8767_REG_BUCK2DVS2;
                if (s5m8767->buck2_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
        case S5M8767_BUCK3:
-               reg = S5M8767_REG_BUCK3DVS1;
+               reg = S5M8767_REG_BUCK3DVS2;
                if (s5m8767->buck3_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
        case S5M8767_BUCK4:
-               reg = S5M8767_REG_BUCK4DVS1;
+               reg = S5M8767_REG_BUCK4DVS2;
                if (s5m8767->buck4_gpiodvs)
                        reg += s5m8767->buck_gpioindex;
                break;
@@ -512,7 +513,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        struct regulator_config config = { };
        struct regulator_dev **rdev;
        struct s5m8767_info *s5m8767;
-       int i, ret, size;
+       int i, ret, size, buck_init;
 
        if (!pdata) {
                dev_err(pdev->dev.parent, "Platform data not supplied\n");
@@ -563,12 +564,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
        s5m8767->buck_gpios[0] = pdata->buck_gpios[0];
        s5m8767->buck_gpios[1] = pdata->buck_gpios[1];
        s5m8767->buck_gpios[2] = pdata->buck_gpios[2];
+       s5m8767->buck_ds[0] = pdata->buck_ds[0];
+       s5m8767->buck_ds[1] = pdata->buck_ds[1];
+       s5m8767->buck_ds[2] = pdata->buck_ds[2];
+
        s5m8767->ramp_delay = pdata->buck_ramp_delay;
        s5m8767->buck2_ramp = pdata->buck2_ramp_enable;
        s5m8767->buck3_ramp = pdata->buck3_ramp_enable;
        s5m8767->buck4_ramp = pdata->buck4_ramp_enable;
        s5m8767->opmode = pdata->opmode;
 
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck2_init,
+                                               pdata->buck2_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init);
+
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck3_init,
+                                               pdata->buck3_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init);
+
+       buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2,
+                                               pdata->buck4_init,
+                                               pdata->buck4_init +
+                                               buck_voltage_val2.step);
+
+       s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init);
+
        for (i = 0; i < 8; i++) {
                if (s5m8767->buck2_gpiodvs) {
                        s5m8767->buck2_vol[i] =
@@ -598,48 +624,71 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev)
                }
        }
 
-       if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
-               pdata->buck4_gpiodvs) {
-               if (gpio_is_valid(pdata->buck_gpios[0]) &&
-                       gpio_is_valid(pdata->buck_gpios[1]) &&
-                       gpio_is_valid(pdata->buck_gpios[2])) {
-                       ret = gpio_request(pdata->buck_gpios[0],
-                                               "S5M8767 SET1");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n");
-
-                       ret = gpio_request(pdata->buck_gpios[1],
-                                          "S5M8767 SET2");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n");
-
-                       ret = gpio_request(pdata->buck_gpios[2],
-                                          "S5M8767 SET3");
-                       if (ret == -EBUSY)
-                               dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n");
-                       /* SET1 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[0],
-                                       (s5m8767->buck_gpioindex >> 2) & 0x1);
-                       /* SET2 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[1],
-                                       (s5m8767->buck_gpioindex >> 1) & 0x1);
-                       /* SET3 GPIO */
-                       gpio_direction_output(pdata->buck_gpios[2],
-                                       (s5m8767->buck_gpioindex >> 0) & 0x1);
-                       ret = 0;
-               } else {
-                       dev_err(&pdev->dev, "GPIO NOT VALID\n");
-                       ret = -EINVAL;
-                       return ret;
-               }
+       if (gpio_is_valid(pdata->buck_gpios[0]) &&
+               gpio_is_valid(pdata->buck_gpios[1]) &&
+               gpio_is_valid(pdata->buck_gpios[2])) {
+               ret = gpio_request(pdata->buck_gpios[0], "S5M8767 SET1");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                               " for SET1\n");
+
+               ret = gpio_request(pdata->buck_gpios[1], "S5M8767 SET2");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                               " for SET2\n");
+
+               ret = gpio_request(pdata->buck_gpios[2], "S5M8767 SET3");
+               if (ret == -EBUSY)
+                       dev_warn(&pdev->dev, "Duplicated gpio request"
+                                       " for SET3\n");
+               /* SET1 GPIO */
+               gpio_direction_output(pdata->buck_gpios[0],
+                               (s5m8767->buck_gpioindex >> 2) & 0x1);
+               /* SET2 GPIO */
+               gpio_direction_output(pdata->buck_gpios[1],
+                               (s5m8767->buck_gpioindex >> 1) & 0x1);
+               /* SET3 GPIO */
+               gpio_direction_output(pdata->buck_gpios[2],
+                               (s5m8767->buck_gpioindex >> 0) & 0x1);
+               ret = 0;
+
+       } else {
+               dev_err(&pdev->dev, "GPIO NOT VALID\n");
+               ret = -EINVAL;
+               return ret;
        }
 
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
-                       (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
-                       (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
-       s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
-                       (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1);
+       ret = gpio_request(pdata->buck_ds[0], "S5M8767 DS2");
+       if (ret == -EBUSY)
+               dev_warn(&pdev->dev, "Duplicated gpio request for DS2\n");
+
+       ret = gpio_request(pdata->buck_ds[1], "S5M8767 DS3");
+       if (ret == -EBUSY)
+               dev_warn(&pdev->dev, "Duplicated gpio request for DS3\n");
+
+       ret = gpio_request(pdata->buck_ds[2], "S5M8767 DS4");
+       if (ret == -EBUSY)
+               dev_warn(&pdev->dev, "Duplicated gpio request for DS4\n");
+
+       /* DS2 GPIO */
+       gpio_direction_output(pdata->buck_ds[0], 0x0);
+       /* DS3 GPIO */
+       gpio_direction_output(pdata->buck_ds[1], 0x0);
+       /* DS4 GPIO */
+       gpio_direction_output(pdata->buck_ds[2], 0x0);
+
+       if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs ||
+          pdata->buck4_gpiodvs) {
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL,
+                               (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL,
+                               (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+               s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL,
+                               (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1),
+                               1 << 1);
+       }
 
        /* Initialize GPIO DVS registers */
        for (i = 0; i < 8; i++) {
index 21603b42f22fb150f73a5be185e6c1d615de6329..0b2e0ed309f51038583a23f168383ab6e6a6f72c 100644 (file)
@@ -347,6 +347,7 @@ struct s5m_platform_data {
        bool                            buck_voltage_lock;
 
        int                             buck_gpios[3];
+       int                             buck_ds[3];
        int                             buck2_voltage[8];
        bool                            buck2_gpiodvs;
        int                             buck3_voltage[8];
@@ -369,6 +370,10 @@ struct s5m_platform_data {
        bool                            buck2_ramp_enable;
        bool                            buck3_ramp_enable;
        bool                            buck4_ramp_enable;
+
+       int                             buck2_init;
+       int                             buck3_init;
+       int                             buck4_init;
 };
 
 #endif /*  __LINUX_MFD_S5M_CORE_H */