diff options
-rw-r--r-- | drivers/regulator/tps65910-regulator.c | 206 | ||||
-rw-r--r-- | include/linux/mfd/tps65910.h | 8 |
2 files changed, 214 insertions, 0 deletions
diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 1d13cf997afb..9092b7f998c1 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <linux/mfd/tps65910.h> | 26 | #include <linux/mfd/tps65910.h> |
27 | 27 | ||
28 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 | 28 | #define TPS65910_SUPPLY_STATE_ENABLED 0x1 |
29 | #define EXT_SLEEP_CONTROL (TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 | \ | ||
30 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 | \ | ||
31 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) | ||
29 | 32 | ||
30 | /* supported VIO voltages in milivolts */ | 33 | /* supported VIO voltages in milivolts */ |
31 | static const u16 VIO_VSEL_table[] = { | 34 | static const u16 VIO_VSEL_table[] = { |
@@ -252,6 +255,39 @@ static struct tps_info tps65911_regs[] = { | |||
252 | }, | 255 | }, |
253 | }; | 256 | }; |
254 | 257 | ||
258 | #define EXT_CONTROL_REG_BITS(id, regs_offs, bits) (((regs_offs) << 8) | (bits)) | ||
259 | static unsigned int tps65910_ext_sleep_control[] = { | ||
260 | 0, | ||
261 | EXT_CONTROL_REG_BITS(VIO, 1, 0), | ||
262 | EXT_CONTROL_REG_BITS(VDD1, 1, 1), | ||
263 | EXT_CONTROL_REG_BITS(VDD2, 1, 2), | ||
264 | EXT_CONTROL_REG_BITS(VDD3, 1, 3), | ||
265 | EXT_CONTROL_REG_BITS(VDIG1, 0, 1), | ||
266 | EXT_CONTROL_REG_BITS(VDIG2, 0, 2), | ||
267 | EXT_CONTROL_REG_BITS(VPLL, 0, 6), | ||
268 | EXT_CONTROL_REG_BITS(VDAC, 0, 7), | ||
269 | EXT_CONTROL_REG_BITS(VAUX1, 0, 3), | ||
270 | EXT_CONTROL_REG_BITS(VAUX2, 0, 4), | ||
271 | EXT_CONTROL_REG_BITS(VAUX33, 0, 5), | ||
272 | EXT_CONTROL_REG_BITS(VMMC, 0, 0), | ||
273 | }; | ||
274 | |||
275 | static unsigned int tps65911_ext_sleep_control[] = { | ||
276 | 0, | ||
277 | EXT_CONTROL_REG_BITS(VIO, 1, 0), | ||
278 | EXT_CONTROL_REG_BITS(VDD1, 1, 1), | ||
279 | EXT_CONTROL_REG_BITS(VDD2, 1, 2), | ||
280 | EXT_CONTROL_REG_BITS(VDDCTRL, 1, 3), | ||
281 | EXT_CONTROL_REG_BITS(LDO1, 0, 1), | ||
282 | EXT_CONTROL_REG_BITS(LDO2, 0, 2), | ||
283 | EXT_CONTROL_REG_BITS(LDO3, 0, 7), | ||
284 | EXT_CONTROL_REG_BITS(LDO4, 0, 6), | ||
285 | EXT_CONTROL_REG_BITS(LDO5, 0, 3), | ||
286 | EXT_CONTROL_REG_BITS(LDO6, 0, 0), | ||
287 | EXT_CONTROL_REG_BITS(LDO7, 0, 5), | ||
288 | EXT_CONTROL_REG_BITS(LDO8, 0, 4), | ||
289 | }; | ||
290 | |||
255 | struct tps65910_reg { | 291 | struct tps65910_reg { |
256 | struct regulator_desc *desc; | 292 | struct regulator_desc *desc; |
257 | struct tps65910 *mfd; | 293 | struct tps65910 *mfd; |
@@ -261,6 +297,8 @@ struct tps65910_reg { | |||
261 | int num_regulators; | 297 | int num_regulators; |
262 | int mode; | 298 | int mode; |
263 | int (*get_ctrl_reg)(int); | 299 | int (*get_ctrl_reg)(int); |
300 | unsigned int *ext_sleep_control; | ||
301 | unsigned int board_ext_control[TPS65910_NUM_REGS]; | ||
264 | }; | 302 | }; |
265 | 303 | ||
266 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) | 304 | static inline int tps65910_read(struct tps65910_reg *pmic, u8 reg) |
@@ -861,6 +899,131 @@ static struct regulator_ops tps65911_ops = { | |||
861 | .list_voltage = tps65911_list_voltage, | 899 | .list_voltage = tps65911_list_voltage, |
862 | }; | 900 | }; |
863 | 901 | ||
902 | static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, | ||
903 | int id, int ext_sleep_config) | ||
904 | { | ||
905 | struct tps65910 *mfd = pmic->mfd; | ||
906 | u8 regoffs = (pmic->ext_sleep_control[id] >> 8) & 0xFF; | ||
907 | u8 bit_pos = (1 << pmic->ext_sleep_control[id] & 0xFF); | ||
908 | int ret; | ||
909 | |||
910 | /* | ||
911 | * Regulator can not be control from multiple external input EN1, EN2 | ||
912 | * and EN3 together. | ||
913 | */ | ||
914 | if (ext_sleep_config & EXT_SLEEP_CONTROL) { | ||
915 | int en_count; | ||
916 | en_count = ((ext_sleep_config & | ||
917 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) != 0); | ||
918 | en_count += ((ext_sleep_config & | ||
919 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) != 0); | ||
920 | en_count += ((ext_sleep_config & | ||
921 | TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) != 0); | ||
922 | if (en_count > 1) { | ||
923 | dev_err(mfd->dev, | ||
924 | "External sleep control flag is not proper\n"); | ||
925 | return -EINVAL; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | pmic->board_ext_control[id] = ext_sleep_config; | ||
930 | |||
931 | /* External EN1 control */ | ||
932 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1) | ||
933 | ret = tps65910_set_bits(mfd, | ||
934 | TPS65910_EN1_LDO_ASS + regoffs, bit_pos); | ||
935 | else | ||
936 | ret = tps65910_clear_bits(mfd, | ||
937 | TPS65910_EN1_LDO_ASS + regoffs, bit_pos); | ||
938 | if (ret < 0) { | ||
939 | dev_err(mfd->dev, | ||
940 | "Error in configuring external control EN1\n"); | ||
941 | return ret; | ||
942 | } | ||
943 | |||
944 | /* External EN2 control */ | ||
945 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2) | ||
946 | ret = tps65910_set_bits(mfd, | ||
947 | TPS65910_EN2_LDO_ASS + regoffs, bit_pos); | ||
948 | else | ||
949 | ret = tps65910_clear_bits(mfd, | ||
950 | TPS65910_EN2_LDO_ASS + regoffs, bit_pos); | ||
951 | if (ret < 0) { | ||
952 | dev_err(mfd->dev, | ||
953 | "Error in configuring external control EN2\n"); | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | /* External EN3 control for TPS65910 LDO only */ | ||
958 | if ((tps65910_chip_id(mfd) == TPS65910) && | ||
959 | (id >= TPS65910_REG_VDIG1)) { | ||
960 | if (ext_sleep_config & TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3) | ||
961 | ret = tps65910_set_bits(mfd, | ||
962 | TPS65910_EN3_LDO_ASS + regoffs, bit_pos); | ||
963 | else | ||
964 | ret = tps65910_clear_bits(mfd, | ||
965 | TPS65910_EN3_LDO_ASS + regoffs, bit_pos); | ||
966 | if (ret < 0) { | ||
967 | dev_err(mfd->dev, | ||
968 | "Error in configuring external control EN3\n"); | ||
969 | return ret; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | /* Return if no external control is selected */ | ||
974 | if (!(ext_sleep_config & EXT_SLEEP_CONTROL)) { | ||
975 | /* Clear all sleep controls */ | ||
976 | ret = tps65910_clear_bits(mfd, | ||
977 | TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); | ||
978 | if (!ret) | ||
979 | ret = tps65910_clear_bits(mfd, | ||
980 | TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); | ||
981 | if (ret < 0) | ||
982 | dev_err(mfd->dev, | ||
983 | "Error in configuring SLEEP register\n"); | ||
984 | return ret; | ||
985 | } | ||
986 | |||
987 | /* | ||
988 | * For regulator that has separate operational and sleep register make | ||
989 | * sure that operational is used and clear sleep register to turn | ||
990 | * regulator off when external control is inactive | ||
991 | */ | ||
992 | if ((id == TPS65910_REG_VDD1) || | ||
993 | (id == TPS65910_REG_VDD2) || | ||
994 | ((id == TPS65911_REG_VDDCTRL) && | ||
995 | (tps65910_chip_id(mfd) == TPS65911))) { | ||
996 | int op_reg_add = pmic->get_ctrl_reg(id) + 1; | ||
997 | int sr_reg_add = pmic->get_ctrl_reg(id) + 2; | ||
998 | int opvsel = tps65910_reg_read(pmic, op_reg_add); | ||
999 | int srvsel = tps65910_reg_read(pmic, sr_reg_add); | ||
1000 | if (opvsel & VDD1_OP_CMD_MASK) { | ||
1001 | u8 reg_val = srvsel & VDD1_OP_SEL_MASK; | ||
1002 | ret = tps65910_reg_write(pmic, op_reg_add, reg_val); | ||
1003 | if (ret < 0) { | ||
1004 | dev_err(mfd->dev, | ||
1005 | "Error in configuring op register\n"); | ||
1006 | return ret; | ||
1007 | } | ||
1008 | } | ||
1009 | ret = tps65910_reg_write(pmic, sr_reg_add, 0); | ||
1010 | if (ret < 0) { | ||
1011 | dev_err(mfd->dev, "Error in settting sr register\n"); | ||
1012 | return ret; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | ret = tps65910_clear_bits(mfd, | ||
1017 | TPS65910_SLEEP_KEEP_LDO_ON + regoffs, bit_pos); | ||
1018 | if (!ret) | ||
1019 | ret = tps65910_set_bits(mfd, | ||
1020 | TPS65910_SLEEP_SET_LDO_OFF + regoffs, bit_pos); | ||
1021 | if (ret < 0) | ||
1022 | dev_err(mfd->dev, | ||
1023 | "Error in configuring SLEEP register\n"); | ||
1024 | return ret; | ||
1025 | } | ||
1026 | |||
864 | static __devinit int tps65910_probe(struct platform_device *pdev) | 1027 | static __devinit int tps65910_probe(struct platform_device *pdev) |
865 | { | 1028 | { |
866 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); | 1029 | struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); |
@@ -891,11 +1054,13 @@ static __devinit int tps65910_probe(struct platform_device *pdev) | |||
891 | case TPS65910: | 1054 | case TPS65910: |
892 | pmic->get_ctrl_reg = &tps65910_get_ctrl_register; | 1055 | pmic->get_ctrl_reg = &tps65910_get_ctrl_register; |
893 | pmic->num_regulators = ARRAY_SIZE(tps65910_regs); | 1056 | pmic->num_regulators = ARRAY_SIZE(tps65910_regs); |
1057 | pmic->ext_sleep_control = tps65910_ext_sleep_control; | ||
894 | info = tps65910_regs; | 1058 | info = tps65910_regs; |
895 | break; | 1059 | break; |
896 | case TPS65911: | 1060 | case TPS65911: |
897 | pmic->get_ctrl_reg = &tps65911_get_ctrl_register; | 1061 | pmic->get_ctrl_reg = &tps65911_get_ctrl_register; |
898 | pmic->num_regulators = ARRAY_SIZE(tps65911_regs); | 1062 | pmic->num_regulators = ARRAY_SIZE(tps65911_regs); |
1063 | pmic->ext_sleep_control = tps65911_ext_sleep_control; | ||
899 | info = tps65911_regs; | 1064 | info = tps65911_regs; |
900 | break; | 1065 | break; |
901 | default: | 1066 | default: |
@@ -958,6 +1123,16 @@ static __devinit int tps65910_probe(struct platform_device *pdev) | |||
958 | pmic->desc[i].ops = &tps65911_ops; | 1123 | pmic->desc[i].ops = &tps65911_ops; |
959 | } | 1124 | } |
960 | 1125 | ||
1126 | err = tps65910_set_ext_sleep_config(pmic, i, | ||
1127 | pmic_plat_data->regulator_ext_sleep_control[i]); | ||
1128 | /* | ||
1129 | * Failing on regulator for configuring externally control | ||
1130 | * is not a serious issue, just throw warning. | ||
1131 | */ | ||
1132 | if (err < 0) | ||
1133 | dev_warn(tps65910->dev, | ||
1134 | "Failed to initialise ext control config\n"); | ||
1135 | |||
961 | pmic->desc[i].type = REGULATOR_VOLTAGE; | 1136 | pmic->desc[i].type = REGULATOR_VOLTAGE; |
962 | pmic->desc[i].owner = THIS_MODULE; | 1137 | pmic->desc[i].owner = THIS_MODULE; |
963 | 1138 | ||
@@ -1004,6 +1179,36 @@ static int __devexit tps65910_remove(struct platform_device *pdev) | |||
1004 | return 0; | 1179 | return 0; |
1005 | } | 1180 | } |
1006 | 1181 | ||
1182 | static void tps65910_shutdown(struct platform_device *pdev) | ||
1183 | { | ||
1184 | struct tps65910_reg *pmic = platform_get_drvdata(pdev); | ||
1185 | int i; | ||
1186 | |||
1187 | /* | ||
1188 | * Before bootloader jumps to kernel, it makes sure that required | ||
1189 | * external control signals are in desired state so that given rails | ||
1190 | * can be configure accordingly. | ||
1191 | * If rails are configured to be controlled from external control | ||
1192 | * then before shutting down/rebooting the system, the external | ||
1193 | * control configuration need to be remove from the rails so that | ||
1194 | * its output will be available as per register programming even | ||
1195 | * if external controls are removed. This is require when the POR | ||
1196 | * value of the control signals are not in active state and before | ||
1197 | * bootloader initializes it, the system requires the rail output | ||
1198 | * to be active for booting. | ||
1199 | */ | ||
1200 | for (i = 0; i < pmic->num_regulators; i++) { | ||
1201 | int err; | ||
1202 | if (!pmic->rdev[i]) | ||
1203 | continue; | ||
1204 | |||
1205 | err = tps65910_set_ext_sleep_config(pmic, i, 0); | ||
1206 | if (err < 0) | ||
1207 | dev_err(&pdev->dev, | ||
1208 | "Error in clearing external control\n"); | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1007 | static struct platform_driver tps65910_driver = { | 1212 | static struct platform_driver tps65910_driver = { |
1008 | .driver = { | 1213 | .driver = { |
1009 | .name = "tps65910-pmic", | 1214 | .name = "tps65910-pmic", |
@@ -1011,6 +1216,7 @@ static struct platform_driver tps65910_driver = { | |||
1011 | }, | 1216 | }, |
1012 | .probe = tps65910_probe, | 1217 | .probe = tps65910_probe, |
1013 | .remove = __devexit_p(tps65910_remove), | 1218 | .remove = __devexit_p(tps65910_remove), |
1219 | .shutdown = tps65910_shutdown, | ||
1014 | }; | 1220 | }; |
1015 | 1221 | ||
1016 | static int __init tps65910_init(void) | 1222 | static int __init tps65910_init(void) |
diff --git a/include/linux/mfd/tps65910.h b/include/linux/mfd/tps65910.h index d0cb12eba402..fa6c6bf7a54d 100644 --- a/include/linux/mfd/tps65910.h +++ b/include/linux/mfd/tps65910.h | |||
@@ -768,6 +768,13 @@ | |||
768 | /* Max number of TPS65910/11 regulators */ | 768 | /* Max number of TPS65910/11 regulators */ |
769 | #define TPS65910_NUM_REGS 13 | 769 | #define TPS65910_NUM_REGS 13 |
770 | 770 | ||
771 | /* External sleep controls through EN1/EN2/EN3 inputs*/ | ||
772 | #define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN1 0x1 | ||
773 | #define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN2 0x2 | ||
774 | #define TPS65910_SLEEP_CONTROL_EXT_INPUT_EN3 0x4 | ||
775 | /* TPS65911 names the EN3 signal as SLEEP */ | ||
776 | #define TPS65911_SLEEP_CONTROL_EXT_INPUT_SLEEP 0x4 | ||
777 | |||
771 | /** | 778 | /** |
772 | * struct tps65910_board | 779 | * struct tps65910_board |
773 | * Board platform data may be used to initialize regulators. | 780 | * Board platform data may be used to initialize regulators. |
@@ -779,6 +786,7 @@ struct tps65910_board { | |||
779 | int irq_base; | 786 | int irq_base; |
780 | int vmbch_threshold; | 787 | int vmbch_threshold; |
781 | int vmbch2_threshold; | 788 | int vmbch2_threshold; |
789 | unsigned long regulator_ext_sleep_control[TPS65910_NUM_REGS]; | ||
782 | struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; | 790 | struct regulator_init_data *tps65910_pmic_init_data[TPS65910_NUM_REGS]; |
783 | }; | 791 | }; |
784 | 792 | ||