Skip to contentSkip to conversation

Platform real time clock driver for Dallas 1511 chip.

PATCH In review Andrew Sharp 2 participants 2 messages Dec 4, 2007 Real time clock (RTC)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Platform real time clock driver for Dallas 1511 chip.

Add RTC support for DS1511 RTC/WDT chip.

---
 drivers/rtc/Kconfig      |   10 +
 drivers/rtc/Makefile     |    1 +
 drivers/rtc/rtc-ds1511.c |  665 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 676 insertions(+), 0 deletions(-)
drivers/rtc/Kconfig +10 -0
index 1e6715e..0e59fcf 100644
@@ -302,6 +302,16 @@ config RTC_DRV_DS1216
 	help
 	  If you say yes here you get support for the Dallas DS1216 RTC chips.
 
+config RTC_DRV_DS1511
+	tristate "Dallas DS1511"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  Dallas DS1511 timekeeping/watchdog chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1511.
+
 config RTC_DRV_DS1553
 	tristate "Dallas DS1553"
 	help
drivers/rtc/Makefile +1 -0
index 465db4d..52239bf 100644
@@ -24,6 +24,7 @@ obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_DS1216)	+= rtc-ds1216.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1374)	+= rtc-ds1374.o
+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_DS1742)	+= rtc-ds1742.o
drivers/rtc/rtc-ds1511.c new file +665 -0

665 lines not on this page · raw message

Signature · 1 line
1.4.4.4
#1 lore raw
Quoted 15 lines · On Tue, 4 Dec 2007 12:00:05 -0800 Andrew Sharp <[email protected]> wrote:

Add RTC support for DS1511 RTC/WDT chip.

...

drivers/rtc/rtc-ds1511.c new file +10 -0
+typedef enum ds1511reg {
+	DS1511_SEC = 0x0,
+	DS1511_MIN = 0x1,
+	DS1511_HOUR = 0x2,
+	DS1511_DOW = 0x3,
+	DS1511_DOM = 0x4,
+	DS1511_MONTH = 0x5,
+	DS1511_YEAR = 0x6,
+	DS1511_CENTURY = 0x7,
+	DS1511_AM1_SEC = 0x8,

drivers/rtc/rtc-ds1511.c line 48

Quoted 10 lines
drivers/rtc/rtc-ds1511.c new file +10 -0
+	DS1511_AM2_MIN = 0x9,
+	DS1511_AM3_HOUR = 0xa,
+	DS1511_AM4_DATE = 0xb,
+	DS1511_WD_MSEC = 0xc,
+	DS1511_WD_SEC = 0xd,
+	DS1511_CONTROL_A = 0xe,
+	DS1511_CONTROL_B = 0xf,
+	DS1511_RAMADDR_LSB = 0x10,
+	DS1511_RAMDATA = 0x13
+} ds1511reg_t;

