26 Jun, 2016

1 commit

  • The mc146818_get_time/mc146818_set_time functions are rather large
    inline functions in a global header file and are used in several
    drivers and in x86 specific code.

    Here we move them into a separate .c file that is compiled whenever
    any of the users require it. This also lets us remove the linux/acpi.h
    header inclusion from mc146818rtc.h, which in turn avoids some
    warnings about duplicate definition of the TRUE/FALSE macros.

    Signed-off-by: Arnd Bergmann
    Signed-off-by: Alexandre Belloni

    Arnd Bergmann
     

04 Jun, 2016

1 commit

  • Drivers should not really include stuff from asm-generic directly,
    and the PC-style cmos rtc driver does this in order to reuse the
    mc146818 implementation of get_rtc_time/set_rtc_time rather than
    the architecture specific one for the architecture it gets built for.

    To make it more obvious what is going on, this moves and renames the
    two functions into include/linux/mc146818rtc.h, which holds the
    other mc146818 specific code. Ideally it would be in a .c file,
    but that would require extra infrastructure as the functions are
    called by multiple drivers with conflicting dependencies.

    With this change, the asm-generic/rtc.h header also becomes much
    more generic, so it can be reused more easily across any architecture
    that still relies on the genrtc driver.

    The only caller of the internal __get_rtc_time/__set_rtc_time
    functions is in arch/alpha/kernel/rtc.c, and we just change those
    over to the new naming.

    Signed-off-by: Arnd Bergmann
    Acked-by: Geert Uytterhoeven
    Signed-off-by: Alexandre Belloni

    Arnd Bergmann
     

07 Jun, 2014

1 commit

  • This brings in drivers/char/rtc.c functionality required for DECstation
    and, should the maintainers decide to switch, Alpha systems to use
    rtc-cmos.

    Specifically these features are made available:

    * RTC iomem rather than x86/PCI port I/O mapping, controlled with the
    RTC_IOMAPPED macro as with the original driver. The DS1287A chip in all
    DECstation systems is mapped in the host bus address space as a
    contiguous block of 64 32-bit words of which the least significant byte
    accesses the RTC chip for both reads and writes. All the address and
    data window register accesses are made transparently by the chipset glue
    logic so that the device appears directly mapped on the host bus.

    * A way to set the size of the address space explicitly with the
    newly-added `address_space' member of the platform part of the RTC
    device structure. This avoids the unreliable heuristics that does not
    work in a setup where the RTC is not explicitly accessed with the usual
    address and data window register pair.

    * The ability to use the RTC periodic interrupt as a system clock
    device, which is implemented by arch/mips/kernel/cevt-ds1287.c for
    DECstation systems and takes the RTC interrupt away from the RTC driver.
    Eventually hooking back to the clock device's interrupt handler should
    be possible for the purpose of the alarm clock and possibly also
    update-in-progress interrupt, but this is not done by this change.

    o To avoid interfering with the clock interrupt all the places where
    the RTC interrupt mask is fiddled with are only executed if and IRQ
    has been assigned to the RTC driver.

    o To avoid changing the clock setup Register A is not fiddled with
    if CMOS_RTC_FLAGS_NOFREQ is set in the newly-added `flags' member of
    the platform part of the RTC device structure. Originally, in
    drivers/char/rtc.c, this was keyed with the absence of the RTC
    interrupt, just like the interrupt mask, but there only the periodic
    interrupt frequency is set, whereas rtc-cmos also sets the divider
    bits. Therefore a new flag is introduced so that systems where the
    RTC interrupt is not usable rather than used as a system clock device
    can fully initialise the RTC.

    * A small clean-up is made to the IRQ assignment code that makes the IRQ
    number hardcoded to -1 rather than arbitrary -ENXIO (or whatever error
    happens to be returned by platform_get_irq) where no IRQ has been
    assigned to the RTC driver (NO_IRQ might be another candidate, but it
    looks like this macro has inconsistent or missing definitions and
    limited use and might therefore be unsafe).

    Verified to work correctly with a DECstation 5000/240 system.

    [akpm@linux-foundation.org: fix weird code layout]
    Signed-off-by: Maciej W. Rozycki
    Cc: Alessandro Zummo
    Cc: Ralf Baechle
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Maciej W. Rozycki
     

