diff options
author | Sangbeom Kim <sbkim73@samsung.com> | 2012-06-17 20:49:20 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2012-06-19 07:06:32 -0400 |
commit | c848bc8538cd29e92223d5e72e8fb60e6f2e176e (patch) | |
tree | a7a40e51dc2efafc2a25959cb05f7bf9cf71732e /drivers/regulator/s5m8767.c | |
parent | 852abad238da723efac29f3e78dd768c18d6a062 (diff) |
regulator: s5m8767a: Support AP watchdog reset operation
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>
Diffstat (limited to 'drivers/regulator/s5m8767.c')
-rw-r--r-- | drivers/regulator/s5m8767.c | 137 |
1 files changed, 93 insertions, 44 deletions
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index a4a3c7eefd1f..fd89574c405c 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c | |||
@@ -41,6 +41,7 @@ struct s5m8767_info { | |||
41 | u8 buck3_vol[8]; | 41 | u8 buck3_vol[8]; |
42 | u8 buck4_vol[8]; | 42 | u8 buck4_vol[8]; |
43 | int buck_gpios[3]; | 43 | int buck_gpios[3]; |
44 | int buck_ds[3]; | ||
44 | int buck_gpioindex; | 45 | int buck_gpioindex; |
45 | }; | 46 | }; |
46 | 47 | ||
@@ -283,17 +284,17 @@ static int s5m8767_get_voltage_register(struct regulator_dev *rdev, int *_reg) | |||
283 | reg = S5M8767_REG_BUCK1CTRL2; | 284 | reg = S5M8767_REG_BUCK1CTRL2; |
284 | break; | 285 | break; |
285 | case S5M8767_BUCK2: | 286 | case S5M8767_BUCK2: |
286 | reg = S5M8767_REG_BUCK2DVS1; | 287 | reg = S5M8767_REG_BUCK2DVS2; |
287 | if (s5m8767->buck2_gpiodvs) | 288 | if (s5m8767->buck2_gpiodvs) |
288 | reg += s5m8767->buck_gpioindex; | 289 | reg += s5m8767->buck_gpioindex; |
289 | break; | 290 | break; |
290 | case S5M8767_BUCK3: | 291 | case S5M8767_BUCK3: |
291 | reg = S5M8767_REG_BUCK3DVS1; | 292 | reg = S5M8767_REG_BUCK3DVS2; |
292 | if (s5m8767->buck3_gpiodvs) | 293 | if (s5m8767->buck3_gpiodvs) |
293 | reg += s5m8767->buck_gpioindex; | 294 | reg += s5m8767->buck_gpioindex; |
294 | break; | 295 | break; |
295 | case S5M8767_BUCK4: | 296 | case S5M8767_BUCK4: |
296 | reg = S5M8767_REG_BUCK4DVS1; | 297 | reg = S5M8767_REG_BUCK4DVS2; |
297 | if (s5m8767->buck4_gpiodvs) | 298 | if (s5m8767->buck4_gpiodvs) |
298 | reg += s5m8767->buck_gpioindex; | 299 | reg += s5m8767->buck_gpioindex; |
299 | break; | 300 | break; |
@@ -512,7 +513,7 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) | |||
512 | struct regulator_config config = { }; | 513 | struct regulator_config config = { }; |
513 | struct regulator_dev **rdev; | 514 | struct regulator_dev **rdev; |
514 | struct s5m8767_info *s5m8767; | 515 | struct s5m8767_info *s5m8767; |
515 | int i, ret, size; | 516 | int i, ret, size, buck_init; |
516 | 517 | ||
517 | if (!pdata) { | 518 | if (!pdata) { |
518 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); | 519 | dev_err(pdev->dev.parent, "Platform data not supplied\n"); |
@@ -563,12 +564,37 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) | |||
563 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; | 564 | s5m8767->buck_gpios[0] = pdata->buck_gpios[0]; |
564 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; | 565 | s5m8767->buck_gpios[1] = pdata->buck_gpios[1]; |
565 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; | 566 | s5m8767->buck_gpios[2] = pdata->buck_gpios[2]; |
567 | s5m8767->buck_ds[0] = pdata->buck_ds[0]; | ||
568 | s5m8767->buck_ds[1] = pdata->buck_ds[1]; | ||
569 | s5m8767->buck_ds[2] = pdata->buck_ds[2]; | ||
570 | |||
566 | s5m8767->ramp_delay = pdata->buck_ramp_delay; | 571 | s5m8767->ramp_delay = pdata->buck_ramp_delay; |
567 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; | 572 | s5m8767->buck2_ramp = pdata->buck2_ramp_enable; |
568 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; | 573 | s5m8767->buck3_ramp = pdata->buck3_ramp_enable; |
569 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; | 574 | s5m8767->buck4_ramp = pdata->buck4_ramp_enable; |
570 | s5m8767->opmode = pdata->opmode; | 575 | s5m8767->opmode = pdata->opmode; |
571 | 576 | ||
577 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | ||
578 | pdata->buck2_init, | ||
579 | pdata->buck2_init + | ||
580 | buck_voltage_val2.step); | ||
581 | |||
582 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK2DVS2, buck_init); | ||
583 | |||
584 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | ||
585 | pdata->buck3_init, | ||
586 | pdata->buck3_init + | ||
587 | buck_voltage_val2.step); | ||
588 | |||
589 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK3DVS2, buck_init); | ||
590 | |||
591 | buck_init = s5m8767_convert_voltage_to_sel(&buck_voltage_val2, | ||
592 | pdata->buck4_init, | ||
593 | pdata->buck4_init + | ||
594 | buck_voltage_val2.step); | ||
595 | |||
596 | s5m_reg_write(s5m8767->iodev, S5M8767_REG_BUCK4DVS2, buck_init); | ||
597 | |||
572 | for (i = 0; i < 8; i++) { | 598 | for (i = 0; i < 8; i++) { |
573 | if (s5m8767->buck2_gpiodvs) { | 599 | if (s5m8767->buck2_gpiodvs) { |
574 | s5m8767->buck2_vol[i] = | 600 | s5m8767->buck2_vol[i] = |
@@ -598,48 +624,71 @@ static __devinit int s5m8767_pmic_probe(struct platform_device *pdev) | |||
598 | } | 624 | } |
599 | } | 625 | } |
600 | 626 | ||
601 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | 627 | if (gpio_is_valid(pdata->buck_gpios[0]) && |
602 | pdata->buck4_gpiodvs) { | 628 | gpio_is_valid(pdata->buck_gpios[1]) && |
603 | if (gpio_is_valid(pdata->buck_gpios[0]) && | 629 | gpio_is_valid(pdata->buck_gpios[2])) { |
604 | gpio_is_valid(pdata->buck_gpios[1]) && | 630 | ret = gpio_request(pdata->buck_gpios[0], "S5M8767 SET1"); |
605 | gpio_is_valid(pdata->buck_gpios[2])) { | 631 | if (ret == -EBUSY) |
606 | ret = gpio_request(pdata->buck_gpios[0], | 632 | dev_warn(&pdev->dev, "Duplicated gpio request" |
607 | "S5M8767 SET1"); | 633 | " for SET1\n"); |
608 | if (ret == -EBUSY) | 634 | |
609 | dev_warn(&pdev->dev, "Duplicated gpio request for SET1\n"); | 635 | ret = gpio_request(pdata->buck_gpios[1], "S5M8767 SET2"); |
610 | 636 | if (ret == -EBUSY) | |
611 | ret = gpio_request(pdata->buck_gpios[1], | 637 | dev_warn(&pdev->dev, "Duplicated gpio request" |
612 | "S5M8767 SET2"); | 638 | " for SET2\n"); |
613 | if (ret == -EBUSY) | 639 | |
614 | dev_warn(&pdev->dev, "Duplicated gpio request for SET2\n"); | 640 | ret = gpio_request(pdata->buck_gpios[2], "S5M8767 SET3"); |
615 | 641 | if (ret == -EBUSY) | |
616 | ret = gpio_request(pdata->buck_gpios[2], | 642 | dev_warn(&pdev->dev, "Duplicated gpio request" |
617 | "S5M8767 SET3"); | 643 | " for SET3\n"); |
618 | if (ret == -EBUSY) | 644 | /* SET1 GPIO */ |
619 | dev_warn(&pdev->dev, "Duplicated gpio request for SET3\n"); | 645 | gpio_direction_output(pdata->buck_gpios[0], |
620 | /* SET1 GPIO */ | 646 | (s5m8767->buck_gpioindex >> 2) & 0x1); |
621 | gpio_direction_output(pdata->buck_gpios[0], | 647 | /* SET2 GPIO */ |
622 | (s5m8767->buck_gpioindex >> 2) & 0x1); | 648 | gpio_direction_output(pdata->buck_gpios[1], |
623 | /* SET2 GPIO */ | 649 | (s5m8767->buck_gpioindex >> 1) & 0x1); |
624 | gpio_direction_output(pdata->buck_gpios[1], | 650 | /* SET3 GPIO */ |
625 | (s5m8767->buck_gpioindex >> 1) & 0x1); | 651 | gpio_direction_output(pdata->buck_gpios[2], |
626 | /* SET3 GPIO */ | 652 | (s5m8767->buck_gpioindex >> 0) & 0x1); |
627 | gpio_direction_output(pdata->buck_gpios[2], | 653 | ret = 0; |
628 | (s5m8767->buck_gpioindex >> 0) & 0x1); | 654 | |
629 | ret = 0; | 655 | } else { |
630 | } else { | 656 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); |
631 | dev_err(&pdev->dev, "GPIO NOT VALID\n"); | 657 | ret = -EINVAL; |
632 | ret = -EINVAL; | 658 | return ret; |
633 | return ret; | ||
634 | } | ||
635 | } | 659 | } |
636 | 660 | ||
637 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, | 661 | ret = gpio_request(pdata->buck_ds[0], "S5M8767 DS2"); |
638 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | 662 | if (ret == -EBUSY) |
639 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, | 663 | dev_warn(&pdev->dev, "Duplicated gpio request for DS2\n"); |
640 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | 664 | |
641 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, | 665 | ret = gpio_request(pdata->buck_ds[1], "S5M8767 DS3"); |
642 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), 1 << 1); | 666 | if (ret == -EBUSY) |
667 | dev_warn(&pdev->dev, "Duplicated gpio request for DS3\n"); | ||
668 | |||
669 | ret = gpio_request(pdata->buck_ds[2], "S5M8767 DS4"); | ||
670 | if (ret == -EBUSY) | ||
671 | dev_warn(&pdev->dev, "Duplicated gpio request for DS4\n"); | ||
672 | |||
673 | /* DS2 GPIO */ | ||
674 | gpio_direction_output(pdata->buck_ds[0], 0x0); | ||
675 | /* DS3 GPIO */ | ||
676 | gpio_direction_output(pdata->buck_ds[1], 0x0); | ||
677 | /* DS4 GPIO */ | ||
678 | gpio_direction_output(pdata->buck_ds[2], 0x0); | ||
679 | |||
680 | if (pdata->buck2_gpiodvs || pdata->buck3_gpiodvs || | ||
681 | pdata->buck4_gpiodvs) { | ||
682 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK2CTRL, | ||
683 | (pdata->buck2_gpiodvs) ? (1 << 1) : (0 << 1), | ||
684 | 1 << 1); | ||
685 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK3CTRL, | ||
686 | (pdata->buck3_gpiodvs) ? (1 << 1) : (0 << 1), | ||
687 | 1 << 1); | ||
688 | s5m_reg_update(s5m8767->iodev, S5M8767_REG_BUCK4CTRL, | ||
689 | (pdata->buck4_gpiodvs) ? (1 << 1) : (0 << 1), | ||
690 | 1 << 1); | ||
691 | } | ||
643 | 692 | ||
644 | /* Initialize GPIO DVS registers */ | 693 | /* Initialize GPIO DVS registers */ |
645 | for (i = 0; i < 8; i++) { | 694 | for (i = 0; i < 8; i++) { |