diff -Naurp linux-2.6.33-20100313.orig//arch/mips/sgi-ip32/ip32-platform.c linux-2.6.33-20100313//arch/mips/sgi-ip32/ip32-platform.c --- linux-2.6.33-20100313.orig//arch/mips/sgi-ip32/ip32-platform.c 2010-02-24 13:52:17.000000000 -0500 +++ linux-2.6.33-20100313//arch/mips/sgi-ip32/ip32-platform.c 2010-06-06 00:59:05.645090587 -0400 @@ -90,21 +90,30 @@ static __init int sgio2btns_devinit(void device_initcall(sgio2btns_devinit); -static struct resource sgio2_cmos_rsrc[] = { +#define MACE_RTC_RES_START (MACE_BASE + offsetof(struct sgi_mace, isa.rtc)) +#define MACE_RTC_RES_END (MACE_RTC_RES_START + 32767) + +static struct resource ip32_rtc_resources[] = { { - .start = 0x70, - .end = 0x71, - .flags = IORESOURCE_IO + .start = MACEISA_RTC_IRQ, + .end = MACEISA_RTC_IRQ, + .flags = IORESOURCE_IRQ + }, { + .start = MACE_RTC_RES_START, + .end = MACE_RTC_RES_END, + .flags = IORESOURCE_MEM, } }; -static __init int sgio2_cmos_devinit(void) + + +static __init int sgio2_rtc_devinit(void) { - return IS_ERR(platform_device_register_simple("rtc_cmos", -1, - sgio2_cmos_rsrc, 1)); + return IS_ERR(platform_device_register_simple("rtc-ds1685", -1, + ip32_rtc_resources, ARRAY_SIZE(ip32_rtc_resources))); } -device_initcall(sgio2_cmos_devinit); +device_initcall(sgio2_rtc_devinit); MODULE_AUTHOR("Ralf Baechle "); MODULE_LICENSE("GPL"); diff -Naurp linux-2.6.33-20100313.orig//arch/mips/sgi-ip32/ip32-reset.c linux-2.6.33-20100313//arch/mips/sgi-ip32/ip32-reset.c --- linux-2.6.33-20100313.orig//arch/mips/sgi-ip32/ip32-reset.c 2010-02-24 13:52:17.000000000 -0500 +++ linux-2.6.33-20100313//arch/mips/sgi-ip32/ip32-reset.c 2010-06-06 01:00:54.794444484 -0400 @@ -33,7 +33,7 @@ #define POWERDOWN_FREQ (HZ / 4) #define PANIC_FREQ (HZ / 8) -static struct timer_list power_timer, blink_timer, debounce_timer; +static struct timer_list power_timer, blink_timer; static int has_panicked, shuting_down; static void ip32_machine_restart(char *command) __attribute__((noreturn)); @@ -89,33 +89,6 @@ static void blink_timeout(unsigned long mod_timer(&blink_timer, jiffies + data); } -static void debounce(unsigned long data) -{ - unsigned char reg_a, reg_c, xctrl_a; - - reg_c = CMOS_READ(RTC_INTR_FLAGS); - reg_a = CMOS_READ(RTC_REG_A); - CMOS_WRITE(reg_a | DS_REGA_DV0, RTC_REG_A); - wbflush(); - xctrl_a = CMOS_READ(DS_B1_XCTRL4A); - if ((xctrl_a & DS_XCTRL4A_IFS) || (reg_c & RTC_IRQF )) { - /* Interrupt still being sent. */ - debounce_timer.expires = jiffies + 50; - add_timer(&debounce_timer); - - /* clear interrupt source */ - CMOS_WRITE(xctrl_a & ~DS_XCTRL4A_IFS, DS_B1_XCTRL4A); - CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); - return; - } - CMOS_WRITE(reg_a & ~DS_REGA_DV0, RTC_REG_A); - - if (has_panicked) - ip32_machine_restart(NULL); - - enable_irq(MACEISA_RTC_IRQ); -} - static inline void ip32_power_button(void) { if (has_panicked) @@ -136,6 +109,7 @@ static inline void ip32_power_button(voi add_timer(&power_timer); } +#if 0 static irqreturn_t ip32_rtc_int(int irq, void *dev_id) { unsigned char reg_c; @@ -156,6 +130,7 @@ static irqreturn_t ip32_rtc_int(int irq, ip32_power_button(); return IRQ_HANDLED; } +#endif static int panic_event(struct notifier_block *this, unsigned long event, void *ptr) @@ -196,9 +171,6 @@ static __init int ip32_reboot_setup(void blink_timer.function = blink_timeout; atomic_notifier_chain_register(&panic_notifier_list, &panic_block); - if (request_irq(MACEISA_RTC_IRQ, ip32_rtc_int, 0, "rtc", NULL)) - panic("Can't allocate MACEISA RTC IRQ"); - return 0; } diff -Naurp linux-2.6.33-20100313.orig//drivers/rtc/Kconfig linux-2.6.33-20100313//drivers/rtc/Kconfig --- linux-2.6.33-20100313.orig//drivers/rtc/Kconfig 2010-02-24 13:52:17.000000000 -0500 +++ linux-2.6.33-20100313//drivers/rtc/Kconfig 2010-06-06 01:20:06.145090598 -0400 @@ -459,6 +459,32 @@ config RTC_DRV_DS1553 This driver can also be built as a module. If so, the module will be called rtc-ds1553. +config RTC_DRV_DS1685 + tristate "Dallas/Maxim DS1685/DS1687" + depends on (I2C || SGI_IP30 || SGI_IP32) + help + If you say yes here you get support for the Dallas/Maxim + DS1685/DS1687 timekeeping chip. + + This module also supports the DS17285/DS17287 timekeeping chips + that are sometimes found in place of the DS1685/DS1687 in some + SGI O2 systems. + + Other systems that use this chip include EPPC-405-UC modules, by + electronic system design GmbH. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1685. + +config RTC_DRV_DS17285 + bool "Enable DS17285/DS17287 Differences" + depends on (SGI_IP32 && RTC_DRV_DS1685) + help + If your SGI O2 has one of these RTC chips instead of the more + common DS1687-5 chip, say Y here to enable the minor differences + this particular chip has. For more information, refer to the + Dallas/Maxim datasheet for the DS17285/DS17287 chip. + config RTC_DRV_DS1742 tristate "Maxim/Dallas DS1742/1743" help diff -Naurp linux-2.6.33-20100313.orig//drivers/rtc/Makefile linux-2.6.33-20100313//drivers/rtc/Makefile --- linux-2.6.33-20100313.orig//drivers/rtc/Makefile 2010-02-24 13:52:17.000000000 -0500 +++ linux-2.6.33-20100313//drivers/rtc/Makefile 2010-03-13 23:22:37.915074973 -0500 @@ -38,6 +38,7 @@ obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds13 obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o +obj-$(CONFIG_RTC_DRV_DS1685) += rtc-ds1685.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o diff -Naurp linux-2.6.33-20100313.orig//drivers/rtc/rtc-ds1685.c linux-2.6.33-20100313//drivers/rtc/rtc-ds1685.c --- linux-2.6.33-20100313.orig//drivers/rtc/rtc-ds1685.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.33-20100313//drivers/rtc/rtc-ds1685.c 2010-06-06 01:43:47.115090339 -0400 @@ -0,0 +1,890 @@ +/* + * An rtc driver for the Dallas DS1685/DS1687. + * + * Copyright (C) 2009 Matthias Fuchs . + * Copyright (C) 2010 Joshua Kinard . + * + * Any code for SGI Octane (IP30)'s quirks for its DS1687-5 RTC are + * Copyright (C) 2005 Stanislaw Skowronek . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_PROC_FS +#include +#endif + +#define DRV_VERSION "0.3" + +static int +ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned long flags, start = jiffies; + unsigned int data; + unsigned int ctrlb, century; + unsigned int seconds, minutes, hours, wday, mday, month, years; + + /* Fetch the time info from the RTC registers. */ + ds1685_rtc_begin_data_access; + seconds = readb(®s->time.sec); + minutes = readb(®s->time.min); + hours = readb(®s->time.hour); + wday = readb(®s->time.wday); + mday = readb(®s->time.mday); + month = readb(®s->time.month); + years = readb(®s->time.year); + century = readb(®s->bank1.century); + ctrlb = readb(®s->time.ctrlb); + ds1685_rtc_end_data_access; + + /* Convert to Binary, perform fixups, and store to rtc_time. */ + tm->tm_sec = bcd2bin(seconds); + tm->tm_min = bcd2bin(minutes); + tm->tm_hour = bcd2bin(hours); + tm->tm_wday = (bcd2bin(wday) - 1); + tm->tm_mday = bcd2bin(mday); + tm->tm_mon = (bcd2bin(month) - 1); + tm->tm_year = ((bcd2bin(years) + (bcd2bin(century) * 100)) - 1900); + tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); + tm->tm_isdst = ((ctrlb & RTC_CTRL_B_DSE) ? 1 : 0); + + /* Make sure valid time was received. */ + if (rtc_valid_tm(tm) < 0) { + dev_err(dev, "retrieved date/time is not valid.\n"); + rtc_time_to_tm(0, tm); + } + return 0; +} + +static int +ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags, start = jiffies; + unsigned int seconds, minutes, hours, wday, mday, month, years; + unsigned int century; + + /* Fetch the time info from rtc_time. */ + seconds = bin2bcd(tm->tm_sec); + minutes = bin2bcd(tm->tm_min); + hours = bin2bcd(tm->tm_hour); + wday = bin2bcd(tm->tm_wday + 1); + mday = bin2bcd(tm->tm_mday); + month = bin2bcd(tm->tm_mon + 1); + years = bin2bcd(tm->tm_year % 100); + century = bin2bcd((tm->tm_year + 1900) / 100); + + /* + * Perform Sanity Checks: + * - Months: !> 12, Month Day != 0. + * - Month Day !> Max days in current month. + * - Hours !>= 24, Mins !>= 60, Secs !>= 60, & Weekday !> 7. + */ + if ((month > 12) || (mday == 0)) + return -EDOM; + + if (tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year)) + return -EDOM; + + if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60) || + (wday > 7)) + return -EDOM; + + /* + * Force datamode to BCD (DM=0) and store the time values in the + * RTC registers. + */ + ds1685_rtc_begin_data_access; + data = readb(®s->time.ctrlb) & ~(RTC_CTRL_B_DM); + writeb(data, ®s->time.ctrlb); + writeb(seconds, ®s->time.sec); + writeb(minutes, ®s->time.min); + writeb(hours, ®s->time.hour); + writeb(wday, ®s->time.wday); + writeb(mday, ®s->time.mday); + writeb(month, ®s->time.month); + writeb(years, ®s->time.year); + writeb(century, ®s->bank1.century); + ds1685_rtc_end_data_access; + + return 0; +} + +static int +ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags, start = jiffies; + unsigned int seconds, minutes, hours, mday; + + /* Fetch the alarm info from the RTC alarm registers. */ + ds1685_rtc_begin_data_access; + seconds = readb(®s->time.sec_alrm); + minutes = readb(®s->time.min_alrm); + hours = readb(®s->time.hour_alrm); + mday = readb(®s->bank1.mday_alrm); + ds1685_rtc_end_data_access; + + /* Convert to Binary format and store in rtc_wkalrm. */ + alrm->time.tm_sec = bcd2bin(seconds); + alrm->time.tm_min = bcd2bin(minutes); + alrm->time.tm_hour = bcd2bin(hours); + alrm->time.tm_mday = bcd2bin(mday); + + return 0; +} + +static int +ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags, start = jiffies; + unsigned int seconds, minutes, hours, mday; + + /* Fetch the alarm info and convert to BCD. */ + seconds = bin2bcd(alrm->time.tm_sec); + minutes = bin2bcd(alrm->time.tm_min); + hours = bin2bcd(alrm->time.tm_hour); + mday = bin2bcd(alrm->time.tm_mday); + + /* Write to the four RTC alarm registers. */ + ds1685_rtc_begin_data_access; + writeb(seconds, ®s->time.sec_alrm); + writeb(minutes, ®s->time.min_alrm); + writeb(hours, ®s->time.hour_alrm); + writeb(mday, ®s->bank1.mday_alrm); + ds1685_rtc_end_data_access; + + return 0; +} + +#ifdef CONFIG_RTC_INTF_DEV +/* + * This function enables/disables an interrupt, depending on what is passed + * in irq_bit. PIE/AIE/UIE are read/written in Ctrl B, and RIE/WIE/KSE in + * Ctrl 4B. + * + * XXX: Only handles PIE/AIE/UIE at present. + */ +static inline void +ds1685_rtc_irq_ctrl(volatile unsigned char *reg, spinlock_t *lock, + const unsigned int *enabled, const unsigned int irq_bit) +{ + unsigned long flags; + + if (*enabled) { + spin_lock_irqsave(lock, flags); + writeb((readb(reg) | irq_bit), reg); + spin_unlock_irqrestore(lock, flags); + } else { + spin_lock_irqsave(lock, flags); + writeb((readb(reg) & ~(irq_bit)), reg); + spin_unlock_irqrestore(lock, flags); + } +} + +/* Replaces ioctl() RTC_PIE on/off. */ +/* 2nd arg should be 'unsigned int', but needs fix in RTC core. */ +static int +ds1685_rtc_periodic_irq_enable(struct device *dev, int enabled) +{ + struct ds1685_priv *rtc = dev_get_drvdata(dev); + + ds1685_rtc_irq_ctrl(&rtc->regs->time.ctrlb, &rtc->lock, + &enabled, RTC_CTRL_B_PIE); + + rtc->p_intr = enabled; + + return 0; +} + +/* Replaces ioctl() RTC_AIE on/off. */ +static int +ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1685_priv *rtc = dev_get_drvdata(dev); + + ds1685_rtc_irq_ctrl(&rtc->regs->time.ctrlb, &rtc->lock, + &enabled, RTC_CTRL_B_AIE); + + rtc->a_intr = enabled; + + return 0; +} + +/* Replaces ioctl() RTC_UIE on/off. */ +static int +ds1685_rtc_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct ds1685_priv *rtc = dev_get_drvdata(dev); + + ds1685_rtc_irq_ctrl(&rtc->regs->time.ctrlb, &rtc->lock, + &enabled, RTC_CTRL_B_UIE); + + rtc->u_intr = enabled; + + return 0; +} + +/* + * Defunct; Will be fully replaced by IRQ API above once RTC Core is modified + * to handle RIE/WIE/KSE. + */ +static int +ds1685_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags; + + switch (cmd) { + case RTC_WIE_ON: + /* Allow Wake-up Alarm Interrupts */ + ds1685_rtc_begin_ctrl_access; + data = readb(®s->bank1.ctrl4b) | RTC_CTRL_4B_WIE; + writeb(data, ®s->bank1.ctrl4b); + ds1685_rtc_end_ctrl_access; + break; + + case RTC_WIE_OFF: + /* Disable Wake-up Alarm Interrupts */ + ds1685_rtc_begin_ctrl_access; + data = readb(®s->bank1.ctrl4b) & ~(RTC_CTRL_4B_WIE); + writeb(data, ®s->bank1.ctrl4b); + ds1685_rtc_end_ctrl_access; + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} +#else +#define ds1685_ioctl NULL +#define ds1685_rtc_periodic_irq_enable NULL +#define ds1685_rtc_alarm_irq_enable NULL +#define ds1685_rtc_update_irq_enable NULL +#endif /* CONFIG_RTC_INTF_DEV */ + +static irqreturn_t +ds1685_rtc_irq_handler(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned int ctrlb, ctrlc; +#if 0 + /* XXX: Ctrl4a/Ctrl4b info unused; needs support in RTC core. */ + unsigned int ctrl4a, ctrl4b; +#endif + unsigned long flags, events = RTC_IRQF; + unsigned int num_irqs = 0; + + /* Fetch data from the four registers holding IRQ info. */ + ds1685_rtc_begin_ctrl_access; + ctrlb = readb(®s->time.ctrlb); + ctrlc = readb(®s->time.ctrlc); +#if 0 + /* XXX: Ctrl4a/Ctrl4b info unused; needs support in RTC core. */ + ctrl4a = readb(®s->bank1.ctrl4a); + ctrl4b = readb(®s->bank1.ctrl4b); +#endif + ds1685_rtc_end_ctrl_access; + + /* Check to see if the IRQF bit is set. */ + if (!(ctrlc & RTC_CTRL_C_IRQF)) + return IRQ_NONE; + + /* Check for alarm interrupts. */ + if ((ctrlc & RTC_CTRL_C_AF) && + (ctrlb & RTC_CTRL_B_AIE)) { + events |= RTC_AF; + num_irqs++; + } + + /* Check for timer interrupts. */ + else if ((ctrlc & RTC_CTRL_C_UF) && + (ctrlb & RTC_CTRL_B_UIE)) { + events |= RTC_UF; + num_irqs++; + } + + /* Check for periodic interrupts. */ + else if ((ctrlc & RTC_CTRL_C_PF) && + (ctrlb & RTC_CTRL_B_PIE)) { + events |= RTC_PF; + num_irqs++; + } + + rtc_update_irq(pdata->rtc, num_irqs, events); + return IRQ_HANDLED; +} + +#ifdef CONFIG_PROC_FS +#define NUM_REGS 8 +#define NUM_SPACES 4 + +/* + * This prints out the flags of the registers for ds1685_rtc_proc. + * It's basically a hex --> binary function, just with extra spacing between + * the binary digits. It only works on single-byte hex values (8 bits), + * which is all that we need. + */ +static char* +print_regs(unsigned int *hex, char *dest) +{ + unsigned int i, j; + char *tmp = dest; + + for(i = 0; i < NUM_REGS; i++) { + *tmp++ = ((*hex & 0x80) !=0 ? '1' : '0'); + for (j = 0; j < NUM_SPACES; j++) + *tmp++ = ' '; + *hex <<= 1; + } + *tmp++ = '\0'; + + return dest; +} + +static int +ds1685_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags; + unsigned int ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b; + char bits[NUM_REGS][(NUM_REGS * NUM_SPACES) + NUM_REGS + 1]; + u8 ssn[8]; + + ds1685_rtc_begin_ctrl_access; + ds1685_rtc_get_ssn; + ctrla = readb(®s->time.ctrla); + ctrlb = readb(®s->time.ctrlb); + ctrlc = readb(®s->time.ctrlc); + ctrld = readb(®s->time.ctrld); + ctrl4a = readb(®s->bank1.ctrl4a); + ctrl4b = readb(®s->bank1.ctrl4b); + ds1685_rtc_end_ctrl_access; + + seq_printf(seq, + "Oscillator\t: %s\n" + "12/24hr\t\t: %s\n" + "DST\t\t: %s\n" + "Data mode\t: %s\n" + "Battery\t\t: %s\n" + "Aux batt\t: %s\n" + "Periodic IRQ\t: %s\n" + "SQW Freq\t: %s\n" + "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n" + "Register Status\t:\n" + " Ctrl A\t: " + "UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n\t\t: %s\n" + " Ctrl B\t: " + "SET PIE AIE UIE SQWE DM 24hr DSE\n\t\t: %s\n" + " Ctrl C\t: " + "IRQF PF AF UF --- --- --- ---\n\t\t: %s\n" + " Ctrl D\t: " + "VRT --- --- --- --- --- --- ---\n\t\t: %s\n" + " Ctrl 4A\t: " + "VRT2 INCR BME --- PAB RF WF KF\n\t\t: %s\n" + " Ctrl 4B\t: " + "ABE E32k CS RCE PRS RIE WIE KSE\n\t\t: %s\n", + ((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"), + ((ctrlb & RTC_CTRL_B_2412) ? "24-hour" : "12-hour"), + ((ctrlb & RTC_CTRL_B_DSE) ? "enabled" : "disabled"), + ((ctrlb & RTC_CTRL_B_DM) ? "binary" : "BCD"), + ((ctrld & RTC_CTRL_D_VRT) ? "ok" : "exhausted or n/a"), + ((ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "exhausted or n/a"), + (!(ctrl4b & RTC_CTRL_4B_E32K) ? + pirq_rate[(ctrla & RTC_CTRL_A_RS_MASK)] : "*"), + (!((ctrl4b & RTC_CTRL_4B_E32K)) ? + sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32.768kHz"), + ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], + ssn[6], ssn[7], + print_regs(&ctrla, bits[0]), + print_regs(&ctrlb, bits[1]), + print_regs(&ctrlc, bits[2]), + print_regs(&ctrld, bits[3]), + print_regs(&ctrl4a, bits[4]), + print_regs(&ctrl4b, bits[5])); + + return 0; +} +#else +#define ds1685_rtc_proc NULL +#endif /* CONFIG_PROC_FS */ + +static const struct rtc_class_ops ds1685_rtc_ops = { + .ioctl = ds1685_ioctl, + .proc = ds1685_rtc_proc, + .read_time = ds1685_rtc_read_time, + .set_time = ds1685_rtc_set_time, + .read_alarm = ds1685_rtc_read_alarm, + .set_alarm = ds1685_rtc_set_alarm, + .irq_set_state = ds1685_rtc_periodic_irq_enable, + .alarm_irq_enable = ds1685_rtc_alarm_irq_enable, + .update_irq_enable = ds1685_rtc_update_irq_enable, +}; + +#ifdef CONFIG_SYSFS +static ssize_t +ds1685_nvram_read(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + ssize_t count; + unsigned int data; + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + ds1685_rtc_switch_to_bank0; + for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0; + count++, size--) + if (count < NVRAM_SZ_TIME) + *buf++ = readb(®s->time.nvram1 + pos++); + else + *buf++ = readb(®s->bank0.nvram2 + pos++); + + if (size > 0) { + ds1685_rtc_switch_to_bank1; + + for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ; + count++, size--) { + writeb((pos - NVRAM_TOTAL_SZ_BANK0), + ®s->bank1.ext_nvram_addr); + *buf++ = readb(®s->bank1.ext_nvram_dport); + pos++; + } + + ds1685_rtc_switch_to_bank0; + } + spin_unlock_irqrestore(&pdata->lock, flags); + return count; +} + +static ssize_t +ds1685_nvram_write(struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + ssize_t count; + unsigned int data; + unsigned long flags; + + spin_lock_irqsave(&pdata->lock, flags); + ds1685_rtc_switch_to_bank0; + for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0; + count++, size--) + if (count < NVRAM_SZ_TIME) + writeb(*buf++, ®s->time.nvram1 + pos++); + else + writeb(*buf++, ®s->bank0.nvram2 + pos++); + + if (size > 0) { + ds1685_rtc_switch_to_bank1; + + for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ; + count++, size--) { + writeb((pos - NVRAM_TOTAL_SZ_BANK0), + ®s->bank1.ext_nvram_addr); + writeb(*buf++, ®s->bank1.ext_nvram_dport); + pos++; + } + + ds1685_rtc_switch_to_bank0; + } + spin_unlock_irqrestore(&pdata->lock, flags); + + return count; +} + +static struct bin_attribute ds1685_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUSR, + }, + .read = ds1685_nvram_read, + .write = ds1685_nvram_write, + .size = NVRAM_TOTAL_SZ +}; + +static ssize_t +ds1685_sysfs_show_battery(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags; + + ds1685_rtc_begin_ctrl_access; + data = readb(®s->time.ctrld); + ds1685_rtc_end_ctrl_access; + + return sprintf(buf, "%s\n", + (data & RTC_CTRL_D_VRT) ? "ok" : "exhausted or n/a"); +} + +static DEVICE_ATTR(battery, S_IRUGO, ds1685_sysfs_show_battery, NULL); + +static ssize_t +ds1685_sysfs_show_auxbatt(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int data; + unsigned long flags; + + ds1685_rtc_begin_ctrl_access; + data = readb(®s->bank1.ctrl4a); + ds1685_rtc_end_ctrl_access; + + return sprintf(buf, "%s\n", + (data & RTC_CTRL_4A_VRT2) ? "ok" : "exhausted or n/a"); +} + +static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_sysfs_show_auxbatt, NULL); + +static ssize_t +ds1685_sysfs_show_serial(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + u8 ssn[8]; + unsigned int data; + unsigned long flags; + + ds1685_rtc_begin_ctrl_access; + ds1685_rtc_get_ssn; + ds1685_rtc_end_ctrl_access; + + return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + ssn[0], ssn[1], ssn[2], ssn[3], + ssn[4], ssn[5], ssn[6], ssn[7]); + + return 0; +} + +static DEVICE_ATTR(serial, S_IRUGO, ds1685_sysfs_show_serial, NULL); + +static int +ds1685_sysfs_register(struct device *dev) +{ + int err; + + err = sysfs_create_bin_file(&dev->kobj, &ds1685_nvram_attr); + if (err) + return err; + + err = device_create_file(dev, &dev_attr_battery); + if (err) { + device_remove_file(dev, &dev_attr_battery); + goto out; + } + + err = device_create_file(dev, &dev_attr_auxbatt); + if (err) { + device_remove_file(dev, &dev_attr_auxbatt); + goto out; + } + + err = device_create_file(dev, &dev_attr_serial); + if (err) { + device_remove_file(dev, &dev_attr_serial); + goto out; + } + + return 0; + +out: + sysfs_remove_bin_file(&dev->kobj, &ds1685_nvram_attr); + return err; +} + +static int +ds1685_sysfs_unregister(struct device *dev) +{ + sysfs_remove_bin_file(&dev->kobj, &ds1685_nvram_attr); + device_remove_file(dev, &dev_attr_battery); + device_remove_file(dev, &dev_attr_auxbatt); + device_remove_file(dev, &dev_attr_serial); + + return 0; +} +#endif /* CONFIG_SYSFS */ + +static int __devinit +ds1685_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc = NULL; + struct device *dev = NULL; + struct resource *res = NULL; + struct ds1685_priv *pdata = NULL; + struct ds1685_rtc_regs __iomem *regs = NULL; + int ret = 0; + unsigned int data, ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b; + unsigned long flags; + + /* Get the platform resources. */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + /* Kzalloc() some memory for the rtc device structure. */ + pdata = kzalloc(sizeof(struct ds1685_priv), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->size = res->end - res->start + 1; + + /* Request a memory region. Remove IOC3 kludge when fixed. */ +#ifndef CONFIG_SGI_IP30 + /* + * XXX: Not sure that IP30 will be integrated in the mainline kernel. + * Consider this a placeholder for now. We can always remove it. + */ + if (!request_mem_region(res->start, pdata->size, pdev->name)) { + ret = -EBUSY; + goto out; + } +#endif + + /* Set the base address for the rtc, and ioremap() its registers. */ + pdata->baseaddr = res->start; + pdata->regs = ioremap(pdata->baseaddr, pdata->size); + if (!pdata->regs) { + ret = -ENOMEM; + goto out; + } + + /* Fetch the assigned IRQ, and init the spinlock. */ + pdata->irq = platform_get_irq(pdev, 0); + spin_lock_init(&pdata->lock); + + /* Begin the RTC setup. */ + regs = pdata->regs; + dev = &pdev->dev; + ds1685_rtc_begin_ctrl_access; + + /* + * Turn the RTC on, if it was not already on and/or Enable the + * countdown chain. + */ + ctrla = readb(®s->time.ctrla); + if (!(ctrla & RTC_CTRL_A_DV1)) { + dev_warn(&pdev->dev, + "oscillator stop detected - enabled!\n"); + ctrla |= RTC_CTRL_A_DV1; + } + ctrla &= ~RTC_CTRL_A_DV2; + writeb(ctrla, ®s->time.ctrla); + + /* Prefer BCD mode (DM = 0). */ + ctrlb = readb(®s->time.ctrlb); + if (ctrlb & RTC_CTRL_B_DM) { + dev_info(&pdev->dev, "Setting data mode to BCD\n"); + ctrlb &= ~RTC_CTRL_B_DM; + writeb(ctrlb, ®s->time.ctrlb); + } + + /* Check the batteries. There can be a main and/or an aux battery. */ + ctrld = readb(®s->time.ctrld); + if (!(ctrld & RTC_CTRL_D_VRT)) + dev_warn(&pdev->dev, + "Main battery is exhausted or not available.\n"); + ctrl4a = readb(®s->bank1.ctrl4a); + if (!(ctrl4a & RTC_CTRL_4A_VRT2)) + dev_warn(&pdev->dev, + "Aux battery is exhausted or not available.\n"); + + /* Setup the interrupt handler. */ + if (pdata->irq > 0) { + /* Read Ctrl B and clear PIE/AIE/UIE. */ + ctrlb = readb(®s->time.ctrlb); + ctrlb &= ~(RTC_CTRL_B_PIE & RTC_CTRL_B_AIE & RTC_CTRL_B_UIE); + writeb(ctrlb, ®s->time.ctrlb); + + /* Reading Ctrl C auto-clears PF/AF/UF. */ + ctrlc = readb(®s->time.ctrlc); + + /* Read Ctrl 4B and clear RIE/WIE/KSE. */ + ctrl4b = readb(®s->bank1.ctrl4b); + ctrl4b &= ~(RTC_CTRL_4B_RIE & RTC_CTRL_4B_WIE & RTC_CTRL_4B_KSE); + writeb(ctrl4b, ®s->bank1.ctrl4b); + + /* Manually clear RF/WF/KF in Ctrl 4A. */ + ctrl4a = readb(®s->bank1.ctrl4a); + ctrl4a &= ~(RTC_CTRL_4A_RF & RTC_CTRL_4A_WF & RTC_CTRL_4A_KF); + writeb(ctrl4a, ®s->bank1.ctrl4a); + + /* Request an IRQ. */ + ret = request_irq(pdata->irq, ds1685_rtc_irq_handler, + IRQF_SHARED, pdev->name, pdev); + + /* Check to see if something came back. */ + if (unlikely(ret)) { + dev_warn(&pdev->dev, "RTC interrupt not available\n"); + pdata->irq = 0; + } + } + + /* Setup complete. */ + ds1685_rtc_end_ctrl_access; + + /* Register the device as an RTC. */ + rtc = rtc_device_register(pdev->name, &pdev->dev, + &ds1685_rtc_ops, THIS_MODULE); + + /* Success? */ + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + pdata->rtc = rtc; + + /* Set driver data, register w/ sysfs. */ + platform_set_drvdata(pdev, pdata); + ret = ds1685_sysfs_register(&pdev->dev); + if (ret) { + goto out; + } + + /* Done! */ + return 0; + + + out: + /* If error, clean up. */ + if (pdata->rtc) + rtc_device_unregister(pdata->rtc); + if (pdata->irq > 0) + free_irq(pdata->irq, pdev); + if (pdata->regs) + iounmap(pdata->regs); + if (pdata->baseaddr) + release_mem_region(pdata->baseaddr, pdata->size); + kfree(pdata); + + return ret; +} + +static int __devexit +ds1685_rtc_remove(struct platform_device *pdev) +{ + struct ds1685_priv *pdata = platform_get_drvdata(pdev); + struct ds1685_rtc_regs __iomem *regs = pdata->regs; + unsigned int ctrlb, ctrlc, ctrl4a, ctrl4b; + + ds1685_sysfs_unregister(&pdev->dev); + rtc_device_unregister(pdata->rtc); + if (pdata->irq > 0) { + /* Read Ctrl B and clear PIE/AIE/UIE. */ + ctrlb = readb(®s->time.ctrlb); + ctrlb &= ~(RTC_CTRL_B_PIE & RTC_CTRL_B_AIE & RTC_CTRL_B_UIE); + writeb(ctrlb, ®s->time.ctrlb); + + /* Reading Ctrl C auto-clears PF/AF/UF. */ + ctrlc = readb(®s->time.ctrlc); + + /* Read Ctrl 4B and clear RIE/WIE/KSE. */ + ctrl4b = readb(®s->bank1.ctrl4b); + ctrl4b &= ~(RTC_CTRL_4B_RIE & RTC_CTRL_4B_WIE & RTC_CTRL_4B_KSE); + writeb(ctrl4b, ®s->bank1.ctrl4b); + + /* Manually clear RF/WF/KF in Ctrl 4A. */ + ctrl4a = readb(®s->bank1.ctrl4a); + ctrl4a &= ~(RTC_CTRL_4A_RF & RTC_CTRL_4A_WF & RTC_CTRL_4A_KF); + writeb(ctrl4a, ®s->bank1.ctrl4a); + + /* Free the IRQ. */ + free_irq(pdata->irq, pdev); + } + + iounmap(pdata->regs); + +/* + * IOC3 on IP30 has memory conflicts that are yet to be resolved. + * Refer to the comment in ds1685_rtc_probe() for more on IP30. + */ +#ifndef CONFIG_SGI_IP30 + release_mem_region(pdata->baseaddr, pdata->size); +#endif + kfree(pdata); + + return 0; +} + +static struct platform_driver ds1685_rtc_driver = { + .driver = { + .name = "rtc-ds1685", + .owner = THIS_MODULE, + }, + .probe = ds1685_rtc_probe, + .remove = __devexit_p(ds1685_rtc_remove), +}; + +static __init +int ds1685_init(void) +{ + return platform_driver_register(&ds1685_rtc_driver); +} + +static __exit +void ds1685_exit(void) +{ + platform_driver_unregister(&ds1685_rtc_driver); +} + + +module_init(ds1685_init); +module_exit(ds1685_exit); + +MODULE_AUTHOR("Matthias Fuchs , " + "Joshua Kinard "); +MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); +MODULE_ALIAS("platform:rtc-ds1685"); diff -Naurp linux-2.6.33-20100313.orig//include/linux/rtc/ds1685.h linux-2.6.33-20100313//include/linux/rtc/ds1685.h --- linux-2.6.33-20100313.orig//include/linux/rtc/ds1685.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.33-20100313//include/linux/rtc/ds1685.h 2010-06-06 01:43:05.292575267 -0400 @@ -0,0 +1,456 @@ +/* + * include/linux/rtc/ds1685.h + * + * Definitions for the control registers and platform data of the + * DS1685/DS1687 RTC chip driver. + * + * This Driver also works for the DS17285/DS17287 RTC chips. Functionally + * similar to the DS1685/DS1687, they support a few extra features. + * + * Copyright (C) 2009 Matthias Fuchs + * Copyright (C) 2010 Joshua Kinard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * IP32 documentation hints that IP32 systems actually have a DS17287 + * RTC chip. Having checked four different O2 systems myself, I have + * only ever seen DS1687-5 chips, same as in SGI Octane systems (IP30). + * + * That said, the DS17287 has some minor differences, so this driver can + * be built to support these small differences if their functionality is + * really needed. Due to the lack of actually seeing one, however, these + * differences are not tested, but follow the information provided in the + * DS17285/DS17287 data sheet. + */ + +#ifndef _LINUX_RTC_DS1685_H_ +#define _LINUX_RTC_DS1685_H_ + +/* + * Magic Number? + * Found in the original RTC driver for SGI IP30 (Octane) systems, it is used + * in the ds1685_begin_access macro while loop to avoid RTC access lockouts. + */ +#define DS1685_MAGIC 137 + + +/* + * NVRAM. + * - 50 bytes of NVRAM are available just past the clock registers. + * - 64 additional bytes are available in Bank0. + * - 128 additional bytes are available in Bank1. + */ +#define NVRAM_SZ_TIME 50 +#define NVRAM_SZ_BANK0 64 +#define NVRAM_SZ_BANK1 128 +#define NVRAM_TOTAL_SZ_BANK0 (NVRAM_SZ_TIME + NVRAM_SZ_BANK0) +#define NVRAM_TOTAL_SZ (NVRAM_TOTAL_SZ_BANK0 + NVRAM_SZ_BANK1) + + +/* + * Some of the register names below are not used in the actual code, but + * are made available per the DS1685/DS1687 documentation for possible + * future use if the need arises. + */ +#define RTC_SECONDS 0x00 +#define RTC_SECONDS_ALARM 0x01 +#define RTC_MINUTES 0x02 +#define RTC_MINUTES_ALARM 0x03 +#define RTC_HOURS 0x04 +#define RTC_HOURS_ALARM 0x05 +#define RTC_DAY 0x06 +#define RTC_DATE 0x07 +#define RTC_MONTH 0x08 +#define RTC_YEAR 0x09 + +#define RTC_CTRL_A 0x0a /* Control Register A */ +#define RTC_CTRL_B 0x0b /* Control Register B */ +#define RTC_CTRL_C 0x0c /* Control Register C */ +#define RTC_CTRL_D 0x0d /* Control Register D */ +#define RTC_EXT_CTRL_4A 0x4a /* Extended Control Register 4A */ +#define RTC_EXT_CTRL_4B 0x4b /* Extended Control Register 4B */ +#define RTC_NVRAM_START_B0 0x0e +#define RTC_NVRAM_BANK1_BASE 0x3f00 + + +/* + * Values of the RTC bits. + */ +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 + +/* + * Bit names in Control Register A. + */ +#define RTC_CTRL_A_RS0 BIT_0 /* Rate-Selection Bit 0 */ +#define RTC_CTRL_A_RS1 BIT_1 /* Rate-Selection Bit 1 */ +#define RTC_CTRL_A_RS2 BIT_2 /* Rate-Selection Bit 2 */ +#define RTC_CTRL_A_RS3 BIT_3 /* Rate-Selection Bit 3 */ +#define RTC_CTRL_A_DV0 BIT_4 /* Bank Select */ +#define RTC_CTRL_A_DV1 BIT_5 /* Oscillator Enable */ +#define RTC_CTRL_A_DV2 BIT_6 /* Countdown Chain */ +#define RTC_CTRL_A_UIP BIT_7 /* Update In Progress */ +#define RTC_CTRL_A_RS_MASK (RTC_CTRL_A_RS0 + RTC_CTRL_A_RS1 + \ + RTC_CTRL_A_RS2 + RTC_CTRL_A_RS3) + +/* + * Bit names in Control Register B. + */ +#define RTC_CTRL_B_DSE BIT_0 /* Daylight Savings Enable */ +#define RTC_CTRL_B_2412 BIT_1 /* 12-Hr/24-Hr Mode */ +#define RTC_CTRL_B_DM BIT_2 /* Data Mode */ +#define RTC_CTRL_B_SQWE BIT_3 /* Square-Wave Enable */ +#define RTC_CTRL_B_UIE BIT_4 /* Update-Ended Interrupt-Enable */ +#define RTC_CTRL_B_AIE BIT_5 /* Alarm-Interrupt Enable */ +#define RTC_CTRL_B_PIE BIT_6 /* Periodic-Interrupt Enable */ +#define RTC_CTRL_B_SET BIT_7 /* SET Bit */ + + +/* + * Bit names in Control Register C. + * + * BIT_0, BIT_1, BIT_2, & BIT_3 are unused, always return 0, and cannot be + * written to. + */ +#define RTC_CTRL_C_UF BIT_4 /* Update-Ended Interrupt Flag */ +#define RTC_CTRL_C_AF BIT_5 /* Alarm-Interrupt Flag */ +#define RTC_CTRL_C_PF BIT_6 /* Periodic-Interrupt Flag */ +#define RTC_CTRL_C_IRQF BIT_7 /* Interrupt-Request Flag */ + + +/* + * Bit names in Control Register D. + * + * BIT_0 through BIT_6 are unused, always return 0, and cannot be written to. + */ +#define RTC_CTRL_D_VRT BIT_7 /* Valid RAM and Time */ + + +/* + * Bit names in Extended Control Register 4A. + * + * BIT_4 and BIT_5 are reserved for future use. They can be read from and + * written to, but have no effect on the RTC's operation. + */ +#define RTC_CTRL_4A_KF BIT_0 /* Kickstart Flag */ +#define RTC_CTRL_4A_WF BIT_1 /* Wake-Up Alarm Flag */ +#define RTC_CTRL_4A_RF BIT_2 /* RAM Clear Flag */ +#define RTC_CTRL_4A_PAB BIT_3 /* Power-Active Bar Control */ +#define RTC_CTRL_4A_INCR BIT_6 /* Increment-in-Progress Status */ +#define RTC_CTRL_4A_VRT2 BIT_7 /* Auxillary Battery Status */ + + +/* + * Bit names in Extended Control Register 4B. + */ +#define RTC_CTRL_4B_KSE BIT_0 /* Kickstart Interrupt-Enable */ +#define RTC_CTRL_4B_WIE BIT_1 /* Wake-Up Alarm-Interrupt Enable */ +#define RTC_CTRL_4B_RIE BIT_2 /* RAM Clear-Interrupt Enable */ +#define RTC_CTRL_4B_PRS BIT_3 /* PAB Reset-Select */ +#define RTC_CTRL_4B_RCE BIT_4 /* RAM Clear-Enable */ +#define RTC_CTRL_4B_CS BIT_5 /* Crystal Select */ +#define RTC_CTRL_4B_E32K BIT_6 /* Enable 32.768Hz Output on SQW Pin */ +#define RTC_CTRL_4B_ABE BIT_7 /* Auxillary Battery Enable */ + + +/* + * Register names in Bank 1. + * + * The DV0 bit in Control Register A must be set to 1 for these registers + * to become available, including Extended Control Registers 4A & 4B. + */ +#define RTC_BANK1_MODEL 0x40 /* Model Number */ +#define RTC_BANK1_SERIAL_BYTE_1 0x41 /* 1st Byte of Serial Number */ +#define RTC_BANK1_SERIAL_BYTE_2 0x42 /* 2nd Byte of Serial Number */ +#define RTC_BANK1_SERIAL_BYTE_3 0x43 /* 3rd Byte of Serial Number */ +#define RTC_BANK1_SERIAL_BYTE_4 0x44 /* 4th Byte of Serial Number */ +#define RTC_BANK1_SERIAL_BYTE_5 0x45 /* 5th Byte of Serial Number */ +#define RTC_BANK1_SERIAL_BYTE_6 0x46 /* 6th Byte of Serial Number */ +#define RTC_BANK1_SERIAL_CRC 0x47 /* Serial CRC Byte */ +#define RTC_BANK1_CENTURY 0x48 /* Century Counter */ +#define RTC_BANK1_DATE_ALARM 0x49 /* Date Alarm */ +#define RTC_BANK1_RAM_ADDR 0x50 /* RAM Address */ +#define RTC_BANK1_RAM_DATA_PORT 0x53 /* RAM Data Port */ + + +#ifdef CONFIG_PROC_FS +/* + * Periodic Interrupt Rates. A static character array is used for displaying + * these values in /proc when procfs is enabled. + */ +static const char *pirq_rate[16] = { + "none", "3.90625ms", "7.8125ms", "122.070µs", "244.141µs", + "488.281µs", "976.5625µs", "1.953125ms", "3.90625ms", "7.8125ms", + "15.625ms", "31.25ms", "62.5ms", "125ms", "250ms", "500ms" +}; + +/* + * Square-Wave Output Frequencies. A static character array is used for + * displaying these values in /proc when procfs is enabled. + */ +static const char *sqw_freq[16] = { + "none", "256Hz", "128Hz", "8.192kHz", "4.096kHz", "2.048kHz", + "1.024kHz", "512Hz", "256Hz", "128Hz", "64Hz", "32Hz", "16Hz", + "8Hz", "4Hz", "2Hz" +}; +#endif /* CONFIG_PROC_FS */ + + +/* + * SGI O2 (IP32) Systems need 1 bytes of padding between the registers in + * order for the driver to function properly. O2's should be using DS17287 + * RTC chips, but most have DS1687-5 modules instead. The differences + * between the two are minor, but accounted for anyways. + */ +#ifdef CONFIG_SGI_IP32 + #define DS1685_PAD 0xff + #define DS1685_REG(r) \ + volatile unsigned char r; \ + unsigned char r##_pad[DS1685_PAD] + #define DS1685_NVRAM1_PAD 0x31ce + #define DS1685_NVRAM2_PAD 0x7fbf + + #ifdef CONFIG_RTC_DS17285 + #define DS17285_RSVRD_PAD 0xa00 + #else + #define DS17285_RSVRD_PAD 0x2c00 + #endif +#else + #define DS1685_REG(r) \ + volatile unsigned char r; +#endif + + +/* + * This structure defines the standard DS1286-style time registers + * that exist in both bank0 and bank1. + */ +struct ds1685_time_regs { + DS1685_REG(sec); /* Seconds */ + DS1685_REG(sec_alrm); /* Seconds Alarm */ + DS1685_REG(min); /* Minutes */ + DS1685_REG(min_alrm); /* Minutes Alarm */ + DS1685_REG(hour); /* Hours */ + DS1685_REG(hour_alrm); /* Hours Alarm */ + DS1685_REG(wday); /* Day of the Week */ + DS1685_REG(mday); /* Day of the Month */ + DS1685_REG(month); /* Current Month */ + DS1685_REG(year); /* Current Year */ + DS1685_REG(ctrla); /* Control Register A */ + DS1685_REG(ctrlb); /* Control Register B */ + DS1685_REG(ctrlc); /* Control Register C */ + DS1685_REG(ctrld); /* Control Register D */ + volatile unsigned char nvram1[NVRAM_SZ_TIME]; +#ifdef CONFIG_SGI_IP32 + unsigned char nvram1_pad[DS1685_NVRAM1_PAD]; +#endif +}; + + +/* + * Bank0-specific registers. This is usually NVRAM. + */ +struct ds1685_bank0_regs { + volatile unsigned char nvram2[NVRAM_SZ_BANK0]; +#ifdef CONFIG_SGI_IP32 + unsigned char nvram2_pad[DS1685_NVRAM2_PAD]; +#endif +}; + + +/* + * Bank1-specific registers. These access extended capabilities present + * in the DS1685. The DS17285/DS17287 has minor differences, including an + * RTC write counter, and two extended NVRAM address registers, for MSB + * or LSB forms of the address. + */ +struct ds1685_bank1_regs { + DS1685_REG(model); /* Model Number */ + DS1685_REG(ssn1); /* 1st Byte of Serial Number */ + DS1685_REG(ssn2); /* 2nd Byte of Serial Number */ + DS1685_REG(ssn3); /* 3rd Byte of Serial Number */ + DS1685_REG(ssn4); /* 4th Byte of Serial Number */ + DS1685_REG(ssn5); /* 5th Byte of Serial Number */ + DS1685_REG(ssn6); /* 6th Byte of Serial Number */ + DS1685_REG(crc); /* Serial # CRC Byte */ + DS1685_REG(century); /* Current Century */ + DS1685_REG(mday_alrm); /* Day of the Month Alarm */ + DS1685_REG(ctrl4a); /* Ext. Control Register 4A */ + DS1685_REG(ctrl4b); /* Ext. Control Register 4B */ + DS1685_REG(rsvrd1); /* Reserved; provides SMI */ + DS1685_REG(rsvrd2); /* Recovery Stack. Holds last */ + DS1685_REG(rtc_addr2); /* four RTC addresses for the */ + DS1685_REG(rtc_addr3); /* BIOS to recover from an SMI. */ +#ifdef CONFIG_RTC_DS17285 + DS1685_REG(ext_nvram_addr_lsb); /* LSB of NVRAM Addr; DS17285/7 */ + DS1685_REG(ext_nvram_addr_msb); /* MSB of NVRAM Addr; DS17285/7 */ +#else + DS1685_REG(ext_nvram_addr); /* Ext. NVRAM Addr; DS1685/7 */ + DS1685_REG(rsvrd3); /* Reserved */ +#endif + DS1685_REG(rsvrd4); /* Reserved */ + DS1685_REG(ext_nvram_dport); /* Ext. NVRAM Data Port */ +#ifdef CONFIG_SGI_IP32 + volatile unsigned char rsvrd_pad[DS17285_RSVRD_PAD]; +#endif +#ifdef CONFIG_RTC_DS17285 + DS1685_REG(rtc_write_cnt); /* RTC Write Counter; DS17285/7 */ +#endif +}; + + +/* + * The actual register struct. Uses a union to combine bank0 and bank1, + * since both use the same address space, but are accessed depending on the + * state of the DV0 bit in Control Register A. + */ +struct ds1685_rtc_regs { + struct ds1685_time_regs time; + union { + struct ds1685_bank0_regs bank0; + struct ds1685_bank1_regs bank1; + }; +}; + + +/* + * DS1685/1687/17285/17287 data structure. + */ +struct ds1685_priv { + struct rtc_device *rtc; /* RTC device pointer */ + struct ds1685_rtc_regs __iomem *regs; /* RTC Registers */ + resource_size_t baseaddr; /* Resource base address */ + size_t size; /* Resource size */ + spinlock_t lock; /* Spinlock struct */ + int irq; /* RTC IRQ # */ + unsigned int p_intr; /* Periodic IRQ status */ + unsigned int a_intr; /* Alarm IRQ status */ + unsigned int u_intr; /* Update IRQ status */ +#if 0 /* Not used just yet; See comments in rtc-ds1685.c */ + unsigned int r_intr; /* RAM-Clear IRQ status */ + unsigned int w_intr; /* Watchdog IRQ status */ + unsigned int k_intr; /* Kickstart IRQ status */ +#endif +}; + + +/* + * These two macros set and unset the SET bit in Control Register B. The + * SET bit inhibits update transfers and allows a safe read/write of the + * time and calendar bits. + */ +#define ds1685_rtc_set_set_bit \ + data = readb(®s->time.ctrlb) | RTC_CTRL_B_SET; \ + writeb(data, ®s->time.ctrlb) + +#define ds1685_rtc_clear_set_bit \ + data = readb(®s->time.ctrlb) & ~(RTC_CTRL_B_SET); \ + writeb(data, ®s->time.ctrlb) + + +/* + * These two macros switch between bank0 and bank1. Bank0 provides access + * to the standard RTC capabilities originally defined with the DS1286 RTC. + * Bank1 provides access to extended capabilities, including extended + * control registers, silicon serial number, century counter, aux battery + * capabilities, wake-up/kick-start features and additional amounts of nvram. + */ +#define ds1685_rtc_switch_to_bank0 \ + data = readb(®s->time.ctrla) & ~(RTC_CTRL_A_DV0); \ + writeb(data, ®s->time.ctrla) + +#define ds1685_rtc_switch_to_bank1 \ + data = readb(®s->time.ctrla) | RTC_CTRL_A_DV0; \ + writeb(data, ®s->time.ctrla) + + +/* + * This begins the RTC data access, such as reading/writing clock/alarm + * registers. It performs several steps in a common block of code that is + * used quite frequently: + * + * - Sets a spinlock on the IRQ. + * - Sets the SET bit in Control Register B. + * - Reads Control Register A. + * - Checks the UIP bit in Control Register A. If UIP is active, + * a delay is forced and a check is run to see if RTC access was + * locked out. The loop runs until UIP is not set. + * - A switch to bank1 occurs. This allows access to all the relevant + * time data, since the time registers are available regardless of + * which bank is currently selected. + */ +#define ds1685_rtc_begin_data_access \ + spin_lock_irqsave(&pdata->lock, flags); \ + ds1685_rtc_set_set_bit; \ + data = readb(®s->time.ctrla); \ + while (data & RTC_CTRL_A_UIP) { \ + udelay(10); \ + if (jiffies > start + DS1685_MAGIC) { \ + dev_err(dev, "Access lockout!\n"); \ + return 1; \ + } \ + data = readb(®s->time.ctrla); \ + } \ + ds1685_rtc_switch_to_bank1 + +/* + * This ends the RTC data access: + * - It switches back to bank0. + * - It clears the SET bit in Control Register B. + * - It unsets the spinlock on the IRQ. + */ +#define ds1685_rtc_end_data_access \ + ds1685_rtc_switch_to_bank0; \ + ds1685_rtc_clear_set_bit; \ + spin_unlock_irqrestore(&pdata->lock, flags) + + +/* + * This begins the RTC access to the control registers only. Such + * accesses need far less handling, just a spinlock and a switch to + * bank1. + */ +#define ds1685_rtc_begin_ctrl_access \ + spin_lock_irqsave(&pdata->lock, flags); \ + ds1685_rtc_switch_to_bank1 + +/* + * This ends the RTC ctrl access: + * - It switches back to bank0. + * - It unsets the spinlock on the IRQ. + */ +#define ds1685_rtc_end_ctrl_access \ + ds1685_rtc_switch_to_bank0; \ + spin_unlock_irqrestore(&pdata->lock, flags) + + +/* + * This fetches the Silicon Serial Number, a unique ID specific to every + * DS1685/1687/17285/17287. + * + * This number starts at 0x40, and is 8-bytes long, ending at 0x47. + * The first byte is the model #, the next six bytes are the serial + * number digits, and the final byte is a CRC check byte. Together, + * they form the SSN of the RTC. + */ +#define ds1685_rtc_get_ssn \ + ssn[0] = readb(®s->bank1.model); \ + ssn[1] = readb(®s->bank1.ssn1); \ + ssn[2] = readb(®s->bank1.ssn2); \ + ssn[3] = readb(®s->bank1.ssn3); \ + ssn[4] = readb(®s->bank1.ssn4); \ + ssn[5] = readb(®s->bank1.ssn5); \ + ssn[6] = readb(®s->bank1.ssn6); \ + ssn[7] = readb(®s->bank1.crc) + +#endif /* _LINUX_RTC_DS1685_H_ */