static void cmos_do_shutdown(int rtc_irq) { spin_lock_irq(&rtc_lock); if (is_valid_irq(rtc_irq)) cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); spin_unlock_irq(&rtc_lock); }
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char mon, mday, hrs, min, sec; if (!is_valid_irq(cmos->irq)) return -EIO; /* REVISIT this assumes PC style usage: always BCD */ /* Writing 0xff means "don't care" or "match all". */ mon = t->time.tm_mon + 1; mon = (mon <= 12) ? BIN2BCD(mon) : 0xff; mday = t->time.tm_mday; mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff; hrs = t->time.tm_hour; hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff; min = t->time.tm_min; min = (min < 60) ? BIN2BCD(min) : 0xff; sec = t->time.tm_sec; sec = (sec < 60) ? BIN2BCD(sec) : 0xff; spin_lock_irq(&rtc_lock); /* next rtc irq must not be from previous alarm setting */ cmos_irq_disable(cmos, RTC_AIE); /* update alarm */ CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); /* the system may support an "enhanced" alarm */ if (cmos->day_alrm) { CMOS_WRITE(mday, cmos->day_alrm); if (cmos->mon_alrm) CMOS_WRITE(mon, cmos->mon_alrm); } /* FIXME the HPET alarm glue currently ignores day_alrm * and mon_alrm ... */ hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec); if (t->enabled) cmos_irq_enable(cmos, RTC_AIE); spin_unlock_irq(&rtc_lock); return 0; }
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char mon, mday, hrs, min, sec, rtc_control; if (!is_valid_irq(cmos->irq)) return -EIO; mon = t->time.tm_mon + 1; mday = t->time.tm_mday; hrs = t->time.tm_hour; min = t->time.tm_min; sec = t->time.tm_sec; rtc_control = CMOS_READ(RTC_CONTROL); if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { /* Writing 0xff means "don't care" or "match all". */ mon = (mon <= 12) ? bin2bcd(mon) : 0xff; mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; min = (min < 60) ? bin2bcd(min) : 0xff; sec = (sec < 60) ? bin2bcd(sec) : 0xff; } spin_lock_irq(&rtc_lock); /* next rtc irq must not be from previous alarm setting */ cmos_irq_disable(cmos, RTC_AIE); /* update alarm */ CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); /* the system may support an "enhanced" alarm */ if (cmos->day_alrm) { CMOS_WRITE(mday, cmos->day_alrm); if (cmos->mon_alrm) CMOS_WRITE(mon, cmos->mon_alrm); } /* FIXME the HPET alarm glue currently ignores day_alrm * and mon_alrm ... */ hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec); if (t->enabled) cmos_irq_enable(cmos, RTC_AIE); spin_unlock_irq(&rtc_lock); cmos->alarm_expires = rtc_tm_to_time64(&t->time); return 0; }
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char mon, mday, hrs, min, sec, rtc_control; if (!is_valid_irq(cmos->irq)) return -EIO; mon = t->time.tm_mon + 1; mday = t->time.tm_mday; hrs = t->time.tm_hour; min = t->time.tm_min; sec = t->time.tm_sec; rtc_control = CMOS_READ(RTC_CONTROL); if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { mon = (mon <= 12) ? bin2bcd(mon) : 0xff; mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; min = (min < 60) ? bin2bcd(min) : 0xff; sec = (sec < 60) ? bin2bcd(sec) : 0xff; } spin_lock_irq(&rtc_lock); cmos_irq_disable(cmos, RTC_AIE); CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); CMOS_WRITE(sec, RTC_SECONDS_ALARM); if (cmos->day_alrm) { CMOS_WRITE(mday, cmos->day_alrm); if (cmos->mon_alrm) CMOS_WRITE(mon, cmos->mon_alrm); } hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec); if (t->enabled) cmos_irq_enable(cmos, RTC_AIE); spin_unlock_irq(&rtc_lock); return 0; }
static int cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned long flags; switch (cmd) { case RTC_AIE_OFF: case RTC_AIE_ON: case RTC_UIE_OFF: case RTC_UIE_ON: if (!is_valid_irq(cmos->irq)) return -EINVAL; break; /* PIE ON/OFF is handled by cmos_irq_set_state() */ default: return -ENOIOCTLCMD; } spin_lock_irqsave(&rtc_lock, flags); switch (cmd) { case RTC_AIE_OFF: /* alarm off */ cmos_irq_disable(cmos, RTC_AIE); break; case RTC_AIE_ON: /* alarm on */ cmos_irq_enable(cmos, RTC_AIE); break; case RTC_UIE_OFF: /* update off */ cmos_irq_disable(cmos, RTC_UIE); break; case RTC_UIE_ON: /* update on */ cmos_irq_enable(cmos, RTC_UIE); break; } spin_unlock_irqrestore(&rtc_lock, flags); return 0; }
static int cmos_irq_set_state(struct device *dev, int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned long flags; if (!is_valid_irq(cmos->irq)) return -ENXIO; spin_lock_irqsave(&rtc_lock, flags); if (enabled) cmos_irq_enable(cmos, RTC_PIE); else cmos_irq_disable(cmos, RTC_PIE); spin_unlock_irqrestore(&rtc_lock, flags); return 0; }
static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned long flags; if (!is_valid_irq(cmos->irq)) return -EINVAL; if (alarm_disable_quirk) return 0; spin_lock_irqsave(&rtc_lock, flags); if (enabled) cmos_irq_enable(cmos, RTC_AIE); else cmos_irq_disable(cmos, RTC_AIE); spin_unlock_irqrestore(&rtc_lock, flags); return 0; }
static void cmos_do_shutdown(void) { spin_lock_irq(&rtc_lock); cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); spin_unlock_irq(&rtc_lock); }
static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { struct cmos_rtc_board_info *info = dev->platform_data; int retval = 0; unsigned char rtc_control; unsigned address_space; /* there can be only one ... */ if (cmos_rtc.dev) return -EBUSY; if (!ports) return -ENODEV; /* Claim I/O ports ASAP, minimizing conflict with legacy driver. * * REVISIT non-x86 systems may instead use memory space resources * (needing ioremap etc), not i/o space resources like this ... */ ports = request_region(ports->start, resource_size(ports), driver_name); if (!ports) { dev_dbg(dev, "i/o registers already in use\n"); return -EBUSY; } cmos_rtc.irq = rtc_irq; cmos_rtc.iomem = ports; /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM * driver did, but don't reject unknown configs. Old hardware * won't address 128 bytes. Newer chips have multiple banks, * though they may not be listed in one I/O resource. */ #if defined(CONFIG_ATARI) address_space = 64; #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \ || defined(__sparc__) || defined(__mips__) \ || defined(__powerpc__) address_space = 128; #else #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. address_space = 128; #endif if (can_bank2 && ports->end > (ports->start + 1)) address_space = 256; /* For ACPI systems extension info comes from the FADT. On others, * board specific setup provides it as appropriate. Systems where * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and * some almost-clones) can provide hooks to make that behave. * * Note that ACPI doesn't preclude putting these registers into * "extended" areas of the chip, including some that we won't yet * expect CMOS_READ and friends to handle. */ if (info) { if (info->rtc_day_alarm && info->rtc_day_alarm < 128) cmos_rtc.day_alrm = info->rtc_day_alarm; if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) cmos_rtc.mon_alrm = info->rtc_mon_alarm; if (info->rtc_century && info->rtc_century < 128) cmos_rtc.century = info->rtc_century; if (info->wake_on && info->wake_off) { cmos_rtc.wake_on = info->wake_on; cmos_rtc.wake_off = info->wake_off; } } cmos_rtc.dev = dev; dev_set_drvdata(dev, &cmos_rtc); cmos_rtc.rtc = rtc_device_register(driver_name, dev, &cmos_rtc_ops, THIS_MODULE); if (IS_ERR(cmos_rtc.rtc)) { retval = PTR_ERR(cmos_rtc.rtc); goto cleanup0; } rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); /* force periodic irq to CMOS reset default of 1024Hz; * * REVISIT it's been reported that at least one x86_64 ALI mobo * doesn't use 32KHz here ... for portability we might need to * do something about other clock frequencies. */ cmos_rtc.rtc->irq_freq = 1024; hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); /* disable irqs */ cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); rtc_control = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); /* FIXME: * <asm-generic/rtc.h> doesn't know 12-hour mode either. */ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { dev_warn(dev, "only 24-hr supported\n"); retval = -ENXIO; goto cleanup1; } if (is_valid_irq(rtc_irq)) { irq_handler_t rtc_cmos_int_handler; if (is_hpet_enabled()) { int err; rtc_cmos_int_handler = hpet_rtc_interrupt; err = hpet_register_irq_handler(cmos_interrupt); if (err != 0) { dev_warn(dev, "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; } } else rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, 0, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); goto cleanup1; } } hpet_rtc_timer_init(); /* export at least the first block of NVRAM */ nvram.size = address_space - NVRAM_OFFSET; retval = sysfs_create_bin_file(&dev->kobj, &nvram); if (retval < 0) { dev_dbg(dev, "can't create nvram file? %d\n", retval); goto cleanup2; } dev_info(dev, "%s%s, %zd bytes nvram%s\n", !is_valid_irq(rtc_irq) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : cmos_rtc.day_alrm ? "alarms up to one month" : "alarms up to one day", cmos_rtc.century ? ", y3k" : "", nvram.size, is_hpet_enabled() ? ", hpet irqs" : ""); return 0; cleanup2: if (is_valid_irq(rtc_irq)) free_irq(rtc_irq, cmos_rtc.rtc); cleanup1: cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); cleanup0: release_region(ports->start, resource_size(ports)); return retval; }
static int INITSECTION cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) { struct cmos_rtc_board_info *info = dev->platform_data; int retval = 0; unsigned char rtc_control; unsigned address_space; if (cmos_rtc.dev) return -EBUSY; if (!ports) return -ENODEV; ports = request_region(ports->start, resource_size(ports), driver_name); if (!ports) { dev_dbg(dev, "i/o registers already in use\n"); return -EBUSY; } cmos_rtc.irq = rtc_irq; cmos_rtc.iomem = ports; #if defined(CONFIG_ATARI) address_space = 64; #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \ || defined(__sparc__) || defined(__mips__) \ || defined(__powerpc__) address_space = 128; #else #warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. address_space = 128; #endif if (can_bank2 && ports->end > (ports->start + 1)) address_space = 256; if (info) { if (info->rtc_day_alarm && info->rtc_day_alarm < 128) cmos_rtc.day_alrm = info->rtc_day_alarm; if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) cmos_rtc.mon_alrm = info->rtc_mon_alarm; if (info->rtc_century && info->rtc_century < 128) cmos_rtc.century = info->rtc_century; if (info->wake_on && info->wake_off) { cmos_rtc.wake_on = info->wake_on; cmos_rtc.wake_off = info->wake_off; } } cmos_rtc.dev = dev; dev_set_drvdata(dev, &cmos_rtc); cmos_rtc.rtc = rtc_device_register(driver_name, dev, &cmos_rtc_ops, THIS_MODULE); if (IS_ERR(cmos_rtc.rtc)) { retval = PTR_ERR(cmos_rtc.rtc); goto cleanup0; } rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); spin_lock_irq(&rtc_lock); cmos_rtc.rtc->irq_freq = 1024; hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); rtc_control = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { dev_warn(dev, "only 24-hr supported\n"); retval = -ENXIO; goto cleanup1; } if (is_valid_irq(rtc_irq)) { irq_handler_t rtc_cmos_int_handler; if (is_hpet_enabled()) { int err; rtc_cmos_int_handler = hpet_rtc_interrupt; err = hpet_register_irq_handler(cmos_interrupt); if (err != 0) { printk(KERN_WARNING "hpet_register_irq_handler " " failed in rtc_init()."); goto cleanup1; } } else rtc_cmos_int_handler = cmos_interrupt; retval = request_irq(rtc_irq, rtc_cmos_int_handler, 0, dev_name(&cmos_rtc.rtc->dev), cmos_rtc.rtc); if (retval < 0) { dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); goto cleanup1; } } hpet_rtc_timer_init(); nvram.size = address_space - NVRAM_OFFSET; retval = sysfs_create_bin_file(&dev->kobj, &nvram); if (retval < 0) { dev_dbg(dev, "can't create nvram file? %d\n", retval); goto cleanup2; } pr_info("%s: %s%s, %zd bytes nvram%s\n", dev_name(&cmos_rtc.rtc->dev), !is_valid_irq(rtc_irq) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : cmos_rtc.day_alrm ? "alarms up to one month" : "alarms up to one day", cmos_rtc.century ? ", y3k" : "", nvram.size, is_hpet_enabled() ? ", hpet irqs" : ""); return 0; cleanup2: if (is_valid_irq(rtc_irq)) free_irq(rtc_irq, cmos_rtc.rtc); cleanup1: cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); cleanup0: release_region(ports->start, resource_size(ports)); return retval; }