aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Walmsley <paul@pwsan.com>2013-01-26 02:58:16 -0500
committerPaul Walmsley <paul@pwsan.com>2013-01-29 16:59:57 -0500
commit3a090284056954f382612da42ebe9f3147403ef5 (patch)
tree6e9627679444b04614577cf55ad77f8e17aed0b9 /arch
parentc4978fba6b2d4e3a584d72c067a371871fecbedc (diff)
ARM: OMAP2+: powerdomain/clockdomain: add a per-powerdomain spinlock
Add a per-powerdomain spinlock. Use that instead of the clockdomain spinlock. Add pwrdm_lock()/pwrdm_unlock() functions to allow other code to acquire or release the powerdomain spinlock without reaching directly into the struct powerdomain. Signed-off-by: Paul Walmsley <paul@pwsan.com> Cc: Jean Pihet <jean.pihet@newoldbits.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c172
-rw-r--r--arch/arm/mach-omap2/clockdomain.h6
-rw-r--r--arch/arm/mach-omap2/powerdomain.c60
-rw-r--r--arch/arm/mach-omap2/powerdomain.h11
4 files changed, 176 insertions, 73 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index f0ec51497ce2..275bdfbb6fc5 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -92,8 +92,6 @@ static int _clkdm_register(struct clockdomain *clkdm)
92 92
93 pwrdm_add_clkdm(pwrdm, clkdm); 93 pwrdm_add_clkdm(pwrdm, clkdm);
94 94
95 spin_lock_init(&clkdm->lock);
96
97 pr_debug("clockdomain: registered %s\n", clkdm->name); 95 pr_debug("clockdomain: registered %s\n", clkdm->name);
98 96
99 return 0; 97 return 0;
@@ -734,18 +732,17 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
734} 732}
735 733
736/** 734/**
737 * clkdm_sleep - force clockdomain sleep transition 735 * clkdm_sleep_nolock - force clockdomain sleep transition (lockless)
738 * @clkdm: struct clockdomain * 736 * @clkdm: struct clockdomain *
739 * 737 *
740 * Instruct the CM to force a sleep transition on the specified 738 * Instruct the CM to force a sleep transition on the specified
741 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if 739 * clockdomain @clkdm. Only for use by the powerdomain code. Returns
742 * clockdomain does not support software-initiated sleep; 0 upon 740 * -EINVAL if @clkdm is NULL or if clockdomain does not support
743 * success. 741 * software-initiated sleep; 0 upon success.
744 */ 742 */
745int clkdm_sleep(struct clockdomain *clkdm) 743int clkdm_sleep_nolock(struct clockdomain *clkdm)
746{ 744{
747 int ret; 745 int ret;
748 unsigned long flags;
749 746
750 if (!clkdm) 747 if (!clkdm)
751 return -EINVAL; 748 return -EINVAL;
@@ -761,27 +758,45 @@ int clkdm_sleep(struct clockdomain *clkdm)
761 758
762 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 759 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
763 760
764 spin_lock_irqsave(&clkdm->lock, flags);
765 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 761 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
766 ret = arch_clkdm->clkdm_sleep(clkdm); 762 ret = arch_clkdm->clkdm_sleep(clkdm);
767 ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); 763 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
768 spin_unlock_irqrestore(&clkdm->lock, flags); 764
769 return ret; 765 return ret;
770} 766}
771 767
772/** 768/**
773 * clkdm_wakeup - force clockdomain wakeup transition 769 * clkdm_sleep - force clockdomain sleep transition
774 * @clkdm: struct clockdomain * 770 * @clkdm: struct clockdomain *
775 * 771 *
776 * Instruct the CM to force a wakeup transition on the specified 772 * Instruct the CM to force a sleep transition on the specified
777 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the 773 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if
778 * clockdomain does not support software-controlled wakeup; 0 upon 774 * clockdomain does not support software-initiated sleep; 0 upon
779 * success. 775 * success.
780 */ 776 */
781int clkdm_wakeup(struct clockdomain *clkdm) 777int clkdm_sleep(struct clockdomain *clkdm)
778{
779 int ret;
780
781 pwrdm_lock(clkdm->pwrdm.ptr);
782 ret = clkdm_sleep_nolock(clkdm);
783 pwrdm_unlock(clkdm->pwrdm.ptr);
784
785 return ret;
786}
787
788/**
789 * clkdm_wakeup_nolock - force clockdomain wakeup transition (lockless)
790 * @clkdm: struct clockdomain *
791 *
792 * Instruct the CM to force a wakeup transition on the specified
793 * clockdomain @clkdm. Only for use by the powerdomain code. Returns
794 * -EINVAL if @clkdm is NULL or if the clockdomain does not support
795 * software-controlled wakeup; 0 upon success.
796 */
797int clkdm_wakeup_nolock(struct clockdomain *clkdm)
782{ 798{
783 int ret; 799 int ret;
784 unsigned long flags;
785 800
786 if (!clkdm) 801 if (!clkdm)
787 return -EINVAL; 802 return -EINVAL;
@@ -797,28 +812,46 @@ int clkdm_wakeup(struct clockdomain *clkdm)
797 812
798 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 813 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
799 814
800 spin_lock_irqsave(&clkdm->lock, flags);
801 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 815 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
802 ret = arch_clkdm->clkdm_wakeup(clkdm); 816 ret = arch_clkdm->clkdm_wakeup(clkdm);
803 ret |= pwrdm_state_switch(clkdm->pwrdm.ptr); 817 ret |= pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
804 spin_unlock_irqrestore(&clkdm->lock, flags); 818
805 return ret; 819 return ret;
806} 820}
807 821
808/** 822/**
809 * clkdm_allow_idle - enable hwsup idle transitions for clkdm 823 * clkdm_wakeup - force clockdomain wakeup transition
810 * @clkdm: struct clockdomain * 824 * @clkdm: struct clockdomain *
811 * 825 *
812 * Allow the hardware to automatically switch the clockdomain @clkdm into 826 * Instruct the CM to force a wakeup transition on the specified
813 * active or idle states, as needed by downstream clocks. If the 827 * clockdomain @clkdm. Returns -EINVAL if @clkdm is NULL or if the
828 * clockdomain does not support software-controlled wakeup; 0 upon
829 * success.
830 */
831int clkdm_wakeup(struct clockdomain *clkdm)
832{
833 int ret;
834
835 pwrdm_lock(clkdm->pwrdm.ptr);
836 ret = clkdm_wakeup_nolock(clkdm);
837 pwrdm_unlock(clkdm->pwrdm.ptr);
838
839 return ret;
840}
841
842/**
843 * clkdm_allow_idle_nolock - enable hwsup idle transitions for clkdm
844 * @clkdm: struct clockdomain *
845 *
846 * Allow the hardware to automatically switch the clockdomain @clkdm
847 * into active or idle states, as needed by downstream clocks. If the
814 * clockdomain has any downstream clocks enabled in the clock 848 * clockdomain has any downstream clocks enabled in the clock
815 * framework, wkdep/sleepdep autodependencies are added; this is so 849 * framework, wkdep/sleepdep autodependencies are added; this is so
816 * device drivers can read and write to the device. No return value. 850 * device drivers can read and write to the device. Only for use by
851 * the powerdomain code. No return value.
817 */ 852 */
818void clkdm_allow_idle(struct clockdomain *clkdm) 853void clkdm_allow_idle_nolock(struct clockdomain *clkdm)
819{ 854{
820 unsigned long flags;
821
822 if (!clkdm) 855 if (!clkdm)
823 return; 856 return;
824 857
@@ -834,11 +867,26 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
834 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 867 pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
835 clkdm->name); 868 clkdm->name);
836 869
837 spin_lock_irqsave(&clkdm->lock, flags);
838 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; 870 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
839 arch_clkdm->clkdm_allow_idle(clkdm); 871 arch_clkdm->clkdm_allow_idle(clkdm);
840 pwrdm_state_switch(clkdm->pwrdm.ptr); 872 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
841 spin_unlock_irqrestore(&clkdm->lock, flags); 873}
874
875/**
876 * clkdm_allow_idle - enable hwsup idle transitions for clkdm
877 * @clkdm: struct clockdomain *
878 *
879 * Allow the hardware to automatically switch the clockdomain @clkdm into
880 * active or idle states, as needed by downstream clocks. If the
881 * clockdomain has any downstream clocks enabled in the clock
882 * framework, wkdep/sleepdep autodependencies are added; this is so
883 * device drivers can read and write to the device. No return value.
884 */
885void clkdm_allow_idle(struct clockdomain *clkdm)
886{
887 pwrdm_lock(clkdm->pwrdm.ptr);
888 clkdm_allow_idle_nolock(clkdm);
889 pwrdm_unlock(clkdm->pwrdm.ptr);
842} 890}
843 891
844/** 892/**
@@ -848,12 +896,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
848 * Prevent the hardware from automatically switching the clockdomain 896 * Prevent the hardware from automatically switching the clockdomain
849 * @clkdm into inactive or idle states. If the clockdomain has 897 * @clkdm into inactive or idle states. If the clockdomain has
850 * downstream clocks enabled in the clock framework, wkdep/sleepdep 898 * downstream clocks enabled in the clock framework, wkdep/sleepdep
851 * autodependencies are removed. No return value. 899 * autodependencies are removed. Only for use by the powerdomain
900 * code. No return value.
852 */ 901 */
853void clkdm_deny_idle(struct clockdomain *clkdm) 902void clkdm_deny_idle_nolock(struct clockdomain *clkdm)
854{ 903{
855 unsigned long flags;
856
857 if (!clkdm) 904 if (!clkdm)
858 return; 905 return;
859 906
@@ -869,11 +916,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
869 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 916 pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
870 clkdm->name); 917 clkdm->name);
871 918
872 spin_lock_irqsave(&clkdm->lock, flags);
873 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 919 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
874 arch_clkdm->clkdm_deny_idle(clkdm); 920 arch_clkdm->clkdm_deny_idle(clkdm);
875 pwrdm_state_switch(clkdm->pwrdm.ptr); 921 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
876 spin_unlock_irqrestore(&clkdm->lock, flags); 922}
923
924/**
925 * clkdm_deny_idle - disable hwsup idle transitions for clkdm
926 * @clkdm: struct clockdomain *
927 *
928 * Prevent the hardware from automatically switching the clockdomain
929 * @clkdm into inactive or idle states. If the clockdomain has
930 * downstream clocks enabled in the clock framework, wkdep/sleepdep
931 * autodependencies are removed. No return value.
932 */
933void clkdm_deny_idle(struct clockdomain *clkdm)
934{
935 pwrdm_lock(clkdm->pwrdm.ptr);
936 clkdm_deny_idle_nolock(clkdm);
937 pwrdm_unlock(clkdm->pwrdm.ptr);
877} 938}
878 939
879/** 940/**
@@ -890,14 +951,11 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
890bool clkdm_in_hwsup(struct clockdomain *clkdm) 951bool clkdm_in_hwsup(struct clockdomain *clkdm)
891{ 952{
892 bool ret; 953 bool ret;
893 unsigned long flags;
894 954
895 if (!clkdm) 955 if (!clkdm)
896 return false; 956 return false;
897 957
898 spin_lock_irqsave(&clkdm->lock, flags);
899 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; 958 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
900 spin_unlock_irqrestore(&clkdm->lock, flags);
901 959
902 return ret; 960 return ret;
903} 961}
@@ -923,12 +981,10 @@ bool clkdm_missing_idle_reporting(struct clockdomain *clkdm)
923 981
924static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) 982static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
925{ 983{
926 unsigned long flags;
927
928 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) 984 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
929 return -EINVAL; 985 return -EINVAL;
930 986
931 spin_lock_irqsave(&clkdm->lock, flags); 987 pwrdm_lock(clkdm->pwrdm.ptr);
932 988
933 /* 989 /*
934 * For arch's with no autodeps, clkcm_clk_enable 990 * For arch's with no autodeps, clkcm_clk_enable
@@ -936,13 +992,13 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
936 * enabled, so the clkdm can be force woken up. 992 * enabled, so the clkdm can be force woken up.
937 */ 993 */
938 if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { 994 if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) {
939 spin_unlock_irqrestore(&clkdm->lock, flags); 995 pwrdm_unlock(clkdm->pwrdm.ptr);
940 return 0; 996 return 0;
941 } 997 }
942 998
943 arch_clkdm->clkdm_clk_enable(clkdm); 999 arch_clkdm->clkdm_clk_enable(clkdm);
944 pwrdm_state_switch(clkdm->pwrdm.ptr); 1000 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
945 spin_unlock_irqrestore(&clkdm->lock, flags); 1001 pwrdm_unlock(clkdm->pwrdm.ptr);
946 1002
947 pr_debug("clockdomain: %s: enabled\n", clkdm->name); 1003 pr_debug("clockdomain: %s: enabled\n", clkdm->name);
948 1004
@@ -991,12 +1047,10 @@ int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
991 */ 1047 */
992int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk) 1048int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
993{ 1049{
994 unsigned long flags;
995
996 if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1050 if (!clkdm || !clk || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
997 return -EINVAL; 1051 return -EINVAL;
998 1052
999 spin_lock_irqsave(&clkdm->lock, flags); 1053 pwrdm_lock(clkdm->pwrdm.ptr);
1000 1054
1001 /* corner case: disabling unused clocks */ 1055 /* corner case: disabling unused clocks */
1002 if ((__clk_get_enable_count(clk) == 0) && 1056 if ((__clk_get_enable_count(clk) == 0) &&
@@ -1004,23 +1058,23 @@ int clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
1004 goto ccd_exit; 1058 goto ccd_exit;
1005 1059
1006 if (atomic_read(&clkdm->usecount) == 0) { 1060 if (atomic_read(&clkdm->usecount) == 0) {
1007 spin_unlock_irqrestore(&clkdm->lock, flags); 1061 pwrdm_unlock(clkdm->pwrdm.ptr);
1008 WARN_ON(1); /* underflow */ 1062 WARN_ON(1); /* underflow */
1009 return -ERANGE; 1063 return -ERANGE;
1010 } 1064 }
1011 1065
1012 if (atomic_dec_return(&clkdm->usecount) > 0) { 1066 if (atomic_dec_return(&clkdm->usecount) > 0) {
1013 spin_unlock_irqrestore(&clkdm->lock, flags); 1067 pwrdm_unlock(clkdm->pwrdm.ptr);
1014 return 0; 1068 return 0;
1015 } 1069 }
1016 1070
1017 arch_clkdm->clkdm_clk_disable(clkdm); 1071 arch_clkdm->clkdm_clk_disable(clkdm);
1018 pwrdm_state_switch(clkdm->pwrdm.ptr); 1072 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
1019 1073
1020 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1074 pr_debug("clockdomain: %s: disabled\n", clkdm->name);
1021 1075
1022ccd_exit: 1076ccd_exit:
1023 spin_unlock_irqrestore(&clkdm->lock, flags); 1077 pwrdm_unlock(clkdm->pwrdm.ptr);
1024 1078
1025 return 0; 1079 return 0;
1026} 1080}
@@ -1073,8 +1127,6 @@ int clkdm_hwmod_enable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1073 */ 1127 */
1074int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh) 1128int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1075{ 1129{
1076 unsigned long flags;
1077
1078 /* The clkdm attribute does not exist yet prior OMAP4 */ 1130 /* The clkdm attribute does not exist yet prior OMAP4 */
1079 if (cpu_is_omap24xx() || cpu_is_omap34xx()) 1131 if (cpu_is_omap24xx() || cpu_is_omap34xx())
1080 return 0; 1132 return 0;
@@ -1087,22 +1139,22 @@ int clkdm_hwmod_disable(struct clockdomain *clkdm, struct omap_hwmod *oh)
1087 if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 1139 if (!clkdm || !oh || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
1088 return -EINVAL; 1140 return -EINVAL;
1089 1141
1090 spin_lock_irqsave(&clkdm->lock, flags); 1142 pwrdm_lock(clkdm->pwrdm.ptr);
1091 1143
1092 if (atomic_read(&clkdm->usecount) == 0) { 1144 if (atomic_read(&clkdm->usecount) == 0) {
1093 spin_unlock_irqrestore(&clkdm->lock, flags); 1145 pwrdm_unlock(clkdm->pwrdm.ptr);
1094 WARN_ON(1); /* underflow */ 1146 WARN_ON(1); /* underflow */
1095 return -ERANGE; 1147 return -ERANGE;
1096 } 1148 }
1097 1149
1098 if (atomic_dec_return(&clkdm->usecount) > 0) { 1150 if (atomic_dec_return(&clkdm->usecount) > 0) {
1099 spin_unlock_irqrestore(&clkdm->lock, flags); 1151 pwrdm_unlock(clkdm->pwrdm.ptr);
1100 return 0; 1152 return 0;
1101 } 1153 }
1102 1154
1103 arch_clkdm->clkdm_clk_disable(clkdm); 1155 arch_clkdm->clkdm_clk_disable(clkdm);
1104 pwrdm_state_switch(clkdm->pwrdm.ptr); 1156 pwrdm_state_switch_nolock(clkdm->pwrdm.ptr);
1105 spin_unlock_irqrestore(&clkdm->lock, flags); 1157 pwrdm_unlock(clkdm->pwrdm.ptr);
1106 1158
1107 pr_debug("clockdomain: %s: disabled\n", clkdm->name); 1159 pr_debug("clockdomain: %s: disabled\n", clkdm->name);
1108 1160
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index bc42446e23ab..e7f1b4ba2d5b 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -15,7 +15,6 @@
15#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H 15#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
16 16
17#include <linux/init.h> 17#include <linux/init.h>
18#include <linux/spinlock.h>
19 18
20#include "powerdomain.h" 19#include "powerdomain.h"
21#include "clock.h" 20#include "clock.h"
@@ -139,7 +138,6 @@ struct clockdomain {
139 struct clkdm_dep *sleepdep_srcs; 138 struct clkdm_dep *sleepdep_srcs;
140 atomic_t usecount; 139 atomic_t usecount;
141 struct list_head node; 140 struct list_head node;
142 spinlock_t lock;
143}; 141};
144 142
145/** 143/**
@@ -196,12 +194,16 @@ int clkdm_del_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
196int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2); 194int clkdm_read_sleepdep(struct clockdomain *clkdm1, struct clockdomain *clkdm2);
197int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm); 195int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm);
198 196
197void clkdm_allow_idle_nolock(struct clockdomain *clkdm);
199void clkdm_allow_idle(struct clockdomain *clkdm); 198void clkdm_allow_idle(struct clockdomain *clkdm);
199void clkdm_deny_idle_nolock(struct clockdomain *clkdm);
200void clkdm_deny_idle(struct clockdomain *clkdm); 200void clkdm_deny_idle(struct clockdomain *clkdm);
201bool clkdm_in_hwsup(struct clockdomain *clkdm); 201bool clkdm_in_hwsup(struct clockdomain *clkdm);
202bool clkdm_missing_idle_reporting(struct clockdomain *clkdm); 202bool clkdm_missing_idle_reporting(struct clockdomain *clkdm);
203 203
204int clkdm_wakeup_nolock(struct clockdomain *clkdm);
204int clkdm_wakeup(struct clockdomain *clkdm); 205int clkdm_wakeup(struct clockdomain *clkdm);
206int clkdm_sleep_nolock(struct clockdomain *clkdm);
205int clkdm_sleep(struct clockdomain *clkdm); 207int clkdm_sleep(struct clockdomain *clkdm);
206 208
207int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk); 209int clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 65c34645c8ed..8e61d80bf6b3 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -19,6 +19,7 @@
19#include <linux/list.h> 19#include <linux/list.h>
20#include <linux/errno.h> 20#include <linux/errno.h>
21#include <linux/string.h> 21#include <linux/string.h>
22#include <linux/spinlock.h>
22#include <trace/events/power.h> 23#include <trace/events/power.h>
23 24
24#include "cm2xxx_3xxx.h" 25#include "cm2xxx_3xxx.h"
@@ -111,6 +112,7 @@ static int _pwrdm_register(struct powerdomain *pwrdm)
111 pwrdm->voltdm.ptr = voltdm; 112 pwrdm->voltdm.ptr = voltdm;
112 INIT_LIST_HEAD(&pwrdm->voltdm_node); 113 INIT_LIST_HEAD(&pwrdm->voltdm_node);
113 voltdm_add_pwrdm(voltdm, pwrdm); 114 voltdm_add_pwrdm(voltdm, pwrdm);
115 spin_lock_init(&pwrdm->_lock);
114 116
115 list_add(&pwrdm->node, &pwrdm_list); 117 list_add(&pwrdm->node, &pwrdm_list);
116 118
@@ -241,7 +243,7 @@ static u8 _pwrdm_save_clkdm_state_and_activate(struct powerdomain *pwrdm,
241 sleep_switch = LOWPOWERSTATE_SWITCH; 243 sleep_switch = LOWPOWERSTATE_SWITCH;
242 } else { 244 } else {
243 *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]); 245 *hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
244 clkdm_wakeup(pwrdm->pwrdm_clkdms[0]); 246 clkdm_wakeup_nolock(pwrdm->pwrdm_clkdms[0]);
245 sleep_switch = FORCEWAKEUP_SWITCH; 247 sleep_switch = FORCEWAKEUP_SWITCH;
246 } 248 }
247 } else { 249 } else {
@@ -271,15 +273,15 @@ static void _pwrdm_restore_clkdm_state(struct powerdomain *pwrdm,
271 switch (sleep_switch) { 273 switch (sleep_switch) {
272 case FORCEWAKEUP_SWITCH: 274 case FORCEWAKEUP_SWITCH:
273 if (hwsup) 275 if (hwsup)
274 clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]); 276 clkdm_allow_idle_nolock(pwrdm->pwrdm_clkdms[0]);
275 else 277 else
276 clkdm_sleep(pwrdm->pwrdm_clkdms[0]); 278 clkdm_sleep_nolock(pwrdm->pwrdm_clkdms[0]);
277 break; 279 break;
278 case LOWPOWERSTATE_SWITCH: 280 case LOWPOWERSTATE_SWITCH:
279 if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE && 281 if (pwrdm->flags & PWRDM_HAS_LOWPOWERSTATECHANGE &&
280 arch_pwrdm->pwrdm_set_lowpwrstchange) 282 arch_pwrdm->pwrdm_set_lowpwrstchange)
281 arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm); 283 arch_pwrdm->pwrdm_set_lowpwrstchange(pwrdm);
282 pwrdm_state_switch(pwrdm); 284 pwrdm_state_switch_nolock(pwrdm);
283 break; 285 break;
284 } 286 }
285} 287}
@@ -360,6 +362,30 @@ int pwrdm_complete_init(void)
360} 362}
361 363
362/** 364/**
365 * pwrdm_lock - acquire a Linux spinlock on a powerdomain
366 * @pwrdm: struct powerdomain * to lock
367 *
368 * Acquire the powerdomain spinlock on @pwrdm. No return value.
369 */
370void pwrdm_lock(struct powerdomain *pwrdm)
371 __acquires(&pwrdm->_lock)
372{
373 spin_lock_irqsave(&pwrdm->_lock, pwrdm->_lock_flags);
374}
375
376/**
377 * pwrdm_unlock - release a Linux spinlock on a powerdomain
378 * @pwrdm: struct powerdomain * to unlock
379 *
380 * Release the powerdomain spinlock on @pwrdm. No return value.
381 */
382void pwrdm_unlock(struct powerdomain *pwrdm)
383 __releases(&pwrdm->_lock)
384{
385 spin_unlock_irqrestore(&pwrdm->_lock, pwrdm->_lock_flags);
386}
387
388/**
363 * pwrdm_lookup - look up a powerdomain by name, return a pointer 389 * pwrdm_lookup - look up a powerdomain by name, return a pointer
364 * @name: name of powerdomain 390 * @name: name of powerdomain
365 * 391 *
@@ -1005,7 +1031,7 @@ bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm)
1005 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0; 1031 return (pwrdm && pwrdm->flags & PWRDM_HAS_HDWR_SAR) ? 1 : 0;
1006} 1032}
1007 1033
1008int pwrdm_state_switch(struct powerdomain *pwrdm) 1034int pwrdm_state_switch_nolock(struct powerdomain *pwrdm)
1009{ 1035{
1010 int ret; 1036 int ret;
1011 1037
@@ -1019,6 +1045,17 @@ int pwrdm_state_switch(struct powerdomain *pwrdm)
1019 return ret; 1045 return ret;
1020} 1046}
1021 1047
1048int __deprecated pwrdm_state_switch(struct powerdomain *pwrdm)
1049{
1050 int ret;
1051
1052 pwrdm_lock(pwrdm);
1053 ret = pwrdm_state_switch_nolock(pwrdm);
1054 pwrdm_unlock(pwrdm);
1055
1056 return ret;
1057}
1058
1022int pwrdm_pre_transition(struct powerdomain *pwrdm) 1059int pwrdm_pre_transition(struct powerdomain *pwrdm)
1023{ 1060{
1024 if (pwrdm) 1061 if (pwrdm)
@@ -1067,15 +1104,19 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
1067 pwrst--; 1104 pwrst--;
1068 } 1105 }
1069 1106
1107 pwrdm_lock(pwrdm);
1108
1070 curr_pwrst = pwrdm_read_pwrst(pwrdm); 1109 curr_pwrst = pwrdm_read_pwrst(pwrdm);
1071 next_pwrst = pwrdm_read_next_pwrst(pwrdm); 1110 next_pwrst = pwrdm_read_next_pwrst(pwrdm);
1072 if (curr_pwrst == pwrst && next_pwrst == pwrst) 1111 if (curr_pwrst == pwrst && next_pwrst == pwrst)
1073 return ret; 1112 goto osps_out;
1074 1113
1075 sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst, 1114 sleep_switch = _pwrdm_save_clkdm_state_and_activate(pwrdm, curr_pwrst,
1076 pwrst, &hwsup); 1115 pwrst, &hwsup);
1077 if (sleep_switch == ERROR_SWITCH) 1116 if (sleep_switch == ERROR_SWITCH) {
1078 return -EINVAL; 1117 ret = -EINVAL;
1118 goto osps_out;
1119 }
1079 1120
1080 ret = pwrdm_set_next_pwrst(pwrdm, pwrst); 1121 ret = pwrdm_set_next_pwrst(pwrdm, pwrst);
1081 if (ret) 1122 if (ret)
@@ -1084,6 +1125,9 @@ int omap_set_pwrdm_state(struct powerdomain *pwrdm, u8 pwrst)
1084 1125
1085 _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup); 1126 _pwrdm_restore_clkdm_state(pwrdm, sleep_switch, hwsup);
1086 1127
1128osps_out:
1129 pwrdm_unlock(pwrdm);
1130
1087 return ret; 1131 return ret;
1088} 1132}
1089 1133
diff --git a/arch/arm/mach-omap2/powerdomain.h b/arch/arm/mach-omap2/powerdomain.h
index 93e7df824650..909cc5c1c23a 100644
--- a/arch/arm/mach-omap2/powerdomain.h
+++ b/arch/arm/mach-omap2/powerdomain.h
@@ -19,8 +19,7 @@
19 19
20#include <linux/types.h> 20#include <linux/types.h>
21#include <linux/list.h> 21#include <linux/list.h>
22 22#include <linux/spinlock.h>
23#include <linux/atomic.h>
24 23
25#include "voltage.h" 24#include "voltage.h"
26 25
@@ -103,6 +102,8 @@ struct powerdomain;
103 * @state_counter: 102 * @state_counter:
104 * @timer: 103 * @timer:
105 * @state_timer: 104 * @state_timer:
105 * @_lock: spinlock used to serialize powerdomain and some clockdomain ops
106 * @_lock_flags: stored flags when @_lock is taken
106 * 107 *
107 * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h. 108 * @prcm_partition possible values are defined in mach-omap2/prcm44xx.h.
108 */ 109 */
@@ -127,7 +128,8 @@ struct powerdomain {
127 unsigned state_counter[PWRDM_MAX_PWRSTS]; 128 unsigned state_counter[PWRDM_MAX_PWRSTS];
128 unsigned ret_logic_off_counter; 129 unsigned ret_logic_off_counter;
129 unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS]; 130 unsigned ret_mem_off_counter[PWRDM_MAX_MEM_BANKS];
130 131 spinlock_t _lock;
132 unsigned long _lock_flags;
131 const u8 pwrstctrl_offs; 133 const u8 pwrstctrl_offs;
132 const u8 pwrstst_offs; 134 const u8 pwrstst_offs;
133 const u32 logicretstate_mask; 135 const u32 logicretstate_mask;
@@ -235,6 +237,7 @@ int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
235int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm); 237int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
236bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm); 238bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
237 239
240int pwrdm_state_switch_nolock(struct powerdomain *pwrdm);
238int pwrdm_state_switch(struct powerdomain *pwrdm); 241int pwrdm_state_switch(struct powerdomain *pwrdm);
239int pwrdm_pre_transition(struct powerdomain *pwrdm); 242int pwrdm_pre_transition(struct powerdomain *pwrdm);
240int pwrdm_post_transition(struct powerdomain *pwrdm); 243int pwrdm_post_transition(struct powerdomain *pwrdm);
@@ -262,5 +265,7 @@ extern u32 omap2_pwrdm_get_mem_bank_stst_mask(u8 bank);
262extern struct powerdomain wkup_omap2_pwrdm; 265extern struct powerdomain wkup_omap2_pwrdm;
263extern struct powerdomain gfx_omap2_pwrdm; 266extern struct powerdomain gfx_omap2_pwrdm;
264 267
268extern void pwrdm_lock(struct powerdomain *pwrdm);
269extern void pwrdm_unlock(struct powerdomain *pwrdm);
265 270
266#endif 271#endif