18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * HP i8042 SDC + MSM-58321 BBRTC driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2001 Brian S. Julin 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 98c2ecf20Sopenharmony_ci * are met: 108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 118c2ecf20Sopenharmony_ci * notice, this list of conditions, and the following disclaimer, 128c2ecf20Sopenharmony_ci * without modification. 138c2ecf20Sopenharmony_ci * 2. The name of the author may not be used to endorse or promote products 148c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the 178c2ecf20Sopenharmony_ci * GNU General Public License ("GPL"). 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 208c2ecf20Sopenharmony_ci * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 218c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 228c2ecf20Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 238c2ecf20Sopenharmony_ci * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 248c2ecf20Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 258c2ecf20Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 268c2ecf20Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 278c2ecf20Sopenharmony_ci * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * References: 308c2ecf20Sopenharmony_ci * System Device Controller Microprocessor Firmware Theory of Operation 318c2ecf20Sopenharmony_ci * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2 328c2ecf20Sopenharmony_ci * efirtc.c by Stephane Eranian/Hewlett Packard 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include <linux/hp_sdc.h> 378c2ecf20Sopenharmony_ci#include <linux/errno.h> 388c2ecf20Sopenharmony_ci#include <linux/types.h> 398c2ecf20Sopenharmony_ci#include <linux/init.h> 408c2ecf20Sopenharmony_ci#include <linux/module.h> 418c2ecf20Sopenharmony_ci#include <linux/time.h> 428c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 438c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 448c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 458c2ecf20Sopenharmony_ci#include <linux/poll.h> 468c2ecf20Sopenharmony_ci#include <linux/rtc.h> 478c2ecf20Sopenharmony_ci#include <linux/mutex.h> 488c2ecf20Sopenharmony_ci#include <linux/semaphore.h> 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciMODULE_AUTHOR("Brian S. Julin <bri@calyx.com>"); 518c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HP i8042 SDC + MSM-58321 RTC Driver"); 528c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define RTC_VERSION "1.10d" 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic unsigned long epoch = 2000; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic struct semaphore i8042tregs; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void hp_sdc_rtc_isr (int irq, void *dev_id, 618c2ecf20Sopenharmony_ci uint8_t status, uint8_t data) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int hp_sdc_rtc_do_read_bbrtc (struct rtc_time *rtctm) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct semaphore tsem; 698c2ecf20Sopenharmony_ci hp_sdc_transaction t; 708c2ecf20Sopenharmony_ci uint8_t tseq[91]; 718c2ecf20Sopenharmony_ci int i; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci i = 0; 748c2ecf20Sopenharmony_ci while (i < 91) { 758c2ecf20Sopenharmony_ci tseq[i++] = HP_SDC_ACT_DATAREG | 768c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN; 778c2ecf20Sopenharmony_ci tseq[i++] = 0x01; /* write i8042[0x70] */ 788c2ecf20Sopenharmony_ci tseq[i] = i / 7; /* BBRTC reg address */ 798c2ecf20Sopenharmony_ci i++; 808c2ecf20Sopenharmony_ci tseq[i++] = HP_SDC_CMD_DO_RTCR; /* Trigger command */ 818c2ecf20Sopenharmony_ci tseq[i++] = 2; /* expect 1 stat/dat pair back. */ 828c2ecf20Sopenharmony_ci i++; i++; /* buffer for stat/dat pair */ 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci tseq[84] |= HP_SDC_ACT_SEMAPHORE; 858c2ecf20Sopenharmony_ci t.endidx = 91; 868c2ecf20Sopenharmony_ci t.seq = tseq; 878c2ecf20Sopenharmony_ci t.act.semaphore = &tsem; 888c2ecf20Sopenharmony_ci sema_init(&tsem, 0); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (hp_sdc_enqueue_transaction(&t)) return -1; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci /* Put ourselves to sleep for results. */ 938c2ecf20Sopenharmony_ci if (WARN_ON(down_interruptible(&tsem))) 948c2ecf20Sopenharmony_ci return -1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci /* Check for nonpresence of BBRTC */ 978c2ecf20Sopenharmony_ci if (!((tseq[83] | tseq[90] | tseq[69] | tseq[76] | 988c2ecf20Sopenharmony_ci tseq[55] | tseq[62] | tseq[34] | tseq[41] | 998c2ecf20Sopenharmony_ci tseq[20] | tseq[27] | tseq[6] | tseq[13]) & 0x0f)) 1008c2ecf20Sopenharmony_ci return -1; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci memset(rtctm, 0, sizeof(struct rtc_time)); 1038c2ecf20Sopenharmony_ci rtctm->tm_year = (tseq[83] & 0x0f) + (tseq[90] & 0x0f) * 10; 1048c2ecf20Sopenharmony_ci rtctm->tm_mon = (tseq[69] & 0x0f) + (tseq[76] & 0x0f) * 10; 1058c2ecf20Sopenharmony_ci rtctm->tm_mday = (tseq[55] & 0x0f) + (tseq[62] & 0x0f) * 10; 1068c2ecf20Sopenharmony_ci rtctm->tm_wday = (tseq[48] & 0x0f); 1078c2ecf20Sopenharmony_ci rtctm->tm_hour = (tseq[34] & 0x0f) + (tseq[41] & 0x0f) * 10; 1088c2ecf20Sopenharmony_ci rtctm->tm_min = (tseq[20] & 0x0f) + (tseq[27] & 0x0f) * 10; 1098c2ecf20Sopenharmony_ci rtctm->tm_sec = (tseq[6] & 0x0f) + (tseq[13] & 0x0f) * 10; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic int hp_sdc_rtc_read_bbrtc (struct rtc_time *rtctm) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct rtc_time tm, tm_last; 1178c2ecf20Sopenharmony_ci int i = 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* MSM-58321 has no read latch, so must read twice and compare. */ 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (hp_sdc_rtc_do_read_bbrtc(&tm_last)) return -1; 1228c2ecf20Sopenharmony_ci if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci while (memcmp(&tm, &tm_last, sizeof(struct rtc_time))) { 1258c2ecf20Sopenharmony_ci if (i++ > 4) return -1; 1268c2ecf20Sopenharmony_ci memcpy(&tm_last, &tm, sizeof(struct rtc_time)); 1278c2ecf20Sopenharmony_ci if (hp_sdc_rtc_do_read_bbrtc(&tm)) return -1; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci memcpy(rtctm, &tm, sizeof(struct rtc_time)); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int64_t hp_sdc_rtc_read_i8042timer (uint8_t loadcmd, int numreg) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci hp_sdc_transaction t; 1398c2ecf20Sopenharmony_ci uint8_t tseq[26] = { 1408c2ecf20Sopenharmony_ci HP_SDC_ACT_PRECMD | HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 1418c2ecf20Sopenharmony_ci 0, 1428c2ecf20Sopenharmony_ci HP_SDC_CMD_READ_T1, 2, 0, 0, 1438c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 1448c2ecf20Sopenharmony_ci HP_SDC_CMD_READ_T2, 2, 0, 0, 1458c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 1468c2ecf20Sopenharmony_ci HP_SDC_CMD_READ_T3, 2, 0, 0, 1478c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 1488c2ecf20Sopenharmony_ci HP_SDC_CMD_READ_T4, 2, 0, 0, 1498c2ecf20Sopenharmony_ci HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN, 1508c2ecf20Sopenharmony_ci HP_SDC_CMD_READ_T5, 2, 0, 0 1518c2ecf20Sopenharmony_ci }; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci t.endidx = numreg * 5; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci tseq[1] = loadcmd; 1568c2ecf20Sopenharmony_ci tseq[t.endidx - 4] |= HP_SDC_ACT_SEMAPHORE; /* numreg assumed > 1 */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci t.seq = tseq; 1598c2ecf20Sopenharmony_ci t.act.semaphore = &i8042tregs; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci /* Sleep if output regs in use. */ 1628c2ecf20Sopenharmony_ci if (WARN_ON(down_interruptible(&i8042tregs))) 1638c2ecf20Sopenharmony_ci return -1; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (hp_sdc_enqueue_transaction(&t)) { 1668c2ecf20Sopenharmony_ci up(&i8042tregs); 1678c2ecf20Sopenharmony_ci return -1; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci /* Sleep until results come back. */ 1718c2ecf20Sopenharmony_ci if (WARN_ON(down_interruptible(&i8042tregs))) 1728c2ecf20Sopenharmony_ci return -1; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci up(&i8042tregs); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return (tseq[5] | 1778c2ecf20Sopenharmony_ci ((uint64_t)(tseq[10]) << 8) | ((uint64_t)(tseq[15]) << 16) | 1788c2ecf20Sopenharmony_ci ((uint64_t)(tseq[20]) << 24) | ((uint64_t)(tseq[25]) << 32)); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Read the i8042 real-time clock */ 1838c2ecf20Sopenharmony_cistatic inline int hp_sdc_rtc_read_rt(struct timespec64 *res) { 1848c2ecf20Sopenharmony_ci int64_t raw; 1858c2ecf20Sopenharmony_ci uint32_t tenms; 1868c2ecf20Sopenharmony_ci unsigned int days; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_RT, 5); 1898c2ecf20Sopenharmony_ci if (raw < 0) return -1; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci tenms = (uint32_t)raw & 0xffffff; 1928c2ecf20Sopenharmony_ci days = (unsigned int)(raw >> 24) & 0xffff; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; 1958c2ecf20Sopenharmony_ci res->tv_sec = (tenms / 100) + (time64_t)days * 86400; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/* Read the i8042 fast handshake timer */ 2028c2ecf20Sopenharmony_cistatic inline int hp_sdc_rtc_read_fhs(struct timespec64 *res) { 2038c2ecf20Sopenharmony_ci int64_t raw; 2048c2ecf20Sopenharmony_ci unsigned int tenms; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_FHS, 2); 2078c2ecf20Sopenharmony_ci if (raw < 0) return -1; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci tenms = (unsigned int)raw & 0xffff; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; 2128c2ecf20Sopenharmony_ci res->tv_sec = (time64_t)(tenms / 100); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return 0; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci/* Read the i8042 match timer (a.k.a. alarm) */ 2198c2ecf20Sopenharmony_cistatic inline int hp_sdc_rtc_read_mt(struct timespec64 *res) { 2208c2ecf20Sopenharmony_ci int64_t raw; 2218c2ecf20Sopenharmony_ci uint32_t tenms; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_MT, 3); 2248c2ecf20Sopenharmony_ci if (raw < 0) return -1; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci tenms = (uint32_t)raw & 0xffffff; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; 2298c2ecf20Sopenharmony_ci res->tv_sec = (time64_t)(tenms / 100); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci/* Read the i8042 delay timer */ 2368c2ecf20Sopenharmony_cistatic inline int hp_sdc_rtc_read_dt(struct timespec64 *res) { 2378c2ecf20Sopenharmony_ci int64_t raw; 2388c2ecf20Sopenharmony_ci uint32_t tenms; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_DT, 3); 2418c2ecf20Sopenharmony_ci if (raw < 0) return -1; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci tenms = (uint32_t)raw & 0xffffff; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; 2468c2ecf20Sopenharmony_ci res->tv_sec = (time64_t)(tenms / 100); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/* Read the i8042 cycle timer (a.k.a. periodic) */ 2538c2ecf20Sopenharmony_cistatic inline int hp_sdc_rtc_read_ct(struct timespec64 *res) { 2548c2ecf20Sopenharmony_ci int64_t raw; 2558c2ecf20Sopenharmony_ci uint32_t tenms; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci raw = hp_sdc_rtc_read_i8042timer(HP_SDC_CMD_LOAD_CT, 3); 2588c2ecf20Sopenharmony_ci if (raw < 0) return -1; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci tenms = (uint32_t)raw & 0xffffff; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci res->tv_nsec = (long)(tenms % 100) * 10000 * 1000; 2638c2ecf20Sopenharmony_ci res->tv_sec = (time64_t)(tenms / 100); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci#define YN(bit) ("no") 2718c2ecf20Sopenharmony_ci#define NY(bit) ("yes") 2728c2ecf20Sopenharmony_ci struct rtc_time tm; 2738c2ecf20Sopenharmony_ci struct timespec64 tv; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci memset(&tm, 0, sizeof(struct rtc_time)); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_bbrtc(&tm)) { 2788c2ecf20Sopenharmony_ci seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci seq_printf(m, 2818c2ecf20Sopenharmony_ci "rtc_time\t: %ptRt\n" 2828c2ecf20Sopenharmony_ci "rtc_date\t: %ptRd\n" 2838c2ecf20Sopenharmony_ci "rtc_epoch\t: %04lu\n", 2848c2ecf20Sopenharmony_ci &tm, &tm, epoch); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_rt(&tv)) { 2888c2ecf20Sopenharmony_ci seq_puts(m, "i8042 rtc\t: READ FAILED!\n"); 2898c2ecf20Sopenharmony_ci } else { 2908c2ecf20Sopenharmony_ci seq_printf(m, "i8042 rtc\t: %lld.%02ld seconds\n", 2918c2ecf20Sopenharmony_ci (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_fhs(&tv)) { 2958c2ecf20Sopenharmony_ci seq_puts(m, "handshake\t: READ FAILED!\n"); 2968c2ecf20Sopenharmony_ci } else { 2978c2ecf20Sopenharmony_ci seq_printf(m, "handshake\t: %lld.%02ld seconds\n", 2988c2ecf20Sopenharmony_ci (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_mt(&tv)) { 3028c2ecf20Sopenharmony_ci seq_puts(m, "alarm\t\t: READ FAILED!\n"); 3038c2ecf20Sopenharmony_ci } else { 3048c2ecf20Sopenharmony_ci seq_printf(m, "alarm\t\t: %lld.%02ld seconds\n", 3058c2ecf20Sopenharmony_ci (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_dt(&tv)) { 3098c2ecf20Sopenharmony_ci seq_puts(m, "delay\t\t: READ FAILED!\n"); 3108c2ecf20Sopenharmony_ci } else { 3118c2ecf20Sopenharmony_ci seq_printf(m, "delay\t\t: %lld.%02ld seconds\n", 3128c2ecf20Sopenharmony_ci (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (hp_sdc_rtc_read_ct(&tv)) { 3168c2ecf20Sopenharmony_ci seq_puts(m, "periodic\t: READ FAILED!\n"); 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci seq_printf(m, "periodic\t: %lld.%02ld seconds\n", 3198c2ecf20Sopenharmony_ci (s64)tv.tv_sec, (long)tv.tv_nsec/1000000L); 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci seq_printf(m, 3238c2ecf20Sopenharmony_ci "DST_enable\t: %s\n" 3248c2ecf20Sopenharmony_ci "BCD\t\t: %s\n" 3258c2ecf20Sopenharmony_ci "24hr\t\t: %s\n" 3268c2ecf20Sopenharmony_ci "square_wave\t: %s\n" 3278c2ecf20Sopenharmony_ci "alarm_IRQ\t: %s\n" 3288c2ecf20Sopenharmony_ci "update_IRQ\t: %s\n" 3298c2ecf20Sopenharmony_ci "periodic_IRQ\t: %s\n" 3308c2ecf20Sopenharmony_ci "periodic_freq\t: %ld\n" 3318c2ecf20Sopenharmony_ci "batt_status\t: %s\n", 3328c2ecf20Sopenharmony_ci YN(RTC_DST_EN), 3338c2ecf20Sopenharmony_ci NY(RTC_DM_BINARY), 3348c2ecf20Sopenharmony_ci YN(RTC_24H), 3358c2ecf20Sopenharmony_ci YN(RTC_SQWE), 3368c2ecf20Sopenharmony_ci YN(RTC_AIE), 3378c2ecf20Sopenharmony_ci YN(RTC_UIE), 3388c2ecf20Sopenharmony_ci YN(RTC_PIE), 3398c2ecf20Sopenharmony_ci 1UL, 3408c2ecf20Sopenharmony_ci 1 ? "okay" : "dead"); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci#undef YN 3448c2ecf20Sopenharmony_ci#undef NY 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic int __init hp_sdc_rtc_init(void) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci int ret; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci#ifdef __mc68000__ 3528c2ecf20Sopenharmony_ci if (!MACH_IS_HP300) 3538c2ecf20Sopenharmony_ci return -ENODEV; 3548c2ecf20Sopenharmony_ci#endif 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci sema_init(&i8042tregs, 1); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr))) 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci proc_create_single("driver/rtc", 0, NULL, hp_sdc_rtc_proc_show); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded " 3648c2ecf20Sopenharmony_ci "(RTC v " RTC_VERSION ")\n"); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic void __exit hp_sdc_rtc_exit(void) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci remove_proc_entry ("driver/rtc", NULL); 3728c2ecf20Sopenharmony_ci hp_sdc_release_timer_irq(hp_sdc_rtc_isr); 3738c2ecf20Sopenharmony_ci printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support unloaded\n"); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cimodule_init(hp_sdc_rtc_init); 3778c2ecf20Sopenharmony_cimodule_exit(hp_sdc_rtc_exit); 378