aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-03 18:52:38 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-03 18:52:38 -0400
commitc4cbe6f96ebf8eb03884c31504d36dccd2ef1062 (patch)
tree37dc6a68db054a3bb0b8e1bed83e54cc67b190d1
parent64151ad5b3a03e236390d6d5160805ee4f4e7c67 (diff)
sparc32: use RTC subsystem
Use rtc subsystem for sparc32 architecture. Actually, only one driver is needed: m48t59 as it supports the most common clocks on sparc32 machines: m48t08 and m48t02. [ Add proper RTC layer calls to set_rtc_mmss() -DaveM ] Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c2
-rw-r--r--arch/sparc/kernel/time.c217
3 files changed, 62 insertions, 159 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index a4c7fb7afc80..97671dac12a6 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -75,6 +75,8 @@ config SPARC
75 select HAVE_ARCH_KGDB if !SMP 75 select HAVE_ARCH_KGDB if !SMP
76 select HAVE_ARCH_TRACEHOOK 76 select HAVE_ARCH_TRACEHOOK
77 select ARCH_WANT_OPTIONAL_GPIOLIB 77 select ARCH_WANT_OPTIONAL_GPIOLIB
78 select RTC_CLASS
79 select RTC_DRV_M48T59
78 80
79# Identify this as a Sparc32 build 81# Identify this as a Sparc32 build
80config SPARC32 82config SPARC32
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 6007ac5a7360..0ce002e39553 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -123,8 +123,6 @@ EXPORT_SYMBOL(phys_cpu_present_map);
123EXPORT_SYMBOL(__udelay); 123EXPORT_SYMBOL(__udelay);
124EXPORT_SYMBOL(__ndelay); 124EXPORT_SYMBOL(__ndelay);
125EXPORT_SYMBOL(rtc_lock); 125EXPORT_SYMBOL(rtc_lock);
126EXPORT_SYMBOL(mostek_lock);
127EXPORT_SYMBOL(mstk48t02_regs);
128#ifdef CONFIG_SUN_AUXIO 126#ifdef CONFIG_SUN_AUXIO
129EXPORT_SYMBOL(set_auxio); 127EXPORT_SYMBOL(set_auxio);
130EXPORT_SYMBOL(get_auxio); 128EXPORT_SYMBOL(get_auxio);
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index f0a2874b04e9..698c45059fa5 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -23,6 +23,8 @@
23#include <linux/mm.h> 23#include <linux/mm.h>
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/time.h> 25#include <linux/time.h>
26#include <linux/rtc.h>
27#include <linux/rtc/m48t59.h>
26#include <linux/timex.h> 28#include <linux/timex.h>
27#include <linux/init.h> 29#include <linux/init.h>
28#include <linux/pci.h> 30#include <linux/pci.h>
@@ -30,10 +32,10 @@
30#include <linux/profile.h> 32#include <linux/profile.h>
31#include <linux/of.h> 33#include <linux/of.h>
32#include <linux/of_device.h> 34#include <linux/of_device.h>
35#include <linux/platform_device.h>
33 36
34#include <asm/oplib.h> 37#include <asm/oplib.h>
35#include <asm/timer.h> 38#include <asm/timer.h>
36#include <asm/mostek.h>
37#include <asm/system.h> 39#include <asm/system.h>
38#include <asm/irq.h> 40#include <asm/irq.h>
39#include <asm/io.h> 41#include <asm/io.h>
@@ -46,10 +48,6 @@
46#include "irq.h" 48#include "irq.h"
47 49
48DEFINE_SPINLOCK(rtc_lock); 50DEFINE_SPINLOCK(rtc_lock);
49static enum sparc_clock_type sp_clock_typ;
50DEFINE_SPINLOCK(mostek_lock);
51void __iomem *mstk48t02_regs = NULL;
52static struct mostek48t08 __iomem *mstk48t08_regs = NULL;
53static int set_rtc_mmss(unsigned long); 51static int set_rtc_mmss(unsigned long);
54static int sbus_do_settimeofday(struct timespec *tv); 52static int sbus_do_settimeofday(struct timespec *tv);
55 53
@@ -118,107 +116,55 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id)
118 return IRQ_HANDLED; 116 return IRQ_HANDLED;
119} 117}
120 118
121/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ 119static unsigned char mostek_read_byte(struct device *dev, u32 ofs)
122static void __devinit kick_start_clock(void)
123{ 120{
124 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; 121 struct platform_device *pdev = to_platform_device(dev);
125 unsigned char sec; 122 struct m48t59_plat_data *pdata = pdev->dev.platform_data;
126 int i, count; 123 void __iomem *regs = pdata->ioaddr;
127 124 unsigned char val = readb(regs + ofs);
128 prom_printf("CLOCK: Clock was stopped. Kick start "); 125
129 126 /* the year 0 is 1968 */
130 spin_lock_irq(&mostek_lock); 127 if (ofs == pdata->offset + M48T59_YEAR) {
131 128 val += 0x68;
132 /* Turn on the kick start bit to start the oscillator. */ 129 if ((val & 0xf) > 9)
133 regs->creg |= MSTK_CREG_WRITE; 130 val += 6;
134 regs->sec &= ~MSTK_STOP;
135 regs->hour |= MSTK_KICK_START;
136 regs->creg &= ~MSTK_CREG_WRITE;
137
138 spin_unlock_irq(&mostek_lock);
139
140 /* Delay to allow the clock oscillator to start. */
141 sec = MSTK_REG_SEC(regs);
142 for (i = 0; i < 3; i++) {
143 while (sec == MSTK_REG_SEC(regs))
144 for (count = 0; count < 100000; count++)
145 /* nothing */ ;
146 prom_printf(".");
147 sec = regs->sec;
148 } 131 }
149 prom_printf("\n"); 132 return val;
150
151 spin_lock_irq(&mostek_lock);
152
153 /* Turn off kick start and set a "valid" time and date. */
154 regs->creg |= MSTK_CREG_WRITE;
155 regs->hour &= ~MSTK_KICK_START;
156 MSTK_SET_REG_SEC(regs,0);
157 MSTK_SET_REG_MIN(regs,0);
158 MSTK_SET_REG_HOUR(regs,0);
159 MSTK_SET_REG_DOW(regs,5);
160 MSTK_SET_REG_DOM(regs,1);
161 MSTK_SET_REG_MONTH(regs,8);
162 MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
163 regs->creg &= ~MSTK_CREG_WRITE;
164
165 spin_unlock_irq(&mostek_lock);
166
167 /* Ensure the kick start bit is off. If it isn't, turn it off. */
168 while (regs->hour & MSTK_KICK_START) {
169 prom_printf("CLOCK: Kick start still on!\n");
170
171 spin_lock_irq(&mostek_lock);
172 regs->creg |= MSTK_CREG_WRITE;
173 regs->hour &= ~MSTK_KICK_START;
174 regs->creg &= ~MSTK_CREG_WRITE;
175 spin_unlock_irq(&mostek_lock);
176 }
177
178 prom_printf("CLOCK: Kick start procedure successful.\n");
179} 133}
180 134
181/* Return nonzero if the clock chip battery is low. */ 135static void mostek_write_byte(struct device *dev, u32 ofs, u8 val)
182static inline int has_low_battery(void)
183{ 136{
184 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; 137 struct platform_device *pdev = to_platform_device(dev);
185 unsigned char data1, data2; 138 struct m48t59_plat_data *pdata = pdev->dev.platform_data;
186 139 void __iomem *regs = pdata->ioaddr;
187 spin_lock_irq(&mostek_lock); 140
188 data1 = regs->eeprom[0]; /* Read some data. */ 141 if (ofs == pdata->offset + M48T59_YEAR) {
189 regs->eeprom[0] = ~data1; /* Write back the complement. */ 142 if (val < 0x68)
190 data2 = regs->eeprom[0]; /* Read back the complement. */ 143 val += 0x32;
191 regs->eeprom[0] = data1; /* Restore the original value. */ 144 else
192 spin_unlock_irq(&mostek_lock); 145 val -= 0x68;
193 146 if ((val & 0xf) > 9)
194 return (data1 == data2); /* Was the write blocked? */ 147 val += 6;
148 if ((val & 0xf0) > 0x9A)
149 val += 0x60;
150 }
151 writeb(val, regs + ofs);
195} 152}
196 153
197static void __devinit mostek_set_system_time(void) 154static struct m48t59_plat_data m48t59_data = {
198{ 155 .read_byte = mostek_read_byte,
199 unsigned int year, mon, day, hour, min, sec; 156 .write_byte = mostek_write_byte,
200 struct mostek48t02 *mregs; 157};
201 158
202 mregs = (struct mostek48t02 *)mstk48t02_regs; 159/* resource is set at runtime */
203 if(!mregs) { 160static struct platform_device m48t59_rtc = {
204 prom_printf("Something wrong, clock regs not mapped yet.\n"); 161 .name = "rtc-m48t59",
205 prom_halt(); 162 .id = 0,
206 } 163 .num_resources = 1,
207 spin_lock_irq(&mostek_lock); 164 .dev = {
208 mregs->creg |= MSTK_CREG_READ; 165 .platform_data = &m48t59_data,
209 sec = MSTK_REG_SEC(mregs); 166 },
210 min = MSTK_REG_MIN(mregs); 167};
211 hour = MSTK_REG_HOUR(mregs);
212 day = MSTK_REG_DOM(mregs);
213 mon = MSTK_REG_MONTH(mregs);
214 year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
215 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
216 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
217 set_normalized_timespec(&wall_to_monotonic,
218 -xtime.tv_sec, -xtime.tv_nsec);
219 mregs->creg &= ~MSTK_CREG_READ;
220 spin_unlock_irq(&mostek_lock);
221}
222 168
223static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) 169static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match)
224{ 170{
@@ -228,33 +174,21 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id
228 if (!model) 174 if (!model)
229 return -ENODEV; 175 return -ENODEV;
230 176
177 m48t59_rtc.resource = &op->resource[0];
231 if (!strcmp(model, "mk48t02")) { 178 if (!strcmp(model, "mk48t02")) {
232 sp_clock_typ = MSTK48T02;
233
234 /* Map the clock register io area read-only */ 179 /* Map the clock register io area read-only */
235 mstk48t02_regs = of_ioremap(&op->resource[0], 0, 180 m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
236 sizeof(struct mostek48t02), 181 2048, "rtc-m48t59");
237 "mk48t02"); 182 m48t59_data.type = M48T59RTC_TYPE_M48T02;
238 mstk48t08_regs = NULL; /* To catch weirdness */
239 } else if (!strcmp(model, "mk48t08")) { 183 } else if (!strcmp(model, "mk48t08")) {
240 sp_clock_typ = MSTK48T08; 184 m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0,
241 mstk48t08_regs = of_ioremap(&op->resource[0], 0, 185 8192, "rtc-m48t59");
242 sizeof(struct mostek48t08), 186 m48t59_data.type = M48T59RTC_TYPE_M48T08;
243 "mk48t08");
244
245 mstk48t02_regs = &mstk48t08_regs->regs;
246 } else 187 } else
247 return -ENODEV; 188 return -ENODEV;
248 189
249 /* Report a low battery voltage condition. */ 190 if (platform_device_register(&m48t59_rtc) < 0)
250 if (has_low_battery()) 191 printk(KERN_ERR "Registering RTC device failed\n");
251 printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
252
253 /* Kick start the clock if it is completely stopped. */
254 if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
255 kick_start_clock();
256
257 mostek_set_system_time();
258 192
259 return 0; 193 return 0;
260} 194}
@@ -270,7 +204,7 @@ static struct of_platform_driver clock_driver = {
270 .match_table = clock_match, 204 .match_table = clock_match,
271 .probe = clock_probe, 205 .probe = clock_probe,
272 .driver = { 206 .driver = {
273 .name = "clock", 207 .name = "rtc",
274 }, 208 },
275}; 209};
276 210
@@ -400,43 +334,12 @@ static int sbus_do_settimeofday(struct timespec *tv)
400 return 0; 334 return 0;
401} 335}
402 336
403/* 337static int set_rtc_mmss(unsigned long secs)
404 * BUG: This routine does not handle hour overflow properly; it just
405 * sets the minutes. Usually you won't notice until after reboot!
406 */
407static int set_rtc_mmss(unsigned long nowtime)
408{ 338{
409 int real_seconds, real_minutes, mostek_minutes; 339 struct rtc_device *rtc = rtc_class_open("rtc0");
410 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
411 unsigned long flags;
412 340
413 spin_lock_irqsave(&mostek_lock, flags); 341 if (rtc)
414 /* Read the current RTC minutes. */ 342 return rtc_set_mmss(rtc, secs);
415 regs->creg |= MSTK_CREG_READ;
416 mostek_minutes = MSTK_REG_MIN(regs);
417 regs->creg &= ~MSTK_CREG_READ;
418 343
419 /* 344 return -1;
420 * since we're only adjusting minutes and seconds,
421 * don't interfere with hour overflow. This avoids
422 * messing with unknown time zones but requires your
423 * RTC not to be off by more than 15 minutes
424 */
425 real_seconds = nowtime % 60;
426 real_minutes = nowtime / 60;
427 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
428 real_minutes += 30; /* correct for half hour time zone */
429 real_minutes %= 60;
430
431 if (abs(real_minutes - mostek_minutes) < 30) {
432 regs->creg |= MSTK_CREG_WRITE;
433 MSTK_SET_REG_SEC(regs,real_seconds);
434 MSTK_SET_REG_MIN(regs,real_minutes);
435 regs->creg &= ~MSTK_CREG_WRITE;
436 spin_unlock_irqrestore(&mostek_lock, flags);
437 return 0;
438 } else {
439 spin_unlock_irqrestore(&mostek_lock, flags);
440 return -1;
441 }
442} 345}