Re: [PATCH] Platform real time clock driver for Dallas 1511 chip.

From: Andrew Morton
Date: Tue Dec 04 2007 - 16:05:53 EST


On Tue, 4 Dec 2007 12:00:05 -0800
Andrew Sharp <andy.sharp@xxxxxxxxxx> wrote:

>
> Add RTC support for DS1511 RTC/WDT chip.
>
> ...
>
> +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,
> + 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.

> + 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?


> +{
> + 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);
> +}
> +
> + 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.

> +#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)
> +{
> + /*
> + * 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?

> + int
> +ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + 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?

> + 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.
> + */
> + 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 ;)

> + 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);
> +}
> +

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/