diff -ru linux-2.6.17.old/arch/sh/boards/hp6xx/pm.c linux-2.6.17/arch/sh/boards/hp6xx/pm.c --- linux-2.6.17.old/arch/sh/boards/hp6xx/pm.c 2009-12-21 10:27:22.776442805 +0200 +++ linux-2.6.17/arch/sh/boards/hp6xx/pm.c 2009-12-21 10:30:09.366428509 +0200 @@ -17,6 +17,10 @@ #include #include +#include +#include +#include + #define STBCR 0xffffff82 #define STBCR2 0xffffff88 @@ -68,6 +72,8 @@ outb(0x00, HD64461_PCC1CSCR); #endif + rtc_sh_get_time(&xtime); + return 0; } diff -ru linux-2.6.17.old/arch/sh/kernel/cpu/irq/ipr.c linux-2.6.17/arch/sh/kernel/cpu/irq/ipr.c --- linux-2.6.17.old/arch/sh/kernel/cpu/irq/ipr.c 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/arch/sh/kernel/cpu/irq/ipr.c 2009-12-21 10:29:58.713508059 +0200 @@ -125,7 +125,12 @@ make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY); make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY); #if defined(CONFIG_SH_RTC) + make_ipr_irq(20, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); + printk("kernel IRQ RTC =%i\n",20); + make_ipr_irq(21, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); + printk("kernel IRQ RTC =%i\n",21); make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY); + printk("kernel IRQ RTC =%i\n",RTC_IRQ); #endif #ifdef SCI_ERI_IRQ diff -ru linux-2.6.17.old/arch/sh/kernel/cpu/sh3/Makefile linux-2.6.17/arch/sh/kernel/cpu/sh3/Makefile --- linux-2.6.17.old/arch/sh/kernel/cpu/sh3/Makefile 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/arch/sh/kernel/cpu/sh3/Makefile 2009-12-21 10:29:58.713508059 +0200 @@ -4,10 +4,13 @@ obj-y := ex.o probe.o +obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh770x.o + clock-$(CONFIG_CPU_SH3) := clock-sh3.o clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o -clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o +# clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o +clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o obj-y += $(clock-y) diff -ru linux-2.6.17.old/arch/sh/kernel/cpu/sh3/setup-sh770x.c linux-2.6.17/arch/sh/kernel/cpu/sh3/setup-sh770x.c --- linux-2.6.17.old/arch/sh/kernel/cpu/sh3/setup-sh770x.c 2009-12-21 10:32:06.699746910 +0200 +++ linux-2.6.17/arch/sh/kernel/cpu/sh3/setup-sh770x.c 2009-12-21 10:29:58.713508059 +0200 @@ -0,0 +1,217 @@ +/* + * SH3 Setup code for SH7706, SH7707, SH7708, SH7709 + * + * Copyright (C) 2007 Magnus Damm + * + * Based on setup-sh7709.c + * + * Copyright (C) 2006 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include +#include +#include +#include +#include +#include + +enum { + UNUSED = 0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, + PINT07, PINT815, + DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3, + SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI, + SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI, + SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI, + ADC_ADI, + LCDC, PCC0, PCC1, + TMU0, TMU1, TMU2_TUNI, TMU2_TICPI, + RTC_ATI, RTC_PRI, RTC_CUI, + WDT, + REF_RCMI, REF_ROVI, + + /* interrupt groups */ + RTC, REF, TMU2, DMAC, SCI, SCIF2, SCIF0, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460), + INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0), + INTC_VECT(RTC_CUI, 0x4c0), + INTC_VECT(SCI_ERI, 0x4e0), INTC_VECT(SCI_RXI, 0x500), + INTC_VECT(SCI_TXI, 0x520), INTC_VECT(SCI_TEI, 0x540), + INTC_VECT(WDT, 0x560), + INTC_VECT(REF_RCMI, 0x580), + INTC_VECT(REF_ROVI, 0x5a0), +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(DMAC_DEI0, 0x800), INTC_VECT(DMAC_DEI1, 0x820), + INTC_VECT(DMAC_DEI2, 0x840), INTC_VECT(DMAC_DEI3, 0x860), + INTC_VECT(ADC_ADI, 0x980), + INTC_VECT(SCIF2_ERI, 0x900), INTC_VECT(SCIF2_RXI, 0x920), + INTC_VECT(SCIF2_BRI, 0x940), INTC_VECT(SCIF2_TXI, 0x960), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + INTC_VECT(PINT07, 0x700), INTC_VECT(PINT815, 0x720), + INTC_VECT(SCIF0_ERI, 0x880), INTC_VECT(SCIF0_RXI, 0x8a0), + INTC_VECT(SCIF0_BRI, 0x8c0), INTC_VECT(SCIF0_TXI, 0x8e0), +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + INTC_VECT(LCDC, 0x9a0), + INTC_VECT(PCC0, 0x9c0), INTC_VECT(PCC1, 0x9e0), +#endif +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI), + INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI), + INTC_GROUP(REF, REF_RCMI, REF_ROVI), + INTC_GROUP(DMAC, DMAC_DEI0, DMAC_DEI1, DMAC_DEI2, DMAC_DEI3), + INTC_GROUP(SCI, SCI_ERI, SCI_RXI, SCI_TXI, SCI_TEI), + INTC_GROUP(SCIF0, SCIF0_ERI, SCIF0_RXI, SCIF0_BRI, SCIF0_TXI), + INTC_GROUP(SCIF2, SCIF2_ERI, SCIF2_RXI, SCIF2_BRI, SCIF2_TXI), +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xfffffee2, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } }, + { 0xfffffee4, 0, 16, 4, /* IPRB */ { WDT, REF, SCI, 0 } }, +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { 0xa4000016, 0, 16, 4, /* IPRC */ { IRQ3, IRQ2, IRQ1, IRQ0 } }, + { 0xa4000018, 0, 16, 4, /* IPRD */ { 0, 0, IRQ5, IRQ4 } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { DMAC, 0, SCIF2, ADC_ADI } }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { 0xa4000018, 0, 16, 4, /* IPRD */ { PINT07, PINT815, } }, + { 0xa400001a, 0, 16, 4, /* IPRE */ { 0, SCIF0 } }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) + { 0xa400001c, 0, 16, 4, /* IPRF */ { 0, LCDC, PCC0, PCC1, } }, +#endif +}; + +static DECLARE_INTC_DESC(intc_desc, "sh770x", vectors, groups, + NULL, prio_registers, NULL); + +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) +static struct intc_vect vectors_irq[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), +}; + +static DECLARE_INTC_DESC(intc_desc_irq, "sh770x-irq", vectors_irq, NULL, + NULL, prio_registers, NULL); +#endif + +static struct resource rtc_resources[] = { + [0] = { + .start = 0xfffffec0, + .end = 0xfffffec0 + 0x1e, + .flags = IORESOURCE_IO, + }, + [1] = { + .start = 21, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = 22, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = 20, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device rtc_device = { + .name = "sh-rtc", + .id = -1, + .num_resources = ARRAY_SIZE(rtc_resources), + .resource = rtc_resources, +}; + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xfffffe80, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCI, + .irqs = { 23, 24, 25, 0 }, + }, +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { + .mapbase = 0xa4000150, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 56, 57, 59, 58 }, + }, +#endif +#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + { + .mapbase = 0xa4000140, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_IRDA, + .irqs = { 52, 53, 55, 54 }, + }, +#endif + { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh770x_devices[] __initdata = { + &sci_device, + &rtc_device, +}; + +static int __init sh770x_devices_setup(void) +{ + return platform_add_devices(sh770x_devices, + ARRAY_SIZE(sh770x_devices)); +} +__initcall(sh770x_devices_setup); + +#define INTC_ICR1 0xa4000010UL +#define INTC_ICR1_IRQLVL (1<<14) + +void __init plat_irq_setup_pins(int mode) +{ + if (mode == IRQ_MODE_IRQ) { +#if defined(CONFIG_CPU_SUBTYPE_SH7706) || \ + defined(CONFIG_CPU_SUBTYPE_SH7707) || \ + defined(CONFIG_CPU_SUBTYPE_SH7709) + ctrl_outw(ctrl_inw(INTC_ICR1) & ~INTC_ICR1_IRQLVL, INTC_ICR1); +/* register_intc_controller(&intc_desc_irq); */ + return; +#endif + } + BUG(); +} + +void __init plat_irq_setup(void) +{ +/* register_intc_controller(&intc_desc); */ +} diff -ru linux-2.6.17.old/drivers/rtc/interface.c linux-2.6.17/drivers/rtc/interface.c --- linux-2.6.17.old/drivers/rtc/interface.c 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/drivers/rtc/interface.c 2009-12-21 10:29:58.713508059 +0200 @@ -145,11 +145,16 @@ } EXPORT_SYMBOL_GPL(rtc_set_alarm); -void rtc_update_irq(struct class_device *class_dev, +/** + * rtc_update_irq - report RTC periodic, alarm, and/or update irqs + * @rtc: the rtc device + * @num: how many irqs are being reported (usually one) + * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF + * Context: in_interrupt(), irqs blocked + */ +void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { - struct rtc_device *rtc = to_rtc_device(class_dev); - spin_lock(&rtc->irq_lock); rtc->irq_data = (rtc->irq_data + (num << 8)) | events; spin_unlock(&rtc->irq_lock); diff -ru linux-2.6.17.old/drivers/rtc/rtc-sh.c linux-2.6.17/drivers/rtc/rtc-sh.c --- linux-2.6.17.old/drivers/rtc/rtc-sh.c 2009-12-21 10:27:23.403110577 +0200 +++ linux-2.6.17/drivers/rtc/rtc-sh.c 2009-12-21 10:29:58.716840103 +0200 @@ -1,7 +1,8 @@ /* * SuperH On-Chip RTC Support * - * Copyright (C) 2006 Paul Mundt + * Copyright (C) 2006, 2007 Paul Mundt + * Copyright (C) 2006 Jamie Lenehan * * Based on the old arch/sh/kernel/cpu/rtc.c by: * @@ -21,34 +22,46 @@ #include #include #include -#include +#include +#include -#ifdef CONFIG_CPU_SH3 -#define rtc_reg_size sizeof(u16) -#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ -#elif defined(CONFIG_CPU_SH4) -#define rtc_reg_size sizeof(u32) -#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */ -#endif +#define DRV_NAME "sh-rtc" +#define DRV_VERSION "0.1.6" #define RTC_REG(r) ((r) * rtc_reg_size) -#define R64CNT RTC_REG(0) -#define RSECCNT RTC_REG(1) -#define RMINCNT RTC_REG(2) -#define RHRCNT RTC_REG(3) -#define RWKCNT RTC_REG(4) -#define RDAYCNT RTC_REG(5) -#define RMONCNT RTC_REG(6) -#define RYRCNT RTC_REG(7) -#define RSECAR RTC_REG(8) -#define RMINAR RTC_REG(9) -#define RHRAR RTC_REG(10) -#define RWKAR RTC_REG(11) -#define RDAYAR RTC_REG(12) -#define RMONAR RTC_REG(13) -#define RCR1 RTC_REG(14) -#define RCR2 RTC_REG(15) +#define R64CNT RTC_REG(0) + +#define RSECCNT RTC_REG(1) /* RTC sec */ +#define RMINCNT RTC_REG(2) /* RTC min */ +#define RHRCNT RTC_REG(3) /* RTC hour */ +#define RWKCNT RTC_REG(4) /* RTC week */ +#define RDAYCNT RTC_REG(5) /* RTC day */ +#define RMONCNT RTC_REG(6) /* RTC month */ +#define RYRCNT RTC_REG(7) /* RTC year */ +#define RSECAR RTC_REG(8) /* ALARM sec */ +#define RMINAR RTC_REG(9) /* ALARM min */ +#define RHRAR RTC_REG(10) /* ALARM hour */ +#define RWKAR RTC_REG(11) /* ALARM week */ +#define RDAYAR RTC_REG(12) /* ALARM day */ +#define RMONAR RTC_REG(13) /* ALARM month */ +#define RCR1 RTC_REG(14) /* Control */ +#define RCR2 RTC_REG(15) /* Control */ + +/* + * Note on RYRAR and RCR3: Up until this point most of the register + * definitions are consistent across all of the available parts. However, + * the placement of the optional RYRAR and RCR3 (the RYRAR control + * register used to control RYRCNT/RYRAR compare) varies considerably + * across various parts, occasionally being mapped in to a completely + * unrelated address space. For proper RYRAR support a separate resource + * would have to be handed off, but as this is purely optional in + * practice, we simply opt not to support it, thereby keeping the code + * quite a bit more simplified. + */ + +/* ALARM Bits - or with BCD encoded value */ +#define AR_ENB 0x80 /* Enable for alarm cmp */ /* RCR1 Bits */ #define RCR1_CF 0x80 /* Carry Flag */ @@ -71,39 +84,82 @@ unsigned int alarm_irq, periodic_irq, carry_irq; struct rtc_device *rtc_dev; spinlock_t lock; + int rearm_aie; + unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */ }; -static irqreturn_t sh_rtc_interrupt(int irq, void *id, struct pt_regs *regs) +static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct platform_device *pdev = id; + struct platform_device *pdev = to_platform_device(dev_id); struct sh_rtc *rtc = platform_get_drvdata(pdev); unsigned int tmp, events = 0; spin_lock(&rtc->lock); tmp = readb(rtc->regbase + RCR1); + tmp &= ~RCR1_CF; - if (tmp & RCR1_AF) - events |= RTC_AF | RTC_IRQF; - - tmp &= ~(RCR1_CF | RCR1_AF); + if (rtc->rearm_aie) { + if (tmp & RCR1_AF) + tmp &= ~RCR1_AF; /* try to clear AF again */ + else { + tmp |= RCR1_AIE; /* AF has cleared, rearm IRQ */ + rtc->rearm_aie = 0; + } + } writeb(tmp, rtc->regbase + RCR1); - - rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events); + + rtc_update_irq(rtc->rtc_dev, 1, events); spin_unlock(&rtc->lock); return IRQ_HANDLED; } -static irqreturn_t sh_rtc_periodic(int irq, void *id, struct pt_regs *regs) +static irqreturn_t sh_rtc_alarm(int irq, void *dev_id, struct pt_regs *regs) +{ + struct platform_device *pdev = to_platform_device(dev_id); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + unsigned int tmp, events = 0; + + spin_lock(&rtc->lock); + + tmp = readb(rtc->regbase + RCR1); + + /* + * If AF is set then the alarm has triggered. If we clear AF while + * the alarm time still matches the RTC time then AF will + * immediately be set again, and if AIE is enabled then the alarm + * interrupt will immediately be retrigger. So we clear AIE here + * and use rtc->rearm_aie so that the carry interrupt will keep + * trying to clear AF and once it stays cleared it'll re-enable + * AIE. + */ + if (tmp & RCR1_AF) { + events |= RTC_AF | RTC_IRQF; + + tmp &= ~(RCR1_AF|RCR1_AIE); + + writeb(tmp, rtc->regbase + RCR1); + + rtc->rearm_aie = 1; + + rtc_update_irq(rtc->rtc_dev, 1, events); + } + + spin_unlock(&rtc->lock); + return IRQ_HANDLED; +} + +static irqreturn_t sh_rtc_periodic(int irq, void *dev_id, struct pt_regs *regs) { - struct sh_rtc *rtc = dev_get_drvdata(id); + struct platform_device *pdev = to_platform_device(dev_id); + struct sh_rtc *rtc = platform_get_drvdata(pdev); spin_lock(&rtc->lock); - rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF); + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF); spin_unlock(&rtc->lock); @@ -139,10 +195,11 @@ tmp = readb(rtc->regbase + RCR1); - if (enable) - tmp |= RCR1_AIE; - else + if (!enable) { tmp &= ~RCR1_AIE; + rtc->rearm_aie = 0; + } else if (rtc->rearm_aie == 0) + tmp |= RCR1_AIE; writeb(tmp, rtc->regbase + RCR1); @@ -177,14 +234,14 @@ goto err_bad_carry; } - ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, SA_INTERRUPT, + ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, SA_INTERRUPT, "sh-rtc alarm", dev); if (unlikely(ret)) { dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n", ret, rtc->alarm_irq); goto err_bad_alarm; } - + return 0; err_bad_alarm: @@ -200,6 +257,7 @@ struct sh_rtc *rtc = dev_get_drvdata(dev); sh_rtc_setpie(dev, 0); + sh_rtc_setaie(dev, 0); free_irq(rtc->periodic_irq, dev); free_irq(rtc->carry_irq, dev); @@ -212,8 +270,6 @@ unsigned int tmp; tmp = readb(rtc->regbase + RCR1); - seq_printf(seq, "alarm_IRQ\t: %s\n", - (tmp & RCR1_AIE) ? "yes" : "no"); seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" : "no"); @@ -267,16 +323,16 @@ tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT)); tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT)); tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT)); - tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)); + tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1; -#if defined(CONFIG_CPU_SH4) - yr = readw(rtc->regbase + RYRCNT); - yr100 = BCD2BIN(yr >> 8); - yr &= 0xff; -#else - yr = readb(rtc->regbase + RYRCNT); - yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + yr = readw(rtc->regbase + RYRCNT); + yr100 = BCD2BIN(yr >> 8); + yr &= 0xff; + } else { + yr = readb(rtc->regbase + RYRCNT); + yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20); + } tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900; @@ -291,14 +347,16 @@ tm->tm_sec--; #endif - dev_dbg(&dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); + tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); - if (rtc_valid_tm(tm) < 0) + if (rtc_valid_tm(tm) < 0) { dev_err(dev, "invalid date\n"); + rtc_time_to_tm(0, tm); + } return 0; } @@ -315,6 +373,7 @@ /* Reset pre-scaler & stop RTC */ tmp = readb(rtc->regbase + RCR2); tmp |= RCR2_RESET; + tmp &= ~RCR2_START; writeb(tmp, rtc->regbase + RCR2); writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT); @@ -322,16 +381,16 @@ writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT); writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT); writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT); - writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT); + writeb(BIN2BCD(tm->tm_mon + 1), rtc->regbase + RMONCNT); -#ifdef CONFIG_CPU_SH3 - year = tm->tm_year % 100; - writeb(BIN2BCD(year), rtc->regbase + RYRCNT); -#else - year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | - BIN2BCD(tm->tm_year % 100); - writew(year, rtc->regbase + RYRCNT); -#endif + if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) { + year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) | + BIN2BCD(tm->tm_year % 100); + writew(year, rtc->regbase + RYRCNT); + } else { + year = tm->tm_year % 100; + writeb(BIN2BCD(year), rtc->regbase + RYRCNT); + } /* Start RTC */ tmp = readb(rtc->regbase + RCR2); @@ -344,12 +403,140 @@ return 0; } +static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off) +{ + unsigned int byte; + int value = 0xff; /* return 0xff for ignored values */ + + byte = readb(rtc->regbase + reg_off); + if (byte & AR_ENB) { + byte &= ~AR_ENB; /* strip the enable bit */ + value = BCD2BIN(byte); + } + + return value; +} + +static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + struct rtc_time* tm = &wkalrm->time; + + spin_lock_irq(&rtc->lock); + + tm->tm_sec = sh_rtc_read_alarm_value(rtc, RSECAR); + tm->tm_min = sh_rtc_read_alarm_value(rtc, RMINAR); + tm->tm_hour = sh_rtc_read_alarm_value(rtc, RHRAR); + tm->tm_wday = sh_rtc_read_alarm_value(rtc, RWKAR); + tm->tm_mday = sh_rtc_read_alarm_value(rtc, RDAYAR); + tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR); + if (tm->tm_mon > 0) + tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */ + tm->tm_year = 0xffff; + + wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0; + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc, + int value, int reg_off) +{ + /* < 0 for a value that is ignored */ + if (value < 0) + writeb(0, rtc->regbase + reg_off); + else + writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off); +} + +static int sh_rtc_check_alarm(struct rtc_time* tm) +{ + /* + * The original rtc says anything > 0xc0 is "don't care" or "match + * all" - most users use 0xff but rtc-dev uses -1 for the same thing. + * The original rtc doesn't support years - some things use -1 and + * some 0xffff. We use -1 to make out tests easier. + */ + if (tm->tm_year == 0xffff) + tm->tm_year = -1; + if (tm->tm_mon >= 0xff) + tm->tm_mon = -1; + if (tm->tm_mday >= 0xff) + tm->tm_mday = -1; + if (tm->tm_wday >= 0xff) + tm->tm_wday = -1; + if (tm->tm_hour >= 0xff) + tm->tm_hour = -1; + if (tm->tm_min >= 0xff) + tm->tm_min = -1; + if (tm->tm_sec >= 0xff) + tm->tm_sec = -1; + + if (tm->tm_year > 9999 || + tm->tm_mon >= 12 || + tm->tm_mday == 0 || tm->tm_mday >= 32 || + tm->tm_wday >= 7 || + tm->tm_hour >= 24 || + tm->tm_min >= 60 || + tm->tm_sec >= 60) + return -EINVAL; + + return 0; +} + +static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sh_rtc *rtc = platform_get_drvdata(pdev); + unsigned int rcr1; + struct rtc_time *tm = &wkalrm->time; + int mon, err; + + err = sh_rtc_check_alarm(tm); + if (unlikely(err < 0)) + return err; + + spin_lock_irq(&rtc->lock); + + /* disable alarm interrupt and clear the alarm flag */ + rcr1 = readb(rtc->regbase + RCR1); + rcr1 &= ~(RCR1_AF|RCR1_AIE); + writeb(rcr1, rtc->regbase + RCR1); + + rtc->rearm_aie = 0; + + /* set alarm time */ + sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR); + sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR); + sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR); + sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR); + sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR); + mon = tm->tm_mon; + if (mon >= 0) + mon += 1; + sh_rtc_write_alarm_value(rtc, mon, RMONAR); + + if (wkalrm->enabled) { + rcr1 |= RCR1_AIE; + writeb(rcr1, rtc->regbase + RCR1); + } + + spin_unlock_irq(&rtc->lock); + + return 0; +} + static struct rtc_class_ops sh_rtc_ops = { .open = sh_rtc_open, .release = sh_rtc_release, .ioctl = sh_rtc_ioctl, .read_time = sh_rtc_read_time, .set_time = sh_rtc_set_time, + .read_alarm = sh_rtc_read_alarm, + .set_alarm = sh_rtc_set_alarm, .proc = sh_rtc_proc, }; @@ -405,11 +592,22 @@ rtc->rtc_dev = rtc_device_register("sh", &pdev->dev, &sh_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { + if (IS_ERR(rtc->rtc_dev)) { ret = PTR_ERR(rtc->rtc_dev); goto err_badmap; } + rtc->capabilities = RTC_DEF_CAPABILITIES; + if (pdev->dev.platform_data) { + struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; + + /* + * Some CPUs have special capabilities in addition to the + * default set. Add those in here. + */ +/* rtc->capabilities |= pinfo->capabilities; */ + } + platform_set_drvdata(pdev, rtc); return 0; @@ -425,7 +623,7 @@ static int __devexit sh_rtc_remove(struct platform_device *pdev) { struct sh_rtc *rtc = platform_get_drvdata(pdev); - + if (likely(rtc->rtc_dev)) rtc_device_unregister(rtc->rtc_dev); @@ -442,7 +640,7 @@ } static struct platform_driver sh_rtc_platform_driver = { .driver = { - .name = "sh-rtc", + .name = DRV_NAME, .owner = THIS_MODULE, }, .probe = sh_rtc_probe, @@ -463,5 +661,7 @@ module_exit(sh_rtc_exit); MODULE_DESCRIPTION("SuperH on-chip RTC driver"); -MODULE_AUTHOR("Paul Mundt "); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Paul Mundt , Jamie Lenehan "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff -ru linux-2.6.17.old/include/asm-sh/cpu-sh3/rtc.h linux-2.6.17/include/asm-sh/cpu-sh3/rtc.h --- linux-2.6.17.old/include/asm-sh/cpu-sh3/rtc.h 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/include/asm-sh/cpu-sh3/rtc.h 2009-12-21 10:30:05.923092336 +0200 @@ -20,6 +20,8 @@ #define RCR2 0xfffffede #define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */ +#define RTC_DEF_CAPABILITIES 0UL +#define rtc_reg_size sizeof(u16) #endif /* __ASM_CPU_SH3_RTC_H */ diff -ru linux-2.6.17.old/include/asm-sh/hw_irq.h linux-2.6.17/include/asm-sh/hw_irq.h --- linux-2.6.17.old/include/asm-sh/hw_irq.h 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/include/asm-sh/hw_irq.h 2009-12-21 10:29:58.716840103 +0200 @@ -1,6 +1,111 @@ #ifndef __ASM_SH_HW_IRQ_H #define __ASM_SH_HW_IRQ_H +#include +#include + +extern atomic_t irq_err_count; + +/* +struct ipr_data { + unsigned char irq; + unsigned char ipr_idx;*/ /* Index for the IPR registered */ +/* + unsigned char shift; */ /* Number of bits to shift the data */ +/* + unsigned char priority; *//* The priority */ +/* };*/ + +/* +struct ipr_desc { + unsigned long *ipr_offsets; + unsigned int nr_offsets; + struct ipr_data *ipr_data; + unsigned int nr_irqs; + struct irq_chip chip; +}; + +void register_ipr_controller(struct ipr_desc *); +*/ + +typedef unsigned char intc_enum; + +struct intc_vect { + intc_enum enum_id; + unsigned short vect; +}; + +#define INTC_VECT(enum_id, vect) { enum_id, vect } +#define INTC_IRQ(enum_id, irq) INTC_VECT(enum_id, irq2evt(irq)) + +struct intc_group { + intc_enum enum_id; + intc_enum enum_ids[32]; +}; + +#define INTC_GROUP(enum_id, ids...) { enum_id, { ids } } + +struct intc_mask_reg { + unsigned long set_reg, clr_reg, reg_width; + intc_enum enum_ids[32]; +#ifdef CONFIG_SMP + unsigned long smp; +#endif +}; + +struct intc_prio_reg { + unsigned long set_reg, clr_reg, reg_width, field_width; + intc_enum enum_ids[16]; +#ifdef CONFIG_SMP + unsigned long smp; +#endif +}; + +struct intc_sense_reg { + unsigned long reg, reg_width, field_width; + intc_enum enum_ids[16]; +}; + +#ifdef CONFIG_SMP +#define INTC_SMP(stride, nr) .smp = (stride) | ((nr) << 8) +#else +#define INTC_SMP(stride, nr) +#endif + +struct intc_desc { + struct intc_vect *vectors; + unsigned int nr_vectors; + struct intc_group *groups; + unsigned int nr_groups; + struct intc_mask_reg *mask_regs; + unsigned int nr_mask_regs; + struct intc_prio_reg *prio_regs; + unsigned int nr_prio_regs; + struct intc_sense_reg *sense_regs; + unsigned int nr_sense_regs; + char *name; +}; + +#define _INTC_ARRAY(a) a, sizeof(a)/sizeof(*a) +#define DECLARE_INTC_DESC(symbol, chipname, vectors, groups, \ + mask_regs, prio_regs, sense_regs) \ +struct intc_desc symbol __initdata = { \ + _INTC_ARRAY(vectors), _INTC_ARRAY(groups), \ + _INTC_ARRAY(mask_regs), _INTC_ARRAY(prio_regs), \ + _INTC_ARRAY(sense_regs), \ + chipname, \ +} + +void __init register_intc_controller(struct intc_desc *desc); +int intc_set_priority(unsigned int irq, unsigned int prio); + +void __init plat_irq_setup(void); + +enum { IRQ_MODE_IRQ, IRQ_MODE_IRQ7654, IRQ_MODE_IRQ3210, + IRQ_MODE_IRL7654_MASK, IRQ_MODE_IRL3210_MASK, + IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 }; +void __init plat_irq_setup_pins(int mode); + static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) { /* Nothing to do */ diff -ru linux-2.6.17.old/include/asm-sh/rtc.h linux-2.6.17/include/asm-sh/rtc.h --- linux-2.6.17.old/include/asm-sh/rtc.h 2009-12-21 10:27:23.566444610 +0200 +++ linux-2.6.17/include/asm-sh/rtc.h 2009-12-21 10:29:58.716840103 +0200 @@ -25,5 +25,7 @@ #define RCR2_RESET 0x02 /* Reset bit */ #define RCR2_START 0x01 /* Start bit */ +#define RTC_CAP_4_DIGIT_YEAR (1 << 0) + #endif /* __KERNEL__ */ #endif /* _ASM_RTC_H */ diff -ru linux-2.6.17.old/include/linux/rtc.h linux-2.6.17/include/linux/rtc.h --- linux-2.6.17.old/include/linux/rtc.h 2006-06-18 04:49:35.000000000 +0300 +++ linux-2.6.17/include/linux/rtc.h 2009-12-21 10:29:58.716840103 +0200 @@ -172,7 +172,8 @@ struct rtc_wkalrm *alrm); extern int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alrm); -extern void rtc_update_irq(struct class_device *class_dev, + +extern void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events); extern struct class_device *rtc_class_open(char *name); diff -ru linux-2.6.17.old/include/linux/serial_sci.h linux-2.6.17/include/linux/serial_sci.h --- linux-2.6.17.old/include/linux/serial_sci.h 2009-12-21 10:33:00.536412963 +0200 +++ linux-2.6.17/include/linux/serial_sci.h 2009-12-21 10:29:58.716840103 +0200 @@ -0,0 +1,32 @@ +#ifndef __LINUX_SERIAL_SCI_H +#define __LINUX_SERIAL_SCI_H + +#include + +/* + * Generic header for SuperH SCI(F) (used by sh/sh64/h8300 and related parts) + */ + +/* Offsets into the sci_port->irqs array */ +enum { + SCIx_ERI_IRQ, + SCIx_RXI_IRQ, + SCIx_TXI_IRQ, + SCIx_BRI_IRQ, + SCIx_NR_IRQS, +}; + +/* + * Platform device specific platform_data struct + */ +struct plat_sci_port { + void __iomem *membase; /* io cookie */ + unsigned long mapbase; /* resource base */ + unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */ + unsigned int type; /* SCI / SCIF / IRDA */ + upf_t flags; /* UPF_* flags */ +}; + +int early_sci_setup(struct uart_port *port); + +#endif /* __LINUX_SERIAL_SCI_H */