Exemplo n.º 1
0
static int ds1305_set_time(struct device *dev, struct rtc_time *time)
{
	struct ds1305	*ds1305 = dev_get_drvdata(dev);
	u8		buf[1 + DS1305_RTC_LEN];
	u8		*bp = buf;

	dev_vdbg(dev, "%s secs=%d, mins=%d, "
		"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
		"write", time->tm_sec, time->tm_min,
		time->tm_hour, time->tm_mday,
		time->tm_mon, time->tm_year, time->tm_wday);

	/* Write registers starting at the first time/date address. */
	*bp++ = DS1305_WRITE | DS1305_SEC;

	*bp++ = bin2bcd(time->tm_sec);
	*bp++ = bin2bcd(time->tm_min);
	*bp++ = hour2bcd(ds1305->hr12, time->tm_hour);
	*bp++ = (time->tm_wday < 7) ? (time->tm_wday + 1) : 1;
	*bp++ = bin2bcd(time->tm_mday);
	*bp++ = bin2bcd(time->tm_mon + 1);
	*bp++ = bin2bcd(time->tm_year - 100);

	dev_dbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
		"write", buf[1], buf[2], buf[3],
		buf[4], buf[5], buf[6], buf[7]);

	/* use write-then-read since dma from stack is nonportable */
	return spi_write_then_read(ds1305->spi, buf, sizeof buf,
			NULL, 0);
}
/*
 * Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
 */
static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
    struct ds1305	*ds1305 = dev_get_drvdata(dev);
    struct spi_device *spi = ds1305->spi;
    unsigned long	now, later;
    struct rtc_time	tm;
    int		status;
    u8		buf[1 + DS1305_ALM_LEN];

    /* convert desired alarm to time_t */
    status = rtc_tm_to_time(&alm->time, &later);
    if (status < 0)
        return status;

    /* Read current time as time_t */
    status = ds1305_get_time(dev, &tm);
    if (status < 0)
        return status;
    status = rtc_tm_to_time(&tm, &now);
    if (status < 0)
        return status;

    /* make sure alarm fires within the next 24 hours */
    if (later <= now)
        return -EINVAL;
    if ((later - now) > 24 * 60 * 60)
        return -EDOM;

    /* disable alarm if needed */
    if (ds1305->ctrl[0] & DS1305_AEI0) {
        ds1305->ctrl[0] &= ~DS1305_AEI0;

        buf[0] = DS1305_WRITE | DS1305_CONTROL;
        buf[1] = ds1305->ctrl[0];
        status = spi_write_then_read(ds1305->spi, buf, 2, NULL, 0);
        if (status < 0)
            return status;
    }

    /* write alarm */
    buf[0] = DS1305_WRITE | DS1305_ALM0(DS1305_SEC);
    buf[1 + DS1305_SEC] = bin2bcd(alm->time.tm_sec);
    buf[1 + DS1305_MIN] = bin2bcd(alm->time.tm_min);
    buf[1 + DS1305_HOUR] = hour2bcd(ds1305->hr12, alm->time.tm_hour);
    buf[1 + DS1305_WDAY] = DS1305_ALM_DISABLE;

    dev_dbg(dev, "%s: %02x %02x %02x %02x\n",
            "alm0 write", buf[1 + DS1305_SEC], buf[1 + DS1305_MIN],
            buf[1 + DS1305_HOUR], buf[1 + DS1305_WDAY]);

    status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
    if (status < 0)
        return status;

    /* enable alarm if requested */
    if (alm->enabled) {
        ds1305->ctrl[0] |= DS1305_AEI0;

        buf[0] = DS1305_WRITE | DS1305_CONTROL;
        buf[1] = ds1305->ctrl[0];
        status = spi_write_then_read(ds1305->spi, buf, 2, NULL, 0);
    }

    return status;
}