0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036 #include <linux/hp_sdc.h>
0037 #include <linux/errno.h>
0038 #include <linux/types.h>
0039 #include <linux/init.h>
0040 #include <linux/module.h>
0041 #include <linux/time.h>
0042 #include <linux/miscdevice.h>
0043 #include <linux/proc_fs.h>
0044 #include <linux/seq_file.h>
0045 #include <linux/poll.h>
0046 #include <linux/rtc.h>
0047 #include <linux/mutex.h>
0048 #include <linux/semaphore.h>
0049
0050 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
0051 MODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver");
0052 MODULE_LICENSE("Dual BSD/GPL");
0053
0054 #define RTC_VERSION "1.10d"
0055
0056 static unsigned long epoch = 2000;
0057
0058 static struct semaphore i8042tregs;
0059
0060 static void hp_sdc_rtc_isr (int irq, void *dev_id,
0061 uint8_t status, uint8_t data)
0062 {
0063 return;
0064 }
0065
0066 static int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm)
0067 {
0068 struct semaphore tsem;
0069 hp_sdc_transaction t;
0070 uint8_t tseq[91];
0071 int i;
0072
0073 i = 0;
0074 while (i < 91) {
0075 tseq[i++] = HP_SDC_ACT_DATAREG |
0076 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN;
0077 tseq[i++] = 0x01;
0078 tseq[i] = i / 7;
0079 i++;
0080 tseq[i++] = HP_SDC_CMD_DO_RTCR;
0081 tseq[i++] = 2;
0082 i++; i++;
0083 }
0084 tseq[84] |= HP_SDC_ACT_SEMAPHORE;
0085 t.endidx = 91;
0086 t.seq = tseq;
0087 t.act.semaphore = &tsem;
0088 sema_init(&tsem, 0);
0089
0090 if (hp_sdc_enqueue_transaction(&t)) return -1;
0091
0092
0093 if (WARN_ON(down_interruptible(&tsem)))
0094 return -1;
0095
0096
0097 if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] |
0098 tseq[55] | tseq[62] | tseq[34] | tseq[41] |
0099 tseq[20] | tseq[27] | tseq[6] | tseq[13]) & 0x0f))
0100 return -1;
0101
0102 memset(rtctm, 0, sizeof(struct rtc_time));
0103 rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10;
0104 rtctm->tm_mon = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10;
0105 rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10;
0106 rtctm->tm_wday = (tseq[48] & 0x0f);
0107 rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10;
0108 rtctm->tm_min = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10;
0109 rtctm->tm_sec = (tseq[6] & 0x0f) + (tseq[13] & 0x0f) * 10;
0110
0111 return 0;
0112 }
0113
0114 static int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm)
0115 {
0116 struct rtc_time tm, tm_last;
0117 int i = 0;
0118
0119
0120
0121 if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1;
0122 if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
0123
0124 while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) {
0125 if (i++ > 4) return -1;
0126 memcpy(&tm_last, &tm, sizeof(struct rtc_time));
0127 if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1;
0128 }
0129
0130 memcpy(rtctm, &tm, sizeof(struct rtc_time));
0131
0132 return 0;
0133 }
0134
0135
0136 static int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg)
0137 {
0138 hp_sdc_transaction t;
0139 uint8_t tseq[26] = {
0140 HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
0141 0,
0142 HP_SDC_CMD_READ_T1, 2, 0, 0,
0143 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
0144 HP_SDC_CMD_READ_T2, 2, 0, 0,
0145 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
0146 HP_SDC_CMD_READ_T3, 2, 0, 0,
0147 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
0148 HP_SDC_CMD_READ_T4, 2, 0, 0,
0149 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN,
0150 HP_SDC_CMD_READ_T5, 2, 0, 0
0151 };
0152
0153 t.endidx = numreg * 5;
0154
0155 tseq[1] = loadcmd;
0156 tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE;
0157
0158 t.seq = tseq;
0159 t.act.semaphore = &i8042tregs;
0160
0161
0162 if (WARN_ON(down_interruptible(&i8042tregs)))
0163 return -1;
0164
0165 if (hp_sdc_enqueue_transaction(&t)) {
0166 up(&i8042tregs);
0167 return -1;
0168 }
0169
0170
0171 if (WARN_ON(down_interruptible(&i8042tregs)))
0172 return -1;
0173
0174 up(&i8042tregs);
0175
0176 return (tseq[5] |
0177 ((uint64_t)(tseq[10]) << 8) | ((uint64_t)(tseq[15]) << 16) |
0178 ((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32));
0179 }
0180
0181
0182
0183 static inline int hp_sdc_rtc_read_rt(struct timespec64 *res) {
0184 int64_t raw;
0185 uint32_t tenms;
0186 unsigned int days;
0187
0188 raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5);
0189 if (raw < 0) return -1;
0190
0191 tenms = (uint32_t)raw & 0xffffff;
0192 days = (unsigned int)(raw >> 24) & 0xffff;
0193
0194 res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
0195 res->tv_sec = (tenms / 100) + (time64_t)days * 86400;
0196
0197 return 0;
0198 }
0199
0200
0201
0202 static inline int hp_sdc_rtc_read_fhs(struct timespec64 *res) {
0203 int64_t raw;
0204 unsigned int tenms;
0205
0206 raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2);
0207 if (raw < 0) return -1;
0208
0209 tenms = (unsigned int)raw & 0xffff;
0210
0211 res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
0212 res->tv_sec = (time64_t)(tenms / 100);
0213
0214 return 0;
0215 }
0216
0217
0218
0219 static inline int hp_sdc_rtc_read_mt(struct timespec64 *res) {
0220 int64_t raw;
0221 uint32_t tenms;
0222
0223 raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3);
0224 if (raw < 0) return -1;
0225
0226 tenms = (uint32_t)raw & 0xffffff;
0227
0228 res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
0229 res->tv_sec = (time64_t)(tenms / 100);
0230
0231 return 0;
0232 }
0233
0234
0235
0236 static inline int hp_sdc_rtc_read_dt(struct timespec64 *res) {
0237 int64_t raw;
0238 uint32_t tenms;
0239
0240 raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3);
0241 if (raw < 0) return -1;
0242
0243 tenms = (uint32_t)raw & 0xffffff;
0244
0245 res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
0246 res->tv_sec = (time64_t)(tenms / 100);
0247
0248 return 0;
0249 }
0250
0251
0252
0253 static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) {
0254 int64_t raw;
0255 uint32_t tenms;
0256
0257 raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3);
0258 if (raw < 0) return -1;
0259
0260 tenms = (uint32_t)raw & 0xffffff;
0261
0262 res->tv_nsec = (long)(tenms % 100) * 10000 * 1000;
0263 res->tv_sec = (time64_t)(tenms / 100);
0264
0265 return 0;
0266 }
0267
0268 static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v)
0269 {
0270 #define YN(bit) ("no")
0271 #define NY(bit) ("yes")
0272 struct rtc_time tm;
0273 struct timespec64 tv;
0274
0275 memset(&tm, 0, sizeof(struct rtc_time));
0276
0277 if (hp_sdc_rtc_read_bbrtc(&tm)) {
0278 seq_puts(m, "BBRTC\t\t: READ FAILED!\n");
0279 } else {
0280 seq_printf(m,
0281 "rtc_time\t: %ptRt\n"
0282 "rtc_date\t: %ptRd\n"
0283 "rtc_epoch\t: %04lu\n",
0284 &tm, &tm, epoch);
0285 }
0286
0287 if (hp_sdc_rtc_read_rt(&tv)) {
0288 seq_puts(m, "i8042 rtc\t: READ FAILED!\n");
0289 } else {
0290 seq_printf(m, "i8042 rtc\t: %lld.%02ld seconds\n",
0291 (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
0292 }
0293
0294 if (hp_sdc_rtc_read_fhs(&tv)) {
0295 seq_puts(m, "handshake\t: READ FAILED!\n");
0296 } else {
0297 seq_printf(m, "handshake\t: %lld.%02ld seconds\n",
0298 (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
0299 }
0300
0301 if (hp_sdc_rtc_read_mt(&tv)) {
0302 seq_puts(m, "alarm\t\t: READ FAILED!\n");
0303 } else {
0304 seq_printf(m, "alarm\t\t: %lld.%02ld seconds\n",
0305 (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
0306 }
0307
0308 if (hp_sdc_rtc_read_dt(&tv)) {
0309 seq_puts(m, "delay\t\t: READ FAILED!\n");
0310 } else {
0311 seq_printf(m, "delay\t\t: %lld.%02ld seconds\n",
0312 (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
0313 }
0314
0315 if (hp_sdc_rtc_read_ct(&tv)) {
0316 seq_puts(m, "periodic\t: READ FAILED!\n");
0317 } else {
0318 seq_printf(m, "periodic\t: %lld.%02ld seconds\n",
0319 (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L);
0320 }
0321
0322 seq_printf(m,
0323 "DST_enable\t: %s\n"
0324 "BCD\t\t: %s\n"
0325 "24hr\t\t: %s\n"
0326 "square_wave\t: %s\n"
0327 "alarm_IRQ\t: %s\n"
0328 "update_IRQ\t: %s\n"
0329 "periodic_IRQ\t: %s\n"
0330 "periodic_freq\t: %ld\n"
0331 "batt_status\t: %s\n",
0332 YN(RTC_DST_EN),
0333 NY(RTC_DM_BINARY),
0334 YN(RTC_24H),
0335 YN(RTC_SQWE),
0336 YN(RTC_AIE),
0337 YN(RTC_UIE),
0338 YN(RTC_PIE),
0339 1UL,
0340 1 ? "okay" : "dead");
0341
0342 return 0;
0343 #undef YN
0344 #undef NY
0345 }
0346
0347 static int __init hp_sdc_rtc_init(void)
0348 {
0349 int ret;
0350
0351 #ifdef __mc68000__
0352 if (!MACH_IS_HP300)
0353 return -ENODEV;
0354 #endif
0355
0356 sema_init(&i8042tregs, 1);
0357
0358 if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
0359 return ret;
0360
0361 proc_create_single("driver/rtc", 0, NULL, hp_sdc_rtc_proc_show);
0362
0363 printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
0364 "(RTC v " RTC_VERSION ")\n");
0365
0366 return 0;
0367 }
0368
0369 static void __exit hp_sdc_rtc_exit(void)
0370 {
0371 remove_proc_entry ("driver/rtc", NULL);
0372 hp_sdc_release_timer_irq(hp_sdc_rtc_isr);
0373 printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n");
0374 }
0375
0376 module_init(hp_sdc_rtc_init);
0377 module_exit(hp_sdc_rtc_exit);