1/* 2 * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com> 3 * 4 * Derived from driver/rtc/rtc-au1xxx.c 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2 of the License, or (at your 9 * option) any later version. 10 */ 11 12#include <linux/module.h> 13#include <linux/kernel.h> 14#include <linux/rtc.h> 15#include <linux/init.h> 16#include <linux/platform_device.h> 17#include <linux/delay.h> 18#include <linux/types.h> 19#include <linux/io.h> 20#include <loongson1.h> 21 22#define LS1X_RTC_REG_OFFSET (LS1X_RTC_BASE + 0x20) 23#define LS1X_RTC_REGS(x) \ 24 ((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x))) 25 26/*RTC programmable counters 0 and 1*/ 27#define SYS_COUNTER_CNTRL (LS1X_RTC_REGS(0x20)) 28#define SYS_CNTRL_ERS (1 << 23) 29#define SYS_CNTRL_RTS (1 << 20) 30#define SYS_CNTRL_RM2 (1 << 19) 31#define SYS_CNTRL_RM1 (1 << 18) 32#define SYS_CNTRL_RM0 (1 << 17) 33#define SYS_CNTRL_RS (1 << 16) 34#define SYS_CNTRL_BP (1 << 14) 35#define SYS_CNTRL_REN (1 << 13) 36#define SYS_CNTRL_BRT (1 << 12) 37#define SYS_CNTRL_TEN (1 << 11) 38#define SYS_CNTRL_BTT (1 << 10) 39#define SYS_CNTRL_E0 (1 << 8) 40#define SYS_CNTRL_ETS (1 << 7) 41#define SYS_CNTRL_32S (1 << 5) 42#define SYS_CNTRL_TTS (1 << 4) 43#define SYS_CNTRL_TM2 (1 << 3) 44#define SYS_CNTRL_TM1 (1 << 2) 45#define SYS_CNTRL_TM0 (1 << 1) 46#define SYS_CNTRL_TS (1 << 0) 47 48/* Programmable Counter 0 Registers */ 49#define SYS_TOYTRIM (LS1X_RTC_REGS(0)) 50#define SYS_TOYWRITE0 (LS1X_RTC_REGS(4)) 51#define SYS_TOYWRITE1 (LS1X_RTC_REGS(8)) 52#define SYS_TOYREAD0 (LS1X_RTC_REGS(0xC)) 53#define SYS_TOYREAD1 (LS1X_RTC_REGS(0x10)) 54#define SYS_TOYMATCH0 (LS1X_RTC_REGS(0x14)) 55#define SYS_TOYMATCH1 (LS1X_RTC_REGS(0x18)) 56#define SYS_TOYMATCH2 (LS1X_RTC_REGS(0x1C)) 57 58/* Programmable Counter 1 Registers */ 59#define SYS_RTCTRIM (LS1X_RTC_REGS(0x40)) 60#define SYS_RTCWRITE0 (LS1X_RTC_REGS(0x44)) 61#define SYS_RTCREAD0 (LS1X_RTC_REGS(0x48)) 62#define SYS_RTCMATCH0 (LS1X_RTC_REGS(0x4C)) 63#define SYS_RTCMATCH1 (LS1X_RTC_REGS(0x50)) 64#define SYS_RTCMATCH2 (LS1X_RTC_REGS(0x54)) 65 66#define LS1X_SEC_OFFSET (4) 67#define LS1X_MIN_OFFSET (10) 68#define LS1X_HOUR_OFFSET (16) 69#define LS1X_DAY_OFFSET (21) 70#define LS1X_MONTH_OFFSET (26) 71 72 73#define LS1X_SEC_MASK (0x3f) 74#define LS1X_MIN_MASK (0x3f) 75#define LS1X_HOUR_MASK (0x1f) 76#define LS1X_DAY_MASK (0x1f) 77#define LS1X_MONTH_MASK (0x3f) 78#define LS1X_YEAR_MASK (0xffffffff) 79 80#define ls1x_get_sec(t) (((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK) 81#define ls1x_get_min(t) (((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK) 82#define ls1x_get_hour(t) (((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK) 83#define ls1x_get_day(t) (((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK) 84#define ls1x_get_month(t) (((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK) 85 86#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) 87 88static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm) 89{ 90 unsigned long v, t; 91 92 v = readl(SYS_TOYREAD0); 93 t = readl(SYS_TOYREAD1); 94 95 memset(rtm, 0, sizeof(struct rtc_time)); 96 t = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v), 97 ls1x_get_day(v), ls1x_get_hour(v), 98 ls1x_get_min(v), ls1x_get_sec(v)); 99 rtc_time_to_tm(t, rtm); 100 101 return rtc_valid_tm(rtm); 102} 103 104static int ls1x_rtc_set_time(struct device *dev, struct rtc_time *rtm) 105{ 106 unsigned long v, t, c; 107 int ret = -ETIMEDOUT; 108 109 v = ((rtm->tm_mon + 1) << LS1X_MONTH_OFFSET) 110 | (rtm->tm_mday << LS1X_DAY_OFFSET) 111 | (rtm->tm_hour << LS1X_HOUR_OFFSET) 112 | (rtm->tm_min << LS1X_MIN_OFFSET) 113 | (rtm->tm_sec << LS1X_SEC_OFFSET); 114 115 writel(v, SYS_TOYWRITE0); 116 c = 0x10000; 117 /* add timeout check counter, for more safe */ 118 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 119 usleep_range(1000, 3000); 120 121 if (!c) { 122 dev_err(dev, "set time timeout!\n"); 123 goto err; 124 } 125 126 t = rtm->tm_year + 1900; 127 writel(t, SYS_TOYWRITE1); 128 c = 0x10000; 129 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 130 usleep_range(1000, 3000); 131 132 if (!c) { 133 dev_err(dev, "set time timeout!\n"); 134 goto err; 135 } 136 return 0; 137err: 138 return ret; 139} 140 141static struct rtc_class_ops ls1x_rtc_ops = { 142 .read_time = ls1x_rtc_read_time, 143 .set_time = ls1x_rtc_set_time, 144}; 145 146static int ls1x_rtc_probe(struct platform_device *pdev) 147{ 148 struct rtc_device *rtcdev; 149 unsigned long v; 150 int ret; 151 152 v = readl(SYS_COUNTER_CNTRL); 153 if (!(v & RTC_CNTR_OK)) { 154 dev_err(&pdev->dev, "rtc counters not working\n"); 155 ret = -ENODEV; 156 goto err; 157 } 158 ret = -ETIMEDOUT; 159 /* set to 1 HZ if needed */ 160 if (readl(SYS_TOYTRIM) != 32767) { 161 v = 0x100000; 162 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v) 163 usleep_range(1000, 3000); 164 165 if (!v) { 166 dev_err(&pdev->dev, "time out\n"); 167 goto err; 168 } 169 writel(32767, SYS_TOYTRIM); 170 } 171 /* this loop coundn't be endless */ 172 while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) 173 usleep_range(1000, 3000); 174 175 rtcdev = devm_rtc_device_register(&pdev->dev, "ls1x-rtc", 176 &ls1x_rtc_ops , THIS_MODULE); 177 if (IS_ERR(rtcdev)) { 178 ret = PTR_ERR(rtcdev); 179 goto err; 180 } 181 182 platform_set_drvdata(pdev, rtcdev); 183 return 0; 184err: 185 return ret; 186} 187 188static struct platform_driver ls1x_rtc_driver = { 189 .driver = { 190 .name = "ls1x-rtc", 191 }, 192 .probe = ls1x_rtc_probe, 193}; 194 195module_platform_driver(ls1x_rtc_driver); 196 197MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>"); 198MODULE_LICENSE("GPL"); 199