15 Nov, 2007

1 commit

  • Firmware like PNPBIOS or ACPI can report the address space consumed by the
    RTC. The actual space consumed may be less than the size (RTC_IO_EXTENT)
    assumed by the RTC driver.

    The PNP core doesn't request resources yet, but I'd like to make it do so.
    If/when it does, the RTC_IO_EXTENT request may fail, which prevents the RTC
    driver from loading.

    Since we only use the RTC index and data registers at RTC_PORT(0) and
    RTC_PORT(1), we can fall back to requesting just enough space for those.

    If the PNP core requests resources, this results in typical I/O port usage
    like this:

    0070-0073 : 00:06
    Cc: Alessandro Zummo
    Cc: David Brownell
    Cc: Ralf Baechle
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Bjorn Helgaas
     

09 May, 2007

1 commit

  • I finally got around to testing the updated wakeup event hooks for rtc-cmos,
    and they follow in two patches:

    - Interface update ... when a simple enable_irq_wake() doesn't suffice,
    the platform data can hold suspend/resume callback hooks.

    - ACPI implementation ... provides callback hooks to do ACPI magic, and
    eliminate the legacy /proc/acpi/alarm file.

    The interface update could go into 2.6.21, but that's not essential; they
    will be NOPs on most PCs, without the ACPI stuff.

    I suspect the ACPI folk may have opinions about how to merge that second
    patch, and how to obsolete that legacy procfs file. I'd like to see that
    merge into 2.6.22 if possible...

    As for how to kick it in ... two ways:

    - The appended "rtcwake" program; updated since the last time it was
    posted, it deals much better with timezones and DST.

    - Write the /sys/class/rtc/.../wakealarm file, then go to sleep.

    For some reason RTC wake from "swsusp" stopped working on a system where
    it previously worked; the alarm setting appears to get clobbered. But
    on the bright side, RTC wake from "standby" worked on a system that had
    never been able to resume from that state before ... IDEACPI is my guess
    as to why it finally started to work. It's the old "two steps forward,
    one step back" dance, I guess.

    - Dave

    /* gcc -Wall -Os -o rtcwake rtcwake.c */

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include

    #include
    #include
    #include

    #include

    /* constants from legacy PC/AT hardware */
    #define RTC_PF 0x40
    #define RTC_AF 0x20
    #define RTC_UF 0x10

    /*
    * rtcwake -- enter a system sleep state until specified wakeup time.
    *
    * This uses cross-platform Linux interfaces to enter a system sleep state,
    * and leave it no later than a specified time. It uses any RTC framework
    * driver that supports standard driver model wakeup flags.
    *
    * This is normally used like the old "apmsleep" utility, to wake from a
    * suspend state like ACPI S1 (standby) or S3 (suspend-to-RAM). Most
    * platforms can implement those without analogues of BIOS, APM, or ACPI.
    *
    * On some systems, this can also be used like "nvram-wakeup", waking
    * from states like ACPI S4 (suspend to disk). Not all systems have
    * persistent media that are appropriate for such suspend modes.
    *
    * The best way to set the system's RTC is so that it holds the current
    * time in UTC. Use the "-l" flag to tell this program that the system
    * RTC uses a local timezone instead (maybe you dual-boot MS-Windows).
    */

    static char *progname;

    #ifdef DEBUG
    #define VERSION "1.0 dev (" __DATE__ " " __TIME__ ")"
    #else
    #define VERSION "0.9"
    #endif

    static unsigned verbose;
    static int rtc_is_utc = -1;

    static int may_wakeup(const char *devname)
    {
    char buf[128], *s;
    FILE *f;

    snprintf(buf, sizeof buf, "/sys/class/rtc/%s/device/power/wakeup",
    devname);
    f = fopen(buf, "r");
    if (!f) {
    perror(buf);
    return 0;
    }
    fgets(buf, sizeof buf, f);
    fclose(f);

    s = strchr(buf, '\n');
    if (!s)
    return 0;
    *s = 0;

    /* wakeup events could be disabled or not supported */
    return strcmp(buf, "enabled") == 0;
    }

    /* all times should be in UTC */
    static time_t sys_time;
    static time_t rtc_time;

    static int get_basetimes(int fd)
    {
    struct tm tm;
    struct rtc_time rtc;

    /* this process works in RTC time, except when working
    * with the system clock (which always uses UTC).
    */
    if (rtc_is_utc)
    setenv("TZ", "UTC", 1);
    tzset();

    /* read rtc and system clocks "at the same time", or as
    * precisely (+/- a second) as we can read them.
    */
    if (ioctl(fd, RTC_RD_TIME, &rtc) < 0) {
    perror("read rtc time");
    return 0;
    }
    sys_time = time(0);
    if (sys_time == (time_t)-1) {
    perror("read system time");
    return 0;
    }

    /* convert rtc_time to normal arithmetic-friendly form,
    * updating tm.tm_wday as used by asctime().
    */
    memset(&tm, 0, sizeof tm);
    tm.tm_sec = rtc.tm_sec;
    tm.tm_min = rtc.tm_min;
    tm.tm_hour = rtc.tm_hour;
    tm.tm_mday = rtc.tm_mday;
    tm.tm_mon = rtc.tm_mon;
    tm.tm_year = rtc.tm_year;
    tm.tm_isdst = rtc.tm_isdst; /* stays unspecified? */
    rtc_time = mktime(&tm);

    if (rtc_time == (time_t)-1) {
    perror("convert rtc time");
    return 0;
    }

    if (verbose) {
    if (!rtc_is_utc) {
    printf("\ttzone = %ld\n", timezone);
    printf("\ttzname = %s\n", tzname[daylight]);
    gmtime_r(&rtc_time, &tm);
    }
    printf("\tsystime = %ld, (UTC) %s",
    (long) sys_time, asctime(gmtime(&sys_time)));
    printf("\trtctime = %ld, (UTC) %s",
    (long) rtc_time, asctime(&tm));
    }

    return 1;
    }

    static int setup_alarm(int fd, time_t *wakeup)
    {
    struct tm *tm;
    struct rtc_wkalrm wake;

    tm = gmtime(wakeup);

    wake.time.tm_sec = tm->tm_sec;
    wake.time.tm_min = tm->tm_min;
    wake.time.tm_hour = tm->tm_hour;
    wake.time.tm_mday = tm->tm_mday;
    wake.time.tm_mon = tm->tm_mon;
    wake.time.tm_year = tm->tm_year;
    wake.time.tm_wday = tm->tm_wday;
    wake.time.tm_yday = tm->tm_yday;
    wake.time.tm_isdst = tm->tm_isdst;

    /* many rtc alarms only support up to 24 hours from 'now' ... */
    if ((rtc_time + (24 * 60 * 60)) > *wakeup) {
    if (ioctl(fd, RTC_ALM_SET, &wake.time) < 0) {
    perror("set rtc alarm");
    return 0;
    }
    if (ioctl(fd, RTC_AIE_ON, 0) < 0) {
    perror("enable rtc alarm");
    return 0;
    }

    /* ... so use the "more than 24 hours" request only if we must */
    } else {
    /* avoid an extra AIE_ON call */
    wake.enabled = 1;

    if (ioctl(fd, RTC_WKALM_SET, &wake) < 0) {
    perror("set rtc wake alarm");
    return 0;
    }
    }

    return 1;
    }

    static void suspend_system(const char *suspend)
    {
    FILE *f = fopen("/sys/power/state", "w");

    if (!f) {
    perror("/sys/power/state");
    return;
    }

    fprintf(f, "%s\n", suspend);
    fflush(f);

    /* this executes after wake from suspend */
    fclose(f);
    }

    int main(int argc, char **argv)
    {
    static char *devname = "rtc0";
    static unsigned seconds = 0;
    static char *suspend = "standby";

    int t;
    int fd;
    time_t alarm = 0;

    progname = strrchr(argv[0], '/');
    if (progname)
    progname++;
    else
    progname = argv[0];
    if (chdir("/dev/") < 0) {
    perror("chdir /dev");
    return 1;
    }

    while ((t = getopt(argc, argv, "d:lm:s:t:uVv")) != EOF) {
    switch (t) {

    case 'd':
    devname = optarg;
    break;

    case 'l':
    rtc_is_utc = 0;
    break;

    /* what system power mode to use? for now handle only
    * standardized mode names; eventually when systems define
    * their own state names, parse /sys/power/state.
    *
    * "on" is used just to test the RTC alarm mechanism,
    * bypassing all the wakeup-from-sleep infrastructure.
    */
    case 'm':
    if (strcmp(optarg, "standby") == 0
    || strcmp(optarg, "mem") == 0
    || strcmp(optarg, "disk") == 0
    || strcmp(optarg, "on") == 0
    ) {
    suspend = optarg;
    break;
    }
    printf("%s: unrecognized suspend state '%s'\n",
    progname, optarg);
    goto usage;

    /* alarm time, seconds-to-sleep (relative) */
    case 's':
    t = atoi(optarg);
    if (t < 0) {
    printf("%s: illegal interval %s seconds\n",
    progname, optarg);
    goto usage;
    }
    seconds = t;
    break;

    /* alarm time, time_t (absolute, seconds since 1/1 1970 UTC) */
    case 't':
    t = atoi(optarg);
    if (t < 0) {
    printf("%s: illegal time_t value %s\n",
    progname, optarg);
    goto usage;
    }
    alarm = t;
    break;

    case 'u':
    rtc_is_utc = 1;
    break;

    case 'v':
    verbose++;
    break;

    case 'V':
    printf("%s: version %s\n", progname, VERSION);
    break;

    default:
    usage:
    printf("usage: %s [options]"
    "\n\t"
    "-d rtc0|rtc1|...\t(select rtc)"
    "\n\t"
    "-l\t\t\t(RTC uses local timezone)"
    "\n\t"
    "-m standby|mem|...\t(sleep mode)"
    "\n\t"
    "-s seconds\t\t(seconds to sleep)"
    "\n\t"
    "-t time_t\t\t(time to wake)"
    "\n\t"
    "-u\t\t\t(RTC uses UTC)"
    "\n\t"
    "-v\t\t\t(verbose messages)"
    "\n\t"
    "-V\t\t\t(show version)"
    "\n",
    progname);
    return 1;
    }
    }

    if (!alarm && !seconds) {
    printf("%s: must provide wake time\n", progname);
    goto usage;
    }

    /* REVISIT: if /etc/adjtime exists, read it to see what
    * the util-linux version of hwclock assumes.
    */
    if (rtc_is_utc == -1) {
    printf("%s: assuming RTC uses UTC ...\n", progname);
    rtc_is_utc = 1;
    }

    /* this RTC must exist and (if we'll sleep) be wakeup-enabled */
    fd = open(devname, O_RDONLY);
    if (fd < 0) {
    perror(devname);
    return 1;
    }
    if (strcmp(suspend, "on") != 0 && !may_wakeup(devname)) {
    printf("%s: %s not enabled for wakeup events\n",
    progname, devname);
    return 1;
    }

    /* relative or absolute alarm time, normalized to time_t */
    if (!get_basetimes(fd))
    return 1;
    if (verbose)
    printf("alarm %ld, sys_time %ld, rtc_time %ld, seconds %u\n",
    alarm, sys_time, rtc_time, seconds);
    if (alarm) {
    if (alarm < sys_time) {
    printf("%s: time doesn't go backward to %s",
    progname, ctime(&alarm));
    return 1;
    }
    alarm += sys_time - rtc_time;
    } else
    alarm = rtc_time + seconds + 1;
    if (setup_alarm(fd, &alarm) < 0)
    return 1;

    sync();
    printf("%s: wakeup from \"%s\" using %s at %s",
    progname, suspend, devname,
    ctime(&alarm));
    fflush(stdout);
    usleep(10 * 1000);

    if (strcmp(suspend, "on") != 0)
    suspend_system(suspend);
    else {
    unsigned long data;

    do {
    t = read(fd, &data, sizeof data);
    if (t < 0) {
    perror("rtc read");
    break;
    }
    if (verbose)
    printf("... %s: %03lx\n", devname, data);
    } while (!(data & RTC_AF));
    }

    if (ioctl(fd, RTC_AIE_OFF, 0) < 0)
    perror("disable rtc alarm interrupt");

    close(fd);
    return 0;
    }

    This patch:

    Make rtc-cmos do the relevant magic so this RTC can wake the system from a
    sleep state. That magic comes in two basic flavors:

    - Straightforward: enable_irq_wake(), the way it'd work on most SOC chips;
    or generally with system sleep states which don't disable core IRQ logic.

    - Roundabout, using non-IRQ platform hooks. This is needed with ACPI and
    one almost-clone chip which uses a special wakeup-only alarm. (That's
    the RTC used on Footbridge boards, FWIW, which don't do PM in Linux.)

    A separate patch implements those hooks for ACPI platforms, so that rtc_cmos
    can issue system wakeup events (and its sysfs "wakealarm" attribute works on
    at least some systems).

    Signed-off-by: David Brownell
    Cc: Alessandro Zummo
    Cc: Len Brown
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Brownell
     

12 Feb, 2007

1 commit

  • This is an "RTC framework" driver for the "CMOS" RTCs which are standard on
    PCs and some other platforms. That's MC146818 compatible silicon.
    Advantages of this vs. drivers/char/rtc.c (use one _or_ the other, only
    one will be able to claim the RTC irq) include:

    - This leverages both the new RTC framework and the driver model; both
    PNPACPI and platform device modes are supported. (A separate patch
    creates a platform device on PCs where PNPACPI isn't configured.)

    - It supports common extensions like longer alarms. (A separate patch
    exports that information from ACPI through platform_data.)

    - Likewise, system wakeup events use "real driver model support", with
    policy control via sysfs "wakeup" attributes and and using normal rtc
    ioctls to manage wakeup. (Patch in the works. The ACPI hooks are
    known; /proc/acpi/alarm can vanish. Making it work with EFI will
    be a minor challenge to someone with e.g. a MiniMac.)

    It's not yet been tested on non-x86 systems, without ACPI, or with HPET.
    And the RTC framework will surely have teething pains on "mainstream"
    PC-based systems (though must embedded Linux systems use it heavily), not
    limited to sorting out the "/dev/rtc0" issue (udev easily tweaked). Also,
    the ALSA rtctimer code doesn't use the new RTC API.

    Otherwise, this should be a no-known-regressions replacement for the old
    drivers/char/rtc.c driver, and should help the non-embedded distros (and
    the new timekeeping code) start to switch to the framework.

    Note also that any systems using "rtc-m48t86" are candidates to switch over
    to this more functional driver; the platform data is different, and the way
    bytes are read is different, but otherwise those chips should be compatible.

    [akpm@osdl.org: sparc32 fix]
    [akpm@osdl.org: sparc64 fix]
    Signed-off-by: David Brownell
    Cc: Woody Suwalski
    Cc: Alessandro Zummo
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    David Brownell
     

11 Jul, 2006

1 commit

  • Handle memory-mapped chips properly, needed for example on DECstations.
    This support was in Linux 2.4 but for some reason got lost in 2.6. This
    patch is taken directly from the linux-mips repository.

    [akpm@osdl.org: cleanup]
    Signed-off-by: Maciej W. Rozycki
    Signed-off-by: Martin Michlmayr
    Cc: Paul Gortmaker
    Cc: Ralf Baechle
    Signed-off-by: Andrew Morton
    Signed-off-by: Linus Torvalds

    Maciej W. Rozycki
     

17 Apr, 2005

1 commit

  • Initial git repository build. I'm not bothering with the full history,
    even though we have it. We can create a separate "historical" git
    archive of that later if we want to, and in the meantime it's about
    3.2GB when imported into git - space that would just make the early
    git days unnecessarily complicated, when we don't have a lot of good
    infrastructure for it.

    Let it rip!

    Linus Torvalds