diff options
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/regulator/Makefile | 2 | ||||
-rw-r--r-- | drivers/regulator/twl-regulator.c | 600 | ||||
-rw-r--r-- | drivers/regulator/twl6030-regulator.c | 805 |
4 files changed, 812 insertions, 596 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064..1317123f100d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -8721,6 +8721,7 @@ F: drivers/regulator/tps65217-regulator.c | |||
8721 | F: drivers/regulator/tps65218-regulator.c | 8721 | F: drivers/regulator/tps65218-regulator.c |
8722 | F: drivers/regulator/tps65910-regulator.c | 8722 | F: drivers/regulator/tps65910-regulator.c |
8723 | F: drivers/regulator/twl-regulator.c | 8723 | F: drivers/regulator/twl-regulator.c |
8724 | F: drivers/regulator/twl6030-regulator.c | ||
8724 | F: include/linux/i2c-omap.h | 8725 | F: include/linux/i2c-omap.h |
8725 | 8726 | ||
8726 | OMAP DEVICE TREE SUPPORT | 8727 | OMAP DEVICE TREE SUPPORT |
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 2142a5d3fc08..14294692beb9 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile | |||
@@ -104,7 +104,7 @@ obj-$(CONFIG_REGULATOR_TPS6586X) += tps6586x-regulator.o | |||
104 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o | 104 | obj-$(CONFIG_REGULATOR_TPS65910) += tps65910-regulator.o |
105 | obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o | 105 | obj-$(CONFIG_REGULATOR_TPS65912) += tps65912-regulator.o |
106 | obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o | 106 | obj-$(CONFIG_REGULATOR_TPS80031) += tps80031-regulator.o |
107 | obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o | 107 | obj-$(CONFIG_REGULATOR_TWL4030) += twl-regulator.o twl6030-regulator.o |
108 | obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o | 108 | obj-$(CONFIG_REGULATOR_VEXPRESS) += vexpress-regulator.o |
109 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o | 109 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-dcdc.o |
110 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o | 110 | obj-$(CONFIG_REGULATOR_WM831X) += wm831x-isink.o |
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index 3f9f53d98ef0..d572b8a583e4 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | 25 | ||
26 | /* | 26 | /* |
27 | * The TWL4030/TW5030/TPS659x0/TWL6030 family chips include power management, a | 27 | * The TWL4030/TW5030/TPS659x0 family chips include power management, a |
28 | * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions | 28 | * USB OTG transceiver, an RTC, ADC, PWM, and lots more. Some versions |
29 | * include an audio codec, battery charger, and more voltage regulators. | 29 | * include an audio codec, battery charger, and more voltage regulators. |
30 | * These chips are often used in OMAP-based systems. | 30 | * These chips are often used in OMAP-based systems. |
@@ -81,33 +81,6 @@ struct twlreg_info { | |||
81 | #define VREG_STATE 2 | 81 | #define VREG_STATE 2 |
82 | #define VREG_VOLTAGE 3 | 82 | #define VREG_VOLTAGE 3 |
83 | #define VREG_VOLTAGE_SMPS 4 | 83 | #define VREG_VOLTAGE_SMPS 4 |
84 | /* TWL6030 Misc register offsets */ | ||
85 | #define VREG_BC_ALL 1 | ||
86 | #define VREG_BC_REF 2 | ||
87 | #define VREG_BC_PROC 3 | ||
88 | #define VREG_BC_CLK_RST 4 | ||
89 | |||
90 | /* TWL6030 LDO register values for CFG_STATE */ | ||
91 | #define TWL6030_CFG_STATE_OFF 0x00 | ||
92 | #define TWL6030_CFG_STATE_ON 0x01 | ||
93 | #define TWL6030_CFG_STATE_OFF2 0x02 | ||
94 | #define TWL6030_CFG_STATE_SLEEP 0x03 | ||
95 | #define TWL6030_CFG_STATE_GRP_SHIFT 5 | ||
96 | #define TWL6030_CFG_STATE_APP_SHIFT 2 | ||
97 | #define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) | ||
98 | #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ | ||
99 | TWL6030_CFG_STATE_APP_SHIFT) | ||
100 | |||
101 | /* Flags for SMPS Voltage reading */ | ||
102 | #define SMPS_OFFSET_EN BIT(0) | ||
103 | #define SMPS_EXTENDED_EN BIT(1) | ||
104 | |||
105 | /* twl6032 SMPS EPROM values */ | ||
106 | #define TWL6030_SMPS_OFFSET 0xB0 | ||
107 | #define TWL6030_SMPS_MULT 0xB3 | ||
108 | #define SMPS_MULTOFFSET_SMPS4 BIT(0) | ||
109 | #define SMPS_MULTOFFSET_VIO BIT(1) | ||
110 | #define SMPS_MULTOFFSET_SMPS3 BIT(6) | ||
111 | 84 | ||
112 | static inline int | 85 | static inline int |
113 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) | 86 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) |
@@ -161,26 +134,6 @@ static int twl4030reg_is_enabled(struct regulator_dev *rdev) | |||
161 | return state & P1_GRP_4030; | 134 | return state & P1_GRP_4030; |
162 | } | 135 | } |
163 | 136 | ||
164 | static int twl6030reg_is_enabled(struct regulator_dev *rdev) | ||
165 | { | ||
166 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
167 | int grp = 0, val; | ||
168 | |||
169 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) { | ||
170 | grp = twlreg_grp(rdev); | ||
171 | if (grp < 0) | ||
172 | return grp; | ||
173 | grp &= P1_GRP_6030; | ||
174 | } else { | ||
175 | grp = 1; | ||
176 | } | ||
177 | |||
178 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); | ||
179 | val = TWL6030_CFG_STATE_APP(val); | ||
180 | |||
181 | return grp && (val == TWL6030_CFG_STATE_ON); | ||
182 | } | ||
183 | |||
184 | #define PB_I2C_BUSY BIT(0) | 137 | #define PB_I2C_BUSY BIT(0) |
185 | #define PB_I2C_BWEN BIT(1) | 138 | #define PB_I2C_BWEN BIT(1) |
186 | 139 | ||
@@ -266,23 +219,6 @@ static int twl4030reg_enable(struct regulator_dev *rdev) | |||
266 | return ret; | 219 | return ret; |
267 | } | 220 | } |
268 | 221 | ||
269 | static int twl6030reg_enable(struct regulator_dev *rdev) | ||
270 | { | ||
271 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
272 | int grp = 0; | ||
273 | int ret; | ||
274 | |||
275 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
276 | grp = twlreg_grp(rdev); | ||
277 | if (grp < 0) | ||
278 | return grp; | ||
279 | |||
280 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, | ||
281 | grp << TWL6030_CFG_STATE_GRP_SHIFT | | ||
282 | TWL6030_CFG_STATE_ON); | ||
283 | return ret; | ||
284 | } | ||
285 | |||
286 | static int twl4030reg_disable(struct regulator_dev *rdev) | 222 | static int twl4030reg_disable(struct regulator_dev *rdev) |
287 | { | 223 | { |
288 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 224 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
@@ -300,23 +236,6 @@ static int twl4030reg_disable(struct regulator_dev *rdev) | |||
300 | return ret; | 236 | return ret; |
301 | } | 237 | } |
302 | 238 | ||
303 | static int twl6030reg_disable(struct regulator_dev *rdev) | ||
304 | { | ||
305 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
306 | int grp = 0; | ||
307 | int ret; | ||
308 | |||
309 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
310 | grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; | ||
311 | |||
312 | /* For 6030, set the off state for all grps enabled */ | ||
313 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, | ||
314 | (grp) << TWL6030_CFG_STATE_GRP_SHIFT | | ||
315 | TWL6030_CFG_STATE_OFF); | ||
316 | |||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | static int twl4030reg_get_status(struct regulator_dev *rdev) | 239 | static int twl4030reg_get_status(struct regulator_dev *rdev) |
321 | { | 240 | { |
322 | int state = twlreg_grp(rdev); | 241 | int state = twlreg_grp(rdev); |
@@ -333,33 +252,6 @@ static int twl4030reg_get_status(struct regulator_dev *rdev) | |||
333 | : REGULATOR_STATUS_STANDBY; | 252 | : REGULATOR_STATUS_STANDBY; |
334 | } | 253 | } |
335 | 254 | ||
336 | static int twl6030reg_get_status(struct regulator_dev *rdev) | ||
337 | { | ||
338 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
339 | int val; | ||
340 | |||
341 | val = twlreg_grp(rdev); | ||
342 | if (val < 0) | ||
343 | return val; | ||
344 | |||
345 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); | ||
346 | |||
347 | switch (TWL6030_CFG_STATE_APP(val)) { | ||
348 | case TWL6030_CFG_STATE_ON: | ||
349 | return REGULATOR_STATUS_NORMAL; | ||
350 | |||
351 | case TWL6030_CFG_STATE_SLEEP: | ||
352 | return REGULATOR_STATUS_STANDBY; | ||
353 | |||
354 | case TWL6030_CFG_STATE_OFF: | ||
355 | case TWL6030_CFG_STATE_OFF2: | ||
356 | default: | ||
357 | break; | ||
358 | } | ||
359 | |||
360 | return REGULATOR_STATUS_OFF; | ||
361 | } | ||
362 | |||
363 | static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | 255 | static int twl4030reg_set_mode(struct regulator_dev *rdev, unsigned mode) |
364 | { | 256 | { |
365 | struct twlreg_info *info = rdev_get_drvdata(rdev); | 257 | struct twlreg_info *info = rdev_get_drvdata(rdev); |
@@ -392,36 +284,6 @@ static inline unsigned int twl4030reg_map_mode(unsigned int mode) | |||
392 | } | 284 | } |
393 | } | 285 | } |
394 | 286 | ||
395 | static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | ||
396 | { | ||
397 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
398 | int grp = 0; | ||
399 | int val; | ||
400 | |||
401 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
402 | grp = twlreg_grp(rdev); | ||
403 | |||
404 | if (grp < 0) | ||
405 | return grp; | ||
406 | |||
407 | /* Compose the state register settings */ | ||
408 | val = grp << TWL6030_CFG_STATE_GRP_SHIFT; | ||
409 | /* We can only set the mode through state machine commands... */ | ||
410 | switch (mode) { | ||
411 | case REGULATOR_MODE_NORMAL: | ||
412 | val |= TWL6030_CFG_STATE_ON; | ||
413 | break; | ||
414 | case REGULATOR_MODE_STANDBY: | ||
415 | val |= TWL6030_CFG_STATE_SLEEP; | ||
416 | break; | ||
417 | |||
418 | default: | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | |||
422 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val); | ||
423 | } | ||
424 | |||
425 | /*----------------------------------------------------------------------*/ | 287 | /*----------------------------------------------------------------------*/ |
426 | 288 | ||
427 | /* | 289 | /* |
@@ -579,75 +441,6 @@ static struct regulator_ops twl4030smps_ops = { | |||
579 | .get_voltage = twl4030smps_get_voltage, | 441 | .get_voltage = twl4030smps_get_voltage, |
580 | }; | 442 | }; |
581 | 443 | ||
582 | static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV, | ||
583 | int max_uV, unsigned *selector) | ||
584 | { | ||
585 | return -ENODEV; | ||
586 | } | ||
587 | |||
588 | static int twl6030coresmps_get_voltage(struct regulator_dev *rdev) | ||
589 | { | ||
590 | return -ENODEV; | ||
591 | } | ||
592 | |||
593 | static struct regulator_ops twl6030coresmps_ops = { | ||
594 | .set_voltage = twl6030coresmps_set_voltage, | ||
595 | .get_voltage = twl6030coresmps_get_voltage, | ||
596 | }; | ||
597 | |||
598 | static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) | ||
599 | { | ||
600 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
601 | |||
602 | switch (sel) { | ||
603 | case 0: | ||
604 | return 0; | ||
605 | case 1 ... 24: | ||
606 | /* Linear mapping from 00000001 to 00011000: | ||
607 | * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001) | ||
608 | */ | ||
609 | return (info->min_mV + 100 * (sel - 1)) * 1000; | ||
610 | case 25 ... 30: | ||
611 | return -EINVAL; | ||
612 | case 31: | ||
613 | return 2750000; | ||
614 | default: | ||
615 | return -EINVAL; | ||
616 | } | ||
617 | } | ||
618 | |||
619 | static int | ||
620 | twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) | ||
621 | { | ||
622 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
623 | |||
624 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, | ||
625 | selector); | ||
626 | } | ||
627 | |||
628 | static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) | ||
629 | { | ||
630 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
631 | int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); | ||
632 | |||
633 | return vsel; | ||
634 | } | ||
635 | |||
636 | static struct regulator_ops twl6030ldo_ops = { | ||
637 | .list_voltage = twl6030ldo_list_voltage, | ||
638 | |||
639 | .set_voltage_sel = twl6030ldo_set_voltage_sel, | ||
640 | .get_voltage_sel = twl6030ldo_get_voltage_sel, | ||
641 | |||
642 | .enable = twl6030reg_enable, | ||
643 | .disable = twl6030reg_disable, | ||
644 | .is_enabled = twl6030reg_is_enabled, | ||
645 | |||
646 | .set_mode = twl6030reg_set_mode, | ||
647 | |||
648 | .get_status = twl6030reg_get_status, | ||
649 | }; | ||
650 | |||
651 | /*----------------------------------------------------------------------*/ | 444 | /*----------------------------------------------------------------------*/ |
652 | 445 | ||
653 | static struct regulator_ops twl4030fixed_ops = { | 446 | static struct regulator_ops twl4030fixed_ops = { |
@@ -662,215 +455,6 @@ static struct regulator_ops twl4030fixed_ops = { | |||
662 | .get_status = twl4030reg_get_status, | 455 | .get_status = twl4030reg_get_status, |
663 | }; | 456 | }; |
664 | 457 | ||
665 | static struct regulator_ops twl6030fixed_ops = { | ||
666 | .list_voltage = regulator_list_voltage_linear, | ||
667 | |||
668 | .enable = twl6030reg_enable, | ||
669 | .disable = twl6030reg_disable, | ||
670 | .is_enabled = twl6030reg_is_enabled, | ||
671 | |||
672 | .set_mode = twl6030reg_set_mode, | ||
673 | |||
674 | .get_status = twl6030reg_get_status, | ||
675 | }; | ||
676 | |||
677 | /* | ||
678 | * SMPS status and control | ||
679 | */ | ||
680 | |||
681 | static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
682 | { | ||
683 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
684 | |||
685 | int voltage = 0; | ||
686 | |||
687 | switch (info->flags) { | ||
688 | case SMPS_OFFSET_EN: | ||
689 | voltage = 100000; | ||
690 | /* fall through */ | ||
691 | case 0: | ||
692 | switch (index) { | ||
693 | case 0: | ||
694 | voltage = 0; | ||
695 | break; | ||
696 | case 58: | ||
697 | voltage = 1350 * 1000; | ||
698 | break; | ||
699 | case 59: | ||
700 | voltage = 1500 * 1000; | ||
701 | break; | ||
702 | case 60: | ||
703 | voltage = 1800 * 1000; | ||
704 | break; | ||
705 | case 61: | ||
706 | voltage = 1900 * 1000; | ||
707 | break; | ||
708 | case 62: | ||
709 | voltage = 2100 * 1000; | ||
710 | break; | ||
711 | default: | ||
712 | voltage += (600000 + (12500 * (index - 1))); | ||
713 | } | ||
714 | break; | ||
715 | case SMPS_EXTENDED_EN: | ||
716 | switch (index) { | ||
717 | case 0: | ||
718 | voltage = 0; | ||
719 | break; | ||
720 | case 58: | ||
721 | voltage = 2084 * 1000; | ||
722 | break; | ||
723 | case 59: | ||
724 | voltage = 2315 * 1000; | ||
725 | break; | ||
726 | case 60: | ||
727 | voltage = 2778 * 1000; | ||
728 | break; | ||
729 | case 61: | ||
730 | voltage = 2932 * 1000; | ||
731 | break; | ||
732 | case 62: | ||
733 | voltage = 3241 * 1000; | ||
734 | break; | ||
735 | default: | ||
736 | voltage = (1852000 + (38600 * (index - 1))); | ||
737 | } | ||
738 | break; | ||
739 | case SMPS_OFFSET_EN | SMPS_EXTENDED_EN: | ||
740 | switch (index) { | ||
741 | case 0: | ||
742 | voltage = 0; | ||
743 | break; | ||
744 | case 58: | ||
745 | voltage = 4167 * 1000; | ||
746 | break; | ||
747 | case 59: | ||
748 | voltage = 2315 * 1000; | ||
749 | break; | ||
750 | case 60: | ||
751 | voltage = 2778 * 1000; | ||
752 | break; | ||
753 | case 61: | ||
754 | voltage = 2932 * 1000; | ||
755 | break; | ||
756 | case 62: | ||
757 | voltage = 3241 * 1000; | ||
758 | break; | ||
759 | default: | ||
760 | voltage = (2161000 + (38600 * (index - 1))); | ||
761 | } | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | return voltage; | ||
766 | } | ||
767 | |||
768 | static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, | ||
769 | int max_uV) | ||
770 | { | ||
771 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
772 | int vsel = 0; | ||
773 | |||
774 | switch (info->flags) { | ||
775 | case 0: | ||
776 | if (min_uV == 0) | ||
777 | vsel = 0; | ||
778 | else if ((min_uV >= 600000) && (min_uV <= 1300000)) { | ||
779 | vsel = DIV_ROUND_UP(min_uV - 600000, 12500); | ||
780 | vsel++; | ||
781 | } | ||
782 | /* Values 1..57 for vsel are linear and can be calculated | ||
783 | * values 58..62 are non linear. | ||
784 | */ | ||
785 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) | ||
786 | vsel = 62; | ||
787 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) | ||
788 | vsel = 61; | ||
789 | else if ((min_uV > 1500000) && (min_uV <= 1800000)) | ||
790 | vsel = 60; | ||
791 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) | ||
792 | vsel = 59; | ||
793 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) | ||
794 | vsel = 58; | ||
795 | else | ||
796 | return -EINVAL; | ||
797 | break; | ||
798 | case SMPS_OFFSET_EN: | ||
799 | if (min_uV == 0) | ||
800 | vsel = 0; | ||
801 | else if ((min_uV >= 700000) && (min_uV <= 1420000)) { | ||
802 | vsel = DIV_ROUND_UP(min_uV - 700000, 12500); | ||
803 | vsel++; | ||
804 | } | ||
805 | /* Values 1..57 for vsel are linear and can be calculated | ||
806 | * values 58..62 are non linear. | ||
807 | */ | ||
808 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) | ||
809 | vsel = 62; | ||
810 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) | ||
811 | vsel = 61; | ||
812 | else if ((min_uV > 1350000) && (min_uV <= 1800000)) | ||
813 | vsel = 60; | ||
814 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) | ||
815 | vsel = 59; | ||
816 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) | ||
817 | vsel = 58; | ||
818 | else | ||
819 | return -EINVAL; | ||
820 | break; | ||
821 | case SMPS_EXTENDED_EN: | ||
822 | if (min_uV == 0) { | ||
823 | vsel = 0; | ||
824 | } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { | ||
825 | vsel = DIV_ROUND_UP(min_uV - 1852000, 38600); | ||
826 | vsel++; | ||
827 | } | ||
828 | break; | ||
829 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: | ||
830 | if (min_uV == 0) { | ||
831 | vsel = 0; | ||
832 | } else if ((min_uV >= 2161000) && (min_uV <= 4321000)) { | ||
833 | vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); | ||
834 | vsel++; | ||
835 | } | ||
836 | break; | ||
837 | } | ||
838 | |||
839 | return vsel; | ||
840 | } | ||
841 | |||
842 | static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev, | ||
843 | unsigned int selector) | ||
844 | { | ||
845 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
846 | |||
847 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, | ||
848 | selector); | ||
849 | } | ||
850 | |||
851 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) | ||
852 | { | ||
853 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
854 | |||
855 | return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); | ||
856 | } | ||
857 | |||
858 | static struct regulator_ops twlsmps_ops = { | ||
859 | .list_voltage = twl6030smps_list_voltage, | ||
860 | .map_voltage = twl6030smps_map_voltage, | ||
861 | |||
862 | .set_voltage_sel = twl6030smps_set_voltage_sel, | ||
863 | .get_voltage_sel = twl6030smps_get_voltage_sel, | ||
864 | |||
865 | .enable = twl6030reg_enable, | ||
866 | .disable = twl6030reg_disable, | ||
867 | .is_enabled = twl6030reg_is_enabled, | ||
868 | |||
869 | .set_mode = twl6030reg_set_mode, | ||
870 | |||
871 | .get_status = twl6030reg_get_status, | ||
872 | }; | ||
873 | |||
874 | /*----------------------------------------------------------------------*/ | 458 | /*----------------------------------------------------------------------*/ |
875 | 459 | ||
876 | #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ | 460 | #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \ |
@@ -908,66 +492,6 @@ static const struct twlreg_info TWL4030_INFO_##label = { \ | |||
908 | }, \ | 492 | }, \ |
909 | } | 493 | } |
910 | 494 | ||
911 | #define TWL6030_ADJUSTABLE_SMPS(label) \ | ||
912 | static const struct twlreg_info TWL6030_INFO_##label = { \ | ||
913 | .desc = { \ | ||
914 | .name = #label, \ | ||
915 | .id = TWL6030_REG_##label, \ | ||
916 | .ops = &twl6030coresmps_ops, \ | ||
917 | .type = REGULATOR_VOLTAGE, \ | ||
918 | .owner = THIS_MODULE, \ | ||
919 | }, \ | ||
920 | } | ||
921 | |||
922 | #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | ||
923 | static const struct twlreg_info TWL6030_INFO_##label = { \ | ||
924 | .base = offset, \ | ||
925 | .min_mV = min_mVolts, \ | ||
926 | .max_mV = max_mVolts, \ | ||
927 | .desc = { \ | ||
928 | .name = #label, \ | ||
929 | .id = TWL6030_REG_##label, \ | ||
930 | .n_voltages = 32, \ | ||
931 | .ops = &twl6030ldo_ops, \ | ||
932 | .type = REGULATOR_VOLTAGE, \ | ||
933 | .owner = THIS_MODULE, \ | ||
934 | }, \ | ||
935 | } | ||
936 | |||
937 | #define TWL6032_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | ||
938 | static const struct twlreg_info TWL6032_INFO_##label = { \ | ||
939 | .base = offset, \ | ||
940 | .min_mV = min_mVolts, \ | ||
941 | .max_mV = max_mVolts, \ | ||
942 | .desc = { \ | ||
943 | .name = #label, \ | ||
944 | .id = TWL6032_REG_##label, \ | ||
945 | .n_voltages = 32, \ | ||
946 | .ops = &twl6030ldo_ops, \ | ||
947 | .type = REGULATOR_VOLTAGE, \ | ||
948 | .owner = THIS_MODULE, \ | ||
949 | }, \ | ||
950 | } | ||
951 | |||
952 | #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ | ||
953 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ | ||
954 | .base = offset, \ | ||
955 | .id = 0, \ | ||
956 | .min_mV = mVolts, \ | ||
957 | .remap = 0, \ | ||
958 | .desc = { \ | ||
959 | .name = #label, \ | ||
960 | .id = TWL6030##_REG_##label, \ | ||
961 | .n_voltages = 1, \ | ||
962 | .ops = &twl6030fixed_ops, \ | ||
963 | .type = REGULATOR_VOLTAGE, \ | ||
964 | .owner = THIS_MODULE, \ | ||
965 | .min_uV = mVolts * 1000, \ | ||
966 | .enable_time = turnon_delay, \ | ||
967 | .of_map_mode = NULL, \ | ||
968 | }, \ | ||
969 | } | ||
970 | |||
971 | #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ | 495 | #define TWL4030_FIXED_LDO(label, offset, mVolts, num, turnon_delay, \ |
972 | remap_conf) \ | 496 | remap_conf) \ |
973 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ | 497 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ |
@@ -988,21 +512,6 @@ static const struct twlreg_info TWLFIXED_INFO_##label = { \ | |||
988 | }, \ | 512 | }, \ |
989 | } | 513 | } |
990 | 514 | ||
991 | #define TWL6032_ADJUSTABLE_SMPS(label, offset) \ | ||
992 | static const struct twlreg_info TWLSMPS_INFO_##label = { \ | ||
993 | .base = offset, \ | ||
994 | .min_mV = 600, \ | ||
995 | .max_mV = 2100, \ | ||
996 | .desc = { \ | ||
997 | .name = #label, \ | ||
998 | .id = TWL6032_REG_##label, \ | ||
999 | .n_voltages = 63, \ | ||
1000 | .ops = &twlsmps_ops, \ | ||
1001 | .type = REGULATOR_VOLTAGE, \ | ||
1002 | .owner = THIS_MODULE, \ | ||
1003 | }, \ | ||
1004 | } | ||
1005 | |||
1006 | /* | 515 | /* |
1007 | * We list regulators here if systems need some level of | 516 | * We list regulators here if systems need some level of |
1008 | * software control over them after boot. | 517 | * software control over them after boot. |
@@ -1023,60 +532,11 @@ TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08); | |||
1023 | TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08); | 532 | TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08); |
1024 | TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08); | 533 | TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08); |
1025 | /* VUSBCP is managed *only* by the USB subchip */ | 534 | /* VUSBCP is managed *only* by the USB subchip */ |
1026 | /* 6030 REG with base as PMC Slave Misc : 0x0030 */ | ||
1027 | /* Turnon-delay and remap configuration values for 6030 are not | ||
1028 | verified since the specification is not public */ | ||
1029 | TWL6030_ADJUSTABLE_SMPS(VDD1); | ||
1030 | TWL6030_ADJUSTABLE_SMPS(VDD2); | ||
1031 | TWL6030_ADJUSTABLE_SMPS(VDD3); | ||
1032 | TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300); | ||
1033 | TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300); | ||
1034 | TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300); | ||
1035 | TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300); | ||
1036 | TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300); | ||
1037 | TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300); | ||
1038 | /* 6025 are renamed compared to 6030 versions */ | ||
1039 | TWL6032_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300); | ||
1040 | TWL6032_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300); | ||
1041 | TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300); | ||
1042 | TWL6032_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300); | ||
1043 | TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300); | ||
1044 | TWL6032_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300); | ||
1045 | TWL6032_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300); | ||
1046 | TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300); | ||
1047 | TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300); | ||
1048 | TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08); | 535 | TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08); |
1049 | TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08); | 536 | TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08); |
1050 | TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08); | 537 | TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08); |
1051 | TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08); | 538 | TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08); |
1052 | TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08); | 539 | TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08); |
1053 | TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0); | ||
1054 | TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0); | ||
1055 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0); | ||
1056 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0); | ||
1057 | TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0); | ||
1058 | TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0); | ||
1059 | TWL6032_ADJUSTABLE_SMPS(SMPS3, 0x34); | ||
1060 | TWL6032_ADJUSTABLE_SMPS(SMPS4, 0x10); | ||
1061 | TWL6032_ADJUSTABLE_SMPS(VIO, 0x16); | ||
1062 | |||
1063 | static u8 twl_get_smps_offset(void) | ||
1064 | { | ||
1065 | u8 value; | ||
1066 | |||
1067 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
1068 | TWL6030_SMPS_OFFSET); | ||
1069 | return value; | ||
1070 | } | ||
1071 | |||
1072 | static u8 twl_get_smps_mult(void) | ||
1073 | { | ||
1074 | u8 value; | ||
1075 | |||
1076 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
1077 | TWL6030_SMPS_MULT); | ||
1078 | return value; | ||
1079 | } | ||
1080 | 540 | ||
1081 | #define TWL_OF_MATCH(comp, family, label) \ | 541 | #define TWL_OF_MATCH(comp, family, label) \ |
1082 | { \ | 542 | { \ |
@@ -1106,38 +566,11 @@ static const struct of_device_id twl_of_match[] = { | |||
1106 | TWL4030_OF_MATCH("ti,twl4030-vio", VIO), | 566 | TWL4030_OF_MATCH("ti,twl4030-vio", VIO), |
1107 | TWL4030_OF_MATCH("ti,twl4030-vdd1", VDD1), | 567 | TWL4030_OF_MATCH("ti,twl4030-vdd1", VDD1), |
1108 | TWL4030_OF_MATCH("ti,twl4030-vdd2", VDD2), | 568 | TWL4030_OF_MATCH("ti,twl4030-vdd2", VDD2), |
1109 | TWL6030_OF_MATCH("ti,twl6030-vdd1", VDD1), | ||
1110 | TWL6030_OF_MATCH("ti,twl6030-vdd2", VDD2), | ||
1111 | TWL6030_OF_MATCH("ti,twl6030-vdd3", VDD3), | ||
1112 | TWL6030_OF_MATCH("ti,twl6030-vaux1", VAUX1_6030), | ||
1113 | TWL6030_OF_MATCH("ti,twl6030-vaux2", VAUX2_6030), | ||
1114 | TWL6030_OF_MATCH("ti,twl6030-vaux3", VAUX3_6030), | ||
1115 | TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC), | ||
1116 | TWL6030_OF_MATCH("ti,twl6030-vpp", VPP), | ||
1117 | TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM), | ||
1118 | TWL6032_OF_MATCH("ti,twl6032-ldo2", LDO2), | ||
1119 | TWL6032_OF_MATCH("ti,twl6032-ldo4", LDO4), | ||
1120 | TWL6032_OF_MATCH("ti,twl6032-ldo3", LDO3), | ||
1121 | TWL6032_OF_MATCH("ti,twl6032-ldo5", LDO5), | ||
1122 | TWL6032_OF_MATCH("ti,twl6032-ldo1", LDO1), | ||
1123 | TWL6032_OF_MATCH("ti,twl6032-ldo7", LDO7), | ||
1124 | TWL6032_OF_MATCH("ti,twl6032-ldo6", LDO6), | ||
1125 | TWL6032_OF_MATCH("ti,twl6032-ldoln", LDOLN), | ||
1126 | TWL6032_OF_MATCH("ti,twl6032-ldousb", LDOUSB), | ||
1127 | TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1), | 569 | TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1), |
1128 | TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG), | 570 | TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG), |
1129 | TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5), | 571 | TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5), |
1130 | TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8), | 572 | TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8), |
1131 | TWLFIXED_OF_MATCH("ti,twl4030-vusb3v1", VUSB3V1), | 573 | TWLFIXED_OF_MATCH("ti,twl4030-vusb3v1", VUSB3V1), |
1132 | TWLFIXED_OF_MATCH("ti,twl6030-vana", VANA), | ||
1133 | TWLFIXED_OF_MATCH("ti,twl6030-vcxio", VCXIO), | ||
1134 | TWLFIXED_OF_MATCH("ti,twl6030-vdac", VDAC), | ||
1135 | TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB), | ||
1136 | TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8), | ||
1137 | TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1), | ||
1138 | TWLSMPS_OF_MATCH("ti,twl6032-smps3", SMPS3), | ||
1139 | TWLSMPS_OF_MATCH("ti,twl6032-smps4", SMPS4), | ||
1140 | TWLSMPS_OF_MATCH("ti,twl6032-vio", VIO), | ||
1141 | {}, | 574 | {}, |
1142 | }; | 575 | }; |
1143 | MODULE_DEVICE_TABLE(of, twl_of_match); | 576 | MODULE_DEVICE_TABLE(of, twl_of_match); |
@@ -1193,27 +626,6 @@ static int twlreg_probe(struct platform_device *pdev) | |||
1193 | break; | 626 | break; |
1194 | } | 627 | } |
1195 | 628 | ||
1196 | switch (id) { | ||
1197 | case TWL6032_REG_SMPS3: | ||
1198 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) | ||
1199 | info->flags |= SMPS_EXTENDED_EN; | ||
1200 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3) | ||
1201 | info->flags |= SMPS_OFFSET_EN; | ||
1202 | break; | ||
1203 | case TWL6032_REG_SMPS4: | ||
1204 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4) | ||
1205 | info->flags |= SMPS_EXTENDED_EN; | ||
1206 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4) | ||
1207 | info->flags |= SMPS_OFFSET_EN; | ||
1208 | break; | ||
1209 | case TWL6032_REG_VIO: | ||
1210 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO) | ||
1211 | info->flags |= SMPS_EXTENDED_EN; | ||
1212 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO) | ||
1213 | info->flags |= SMPS_OFFSET_EN; | ||
1214 | break; | ||
1215 | } | ||
1216 | |||
1217 | config.dev = &pdev->dev; | 629 | config.dev = &pdev->dev; |
1218 | config.init_data = initdata; | 630 | config.init_data = initdata; |
1219 | config.driver_data = info; | 631 | config.driver_data = info; |
@@ -1227,9 +639,7 @@ static int twlreg_probe(struct platform_device *pdev) | |||
1227 | } | 639 | } |
1228 | platform_set_drvdata(pdev, rdev); | 640 | platform_set_drvdata(pdev, rdev); |
1229 | 641 | ||
1230 | if (twl_class_is_4030()) | 642 | twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP, info->remap); |
1231 | twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_REMAP, | ||
1232 | info->remap); | ||
1233 | 643 | ||
1234 | /* NOTE: many regulators support short-circuit IRQs (presentable | 644 | /* NOTE: many regulators support short-circuit IRQs (presentable |
1235 | * as REGULATOR_OVER_CURRENT notifications?) configured via: | 645 | * as REGULATOR_OVER_CURRENT notifications?) configured via: |
@@ -1242,7 +652,7 @@ static int twlreg_probe(struct platform_device *pdev) | |||
1242 | return 0; | 652 | return 0; |
1243 | } | 653 | } |
1244 | 654 | ||
1245 | MODULE_ALIAS("platform:twl_reg"); | 655 | MODULE_ALIAS("platform:twl4030_reg"); |
1246 | 656 | ||
1247 | static struct platform_driver twlreg_driver = { | 657 | static struct platform_driver twlreg_driver = { |
1248 | .probe = twlreg_probe, | 658 | .probe = twlreg_probe, |
@@ -1250,7 +660,7 @@ static struct platform_driver twlreg_driver = { | |||
1250 | * "twl_regulator.12" (and friends) to "twl_regulator.1". | 660 | * "twl_regulator.12" (and friends) to "twl_regulator.1". |
1251 | */ | 661 | */ |
1252 | .driver = { | 662 | .driver = { |
1253 | .name = "twl_reg", | 663 | .name = "twl4030_reg", |
1254 | .of_match_table = of_match_ptr(twl_of_match), | 664 | .of_match_table = of_match_ptr(twl_of_match), |
1255 | }, | 665 | }, |
1256 | }; | 666 | }; |
@@ -1267,5 +677,5 @@ static void __exit twlreg_exit(void) | |||
1267 | } | 677 | } |
1268 | module_exit(twlreg_exit) | 678 | module_exit(twlreg_exit) |
1269 | 679 | ||
1270 | MODULE_DESCRIPTION("TWL regulator driver"); | 680 | MODULE_DESCRIPTION("TWL4030 regulator driver"); |
1271 | MODULE_LICENSE("GPL"); | 681 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c new file mode 100644 index 000000000000..a446137f57bb --- /dev/null +++ b/drivers/regulator/twl6030-regulator.c | |||
@@ -0,0 +1,805 @@ | |||
1 | /* | ||
2 | * Split TWL6030 logic from twl-regulator.c: | ||
3 | * Copyright (C) 2008 David Brownell | ||
4 | * | ||
5 | * Copyright (C) 2016 Nicolae Rosia <nicolae.rosia@gmail.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/string.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/of.h> | ||
20 | #include <linux/of_device.h> | ||
21 | #include <linux/regulator/driver.h> | ||
22 | #include <linux/regulator/machine.h> | ||
23 | #include <linux/regulator/of_regulator.h> | ||
24 | #include <linux/i2c/twl.h> | ||
25 | #include <linux/delay.h> | ||
26 | |||
27 | struct twlreg_info { | ||
28 | /* start of regulator's PM_RECEIVER control register bank */ | ||
29 | u8 base; | ||
30 | |||
31 | /* twl resource ID, for resource control state machine */ | ||
32 | u8 id; | ||
33 | |||
34 | /* voltage in mV = table[VSEL]; table_len must be a power-of-two */ | ||
35 | u8 table_len; | ||
36 | const u16 *table; | ||
37 | |||
38 | /* State REMAP default configuration */ | ||
39 | u8 remap; | ||
40 | |||
41 | /* chip constraints on regulator behavior */ | ||
42 | u16 min_mV; | ||
43 | u16 max_mV; | ||
44 | |||
45 | u8 flags; | ||
46 | |||
47 | /* used by regulator core */ | ||
48 | struct regulator_desc desc; | ||
49 | |||
50 | /* chip specific features */ | ||
51 | unsigned long features; | ||
52 | |||
53 | /* data passed from board for external get/set voltage */ | ||
54 | void *data; | ||
55 | }; | ||
56 | |||
57 | |||
58 | /* LDO control registers ... offset is from the base of its register bank. | ||
59 | * The first three registers of all power resource banks help hardware to | ||
60 | * manage the various resource groups. | ||
61 | */ | ||
62 | /* Common offset in TWL4030/6030 */ | ||
63 | #define VREG_GRP 0 | ||
64 | /* TWL6030 register offsets */ | ||
65 | #define VREG_TRANS 1 | ||
66 | #define VREG_STATE 2 | ||
67 | #define VREG_VOLTAGE 3 | ||
68 | #define VREG_VOLTAGE_SMPS 4 | ||
69 | /* TWL6030 Misc register offsets */ | ||
70 | #define VREG_BC_ALL 1 | ||
71 | #define VREG_BC_REF 2 | ||
72 | #define VREG_BC_PROC 3 | ||
73 | #define VREG_BC_CLK_RST 4 | ||
74 | |||
75 | /* TWL6030 LDO register values for CFG_STATE */ | ||
76 | #define TWL6030_CFG_STATE_OFF 0x00 | ||
77 | #define TWL6030_CFG_STATE_ON 0x01 | ||
78 | #define TWL6030_CFG_STATE_OFF2 0x02 | ||
79 | #define TWL6030_CFG_STATE_SLEEP 0x03 | ||
80 | #define TWL6030_CFG_STATE_GRP_SHIFT 5 | ||
81 | #define TWL6030_CFG_STATE_APP_SHIFT 2 | ||
82 | #define TWL6030_CFG_STATE_APP_MASK (0x03 << TWL6030_CFG_STATE_APP_SHIFT) | ||
83 | #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ | ||
84 | TWL6030_CFG_STATE_APP_SHIFT) | ||
85 | |||
86 | /* Flags for SMPS Voltage reading */ | ||
87 | #define SMPS_OFFSET_EN BIT(0) | ||
88 | #define SMPS_EXTENDED_EN BIT(1) | ||
89 | |||
90 | /* twl6032 SMPS EPROM values */ | ||
91 | #define TWL6030_SMPS_OFFSET 0xB0 | ||
92 | #define TWL6030_SMPS_MULT 0xB3 | ||
93 | #define SMPS_MULTOFFSET_SMPS4 BIT(0) | ||
94 | #define SMPS_MULTOFFSET_VIO BIT(1) | ||
95 | #define SMPS_MULTOFFSET_SMPS3 BIT(6) | ||
96 | |||
97 | static inline int | ||
98 | twlreg_read(struct twlreg_info *info, unsigned slave_subgp, unsigned offset) | ||
99 | { | ||
100 | u8 value; | ||
101 | int status; | ||
102 | |||
103 | status = twl_i2c_read_u8(slave_subgp, | ||
104 | &value, info->base + offset); | ||
105 | return (status < 0) ? status : value; | ||
106 | } | ||
107 | |||
108 | static inline int | ||
109 | twlreg_write(struct twlreg_info *info, unsigned slave_subgp, unsigned offset, | ||
110 | u8 value) | ||
111 | { | ||
112 | return twl_i2c_write_u8(slave_subgp, | ||
113 | value, info->base + offset); | ||
114 | } | ||
115 | |||
116 | /* generic power resource operations, which work on all regulators */ | ||
117 | static int twlreg_grp(struct regulator_dev *rdev) | ||
118 | { | ||
119 | return twlreg_read(rdev_get_drvdata(rdev), TWL_MODULE_PM_RECEIVER, | ||
120 | VREG_GRP); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Enable/disable regulators by joining/leaving the P1 (processor) group. | ||
125 | * We assume nobody else is updating the DEV_GRP registers. | ||
126 | */ | ||
127 | /* definition for 6030 family */ | ||
128 | #define P3_GRP_6030 BIT(2) /* secondary processor, modem, etc */ | ||
129 | #define P2_GRP_6030 BIT(1) /* "peripherals" */ | ||
130 | #define P1_GRP_6030 BIT(0) /* CPU/Linux */ | ||
131 | |||
132 | static int twl6030reg_is_enabled(struct regulator_dev *rdev) | ||
133 | { | ||
134 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
135 | int grp = 0, val; | ||
136 | |||
137 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) { | ||
138 | grp = twlreg_grp(rdev); | ||
139 | if (grp < 0) | ||
140 | return grp; | ||
141 | grp &= P1_GRP_6030; | ||
142 | } else { | ||
143 | grp = 1; | ||
144 | } | ||
145 | |||
146 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); | ||
147 | val = TWL6030_CFG_STATE_APP(val); | ||
148 | |||
149 | return grp && (val == TWL6030_CFG_STATE_ON); | ||
150 | } | ||
151 | |||
152 | #define PB_I2C_BUSY BIT(0) | ||
153 | #define PB_I2C_BWEN BIT(1) | ||
154 | |||
155 | |||
156 | static int twl6030reg_enable(struct regulator_dev *rdev) | ||
157 | { | ||
158 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
159 | int grp = 0; | ||
160 | int ret; | ||
161 | |||
162 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
163 | grp = twlreg_grp(rdev); | ||
164 | if (grp < 0) | ||
165 | return grp; | ||
166 | |||
167 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, | ||
168 | grp << TWL6030_CFG_STATE_GRP_SHIFT | | ||
169 | TWL6030_CFG_STATE_ON); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | static int twl6030reg_disable(struct regulator_dev *rdev) | ||
174 | { | ||
175 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
176 | int grp = 0; | ||
177 | int ret; | ||
178 | |||
179 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
180 | grp = P1_GRP_6030 | P2_GRP_6030 | P3_GRP_6030; | ||
181 | |||
182 | /* For 6030, set the off state for all grps enabled */ | ||
183 | ret = twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, | ||
184 | (grp) << TWL6030_CFG_STATE_GRP_SHIFT | | ||
185 | TWL6030_CFG_STATE_OFF); | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int twl6030reg_get_status(struct regulator_dev *rdev) | ||
191 | { | ||
192 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
193 | int val; | ||
194 | |||
195 | val = twlreg_grp(rdev); | ||
196 | if (val < 0) | ||
197 | return val; | ||
198 | |||
199 | val = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_STATE); | ||
200 | |||
201 | switch (TWL6030_CFG_STATE_APP(val)) { | ||
202 | case TWL6030_CFG_STATE_ON: | ||
203 | return REGULATOR_STATUS_NORMAL; | ||
204 | |||
205 | case TWL6030_CFG_STATE_SLEEP: | ||
206 | return REGULATOR_STATUS_STANDBY; | ||
207 | |||
208 | case TWL6030_CFG_STATE_OFF: | ||
209 | case TWL6030_CFG_STATE_OFF2: | ||
210 | default: | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | return REGULATOR_STATUS_OFF; | ||
215 | } | ||
216 | |||
217 | static int twl6030reg_set_mode(struct regulator_dev *rdev, unsigned mode) | ||
218 | { | ||
219 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
220 | int grp = 0; | ||
221 | int val; | ||
222 | |||
223 | if (!(twl_class_is_6030() && (info->features & TWL6032_SUBCLASS))) | ||
224 | grp = twlreg_grp(rdev); | ||
225 | |||
226 | if (grp < 0) | ||
227 | return grp; | ||
228 | |||
229 | /* Compose the state register settings */ | ||
230 | val = grp << TWL6030_CFG_STATE_GRP_SHIFT; | ||
231 | /* We can only set the mode through state machine commands... */ | ||
232 | switch (mode) { | ||
233 | case REGULATOR_MODE_NORMAL: | ||
234 | val |= TWL6030_CFG_STATE_ON; | ||
235 | break; | ||
236 | case REGULATOR_MODE_STANDBY: | ||
237 | val |= TWL6030_CFG_STATE_SLEEP; | ||
238 | break; | ||
239 | |||
240 | default: | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | |||
244 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_STATE, val); | ||
245 | } | ||
246 | |||
247 | static int twl6030coresmps_set_voltage(struct regulator_dev *rdev, int min_uV, | ||
248 | int max_uV, unsigned *selector) | ||
249 | { | ||
250 | return -ENODEV; | ||
251 | } | ||
252 | |||
253 | static int twl6030coresmps_get_voltage(struct regulator_dev *rdev) | ||
254 | { | ||
255 | return -ENODEV; | ||
256 | } | ||
257 | |||
258 | static struct regulator_ops twl6030coresmps_ops = { | ||
259 | .set_voltage = twl6030coresmps_set_voltage, | ||
260 | .get_voltage = twl6030coresmps_get_voltage, | ||
261 | }; | ||
262 | |||
263 | static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned sel) | ||
264 | { | ||
265 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
266 | |||
267 | switch (sel) { | ||
268 | case 0: | ||
269 | return 0; | ||
270 | case 1 ... 24: | ||
271 | /* Linear mapping from 00000001 to 00011000: | ||
272 | * Absolute voltage value = 1.0 V + 0.1 V × (sel – 00000001) | ||
273 | */ | ||
274 | return (info->min_mV + 100 * (sel - 1)) * 1000; | ||
275 | case 25 ... 30: | ||
276 | return -EINVAL; | ||
277 | case 31: | ||
278 | return 2750000; | ||
279 | default: | ||
280 | return -EINVAL; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static int | ||
285 | twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) | ||
286 | { | ||
287 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
288 | |||
289 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, | ||
290 | selector); | ||
291 | } | ||
292 | |||
293 | static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) | ||
294 | { | ||
295 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
296 | int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); | ||
297 | |||
298 | return vsel; | ||
299 | } | ||
300 | |||
301 | static struct regulator_ops twl6030ldo_ops = { | ||
302 | .list_voltage = twl6030ldo_list_voltage, | ||
303 | |||
304 | .set_voltage_sel = twl6030ldo_set_voltage_sel, | ||
305 | .get_voltage_sel = twl6030ldo_get_voltage_sel, | ||
306 | |||
307 | .enable = twl6030reg_enable, | ||
308 | .disable = twl6030reg_disable, | ||
309 | .is_enabled = twl6030reg_is_enabled, | ||
310 | |||
311 | .set_mode = twl6030reg_set_mode, | ||
312 | |||
313 | .get_status = twl6030reg_get_status, | ||
314 | }; | ||
315 | |||
316 | static struct regulator_ops twl6030fixed_ops = { | ||
317 | .list_voltage = regulator_list_voltage_linear, | ||
318 | |||
319 | .enable = twl6030reg_enable, | ||
320 | .disable = twl6030reg_disable, | ||
321 | .is_enabled = twl6030reg_is_enabled, | ||
322 | |||
323 | .set_mode = twl6030reg_set_mode, | ||
324 | |||
325 | .get_status = twl6030reg_get_status, | ||
326 | }; | ||
327 | |||
328 | /* | ||
329 | * SMPS status and control | ||
330 | */ | ||
331 | |||
332 | static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index) | ||
333 | { | ||
334 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
335 | |||
336 | int voltage = 0; | ||
337 | |||
338 | switch (info->flags) { | ||
339 | case SMPS_OFFSET_EN: | ||
340 | voltage = 100000; | ||
341 | /* fall through */ | ||
342 | case 0: | ||
343 | switch (index) { | ||
344 | case 0: | ||
345 | voltage = 0; | ||
346 | break; | ||
347 | case 58: | ||
348 | voltage = 1350 * 1000; | ||
349 | break; | ||
350 | case 59: | ||
351 | voltage = 1500 * 1000; | ||
352 | break; | ||
353 | case 60: | ||
354 | voltage = 1800 * 1000; | ||
355 | break; | ||
356 | case 61: | ||
357 | voltage = 1900 * 1000; | ||
358 | break; | ||
359 | case 62: | ||
360 | voltage = 2100 * 1000; | ||
361 | break; | ||
362 | default: | ||
363 | voltage += (600000 + (12500 * (index - 1))); | ||
364 | } | ||
365 | break; | ||
366 | case SMPS_EXTENDED_EN: | ||
367 | switch (index) { | ||
368 | case 0: | ||
369 | voltage = 0; | ||
370 | break; | ||
371 | case 58: | ||
372 | voltage = 2084 * 1000; | ||
373 | break; | ||
374 | case 59: | ||
375 | voltage = 2315 * 1000; | ||
376 | break; | ||
377 | case 60: | ||
378 | voltage = 2778 * 1000; | ||
379 | break; | ||
380 | case 61: | ||
381 | voltage = 2932 * 1000; | ||
382 | break; | ||
383 | case 62: | ||
384 | voltage = 3241 * 1000; | ||
385 | break; | ||
386 | default: | ||
387 | voltage = (1852000 + (38600 * (index - 1))); | ||
388 | } | ||
389 | break; | ||
390 | case SMPS_OFFSET_EN | SMPS_EXTENDED_EN: | ||
391 | switch (index) { | ||
392 | case 0: | ||
393 | voltage = 0; | ||
394 | break; | ||
395 | case 58: | ||
396 | voltage = 4167 * 1000; | ||
397 | break; | ||
398 | case 59: | ||
399 | voltage = 2315 * 1000; | ||
400 | break; | ||
401 | case 60: | ||
402 | voltage = 2778 * 1000; | ||
403 | break; | ||
404 | case 61: | ||
405 | voltage = 2932 * 1000; | ||
406 | break; | ||
407 | case 62: | ||
408 | voltage = 3241 * 1000; | ||
409 | break; | ||
410 | default: | ||
411 | voltage = (2161000 + (38600 * (index - 1))); | ||
412 | } | ||
413 | break; | ||
414 | } | ||
415 | |||
416 | return voltage; | ||
417 | } | ||
418 | |||
419 | static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, | ||
420 | int max_uV) | ||
421 | { | ||
422 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
423 | int vsel = 0; | ||
424 | |||
425 | switch (info->flags) { | ||
426 | case 0: | ||
427 | if (min_uV == 0) | ||
428 | vsel = 0; | ||
429 | else if ((min_uV >= 600000) && (min_uV <= 1300000)) { | ||
430 | vsel = DIV_ROUND_UP(min_uV - 600000, 12500); | ||
431 | vsel++; | ||
432 | } | ||
433 | /* Values 1..57 for vsel are linear and can be calculated | ||
434 | * values 58..62 are non linear. | ||
435 | */ | ||
436 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) | ||
437 | vsel = 62; | ||
438 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) | ||
439 | vsel = 61; | ||
440 | else if ((min_uV > 1500000) && (min_uV <= 1800000)) | ||
441 | vsel = 60; | ||
442 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) | ||
443 | vsel = 59; | ||
444 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) | ||
445 | vsel = 58; | ||
446 | else | ||
447 | return -EINVAL; | ||
448 | break; | ||
449 | case SMPS_OFFSET_EN: | ||
450 | if (min_uV == 0) | ||
451 | vsel = 0; | ||
452 | else if ((min_uV >= 700000) && (min_uV <= 1420000)) { | ||
453 | vsel = DIV_ROUND_UP(min_uV - 700000, 12500); | ||
454 | vsel++; | ||
455 | } | ||
456 | /* Values 1..57 for vsel are linear and can be calculated | ||
457 | * values 58..62 are non linear. | ||
458 | */ | ||
459 | else if ((min_uV > 1900000) && (min_uV <= 2100000)) | ||
460 | vsel = 62; | ||
461 | else if ((min_uV > 1800000) && (min_uV <= 1900000)) | ||
462 | vsel = 61; | ||
463 | else if ((min_uV > 1350000) && (min_uV <= 1800000)) | ||
464 | vsel = 60; | ||
465 | else if ((min_uV > 1350000) && (min_uV <= 1500000)) | ||
466 | vsel = 59; | ||
467 | else if ((min_uV > 1300000) && (min_uV <= 1350000)) | ||
468 | vsel = 58; | ||
469 | else | ||
470 | return -EINVAL; | ||
471 | break; | ||
472 | case SMPS_EXTENDED_EN: | ||
473 | if (min_uV == 0) { | ||
474 | vsel = 0; | ||
475 | } else if ((min_uV >= 1852000) && (max_uV <= 4013600)) { | ||
476 | vsel = DIV_ROUND_UP(min_uV - 1852000, 38600); | ||
477 | vsel++; | ||
478 | } | ||
479 | break; | ||
480 | case SMPS_OFFSET_EN|SMPS_EXTENDED_EN: | ||
481 | if (min_uV == 0) { | ||
482 | vsel = 0; | ||
483 | } else if ((min_uV >= 2161000) && (min_uV <= 4321000)) { | ||
484 | vsel = DIV_ROUND_UP(min_uV - 2161000, 38600); | ||
485 | vsel++; | ||
486 | } | ||
487 | break; | ||
488 | } | ||
489 | |||
490 | return vsel; | ||
491 | } | ||
492 | |||
493 | static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev, | ||
494 | unsigned int selector) | ||
495 | { | ||
496 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
497 | |||
498 | return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS, | ||
499 | selector); | ||
500 | } | ||
501 | |||
502 | static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev) | ||
503 | { | ||
504 | struct twlreg_info *info = rdev_get_drvdata(rdev); | ||
505 | |||
506 | return twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS); | ||
507 | } | ||
508 | |||
509 | static struct regulator_ops twlsmps_ops = { | ||
510 | .list_voltage = twl6030smps_list_voltage, | ||
511 | .map_voltage = twl6030smps_map_voltage, | ||
512 | |||
513 | .set_voltage_sel = twl6030smps_set_voltage_sel, | ||
514 | .get_voltage_sel = twl6030smps_get_voltage_sel, | ||
515 | |||
516 | .enable = twl6030reg_enable, | ||
517 | .disable = twl6030reg_disable, | ||
518 | .is_enabled = twl6030reg_is_enabled, | ||
519 | |||
520 | .set_mode = twl6030reg_set_mode, | ||
521 | |||
522 | .get_status = twl6030reg_get_status, | ||
523 | }; | ||
524 | |||
525 | /*----------------------------------------------------------------------*/ | ||
526 | |||
527 | #define TWL6030_ADJUSTABLE_SMPS(label) \ | ||
528 | static const struct twlreg_info TWL6030_INFO_##label = { \ | ||
529 | .desc = { \ | ||
530 | .name = #label, \ | ||
531 | .id = TWL6030_REG_##label, \ | ||
532 | .ops = &twl6030coresmps_ops, \ | ||
533 | .type = REGULATOR_VOLTAGE, \ | ||
534 | .owner = THIS_MODULE, \ | ||
535 | }, \ | ||
536 | } | ||
537 | |||
538 | #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | ||
539 | static const struct twlreg_info TWL6030_INFO_##label = { \ | ||
540 | .base = offset, \ | ||
541 | .min_mV = min_mVolts, \ | ||
542 | .max_mV = max_mVolts, \ | ||
543 | .desc = { \ | ||
544 | .name = #label, \ | ||
545 | .id = TWL6030_REG_##label, \ | ||
546 | .n_voltages = 32, \ | ||
547 | .ops = &twl6030ldo_ops, \ | ||
548 | .type = REGULATOR_VOLTAGE, \ | ||
549 | .owner = THIS_MODULE, \ | ||
550 | }, \ | ||
551 | } | ||
552 | |||
553 | #define TWL6032_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \ | ||
554 | static const struct twlreg_info TWL6032_INFO_##label = { \ | ||
555 | .base = offset, \ | ||
556 | .min_mV = min_mVolts, \ | ||
557 | .max_mV = max_mVolts, \ | ||
558 | .desc = { \ | ||
559 | .name = #label, \ | ||
560 | .id = TWL6032_REG_##label, \ | ||
561 | .n_voltages = 32, \ | ||
562 | .ops = &twl6030ldo_ops, \ | ||
563 | .type = REGULATOR_VOLTAGE, \ | ||
564 | .owner = THIS_MODULE, \ | ||
565 | }, \ | ||
566 | } | ||
567 | |||
568 | #define TWL6030_FIXED_LDO(label, offset, mVolts, turnon_delay) \ | ||
569 | static const struct twlreg_info TWLFIXED_INFO_##label = { \ | ||
570 | .base = offset, \ | ||
571 | .id = 0, \ | ||
572 | .min_mV = mVolts, \ | ||
573 | .remap = 0, \ | ||
574 | .desc = { \ | ||
575 | .name = #label, \ | ||
576 | .id = TWL6030##_REG_##label, \ | ||
577 | .n_voltages = 1, \ | ||
578 | .ops = &twl6030fixed_ops, \ | ||
579 | .type = REGULATOR_VOLTAGE, \ | ||
580 | .owner = THIS_MODULE, \ | ||
581 | .min_uV = mVolts * 1000, \ | ||
582 | .enable_time = turnon_delay, \ | ||
583 | .of_map_mode = NULL, \ | ||
584 | }, \ | ||
585 | } | ||
586 | |||
587 | #define TWL6032_ADJUSTABLE_SMPS(label, offset) \ | ||
588 | static const struct twlreg_info TWLSMPS_INFO_##label = { \ | ||
589 | .base = offset, \ | ||
590 | .min_mV = 600, \ | ||
591 | .max_mV = 2100, \ | ||
592 | .desc = { \ | ||
593 | .name = #label, \ | ||
594 | .id = TWL6032_REG_##label, \ | ||
595 | .n_voltages = 63, \ | ||
596 | .ops = &twlsmps_ops, \ | ||
597 | .type = REGULATOR_VOLTAGE, \ | ||
598 | .owner = THIS_MODULE, \ | ||
599 | }, \ | ||
600 | } | ||
601 | |||
602 | /* VUSBCP is managed *only* by the USB subchip */ | ||
603 | /* 6030 REG with base as PMC Slave Misc : 0x0030 */ | ||
604 | /* Turnon-delay and remap configuration values for 6030 are not | ||
605 | verified since the specification is not public */ | ||
606 | TWL6030_ADJUSTABLE_SMPS(VDD1); | ||
607 | TWL6030_ADJUSTABLE_SMPS(VDD2); | ||
608 | TWL6030_ADJUSTABLE_SMPS(VDD3); | ||
609 | TWL6030_ADJUSTABLE_LDO(VAUX1_6030, 0x54, 1000, 3300); | ||
610 | TWL6030_ADJUSTABLE_LDO(VAUX2_6030, 0x58, 1000, 3300); | ||
611 | TWL6030_ADJUSTABLE_LDO(VAUX3_6030, 0x5c, 1000, 3300); | ||
612 | TWL6030_ADJUSTABLE_LDO(VMMC, 0x68, 1000, 3300); | ||
613 | TWL6030_ADJUSTABLE_LDO(VPP, 0x6c, 1000, 3300); | ||
614 | TWL6030_ADJUSTABLE_LDO(VUSIM, 0x74, 1000, 3300); | ||
615 | /* 6025 are renamed compared to 6030 versions */ | ||
616 | TWL6032_ADJUSTABLE_LDO(LDO2, 0x54, 1000, 3300); | ||
617 | TWL6032_ADJUSTABLE_LDO(LDO4, 0x58, 1000, 3300); | ||
618 | TWL6032_ADJUSTABLE_LDO(LDO3, 0x5c, 1000, 3300); | ||
619 | TWL6032_ADJUSTABLE_LDO(LDO5, 0x68, 1000, 3300); | ||
620 | TWL6032_ADJUSTABLE_LDO(LDO1, 0x6c, 1000, 3300); | ||
621 | TWL6032_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300); | ||
622 | TWL6032_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300); | ||
623 | TWL6032_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300); | ||
624 | TWL6032_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300); | ||
625 | TWL6030_FIXED_LDO(VANA, 0x50, 2100, 0); | ||
626 | TWL6030_FIXED_LDO(VCXIO, 0x60, 1800, 0); | ||
627 | TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0); | ||
628 | TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0); | ||
629 | TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0); | ||
630 | TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0); | ||
631 | TWL6032_ADJUSTABLE_SMPS(SMPS3, 0x34); | ||
632 | TWL6032_ADJUSTABLE_SMPS(SMPS4, 0x10); | ||
633 | TWL6032_ADJUSTABLE_SMPS(VIO, 0x16); | ||
634 | |||
635 | static u8 twl_get_smps_offset(void) | ||
636 | { | ||
637 | u8 value; | ||
638 | |||
639 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
640 | TWL6030_SMPS_OFFSET); | ||
641 | return value; | ||
642 | } | ||
643 | |||
644 | static u8 twl_get_smps_mult(void) | ||
645 | { | ||
646 | u8 value; | ||
647 | |||
648 | twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &value, | ||
649 | TWL6030_SMPS_MULT); | ||
650 | return value; | ||
651 | } | ||
652 | |||
653 | #define TWL_OF_MATCH(comp, family, label) \ | ||
654 | { \ | ||
655 | .compatible = comp, \ | ||
656 | .data = &family##_INFO_##label, \ | ||
657 | } | ||
658 | |||
659 | #define TWL6030_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6030, label) | ||
660 | #define TWL6032_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWL6032, label) | ||
661 | #define TWLFIXED_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLFIXED, label) | ||
662 | #define TWLSMPS_OF_MATCH(comp, label) TWL_OF_MATCH(comp, TWLSMPS, label) | ||
663 | |||
664 | static const struct of_device_id twl_of_match[] = { | ||
665 | TWL6030_OF_MATCH("ti,twl6030-vdd1", VDD1), | ||
666 | TWL6030_OF_MATCH("ti,twl6030-vdd2", VDD2), | ||
667 | TWL6030_OF_MATCH("ti,twl6030-vdd3", VDD3), | ||
668 | TWL6030_OF_MATCH("ti,twl6030-vaux1", VAUX1_6030), | ||
669 | TWL6030_OF_MATCH("ti,twl6030-vaux2", VAUX2_6030), | ||
670 | TWL6030_OF_MATCH("ti,twl6030-vaux3", VAUX3_6030), | ||
671 | TWL6030_OF_MATCH("ti,twl6030-vmmc", VMMC), | ||
672 | TWL6030_OF_MATCH("ti,twl6030-vpp", VPP), | ||
673 | TWL6030_OF_MATCH("ti,twl6030-vusim", VUSIM), | ||
674 | TWL6032_OF_MATCH("ti,twl6032-ldo2", LDO2), | ||
675 | TWL6032_OF_MATCH("ti,twl6032-ldo4", LDO4), | ||
676 | TWL6032_OF_MATCH("ti,twl6032-ldo3", LDO3), | ||
677 | TWL6032_OF_MATCH("ti,twl6032-ldo5", LDO5), | ||
678 | TWL6032_OF_MATCH("ti,twl6032-ldo1", LDO1), | ||
679 | TWL6032_OF_MATCH("ti,twl6032-ldo7", LDO7), | ||
680 | TWL6032_OF_MATCH("ti,twl6032-ldo6", LDO6), | ||
681 | TWL6032_OF_MATCH("ti,twl6032-ldoln", LDOLN), | ||
682 | TWL6032_OF_MATCH("ti,twl6032-ldousb", LDOUSB), | ||
683 | TWLFIXED_OF_MATCH("ti,twl6030-vana", VANA), | ||
684 | TWLFIXED_OF_MATCH("ti,twl6030-vcxio", VCXIO), | ||
685 | TWLFIXED_OF_MATCH("ti,twl6030-vdac", VDAC), | ||
686 | TWLFIXED_OF_MATCH("ti,twl6030-vusb", VUSB), | ||
687 | TWLFIXED_OF_MATCH("ti,twl6030-v1v8", V1V8), | ||
688 | TWLFIXED_OF_MATCH("ti,twl6030-v2v1", V2V1), | ||
689 | TWLSMPS_OF_MATCH("ti,twl6032-smps3", SMPS3), | ||
690 | TWLSMPS_OF_MATCH("ti,twl6032-smps4", SMPS4), | ||
691 | TWLSMPS_OF_MATCH("ti,twl6032-vio", VIO), | ||
692 | {}, | ||
693 | }; | ||
694 | MODULE_DEVICE_TABLE(of, twl_of_match); | ||
695 | |||
696 | static int twlreg_probe(struct platform_device *pdev) | ||
697 | { | ||
698 | int id; | ||
699 | struct twlreg_info *info; | ||
700 | const struct twlreg_info *template; | ||
701 | struct regulator_init_data *initdata; | ||
702 | struct regulation_constraints *c; | ||
703 | struct regulator_dev *rdev; | ||
704 | const struct of_device_id *match; | ||
705 | struct regulator_config config = { }; | ||
706 | |||
707 | match = of_match_device(twl_of_match, &pdev->dev); | ||
708 | if (!match) | ||
709 | return -ENODEV; | ||
710 | |||
711 | template = match->data; | ||
712 | if (!template) | ||
713 | return -ENODEV; | ||
714 | |||
715 | id = template->desc.id; | ||
716 | initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, | ||
717 | &template->desc); | ||
718 | if (!initdata) | ||
719 | return -EINVAL; | ||
720 | |||
721 | info = devm_kmemdup(&pdev->dev, template, sizeof(*info), GFP_KERNEL); | ||
722 | if (!info) | ||
723 | return -ENOMEM; | ||
724 | |||
725 | /* Constrain board-specific capabilities according to what | ||
726 | * this driver and the chip itself can actually do. | ||
727 | */ | ||
728 | c = &initdata->constraints; | ||
729 | c->valid_modes_mask &= REGULATOR_MODE_NORMAL | REGULATOR_MODE_STANDBY; | ||
730 | c->valid_ops_mask &= REGULATOR_CHANGE_VOLTAGE | ||
731 | | REGULATOR_CHANGE_MODE | ||
732 | | REGULATOR_CHANGE_STATUS; | ||
733 | |||
734 | switch (id) { | ||
735 | case TWL6032_REG_SMPS3: | ||
736 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS3) | ||
737 | info->flags |= SMPS_EXTENDED_EN; | ||
738 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS3) | ||
739 | info->flags |= SMPS_OFFSET_EN; | ||
740 | break; | ||
741 | case TWL6032_REG_SMPS4: | ||
742 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_SMPS4) | ||
743 | info->flags |= SMPS_EXTENDED_EN; | ||
744 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_SMPS4) | ||
745 | info->flags |= SMPS_OFFSET_EN; | ||
746 | break; | ||
747 | case TWL6032_REG_VIO: | ||
748 | if (twl_get_smps_mult() & SMPS_MULTOFFSET_VIO) | ||
749 | info->flags |= SMPS_EXTENDED_EN; | ||
750 | if (twl_get_smps_offset() & SMPS_MULTOFFSET_VIO) | ||
751 | info->flags |= SMPS_OFFSET_EN; | ||
752 | break; | ||
753 | } | ||
754 | |||
755 | config.dev = &pdev->dev; | ||
756 | config.init_data = initdata; | ||
757 | config.driver_data = info; | ||
758 | config.of_node = pdev->dev.of_node; | ||
759 | |||
760 | rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); | ||
761 | if (IS_ERR(rdev)) { | ||
762 | dev_err(&pdev->dev, "can't register %s, %ld\n", | ||
763 | info->desc.name, PTR_ERR(rdev)); | ||
764 | return PTR_ERR(rdev); | ||
765 | } | ||
766 | platform_set_drvdata(pdev, rdev); | ||
767 | |||
768 | /* NOTE: many regulators support short-circuit IRQs (presentable | ||
769 | * as REGULATOR_OVER_CURRENT notifications?) configured via: | ||
770 | * - SC_CONFIG | ||
771 | * - SC_DETECT1 (vintana2, vmmc1/2, vaux1/2/3/4) | ||
772 | * - SC_DETECT2 (vusb, vdac, vio, vdd1/2, vpll2) | ||
773 | * - IT_CONFIG | ||
774 | */ | ||
775 | |||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | MODULE_ALIAS("platform:twl6030_reg"); | ||
780 | |||
781 | static struct platform_driver twlreg_driver = { | ||
782 | .probe = twlreg_probe, | ||
783 | /* NOTE: short name, to work around driver model truncation of | ||
784 | * "twl_regulator.12" (and friends) to "twl_regulator.1". | ||
785 | */ | ||
786 | .driver = { | ||
787 | .name = "twl6030_reg", | ||
788 | .of_match_table = of_match_ptr(twl_of_match), | ||
789 | }, | ||
790 | }; | ||
791 | |||
792 | static int __init twlreg_init(void) | ||
793 | { | ||
794 | return platform_driver_register(&twlreg_driver); | ||
795 | } | ||
796 | subsys_initcall(twlreg_init); | ||
797 | |||
798 | static void __exit twlreg_exit(void) | ||
799 | { | ||
800 | platform_driver_unregister(&twlreg_driver); | ||
801 | } | ||
802 | module_exit(twlreg_exit) | ||
803 | |||
804 | MODULE_DESCRIPTION("TWL6030 regulator driver"); | ||
805 | MODULE_LICENSE("GPL"); | ||