0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/kobject.h>
0010 #include <linux/suspend.h>
0011 #include <linux/sysfs.h>
0012 #include <asm/mach-au1x00/au1000.h>
0013 #include <asm/mach-au1x00/gpio-au1000.h>
0014 #include <asm/mach-db1x00/bcsr.h>
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025 static unsigned long db1x_pm_sleep_secs;
0026 static unsigned long db1x_pm_wakemsk;
0027 static unsigned long db1x_pm_last_wakesrc;
0028
0029 static int db1x_pm_enter(suspend_state_t state)
0030 {
0031 unsigned short bcsrs[16];
0032 int i, j, hasint;
0033
0034
0035 hasint = bcsr_read(BCSR_WHOAMI);
0036 hasint = BCSR_WHOAMI_BOARD(hasint) >= BCSR_WHOAMI_DB1200;
0037 j = (hasint) ? BCSR_MASKSET : BCSR_SYSTEM;
0038
0039 for (i = BCSR_STATUS; i <= j; i++)
0040 bcsrs[i] = bcsr_read(i);
0041
0042
0043 bcsr_write(BCSR_HEXCLEAR, 3);
0044
0045
0046 alchemy_gpio1_input_enable();
0047
0048
0049 alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
0050 alchemy_wrsys(0, AU1000_SYS_WAKESRC);
0051
0052 alchemy_wrsys(db1x_pm_wakemsk, AU1000_SYS_WAKEMSK);
0053
0054
0055 while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
0056 asm volatile ("nop");
0057
0058 alchemy_wrsys(alchemy_rdsys(AU1000_SYS_TOYREAD) + db1x_pm_sleep_secs,
0059 AU1000_SYS_TOYMATCH2);
0060
0061
0062 while (alchemy_rdsys(AU1000_SYS_CNTRCTRL) & SYS_CNTRL_M20)
0063 asm volatile ("nop");
0064
0065
0066 au_sleep();
0067
0068
0069
0070 for (i = BCSR_STATUS; i <= BCSR_SYSTEM; i++)
0071 bcsr_write(i, bcsrs[i]);
0072
0073
0074 if (hasint) {
0075 bcsr_write(BCSR_INTCLR, 0xffff);
0076 bcsr_write(BCSR_MASKCLR, 0xffff);
0077 bcsr_write(BCSR_INTSTAT, 0xffff);
0078 bcsr_write(BCSR_INTSET, bcsrs[BCSR_INTSET]);
0079 bcsr_write(BCSR_MASKSET, bcsrs[BCSR_MASKSET]);
0080 }
0081
0082
0083 bcsr_write(BCSR_HEXCLEAR, 0);
0084
0085 return 0;
0086 }
0087
0088 static int db1x_pm_begin(suspend_state_t state)
0089 {
0090 if (!db1x_pm_wakemsk) {
0091 printk(KERN_ERR "db1x: no wakeup source activated!\n");
0092 return -EINVAL;
0093 }
0094
0095 return 0;
0096 }
0097
0098 static void db1x_pm_end(void)
0099 {
0100
0101
0102
0103 db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
0104
0105 alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
0106 alchemy_wrsys(0, AU1000_SYS_WAKESRC);
0107 }
0108
0109 static const struct platform_suspend_ops db1x_pm_ops = {
0110 .valid = suspend_valid_only_mem,
0111 .begin = db1x_pm_begin,
0112 .enter = db1x_pm_enter,
0113 .end = db1x_pm_end,
0114 };
0115
0116 #define ATTRCMP(x) (0 == strcmp(attr->attr.name, #x))
0117
0118 static ssize_t db1x_pmattr_show(struct kobject *kobj,
0119 struct kobj_attribute *attr,
0120 char *buf)
0121 {
0122 int idx;
0123
0124 if (ATTRCMP(timer_timeout))
0125 return sprintf(buf, "%lu\n", db1x_pm_sleep_secs);
0126
0127 else if (ATTRCMP(timer))
0128 return sprintf(buf, "%u\n",
0129 !!(db1x_pm_wakemsk & SYS_WAKEMSK_M2));
0130
0131 else if (ATTRCMP(wakesrc))
0132 return sprintf(buf, "%lu\n", db1x_pm_last_wakesrc);
0133
0134 else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
0135 ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
0136 ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
0137 idx = (attr->attr.name)[4] - '0';
0138 return sprintf(buf, "%d\n",
0139 !!(db1x_pm_wakemsk & SYS_WAKEMSK_GPIO(idx)));
0140
0141 } else if (ATTRCMP(wakemsk)) {
0142 return sprintf(buf, "%08lx\n", db1x_pm_wakemsk);
0143 }
0144
0145 return -ENOENT;
0146 }
0147
0148 static ssize_t db1x_pmattr_store(struct kobject *kobj,
0149 struct kobj_attribute *attr,
0150 const char *instr,
0151 size_t bytes)
0152 {
0153 unsigned long l;
0154 int tmp;
0155
0156 if (ATTRCMP(timer_timeout)) {
0157 tmp = kstrtoul(instr, 0, &l);
0158 if (tmp)
0159 return tmp;
0160
0161 db1x_pm_sleep_secs = l;
0162
0163 } else if (ATTRCMP(timer)) {
0164 if (instr[0] != '0')
0165 db1x_pm_wakemsk |= SYS_WAKEMSK_M2;
0166 else
0167 db1x_pm_wakemsk &= ~SYS_WAKEMSK_M2;
0168
0169 } else if (ATTRCMP(gpio0) || ATTRCMP(gpio1) || ATTRCMP(gpio2) ||
0170 ATTRCMP(gpio3) || ATTRCMP(gpio4) || ATTRCMP(gpio5) ||
0171 ATTRCMP(gpio6) || ATTRCMP(gpio7)) {
0172 tmp = (attr->attr.name)[4] - '0';
0173 if (instr[0] != '0') {
0174 db1x_pm_wakemsk |= SYS_WAKEMSK_GPIO(tmp);
0175 } else {
0176 db1x_pm_wakemsk &= ~SYS_WAKEMSK_GPIO(tmp);
0177 }
0178
0179 } else if (ATTRCMP(wakemsk)) {
0180 tmp = kstrtoul(instr, 0, &l);
0181 if (tmp)
0182 return tmp;
0183
0184 db1x_pm_wakemsk = l & 0x0000003f;
0185
0186 } else
0187 bytes = -ENOENT;
0188
0189 return bytes;
0190 }
0191
0192 #define ATTR(x) \
0193 static struct kobj_attribute x##_attribute = \
0194 __ATTR(x, 0664, db1x_pmattr_show, \
0195 db1x_pmattr_store);
0196
0197 ATTR(gpio0)
0198 ATTR(gpio1)
0199 ATTR(gpio2)
0200 ATTR(gpio3)
0201 ATTR(gpio4)
0202 ATTR(gpio5)
0203 ATTR(gpio6)
0204 ATTR(gpio7)
0205 ATTR(timer)
0206 ATTR(timer_timeout)
0207 ATTR(wakesrc)
0208 ATTR(wakemsk)
0209
0210 #define ATTR_LIST(x) & x ## _attribute.attr
0211 static struct attribute *db1x_pmattrs[] = {
0212 ATTR_LIST(gpio0),
0213 ATTR_LIST(gpio1),
0214 ATTR_LIST(gpio2),
0215 ATTR_LIST(gpio3),
0216 ATTR_LIST(gpio4),
0217 ATTR_LIST(gpio5),
0218 ATTR_LIST(gpio6),
0219 ATTR_LIST(gpio7),
0220 ATTR_LIST(timer),
0221 ATTR_LIST(timer_timeout),
0222 ATTR_LIST(wakesrc),
0223 ATTR_LIST(wakemsk),
0224 NULL,
0225 };
0226
0227 static struct attribute_group db1x_pmattr_group = {
0228 .name = "db1x",
0229 .attrs = db1x_pmattrs,
0230 };
0231
0232
0233
0234
0235 static int __init pm_init(void)
0236 {
0237
0238
0239
0240
0241 if (alchemy_rdsys(AU1000_SYS_TOYTRIM) != 32767)
0242 alchemy_wrsys(32767, AU1000_SYS_TOYTRIM);
0243
0244 db1x_pm_last_wakesrc = alchemy_rdsys(AU1000_SYS_WAKESRC);
0245
0246 alchemy_wrsys(0, AU1000_SYS_WAKESRC);
0247 alchemy_wrsys(0, AU1000_SYS_WAKEMSK);
0248
0249 suspend_set_ops(&db1x_pm_ops);
0250
0251 return sysfs_create_group(power_kobj, &db1x_pmattr_group);
0252 }
0253
0254 late_initcall(pm_init);