![Anton Vorontsov](/assets/img/avatar_default.png)
RTC core won't allow wakeup alarms to be set if RTC devices' parent (i.e. i2c_client or spi_device) isn't wakeup capable. For I2C devices there is I2C_CLIENT_WAKE flag exists that we can pass via board info, and if set, I2C core will initialize wakeup capability. For SPI devices there is no such flag at all. I believe that it's not platform code responsibility to allow or disallow wakeups, instead, drivers themselves should set the capability if a device can trigger wakeups. That's what drivers/base/power/sysfs.c says: * It is the responsibility of device drivers to enable (or disable) * wakeup signaling as part of changing device power states, respecting * the policy choices provided through the driver model. I2C and SPI RTC devices send wakeup events via interrupt lines, so we should set the wakeup capability if IRQ is routed. Ideally we should also check irq for wakeup capability before setting device's capability, i.e. if (can_irq_wake(irq)) device_set_wakeup_capable(&client->dev, 1); But there is no can_irq_wake() call exist, and it is not that trivial to implement it for all interrupts controllers and complex/cascaded setups. drivers/base/power/sysfs.c also covers these cases: * Devices may not be able to generate wakeup events from all power * states. Also, the events may be ignored in some configurations; * for example, they might need help from other devices that aren't * active So there is no guarantee that wakeup will actually work, and so I think there is no point in being pedantic wrt checking IRQ wakeup capability. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Cc: David Brownell <dbrownell@users.sourceforge.net> Cc: Ben Dooks <ben-linux@fluff.org> Cc: Jean Delvare <khali@linux-fr.org> Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
845 lines
22 KiB
C
845 lines
22 KiB
C
/*
|
|
* rtc-ds1305.c -- driver for DS1305 and DS1306 SPI RTC chips
|
|
*
|
|
* Copyright (C) 2008 David Brownell
|
|
*
|
|
* 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 <linux/kernel.h>
|
|
#include <linux/init.h>
|
|
#include <linux/bcd.h>
|
|
#include <linux/rtc.h>
|
|
#include <linux/workqueue.h>
|
|
|
|
#include <linux/spi/spi.h>
|
|
#include <linux/spi/ds1305.h>
|
|
|
|
|
|
/*
|
|
* Registers ... mask DS1305_WRITE into register address to write,
|
|
* otherwise you're reading it. All non-bitmask values are BCD.
|
|
*/
|
|
#define DS1305_WRITE 0x80
|
|
|
|
|
|
/* RTC date/time ... the main special cases are that we:
|
|
* - Need fancy "hours" encoding in 12hour mode
|
|
* - Don't rely on the "day-of-week" field (or tm_wday)
|
|
* - Are a 21st-century clock (2000 <= year < 2100)
|
|
*/
|
|
#define DS1305_RTC_LEN 7 /* bytes for RTC regs */
|
|
|
|
#define DS1305_SEC 0x00 /* register addresses */
|
|
#define DS1305_MIN 0x01
|
|
#define DS1305_HOUR 0x02
|
|
# define DS1305_HR_12 0x40 /* set == 12 hr mode */
|
|
# define DS1305_HR_PM 0x20 /* set == PM (12hr mode) */
|
|
#define DS1305_WDAY 0x03
|
|
#define DS1305_MDAY 0x04
|
|
#define DS1305_MON 0x05
|
|
#define DS1305_YEAR 0x06
|
|
|
|
|
|
/* The two alarms have only sec/min/hour/wday fields (ALM_LEN).
|
|
* DS1305_ALM_DISABLE disables a match field (some combos are bad).
|
|
*
|
|
* NOTE that since we don't use WDAY, we limit ourselves to alarms
|
|
* only one day into the future (vs potentially up to a week).
|
|
*
|
|
* NOTE ALSO that while we could generate once-a-second IRQs (UIE), we
|
|
* don't currently support them. We'd either need to do it only when
|
|
* no alarm is pending (not the standard model), or to use the second
|
|
* alarm (implying that this is a DS1305 not DS1306, *and* that either
|
|
* it's wired up a second IRQ we know, or that INTCN is set)
|
|
*/
|
|
#define DS1305_ALM_LEN 4 /* bytes for ALM regs */
|
|
#define DS1305_ALM_DISABLE 0x80
|
|
|
|
#define DS1305_ALM0(r) (0x07 + (r)) /* register addresses */
|
|
#define DS1305_ALM1(r) (0x0b + (r))
|
|
|
|
|
|
/* three control registers */
|
|
#define DS1305_CONTROL_LEN 3 /* bytes of control regs */
|
|
|
|
#define DS1305_CONTROL 0x0f /* register addresses */
|
|
# define DS1305_nEOSC 0x80 /* low enables oscillator */
|
|
# define DS1305_WP 0x40 /* write protect */
|
|
# define DS1305_INTCN 0x04 /* clear == only int0 used */
|
|
# define DS1306_1HZ 0x04 /* enable 1Hz output */
|
|
# define DS1305_AEI1 0x02 /* enable ALM1 IRQ */
|
|
# define DS1305_AEI0 0x01 /* enable ALM0 IRQ */
|
|
#define DS1305_STATUS 0x10
|
|
/* status has just AEIx bits, mirrored as IRQFx */
|
|
#define DS1305_TRICKLE 0x11
|
|
/* trickle bits are defined in <linux/spi/ds1305.h> */
|
|
|
|
/* a bunch of NVRAM */
|
|
#define DS1305_NVRAM_LEN 96 /* bytes of NVRAM */
|
|
|
|
#define DS1305_NVRAM 0x20 /* register addresses */
|
|
|
|
|
|
struct ds1305 {
|
|
struct spi_device *spi;
|
|
struct rtc_device *rtc;
|
|
|
|
struct work_struct work;
|
|
|
|
unsigned long flags;
|
|
#define FLAG_EXITING 0
|
|
|
|
bool hr12;
|
|
u8 ctrl[DS1305_CONTROL_LEN];
|
|
};
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Utilities ... tolerate 12-hour AM/PM notation in case of non-Linux
|
|
* software (like a bootloader) which may require it.
|
|
*/
|
|
|
|
static unsigned bcd2hour(u8 bcd)
|
|
{
|
|
if (bcd & DS1305_HR_12) {
|
|
unsigned hour = 0;
|
|
|
|
bcd &= ~DS1305_HR_12;
|
|
if (bcd & DS1305_HR_PM) {
|
|
hour = 12;
|
|
bcd &= ~DS1305_HR_PM;
|
|
}
|
|
hour += bcd2bin(bcd);
|
|
return hour - 1;
|
|
}
|
|
return bcd2bin(bcd);
|
|
}
|
|
|
|
static u8 hour2bcd(bool hr12, int hour)
|
|
{
|
|
if (hr12) {
|
|
hour++;
|
|
if (hour <= 12)
|
|
return DS1305_HR_12 | bin2bcd(hour);
|
|
hour -= 12;
|
|
return DS1305_HR_12 | DS1305_HR_PM | bin2bcd(hour);
|
|
}
|
|
return bin2bcd(hour);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Interface to RTC framework
|
|
*/
|
|
|
|
#ifdef CONFIG_RTC_INTF_DEV
|
|
|
|
/*
|
|
* Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
|
|
*/
|
|
static int ds1305_ioctl(struct device *dev, unsigned cmd, unsigned long arg)
|
|
{
|
|
struct ds1305 *ds1305 = dev_get_drvdata(dev);
|
|
u8 buf[2];
|
|
int status = -ENOIOCTLCMD;
|
|
|
|
buf[0] = DS1305_WRITE | DS1305_CONTROL;
|
|
buf[1] = ds1305->ctrl[0];
|
|
|
|
switch (cmd) {
|
|
case RTC_AIE_OFF:
|
|
status = 0;
|
|
if (!(buf[1] & DS1305_AEI0))
|
|
goto done;
|
|
buf[1] &= ~DS1305_AEI0;
|
|
break;
|
|
|
|
case RTC_AIE_ON:
|
|
status = 0;
|
|
if (ds1305->ctrl[0] & DS1305_AEI0)
|
|
goto done;
|
|
buf[1] |= DS1305_AEI0;
|
|
break;
|
|
}
|
|
if (status == 0) {
|
|
status = spi_write_then_read(ds1305->spi, buf, sizeof buf,
|
|
NULL, 0);
|
|
if (status >= 0)
|
|
ds1305->ctrl[0] = buf[1];
|
|
}
|
|
|
|
done:
|
|
return status;
|
|
}
|
|
|
|
#else
|
|
#define ds1305_ioctl NULL
|
|
#endif
|
|
|
|
/*
|
|
* Get/set of date and time is pretty normal.
|
|
*/
|
|
|
|
static int ds1305_get_time(struct device *dev, struct rtc_time *time)
|
|
{
|
|
struct ds1305 *ds1305 = dev_get_drvdata(dev);
|
|
u8 addr = DS1305_SEC;
|
|
u8 buf[DS1305_RTC_LEN];
|
|
int status;
|
|
|
|
/* Use write-then-read to get all the date/time registers
|
|
* since dma from stack is nonportable
|
|
*/
|
|
status = spi_write_then_read(ds1305->spi, &addr, sizeof addr,
|
|
buf, sizeof buf);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
dev_vdbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
|
|
"read", buf[0], buf[1], buf[2], buf[3],
|
|
buf[4], buf[5], buf[6]);
|
|
|
|
/* Decode the registers */
|
|
time->tm_sec = bcd2bin(buf[DS1305_SEC]);
|
|
time->tm_min = bcd2bin(buf[DS1305_MIN]);
|
|
time->tm_hour = bcd2hour(buf[DS1305_HOUR]);
|
|
time->tm_wday = buf[DS1305_WDAY] - 1;
|
|
time->tm_mday = bcd2bin(buf[DS1305_MDAY]);
|
|
time->tm_mon = bcd2bin(buf[DS1305_MON]) - 1;
|
|
time->tm_year = bcd2bin(buf[DS1305_YEAR]) + 100;
|
|
|
|
dev_vdbg(dev, "%s secs=%d, mins=%d, "
|
|
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
|
"read", time->tm_sec, time->tm_min,
|
|
time->tm_hour, time->tm_mday,
|
|
time->tm_mon, time->tm_year, time->tm_wday);
|
|
|
|
/* Time may not be set */
|
|
return rtc_valid_tm(time);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/*
|
|
* Get/set of alarm is a bit funky:
|
|
*
|
|
* - First there's the inherent raciness of getting the (partitioned)
|
|
* status of an alarm that could trigger while we're reading parts
|
|
* of that status.
|
|
*
|
|
* - Second there's its limited range (we could increase it a bit by
|
|
* relying on WDAY), which means it will easily roll over.
|
|
*
|
|
* - Third there's the choice of two alarms and alarm signals.
|
|
* Here we use ALM0 and expect that nINT0 (open drain) is used;
|
|
* that's the only real option for DS1306 runtime alarms, and is
|
|
* natural on DS1305.
|
|
*
|
|
* - Fourth, there's also ALM1, and a second interrupt signal:
|
|
* + On DS1305 ALM1 uses nINT1 (when INTCN=1) else nINT0;
|
|
* + On DS1306 ALM1 only uses INT1 (an active high pulse)
|
|
* and it won't work when VCC1 is active.
|
|
*
|
|
* So to be most general, we should probably set both alarms to the
|
|
* same value, letting ALM1 be the wakeup event source on DS1306
|
|
* and handling several wiring options on DS1305.
|
|
*
|
|
* - Fifth, we support the polled mode (as well as possible; why not?)
|
|
* even when no interrupt line is wired to an IRQ.
|
|
*/
|
|
|
|
/*
|
|
* Context: caller holds rtc->ops_lock (to protect ds1305->ctrl)
|
|
*/
|
|
static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
|
{
|
|
struct ds1305 *ds1305 = dev_get_drvdata(dev);
|
|
struct spi_device *spi = ds1305->spi;
|
|
u8 addr;
|
|
int status;
|
|
u8 buf[DS1305_ALM_LEN];
|
|
|
|
/* Refresh control register cache BEFORE reading ALM0 registers,
|
|
* since reading alarm registers acks any pending IRQ. That
|
|
* makes returning "pending" status a bit of a lie, but that bit
|
|
* of EFI status is at best fragile anyway (given IRQ handlers).
|
|
*/
|
|
addr = DS1305_CONTROL;
|
|
status = spi_write_then_read(spi, &addr, sizeof addr,
|
|
ds1305->ctrl, sizeof ds1305->ctrl);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
alm->enabled = !!(ds1305->ctrl[0] & DS1305_AEI0);
|
|
alm->pending = !!(ds1305->ctrl[1] & DS1305_AEI0);
|
|
|
|
/* get and check ALM0 registers */
|
|
addr = DS1305_ALM0(DS1305_SEC);
|
|
status = spi_write_then_read(spi, &addr, sizeof addr,
|
|
buf, sizeof buf);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
dev_vdbg(dev, "%s: %02x %02x %02x %02x\n",
|
|
"alm0 read", buf[DS1305_SEC], buf[DS1305_MIN],
|
|
buf[DS1305_HOUR], buf[DS1305_WDAY]);
|
|
|
|
if ((DS1305_ALM_DISABLE & buf[DS1305_SEC])
|
|
|| (DS1305_ALM_DISABLE & buf[DS1305_MIN])
|
|
|| (DS1305_ALM_DISABLE & buf[DS1305_HOUR]))
|
|
return -EIO;
|
|
|
|
/* Stuff these values into alm->time and let RTC framework code
|
|
* fill in the rest ... and also handle rollover to tomorrow when
|
|
* that's needed.
|
|
*/
|
|
alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
|
|
alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
|
|
alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
|
|
alm->time.tm_mday = -1;
|
|
alm->time.tm_mon = -1;
|
|
alm->time.tm_year = -1;
|
|
/* next three fields are unused by Linux */
|
|
alm->time.tm_wday = -1;
|
|
alm->time.tm_mday = -1;
|
|
alm->time.tm_isdst = -1;
|
|
|
|
return 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;
|
|
}
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
|
|
static int ds1305_proc(struct device *dev, struct seq_file *seq)
|
|
{
|
|
struct ds1305 *ds1305 = dev_get_drvdata(dev);
|
|
char *diodes = "no";
|
|
char *resistors = "";
|
|
|
|
/* ctrl[2] is treated as read-only; no locking needed */
|
|
if ((ds1305->ctrl[2] & 0xf0) == DS1305_TRICKLE_MAGIC) {
|
|
switch (ds1305->ctrl[2] & 0x0c) {
|
|
case DS1305_TRICKLE_DS2:
|
|
diodes = "2 diodes, ";
|
|
break;
|
|
case DS1305_TRICKLE_DS1:
|
|
diodes = "1 diode, ";
|
|
break;
|
|
default:
|
|
goto done;
|
|
}
|
|
switch (ds1305->ctrl[2] & 0x03) {
|
|
case DS1305_TRICKLE_2K:
|
|
resistors = "2k Ohm";
|
|
break;
|
|
case DS1305_TRICKLE_4K:
|
|
resistors = "4k Ohm";
|
|
break;
|
|
case DS1305_TRICKLE_8K:
|
|
resistors = "8k Ohm";
|
|
break;
|
|
default:
|
|
diodes = "no";
|
|
break;
|
|
}
|
|
}
|
|
|
|
done:
|
|
return seq_printf(seq,
|
|
"trickle_charge\t: %s%s\n",
|
|
diodes, resistors);
|
|
}
|
|
|
|
#else
|
|
#define ds1305_proc NULL
|
|
#endif
|
|
|
|
static const struct rtc_class_ops ds1305_ops = {
|
|
.ioctl = ds1305_ioctl,
|
|
.read_time = ds1305_get_time,
|
|
.set_time = ds1305_set_time,
|
|
.read_alarm = ds1305_get_alarm,
|
|
.set_alarm = ds1305_set_alarm,
|
|
.proc = ds1305_proc,
|
|
};
|
|
|
|
static void ds1305_work(struct work_struct *work)
|
|
{
|
|
struct ds1305 *ds1305 = container_of(work, struct ds1305, work);
|
|
struct mutex *lock = &ds1305->rtc->ops_lock;
|
|
struct spi_device *spi = ds1305->spi;
|
|
u8 buf[3];
|
|
int status;
|
|
|
|
/* lock to protect ds1305->ctrl */
|
|
mutex_lock(lock);
|
|
|
|
/* Disable the IRQ, and clear its status ... for now, we "know"
|
|
* that if more than one alarm is active, they're in sync.
|
|
* Note that reading ALM data registers also clears IRQ status.
|
|
*/
|
|
ds1305->ctrl[0] &= ~(DS1305_AEI1 | DS1305_AEI0);
|
|
ds1305->ctrl[1] = 0;
|
|
|
|
buf[0] = DS1305_WRITE | DS1305_CONTROL;
|
|
buf[1] = ds1305->ctrl[0];
|
|
buf[2] = 0;
|
|
|
|
status = spi_write_then_read(spi, buf, sizeof buf,
|
|
NULL, 0);
|
|
if (status < 0)
|
|
dev_dbg(&spi->dev, "clear irq --> %d\n", status);
|
|
|
|
mutex_unlock(lock);
|
|
|
|
if (!test_bit(FLAG_EXITING, &ds1305->flags))
|
|
enable_irq(spi->irq);
|
|
|
|
rtc_update_irq(ds1305->rtc, 1, RTC_AF | RTC_IRQF);
|
|
}
|
|
|
|
/*
|
|
* This "real" IRQ handler hands off to a workqueue mostly to allow
|
|
* mutex locking for ds1305->ctrl ... unlike I2C, we could issue async
|
|
* I/O requests in IRQ context (to clear the IRQ status).
|
|
*/
|
|
static irqreturn_t ds1305_irq(int irq, void *p)
|
|
{
|
|
struct ds1305 *ds1305 = p;
|
|
|
|
disable_irq(irq);
|
|
schedule_work(&ds1305->work);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Interface for NVRAM
|
|
*/
|
|
|
|
static void msg_init(struct spi_message *m, struct spi_transfer *x,
|
|
u8 *addr, size_t count, char *tx, char *rx)
|
|
{
|
|
spi_message_init(m);
|
|
memset(x, 0, 2 * sizeof(*x));
|
|
|
|
x->tx_buf = addr;
|
|
x->len = 1;
|
|
spi_message_add_tail(x, m);
|
|
|
|
x++;
|
|
|
|
x->tx_buf = tx;
|
|
x->rx_buf = rx;
|
|
x->len = count;
|
|
spi_message_add_tail(x, m);
|
|
}
|
|
|
|
static ssize_t
|
|
ds1305_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
|
|
char *buf, loff_t off, size_t count)
|
|
{
|
|
struct spi_device *spi;
|
|
u8 addr;
|
|
struct spi_message m;
|
|
struct spi_transfer x[2];
|
|
int status;
|
|
|
|
spi = container_of(kobj, struct spi_device, dev.kobj);
|
|
|
|
if (unlikely(off >= DS1305_NVRAM_LEN))
|
|
return 0;
|
|
if (count >= DS1305_NVRAM_LEN)
|
|
count = DS1305_NVRAM_LEN;
|
|
if ((off + count) > DS1305_NVRAM_LEN)
|
|
count = DS1305_NVRAM_LEN - off;
|
|
if (unlikely(!count))
|
|
return count;
|
|
|
|
addr = DS1305_NVRAM + off;
|
|
msg_init(&m, x, &addr, count, NULL, buf);
|
|
|
|
status = spi_sync(spi, &m);
|
|
if (status < 0)
|
|
dev_err(&spi->dev, "nvram %s error %d\n", "read", status);
|
|
return (status < 0) ? status : count;
|
|
}
|
|
|
|
static ssize_t
|
|
ds1305_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
|
|
char *buf, loff_t off, size_t count)
|
|
{
|
|
struct spi_device *spi;
|
|
u8 addr;
|
|
struct spi_message m;
|
|
struct spi_transfer x[2];
|
|
int status;
|
|
|
|
spi = container_of(kobj, struct spi_device, dev.kobj);
|
|
|
|
if (unlikely(off >= DS1305_NVRAM_LEN))
|
|
return -EFBIG;
|
|
if (count >= DS1305_NVRAM_LEN)
|
|
count = DS1305_NVRAM_LEN;
|
|
if ((off + count) > DS1305_NVRAM_LEN)
|
|
count = DS1305_NVRAM_LEN - off;
|
|
if (unlikely(!count))
|
|
return count;
|
|
|
|
addr = (DS1305_WRITE | DS1305_NVRAM) + off;
|
|
msg_init(&m, x, &addr, count, buf, NULL);
|
|
|
|
status = spi_sync(spi, &m);
|
|
if (status < 0)
|
|
dev_err(&spi->dev, "nvram %s error %d\n", "write", status);
|
|
return (status < 0) ? status : count;
|
|
}
|
|
|
|
static struct bin_attribute nvram = {
|
|
.attr.name = "nvram",
|
|
.attr.mode = S_IRUGO | S_IWUSR,
|
|
.read = ds1305_nvram_read,
|
|
.write = ds1305_nvram_write,
|
|
.size = DS1305_NVRAM_LEN,
|
|
};
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/*
|
|
* Interface to SPI stack
|
|
*/
|
|
|
|
static int __devinit ds1305_probe(struct spi_device *spi)
|
|
{
|
|
struct ds1305 *ds1305;
|
|
int status;
|
|
u8 addr, value;
|
|
struct ds1305_platform_data *pdata = spi->dev.platform_data;
|
|
bool write_ctrl = false;
|
|
|
|
/* Sanity check board setup data. This may be hooked up
|
|
* in 3wire mode, but we don't care. Note that unless
|
|
* there's an inverter in place, this needs SPI_CS_HIGH!
|
|
*/
|
|
if ((spi->bits_per_word && spi->bits_per_word != 8)
|
|
|| (spi->max_speed_hz > 2000000)
|
|
|| !(spi->mode & SPI_CPHA))
|
|
return -EINVAL;
|
|
|
|
/* set up driver data */
|
|
ds1305 = kzalloc(sizeof *ds1305, GFP_KERNEL);
|
|
if (!ds1305)
|
|
return -ENOMEM;
|
|
ds1305->spi = spi;
|
|
spi_set_drvdata(spi, ds1305);
|
|
|
|
/* read and cache control registers */
|
|
addr = DS1305_CONTROL;
|
|
status = spi_write_then_read(spi, &addr, sizeof addr,
|
|
ds1305->ctrl, sizeof ds1305->ctrl);
|
|
if (status < 0) {
|
|
dev_dbg(&spi->dev, "can't %s, %d\n",
|
|
"read", status);
|
|
goto fail0;
|
|
}
|
|
|
|
dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
|
|
"read", ds1305->ctrl[0],
|
|
ds1305->ctrl[1], ds1305->ctrl[2]);
|
|
|
|
/* Sanity check register values ... partially compensating for the
|
|
* fact that SPI has no device handshake. A pullup on MISO would
|
|
* make these tests fail; but not all systems will have one. If
|
|
* some register is neither 0x00 nor 0xff, a chip is likely there.
|
|
*/
|
|
if ((ds1305->ctrl[0] & 0x38) != 0 || (ds1305->ctrl[1] & 0xfc) != 0) {
|
|
dev_dbg(&spi->dev, "RTC chip is not present\n");
|
|
status = -ENODEV;
|
|
goto fail0;
|
|
}
|
|
if (ds1305->ctrl[2] == 0)
|
|
dev_dbg(&spi->dev, "chip may not be present\n");
|
|
|
|
/* enable writes if needed ... if we were paranoid it would
|
|
* make sense to enable them only when absolutely necessary.
|
|
*/
|
|
if (ds1305->ctrl[0] & DS1305_WP) {
|
|
u8 buf[2];
|
|
|
|
ds1305->ctrl[0] &= ~DS1305_WP;
|
|
|
|
buf[0] = DS1305_WRITE | DS1305_CONTROL;
|
|
buf[1] = ds1305->ctrl[0];
|
|
status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
|
|
|
|
dev_dbg(&spi->dev, "clear WP --> %d\n", status);
|
|
if (status < 0)
|
|
goto fail0;
|
|
}
|
|
|
|
/* on DS1305, maybe start oscillator; like most low power
|
|
* oscillators, it may take a second to stabilize
|
|
*/
|
|
if (ds1305->ctrl[0] & DS1305_nEOSC) {
|
|
ds1305->ctrl[0] &= ~DS1305_nEOSC;
|
|
write_ctrl = true;
|
|
dev_warn(&spi->dev, "SET TIME!\n");
|
|
}
|
|
|
|
/* ack any pending IRQs */
|
|
if (ds1305->ctrl[1]) {
|
|
ds1305->ctrl[1] = 0;
|
|
write_ctrl = true;
|
|
}
|
|
|
|
/* this may need one-time (re)init */
|
|
if (pdata) {
|
|
/* maybe enable trickle charge */
|
|
if (((ds1305->ctrl[2] & 0xf0) != DS1305_TRICKLE_MAGIC)) {
|
|
ds1305->ctrl[2] = DS1305_TRICKLE_MAGIC
|
|
| pdata->trickle;
|
|
write_ctrl = true;
|
|
}
|
|
|
|
/* on DS1306, configure 1 Hz signal */
|
|
if (pdata->is_ds1306) {
|
|
if (pdata->en_1hz) {
|
|
if (!(ds1305->ctrl[0] & DS1306_1HZ)) {
|
|
ds1305->ctrl[0] |= DS1306_1HZ;
|
|
write_ctrl = true;
|
|
}
|
|
} else {
|
|
if (ds1305->ctrl[0] & DS1306_1HZ) {
|
|
ds1305->ctrl[0] &= ~DS1306_1HZ;
|
|
write_ctrl = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (write_ctrl) {
|
|
u8 buf[4];
|
|
|
|
buf[0] = DS1305_WRITE | DS1305_CONTROL;
|
|
buf[1] = ds1305->ctrl[0];
|
|
buf[2] = ds1305->ctrl[1];
|
|
buf[3] = ds1305->ctrl[2];
|
|
status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
|
|
if (status < 0) {
|
|
dev_dbg(&spi->dev, "can't %s, %d\n",
|
|
"write", status);
|
|
goto fail0;
|
|
}
|
|
|
|
dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
|
|
"write", ds1305->ctrl[0],
|
|
ds1305->ctrl[1], ds1305->ctrl[2]);
|
|
}
|
|
|
|
/* see if non-Linux software set up AM/PM mode */
|
|
addr = DS1305_HOUR;
|
|
status = spi_write_then_read(spi, &addr, sizeof addr,
|
|
&value, sizeof value);
|
|
if (status < 0) {
|
|
dev_dbg(&spi->dev, "read HOUR --> %d\n", status);
|
|
goto fail0;
|
|
}
|
|
|
|
ds1305->hr12 = (DS1305_HR_12 & value) != 0;
|
|
if (ds1305->hr12)
|
|
dev_dbg(&spi->dev, "AM/PM\n");
|
|
|
|
/* register RTC ... from here on, ds1305->ctrl needs locking */
|
|
ds1305->rtc = rtc_device_register("ds1305", &spi->dev,
|
|
&ds1305_ops, THIS_MODULE);
|
|
if (IS_ERR(ds1305->rtc)) {
|
|
status = PTR_ERR(ds1305->rtc);
|
|
dev_dbg(&spi->dev, "register rtc --> %d\n", status);
|
|
goto fail0;
|
|
}
|
|
|
|
/* Maybe set up alarm IRQ; be ready to handle it triggering right
|
|
* away. NOTE that we don't share this. The signal is active low,
|
|
* and we can't ack it before a SPI message delay. We temporarily
|
|
* disable the IRQ until it's acked, which lets us work with more
|
|
* IRQ trigger modes (not all IRQ controllers can do falling edge).
|
|
*/
|
|
if (spi->irq) {
|
|
INIT_WORK(&ds1305->work, ds1305_work);
|
|
status = request_irq(spi->irq, ds1305_irq,
|
|
0, dev_name(&ds1305->rtc->dev), ds1305);
|
|
if (status < 0) {
|
|
dev_dbg(&spi->dev, "request_irq %d --> %d\n",
|
|
spi->irq, status);
|
|
goto fail1;
|
|
}
|
|
|
|
device_set_wakeup_capable(&spi->dev, 1);
|
|
}
|
|
|
|
/* export NVRAM */
|
|
status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
|
|
if (status < 0) {
|
|
dev_dbg(&spi->dev, "register nvram --> %d\n", status);
|
|
goto fail2;
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail2:
|
|
free_irq(spi->irq, ds1305);
|
|
fail1:
|
|
rtc_device_unregister(ds1305->rtc);
|
|
fail0:
|
|
kfree(ds1305);
|
|
return status;
|
|
}
|
|
|
|
static int __devexit ds1305_remove(struct spi_device *spi)
|
|
{
|
|
struct ds1305 *ds1305 = spi_get_drvdata(spi);
|
|
|
|
sysfs_remove_bin_file(&spi->dev.kobj, &nvram);
|
|
|
|
/* carefully shut down irq and workqueue, if present */
|
|
if (spi->irq) {
|
|
set_bit(FLAG_EXITING, &ds1305->flags);
|
|
free_irq(spi->irq, ds1305);
|
|
flush_scheduled_work();
|
|
}
|
|
|
|
rtc_device_unregister(ds1305->rtc);
|
|
spi_set_drvdata(spi, NULL);
|
|
kfree(ds1305);
|
|
return 0;
|
|
}
|
|
|
|
static struct spi_driver ds1305_driver = {
|
|
.driver.name = "rtc-ds1305",
|
|
.driver.owner = THIS_MODULE,
|
|
.probe = ds1305_probe,
|
|
.remove = __devexit_p(ds1305_remove),
|
|
/* REVISIT add suspend/resume */
|
|
};
|
|
|
|
static int __init ds1305_init(void)
|
|
{
|
|
return spi_register_driver(&ds1305_driver);
|
|
}
|
|
module_init(ds1305_init);
|
|
|
|
static void __exit ds1305_exit(void)
|
|
{
|
|
spi_unregister_driver(&ds1305_driver);
|
|
}
|
|
module_exit(ds1305_exit);
|
|
|
|
MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS("spi:rtc-ds1305");
|