Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.0-rc3 196 lines 5.4 kB view raw
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; 91 time64_t t; 92 93 v = readl(SYS_TOYREAD0); 94 t = readl(SYS_TOYREAD1); 95 96 memset(rtm, 0, sizeof(struct rtc_time)); 97 t = mktime64((t & LS1X_YEAR_MASK), ls1x_get_month(v), 98 ls1x_get_day(v), ls1x_get_hour(v), 99 ls1x_get_min(v), ls1x_get_sec(v)); 100 rtc_time64_to_tm(t, rtm); 101 102 return 0; 103} 104 105static int ls1x_rtc_set_time(struct device *dev, struct rtc_time *rtm) 106{ 107 unsigned long v, t, c; 108 int ret = -ETIMEDOUT; 109 110 v = ((rtm->tm_mon + 1) << LS1X_MONTH_OFFSET) 111 | (rtm->tm_mday << LS1X_DAY_OFFSET) 112 | (rtm->tm_hour << LS1X_HOUR_OFFSET) 113 | (rtm->tm_min << LS1X_MIN_OFFSET) 114 | (rtm->tm_sec << LS1X_SEC_OFFSET); 115 116 writel(v, SYS_TOYWRITE0); 117 c = 0x10000; 118 /* add timeout check counter, for more safe */ 119 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 120 usleep_range(1000, 3000); 121 122 if (!c) { 123 dev_err(dev, "set time timeout!\n"); 124 goto err; 125 } 126 127 t = rtm->tm_year + 1900; 128 writel(t, SYS_TOYWRITE1); 129 c = 0x10000; 130 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 131 usleep_range(1000, 3000); 132 133 if (!c) { 134 dev_err(dev, "set time timeout!\n"); 135 goto err; 136 } 137 return 0; 138err: 139 return ret; 140} 141 142static const struct rtc_class_ops ls1x_rtc_ops = { 143 .read_time = ls1x_rtc_read_time, 144 .set_time = ls1x_rtc_set_time, 145}; 146 147static int ls1x_rtc_probe(struct platform_device *pdev) 148{ 149 struct rtc_device *rtcdev; 150 unsigned long v; 151 152 v = readl(SYS_COUNTER_CNTRL); 153 if (!(v & RTC_CNTR_OK)) { 154 dev_err(&pdev->dev, "rtc counters not working\n"); 155 return -ENODEV; 156 } 157 158 /* set to 1 HZ if needed */ 159 if (readl(SYS_TOYTRIM) != 32767) { 160 v = 0x100000; 161 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v) 162 usleep_range(1000, 3000); 163 164 if (!v) { 165 dev_err(&pdev->dev, "time out\n"); 166 return -ETIMEDOUT; 167 } 168 writel(32767, SYS_TOYTRIM); 169 } 170 /* this loop coundn't be endless */ 171 while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) 172 usleep_range(1000, 3000); 173 174 rtcdev = devm_rtc_allocate_device(&pdev->dev); 175 if (IS_ERR(rtcdev)) 176 return PTR_ERR(rtcdev); 177 178 platform_set_drvdata(pdev, rtcdev); 179 rtcdev->ops = &ls1x_rtc_ops; 180 rtcdev->range_min = RTC_TIMESTAMP_BEGIN_1900; 181 rtcdev->range_max = RTC_TIMESTAMP_END_2099; 182 183 return rtc_register_device(rtcdev); 184} 185 186static struct platform_driver ls1x_rtc_driver = { 187 .driver = { 188 .name = "ls1x-rtc", 189 }, 190 .probe = ls1x_rtc_probe, 191}; 192 193module_platform_driver(ls1x_rtc_driver); 194 195MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>"); 196MODULE_LICENSE("GPL");