~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/mips/alchemy/devboards/pm.c

Version: ~ [ linux-5.2-rc4 ] ~ [ linux-5.1.9 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.50 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.125 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.181 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.181 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.68 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Alchemy Development Board example suspend userspace interface.
  3  *
  4  * (c) 2008 Manuel Lauss <mano@roarinelk.homelinux.net>
  5  */
  6 
  7 #include <linux/init.h>
  8 #include <linux/kobject.h>
  9 #include <linux/suspend.h>
 10 #include <linux/sysfs.h>
 11 #include <asm/mach-au1x00/au1000.h>
 12 #include <asm/mach-au1x00/gpio-au1000.h>
 13 #include <asm/mach-db1x00/bcsr.h>
 14 
 15 /*
 16  * Generic suspend userspace interface for Alchemy development boards.
 17  * This code exports a few sysfs nodes under /sys/power/db1x/ which
 18  * can be used by userspace to en/disable all au1x-provided wakeup
 19  * sources and configure the timeout after which the the TOYMATCH2 irq
 20  * is to trigger a wakeup.
 21  */
 22 
 23 
 24 static unsigned long db1x_pm_sleep_secs;
 25 static unsigned long db1x_pm_wakemsk;
 26 static unsigned long db1x_pm_last_wakesrc;
 27 
 28 static int db1x_pm_enter(suspend_state_t state)
 29 {
 30         unsigned short bcsrs[16];
 31         int i, j, hasint;
 32 
 33         /* save CPLD regs */
 34         hasint = bcsr_read(BCSR_WHOAMI);
 35         hasint = BCSR_WHOAMI_BOARD(hasint) >= BCSR_WHOAMI_DB1200;
 36         j = (hasint) ? BCSR_MASKSET : BCSR_SYSTEM;
 37 
 38         for (i = BCSR_STATUS; i <= j; i++)
 39                 bcsrs[i] = bcsr_read(i);
 40 
 41         /* shut off hexleds */
 42         bcsr_write(BCSR_HEXCLEAR, 3);
 43 
 44         /* enable GPIO based wakeup */
 45         alchemy_gpio1_input_enable();
 46 
 47         /* clear and setup wake cause and source */
 48         alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
 49         alchemy_wrsys(0, AU1000_SYS_WAKESRC);
 50 
 51         alchemy_wrsys(db1x_pm_wakemsk, AU1000_SYS_WAKEMSK);
 52 
 53         /* setup 1Hz-timer-based wakeup: wait for reg access */
 54         while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
 55                 asm volatile ("nop");
 56 
 57         alchemy_wrsys(alchemy_rdsys(AU1000_SYS_TOYREAD) + db1x_pm_sleep_secs,
 58                       AU1000_SYS_TOYMATCH2);
 59 
 60         /* wait for value to really hit the register */
 61         while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
 62                 asm volatile ("nop");
 63 
 64         /* ...and now the sandman can come! */
 65         au_sleep();
 66 
 67 
 68         /* restore CPLD regs */
 69         for (i = BCSR_STATUS; i <= BCSR_SYSTEM; i++)
 70                 bcsr_write(i, bcsrs[i]);
 71 
 72         /* restore CPLD int registers */
 73         if (hasint) {
 74                 bcsr_write(BCSR_INTCLR, 0xffff);
 75                 bcsr_write(BCSR_MASKCLR, 0xffff);
 76                 bcsr_write(BCSR_INTSTAT, 0xffff);
 77                 bcsr_write(BCSR_INTSET, bcsrs[BCSR_INTSET]);
 78                 bcsr_write(BCSR_MASKSET, bcsrs[BCSR_MASKSET]);
 79         }
 80 
 81         /* light up hexleds */
 82         bcsr_write(BCSR_HEXCLEAR, 0);
 83 
 84         return 0;
 85 }
 86 
 87 static int db1x_pm_begin(suspend_state_t state)
 88 {
 89         if (!db1x_pm_wakemsk) {
 90                 printk(KERN_ERR "db1x: no wakeup source activated!\n");
 91                 return -EINVAL;
 92         }
 93 
 94         return 0;
 95 }
 96 
 97 static void db1x_pm_end(void)
 98 {
 99         /* read and store wakeup source, the clear the register. To
100          * be able to clear it, WAKEMSK must be cleared first.
101          */
102         db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
103 
104         alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
105         alchemy_wrsys(0, AU1000_SYS_WAKESRC);
106 }
107 
108 static const struct platform_suspend_ops db1x_pm_ops = {
109         .valid          = suspend_valid_only_mem,
110         .begin          = db1x_pm_begin,
111         .enter          = db1x_pm_enter,
112         .end            = db1x_pm_end,
113 };
114 
115 #define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
116 
117 static ssize_t db1x_pmattr_show(struct kobject *kobj,
118                                 struct kobj_attribute *attr,
119                                 char *buf)
120 {
121         int idx;
122 
123         if (ATTRCMP(timer_timeout))
124                 return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);
125 
126         else if (ATTRCMP(timer))
127                 return sprintf(buf, "%u\n",
128                                 !!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));
129 
130         else if (ATTRCMP(wakesrc))
131                 return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);
132 
133         else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
134                  ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
135                  ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
136                 idx = (attr->attr.name)[4] - '';
137                 return sprintf(buf, "%d\n",
138                         !!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));
139 
140         } else if (ATTRCMP(wakemsk)) {
141                 return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
142         }
143 
144         return -ENOENT;
145 }
146 
147 static ssize_t db1x_pmattr_store(struct kobject *kobj,
148                                  struct kobj_attribute *attr,
149                                  const char *instr,
150                                  size_t bytes)
151 {
152         unsigned long l;
153         int tmp;
154 
155         if (ATTRCMP(timer_timeout)) {
156                 tmp = kstrtoul(instr, 0, &l);
157                 if (tmp)
158                         return tmp;
159 
160                 db1x_pm_sleep_secs = l;
161 
162         } else if (ATTRCMP(timer)) {
163                 if (instr[0] != '')
164                         db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
165                 else
166                         db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;
167 
168         } else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
169                    ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
170                    ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
171                 tmp = (attr->attr.name)[4] - '';
172                 if (instr[0] != '') {
173                         db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
174                 } else {
175                         db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
176                 }
177 
178         } else if (ATTRCMP(wakemsk)) {
179                 tmp = kstrtoul(instr, 0, &l);
180                 if (tmp)
181                         return tmp;
182 
183                 db1x_pm_wakemsk = l & 0x0000003f;
184 
185         } else
186                 bytes = -ENOENT;
187 
188         return bytes;
189 }
190 
191 #define ATTR(x)                                                 \
192         static struct kobj_attribute x##_attribute =            \
193                 __ATTR(x, 0664, db1x_pmattr_show,               \
194                                 db1x_pmattr_store);
195 
196 ATTR(gpio0)             /* GPIO-based wakeup enable */
197 ATTR(gpio1)
198 ATTR(gpio2)
199 ATTR(gpio3)
200 ATTR(gpio4)
201 ATTR(gpio5)
202 ATTR(gpio6)
203 ATTR(gpio7)
204 ATTR(timer)             /* TOYMATCH2-based wakeup enable */
205 ATTR(timer_timeout)     /* timer-based wakeup timeout value, in seconds */
206 ATTR(wakesrc)           /* contents of SYS_WAKESRC after last wakeup */
207 ATTR(wakemsk)           /* direct access to SYS_WAKEMSK */
208 
209 #define ATTR_LIST(x)    & x ## _attribute.attr
210 static struct attribute *db1x_pmattrs[] = {
211         ATTR_LIST(gpio0),
212         ATTR_LIST(gpio1),
213         ATTR_LIST(gpio2),
214         ATTR_LIST(gpio3),
215         ATTR_LIST(gpio4),
216         ATTR_LIST(gpio5),
217         ATTR_LIST(gpio6),
218         ATTR_LIST(gpio7),
219         ATTR_LIST(timer),
220         ATTR_LIST(timer_timeout),
221         ATTR_LIST(wakesrc),
222         ATTR_LIST(wakemsk),
223         NULL,           /* terminator */
224 };
225 
226 static struct attribute_group db1x_pmattr_group = {
227         .name   = "db1x",
228         .attrs  = db1x_pmattrs,
229 };
230 
231 /*
232  * Initialize suspend interface
233  */
234 static int __init pm_init(void)
235 {
236         /* init TOY to tick at 1Hz if not already done. No need to wait
237          * for confirmation since there's plenty of time from here to
238          * the next suspend cycle.
239          */
240         if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767)
241                 alchemy_wrsys(32767, AU1000_SYS_TOYTRIM);
242 
243         db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
244 
245         alchemy_wrsys(0, AU1000_SYS_WAKESRC);
246         alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
247 
248         suspend_set_ops(&db1x_pm_ops);
249 
250         return sysfs_create_group(power_kobj, &db1x_pmattr_group);
251 }
252 
253 late_initcall(pm_init);
254 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp