diff options
Diffstat (limited to 'drivers/regulator')
-rw-r--r-- | drivers/regulator/twl-regulator.c | 329 |
1 files changed, 321 insertions, 8 deletions
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 4702b8a7e0ef..87fe0f75a56e 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c | |||
@@ -51,8 +51,13 @@ struct twlreg_info { | |||
51 | u16 min_mV; | 51 | u16 min_mV; |
52 | u16 max_mV; | 52 | u16 max_mV; |
53 | 53 | ||
54 | u8 flags; | ||
55 | |||
54 | /* used by regulator core */ | 56 | /* used by regulator core */ |
55 | struct regulator_desc desc; | 57 | struct regulator_desc desc; |
58 | |||
59 | /* chip specific features */ | ||
60 | unsigned long features; | ||
56 | }; | 61 | }; |
57 | 62 | ||
58 | 63 | ||
@@ -70,6 +75,7 @@ struct twlreg_info { | |||
70 | #define VREG_TRANS 1 | 75 | #define VREG_TRANS 1 |
71 | #define VREG_STATE 2 | 76 | #define VREG_STATE 2 |
72 | #define VREG_VOLTAGE 3 | 77 | #define VREG_VOLTAGE 3 |
78 | #define VREG_VOLTAGE_SMPS 4 | ||
73 | /* TWL6030 Misc register offsets */ | 79 | /* TWL6030 Misc register offsets */ |
74 | #define VREG_BC_ALL 1 | 80 | #define VREG_BC_ALL 1 |
75 | #define VREG_BC_REF 2 | 81 | #define VREG_BC_REF 2 |
@@ -87,6 +93,17 @@ struct twlreg_info { | |||
87 | #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ | 93 | #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ |
88 | TWL6030_CFG_STATE_APP_SHIFT) | 94 | TWL6030_CFG_STATE_APP_SHIFT) |
89 | 95 | ||
96 | /* Flags for SMPS Voltage reading */ | ||
97 | #define SMPS_OFFSET_EN BIT(0) | ||
98 | #define SMPS_EXTENDED_EN BIT(1) | ||
99 | |||
100 | /* twl6025 SMPS EPROM values */ | ||
101 | #define TWL6030_SMPS_OFFSET 0xB0 | ||
102 | #define TWL6030_SMPS_MULT 0xB3 | ||
103 | #define SMPS_MULTOFFSET_SMPS4 BIT(0) | ||
104 | #define SMPS_MULTOFFSET_VIO BIT(1) | ||
105 | #define SMPS_MULTOFFSET_SMPS3 BIT(6) | ||
106 | |||
90 | static inline int | 107 | static inline int |
91 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) | 108 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) |
92 | { | 109 | { |
@@ -142,13 +159,17 @@ static int twl4030reg_is_enabled(struct regulator_dev *rdev) | |||
142 | static int twl6030reg_is_enabled(struct regulator_dev *rdev) | 159 | static int twl6030reg_is_enabled(struct regulator_dev *rdev) |
143 | { | 160 | { |
144 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 161 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
145 | int grp, val; | 162 | int grp = 0, val; |
146 | 163 | ||
147 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | 164 | if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) |
165 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | ||
148 | if (grp < 0) | 166 | if (grp < 0) |
149 | return grp; | 167 | return grp; |
150 | 168 | ||
151 | grp &= P1_GRP_6030; | 169 | if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) |
170 | grp &= P1_GRP_6030; | ||
171 | else | ||
172 | grp = 1; | ||
152 | 173 | ||
153 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); | 174 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); |
154 | val = TWL6030_CFG_STATE_APP(val); | 175 | val = TWL6030_CFG_STATE_APP(val); |
@@ -178,10 +199,11 @@ static int twl4030reg_enable(struct regulator_dev *rdev) | |||
178 | static int twl6030reg_enable(struct regulator_dev *rdev) | 199 | static int twl6030reg_enable(struct regulator_dev *rdev) |
179 | { | 200 | { |
180 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 201 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
181 | int grp; | 202 | int grp = 0; |
182 | int ret; | 203 | int ret; |
183 | 204 | ||
184 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | 205 | if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) |
206 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | ||
185 | if (grp < 0) | 207 | if (grp < 0) |
186 | return grp; | 208 | return grp; |
187 | 209 | ||
@@ -217,7 +239,8 @@ static int twl6030reg_disable(struct regulator_dev *rdev) | |||
217 | int grp = 0; | 239 | int grp = 0; |
218 | int ret; | 240 | int ret; |
219 | 241 | ||
220 | grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; | 242 | if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) |
243 | grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; | ||
221 | 244 | ||
222 | /* For 6030, set the off state for all grps enabled */ | 245 | /* For 6030, set the off state for all grps enabled */ |
223 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, | 246 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, |
@@ -307,10 +330,11 @@ static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | |||
307 | static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | 330 | static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) |
308 | { | 331 | { |
309 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 332 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
310 | int grp; | 333 | int grp = 0; |
311 | int val; | 334 | int val; |
312 | 335 | ||
313 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | 336 | if (!(twl_class_is_6030() && (info->features & TWL6025_SUBCLASS))) |
337 | grp = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_GRP); | ||
314 | 338 | ||
315 | if (grp < 0) | 339 | if (grp < 0) |
316 | return grp; | 340 | return grp; |
@@ -602,6 +626,209 @@ static struct regulator_ops twl6030_fixed_resource = { | |||
602 | .get_status = twl6030reg_get_status, | 626 | .get_status = twl6030reg_get_status, |
603 | }; | 627 | }; |
604 | 628 | ||
629 | /* | ||
630 | * SMPS status and control | ||
631 | */ | ||
632 | |||
633 | static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
634 | { | ||
635 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
636 | |||
637 | int voltage = 0; | ||
638 | |||
639 | switch (info->flags) { | ||
640 | case SMPS_OFFSET_EN: | ||
641 | voltage = 100000; | ||
642 | /* fall through */ | ||
643 | case 0: | ||
644 | switch (index) { | ||
645 | case 0: | ||
646 | voltage = 0; | ||
647 | break; | ||
648 | case 58: | ||
649 | voltage = 1350 * 1000; | ||
650 | break; | ||
651 | case 59: | ||
652 | voltage = 1500 * 1000; | ||
653 | break; | ||
654 | case 60: | ||
655 | voltage = 1800 * 1000; | ||
656 | break; | ||
657 | case 61: | ||
658 | voltage = 1900 * 1000; | ||
659 | break; | ||
660 | case 62: | ||
661 | voltage = 2100 * 1000; | ||
662 | break; | ||
663 | default: | ||
664 | voltage += (600000 + (12500 * (index - 1))); | ||
665 | } | ||
666 | break; | ||
667 | case SMPS_EXTENDED_EN: | ||
668 | switch (index) { | ||
669 | case 0: | ||
670 | voltage = 0; | ||
671 | break; | ||
672 | case 58: | ||
673 | voltage = 2084 * 1000; | ||
674 | break; | ||
675 | case 59: | ||
676 | voltage = 2315 * 1000; | ||
677 | break; | ||
678 | case 60: | ||
679 | voltage = 2778 * 1000; | ||
680 | break; | ||
681 | case 61: | ||
682 | voltage = 2932 * 1000; | ||
683 | break; | ||
684 | case 62: | ||
685 | voltage = 3241 * 1000; | ||
686 | break; | ||
687 | default: | ||
688 | voltage = (1852000 + (38600 * (index - 1))); | ||
689 | } | ||
690 | break; | ||
691 | case SMPS_OFFSET_EN | SMPS_EXTENDED_EN: | ||
692 | switch (index) { | ||
693 | case 0: | ||
694 | voltage = 0; | ||
695 | break; | ||
696 | case 58: | ||
697 | voltage = 4167 * 1000; | ||
698 | break; | ||
699 | case 59: | ||
700 | voltage = 2315 * 1000; | ||
701 | break; | ||
702 | case 60: | ||
703 | voltage = 2778 * 1000; | ||
704 | break; | ||
705 | case 61: | ||
706 | voltage = 2932 * 1000; | ||
707 | break; | ||
708 | case 62: | ||
709 | voltage = 3241 * 1000; | ||
710 | break; | ||
711 | default: | ||
712 | voltage = (2161000 + (38600 * (index - 1))); | ||
713 | } | ||
714 | break; | ||
715 | } | ||
716 | |||
717 | return voltage; | ||
718 | } | ||
719 | |||
720 | static int | ||
721 | twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, | ||
722 | unsigned int *selector) | ||
723 | { | ||
724 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
725 | int vsel = 0; | ||
726 | |||
727 | switch (info->flags) { | ||
728 | case 0: | ||
729 | if (min_uV == 0) | ||
730 | vsel = 0; | ||
731 | else if ((min_uV >= 600000) && (max_uV <= 1300000)) { | ||
732 | vsel = (min_uV - 600000) / 125; | ||
733 | if (vsel % 100) | ||
734 | vsel += 100; | ||
735 | vsel /= 100; | ||
736 | vsel++; | ||
737 | } | ||
738 | /* Values 1..57 for vsel are linear and can be calculated | ||
739 | * values 58..62 are non linear. | ||
740 | */ | ||
741 | else if ((min_uV > 1900000) && (max_uV >= 2100000)) | ||
742 | vsel = 62; | ||
743 | else if ((min_uV > 1800000) && (max_uV >= 1900000)) | ||
744 | vsel = 61; | ||
745 | else if ((min_uV > 1500000) && (max_uV >= 1800000)) | ||
746 | vsel = 60; | ||
747 | else if ((min_uV > 1350000) && (max_uV >= 1500000)) | ||
748 | vsel = 59; | ||
749 | else if ((min_uV > 1300000) && (max_uV >= 1350000)) | ||
750 | vsel = 58; | ||
751 | else | ||
752 | return -EINVAL; | ||
753 | break; | ||
754 | case SMPS_OFFSET_EN: | ||
755 | if (min_uV == 0) | ||
756 | vsel = 0; | ||
757 | else if ((min_uV >= 700000) && (max_uV <= 1420000)) { | ||
758 | vsel = (min_uV - 700000) / 125; | ||
759 | if (vsel % 100) | ||
760 | vsel += 100; | ||
761 | vsel /= 100; | ||
762 | vsel++; | ||
763 | } | ||
764 | /* Values 1..57 for vsel are linear and can be calculated | ||
765 | * values 58..62 are non linear. | ||
766 | */ | ||
767 | else if ((min_uV > 1900000) && (max_uV >= 2100000)) | ||
768 | vsel = 62; | ||
769 | else if ((min_uV > 1800000) && (max_uV >= 1900000)) | ||
770 | vsel = 61; | ||
771 | else if ((min_uV > 1350000) && (max_uV >= 1800000)) | ||
772 | vsel = 60; | ||
773 | else if ((min_uV > 1350000) && (max_uV >= 1500000)) | ||
774 | vsel = 59; | ||
775 | else if ((min_uV > 1300000) && (max_uV >= 1350000)) | ||
776 | vsel = 58; | ||
777 | else | ||
778 | return -EINVAL; | ||
779 | break; | ||
780 | case SMPS_EXTENDED_EN: | ||
781 | if (min_uV == 0) | ||
782 | vsel = 0; | ||
783 | else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { | ||
784 | vsel = (min_uV - 1852000) / 386; | ||
785 | if (vsel % 100) | ||
786 | vsel += 100; | ||
787 | vsel /= 100; | ||
788 | vsel++; | ||
789 | } | ||
790 | break; | ||
791 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: | ||
792 | if (min_uV == 0) | ||
793 | vsel = 0; | ||
794 | else if ((min_uV >= 2161000) && (max_uV <= 4321000)) { | ||
795 | vsel = (min_uV - 1852000) / 386; | ||
796 | if (vsel % 100) | ||
797 | vsel += 100; | ||
798 | vsel /= 100; | ||
799 | vsel++; | ||
800 | } | ||
801 | break; | ||
802 | } | ||
803 | |||
804 | *selector = vsel; | ||
805 | |||
806 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, | ||
807 | vsel); | ||
808 | } | ||
809 | |||
810 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) | ||
811 | { | ||
812 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
813 | |||
814 | return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); | ||
815 | } | ||
816 | |||
817 | static struct regulator_ops twlsmps_ops = { | ||
818 | .list_voltage = twl6030smps_list_voltage, | ||
819 | |||
820 | .set_voltage = twl6030smps_set_voltage, | ||
821 | .get_voltage_sel = twl6030smps_get_voltage_sel, | ||
822 | |||
823 | .enable = twl6030reg_enable, | ||
824 | .disable = twl6030reg_disable, | ||
825 | .is_enabled = twl6030reg_is_enabled, | ||
826 | |||
827 | .set_mode = twl6030reg_set_mode, | ||
828 | |||
829 | .get_status = twl6030reg_get_status, | ||
830 | }; | ||
831 | |||
605 | /*----------------------------------------------------------------------*/ | 832 | /*----------------------------------------------------------------------*/ |
606 | 833 | ||
607 | #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ | 834 | #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ |
@@ -644,6 +871,20 @@ static struct regulator_ops twl6030_fixed_resource = { | |||
644 | }, \ | 871 | }, \ |
645 | } | 872 | } |
646 | 873 | ||
874 | #define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts, num) { \ | ||
875 | .base = offset, \ | ||
876 | .id = num, \ | ||
877 | .min_mV = min_mVolts, \ | ||
878 | .max_mV = max_mVolts, \ | ||
879 | .desc = { \ | ||
880 | .name = #label, \ | ||
881 | .id = TWL6025_REG_##label, \ | ||
882 | .n_voltages = ((max_mVolts - min_mVolts)/100) + 1, \ | ||
883 | .ops = &twl6030ldo_ops, \ | ||
884 | .type = REGULATOR_VOLTAGE, \ | ||
885 | .owner = THIS_MODULE, \ | ||
886 | }, \ | ||
887 | } | ||
647 | 888 | ||
648 | #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ | 889 | #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \ |
649 | family, operations) { \ | 890 | family, operations) { \ |
@@ -675,6 +916,21 @@ static struct regulator_ops twl6030_fixed_resource = { | |||
675 | }, \ | 916 | }, \ |
676 | } | 917 | } |
677 | 918 | ||
919 | #define TWL6025_ADJUSTABLE_SMPS(label, offset, num) { \ | ||
920 | .base = offset, \ | ||
921 | .id = num, \ | ||
922 | .min_mV = 600, \ | ||
923 | .max_mV = 2100, \ | ||
924 | .desc = { \ | ||
925 | .name = #label, \ | ||
926 | .id = TWL6025_REG_##label, \ | ||
927 | .n_voltages = 63, \ | ||
928 | .ops = &twlsmps_ops, \ | ||
929 | .type = REGULATOR_VOLTAGE, \ | ||
930 | .owner = THIS_MODULE, \ | ||
931 | }, \ | ||
932 | } | ||
933 | |||
678 | /* | 934 | /* |
679 | * We list regulators here if systems need some level of | 935 | * We list regulators here if systems need some level of |
680 | * software control over them after boot. | 936 | * software control over them after boot. |
@@ -716,8 +972,41 @@ static struct twlreg_info twl_regs[] = { | |||
716 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0), | 972 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 17, 0), |
717 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0), | 973 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 18, 0), |
718 | TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0), | 974 | TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 48, 0), |
975 | |||
976 | /* 6025 are renamed compared to 6030 versions */ | ||
977 | TWL6025_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300, 1), | ||
978 | TWL6025_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300, 2), | ||
979 | TWL6025_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300, 3), | ||
980 | TWL6025_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300, 4), | ||
981 | TWL6025_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300, 5), | ||
982 | TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300, 7), | ||
983 | TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300, 16), | ||
984 | TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300, 17), | ||
985 | TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300, 18), | ||
986 | |||
987 | TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34, 1), | ||
988 | TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10, 2), | ||
989 | TWL6025_ADJUSTABLE_SMPS(VIO, 0x16, 3), | ||
719 | }; | 990 | }; |
720 | 991 | ||
992 | static u8 twl_get_smps_offset(void) | ||
993 | { | ||
994 | u8 value; | ||
995 | |||
996 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
997 | TWL6030_SMPS_OFFSET); | ||
998 | return value; | ||
999 | } | ||
1000 | |||
1001 | static u8 twl_get_smps_mult(void) | ||
1002 | { | ||
1003 | u8 value; | ||
1004 | |||
1005 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
1006 | TWL6030_SMPS_MULT); | ||
1007 | return value; | ||
1008 | } | ||
1009 | |||
721 | static int __devinit twlreg_probe(struct platform_device *pdev) | 1010 | static int __devinit twlreg_probe(struct platform_device *pdev) |
722 | { | 1011 | { |
723 | int i; | 1012 | int i; |
@@ -739,6 +1028,9 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
739 | if (!initdata) | 1028 | if (!initdata) |
740 | return -EINVAL; | 1029 | return -EINVAL; |
741 | 1030 | ||
1031 | /* copy the features into regulator data */ | ||
1032 | info->features = (unsigned long)initdata->driver_data; | ||
1033 | |||
742 | /* Constrain board-specific capabilities according to what | 1034 | /* Constrain board-specific capabilities according to what |
743 | * this driver and the chip itself can actually do. | 1035 | * this driver and the chip itself can actually do. |
744 | */ | 1036 | */ |
@@ -761,6 +1053,27 @@ static int __devinit twlreg_probe(struct platform_device *pdev) | |||
761 | break; | 1053 | break; |
762 | } | 1054 | } |
763 | 1055 | ||
1056 | switch (pdev->id) { | ||
1057 | case TWL6025_REG_SMPS3: | ||
1058 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) | ||
1059 | info->flags |= SMPS_EXTENDED_EN; | ||
1060 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3) | ||
1061 | info->flags |= SMPS_OFFSET_EN; | ||
1062 | break; | ||
1063 | case TWL6025_REG_SMPS4: | ||
1064 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4) | ||
1065 | info->flags |= SMPS_EXTENDED_EN; | ||
1066 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4) | ||
1067 | info->flags |= SMPS_OFFSET_EN; | ||
1068 | break; | ||
1069 | case TWL6025_REG_VIO: | ||
1070 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO) | ||
1071 | info->flags |= SMPS_EXTENDED_EN; | ||
1072 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO) | ||
1073 | info->flags |= SMPS_OFFSET_EN; | ||
1074 | break; | ||
1075 | } | ||
1076 | |||
764 | rdev = regulator_register(&info->desc, &pdev->dev, initdata, info); | 1077 | rdev = regulator_register(&info->desc, &pdev->dev, initdata, info); |
765 | if (IS_ERR(rdev)) { | 1078 | if (IS_ERR(rdev)) { |
766 | dev_err(&pdev->dev, "can't register %s, %ld\n", | 1079 | dev_err(&pdev->dev, "can't register %s, %ld\n", |