Please remove the typedef and just use `enum ds1511reg' everywhere.

Quoted 2 lines

+ static noinline void
+rtc_write(uint8_t val, uint32_t reg)

It's unusual (unique) to indent the function declaration by a single space in this way. Maybe an editor option which needs fixing?

Also, although there are good reasons to always put a newline after the declaration of the return type, kernel code generally doesn't do that except as a way of avoiding 80-col wraparound sometimes.

IOW, please use

static noinline void rtc_write(uint8_t val, uint32_t reg) {

Why was this function declared noinline?

Quoted 20 lines
drivers/rtc/rtc-ds1511.c new file +20 -0
+{
+	writeb(val, ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_write_alarm(uint8_t val, ds1511reg_t reg)
+{
+	rtc_write((val | 0x80), reg);
+}
+
+ static noinline uint8_t
+rtc_read(ds1511reg_t reg)
+{
+	return readb(ds1511_base + (reg * reg_spacing));
+}
+
+ static inline void
+rtc_disable_update(void)
+{
+	rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);

drivers/rtc/rtc-ds1511.c line 138

Quoted 10 lines
drivers/rtc/rtc-ds1511.c new file +10 -0
+}
+
+ static noinline void
+rtc_enable_update(void)
+{
+	rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
+}
+
+//#define DS1511_WDOG_RESET_SUPPORT
+//#undef DS1511_WDOG_RESET_SUPPORT

c99-style comments will generate checkpatch warnings.

Please run checkpatch. It detects a lot of coding-style breakage in this patch.

Quoted 27 lines
drivers/rtc/rtc-ds1511.c new file +27 -0
+#ifdef DS1511_WDOG_RESET_SUPPORT
+/*
+ * just enough code to set the watchdog timer so that it
+ * will reboot the system
+ */
+ void
+ds1511_wdog_set(unsigned long deciseconds)
+{
+	/*
+	 * the wdog timer can take 99.99 seconds
+	 */
+	deciseconds %= 10000;
+	/*
+	 * set the wdog values in the wdog registers
+	 */
+	rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC);
+	rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC);
+	/*
+	 * set wdog enable and wdog 'steering' bit to issue a reset
+	 */
+	rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
+}
+
+ void
+ds1511_wdog_disable(void)
+{
+	/*

drivers/rtc/rtc-ds1511.c line 175

Quoted 10 lines
drivers/rtc/rtc-ds1511.c new file +10 -0
+	 * clear wdog enable and wdog 'steering' bits
+	 */
+	rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
+	/*
+	 * clear the wdog counter
+	 */
+	rtc_write(0, DS1511_WD_MSEC);
+	rtc_write(0, DS1511_WD_SEC);
+}
+#endif

What's the story here? This code is permanently disabled?

Quoted 4 lines

+ int

drivers/rtc/rtc-ds1511.c new file +3 -0
+ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+	struct platform_device *pdev = to_platform_device(dev);

drivers/rtc/rtc-ds1511.c line 259

Quoted 10 lines
drivers/rtc/rtc-ds1511.c new file +10 -0
+	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
+	unsigned int century;
+	unsigned int flags;
+
+	/*
+	 * give enough time to update RTC in case of continuous read
+	 */
+	if (pdata->last_jiffies == jiffies) {
+		msleep(1);
+	}

hm, that could be pretty obnoxious for some applications, I expect. They'll run veeeery sloooowly, and inconsistently slowly across different values of CONFIG_HZ. And the uninterruptible sleep will contribute to system load average.

What's going on here?

Do other RTC drivers do things like this?

Quoted 49 lines
drivers/rtc/rtc-ds1511.c new file +49 -0
+	pdata->last_jiffies = jiffies;
+
+	spin_lock_irqsave(&ds1511_lock, flags);
+	rtc_disable_update();
+
+	rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
+	rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
+	rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
+	rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
+	rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
+	rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
+	rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
+	century = rtc_read(RTC_CENTURY);
+
+	rtc_enable_update();
+	spin_unlock_irqrestore(&ds1511_lock, flags);
+
+	rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec);
+	rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min);
+	rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour);
+	rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday);
+	rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday);
+	rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon);
+	rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year);
+	century = BCD2BIN(century) * 100;
+
+	/*
+	 * Account for differences between how the RTC uses the values
+	 * and how they are defined in a struct rtc_time;
+	 */
+	century += rtc_tm->tm_year;
+	rtc_tm->tm_year = century - 1900;
+
+	rtc_tm->tm_mon--;
+
+	if (rtc_valid_tm(rtc_tm) < 0) {
+		dev_err(dev, "retrieved date/time is not valid.\n");
+		rtc_time_to_tm(0, rtc_tm);
+	}
+	return 0;
+}
+
+/*
+ * write the alarm register settings
+ *
+ * we only have the use to interrupt every second, otherwise
+ * known as the update interrupt, or the interrupt if the whole
+ * date/hours/mins/secs matches.  the ds1511 has many more
+ * permutations, but the kernel doesn't.

drivers/rtc/rtc-ds1511.c line 318

Quoted 10 lines
drivers/rtc/rtc-ds1511.c new file +10 -0
+ */
+ static void
+ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&pdata->rtc->irq_lock, flags);
+	rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f,
+	       RTC_ALARM_DATE);

hm. You appear to be a C precedence whizz ;)

Quoted 14 lines
drivers/rtc/rtc-ds1511.c new file +14 -0
+	rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f,
+	       RTC_ALARM_HOUR);
+	rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_min) & 0x7f,
+	       RTC_ALARM_MIN);
+	rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
+	       0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f,
+	       RTC_ALARM_SEC);
+	rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
+	rtc_read(RTC_CMD1);	/* clear interrupts */
+	spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags);
+}
+