From: Grant Likely <grant.likely@secretlab.ca>
To: Wolfgang Denk <wd@denx.de>
Cc: rtc-linux@googlegroups.com, linuxppc-dev@ozlabs.org,
Piotr Ziecik <kosmo@semihalf.com>,
John Rigby <jrigby@freescale.com>
Subject: Re: [PATCH 10/12] mpc5121: Add MPC5121 Real time clock driver.
Date: Wed, 6 May 2009 15:03:56 -0600 [thread overview]
Message-ID: <fa686aa40905061403v12345cacsad61c7ea95726781@mail.gmail.com> (raw)
In-Reply-To: <1241640919-4650-11-git-send-email-wd@denx.de>
On Wed, May 6, 2009 at 2:15 PM, Wolfgang Denk <wd@denx.de> wrote:
> From: John Rigby <jrigby@freescale.com>
>
> Based on Domen Puncer's rtc driver for 5200 posted to
> the ppclinux mailing list:
> =A0 =A0 =A0 =A0http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=3D1=
1675
> but never commited anywhere.
>
> Changes to Domen's original:
>
> =A0 =A0Changed filenames/routine names from mpc5200* to mpc5121*
> =A0 =A0Changed match to only care about compatible and use "fsl,"
> =A0 =A0convention for compatible.
>
> =A0 =A0Make alarms more sane by dealing with lack of second alarm resolut=
ion.
>
> =A0 =A0Deal with the fact that most of the 5121 rtc registers are not per=
sistent
> =A0 =A0across a reset even with a battery attached:
>
> =A0 =A0 =A0 =A0Use actual_time register for time keeping
> =A0 =A0 =A0 =A0and target_time register as an offset to linux time
>
> =A0 =A0 =A0 =A0The target_time register would normally be used for hibern=
ation
> =A0 =A0 =A0 =A0but hibernation does not work on current silicon
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Cc: <rtc-linux@googlegroups.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
On a *very* cursory review, I don't see anything here I object to.
And it does not look dangerous.
Acked-by: Grant Likely <grant.likely@secretlab.ca>
> ---
> =A0drivers/rtc/Kconfig =A0 =A0 =A0 | =A0 10 +
> =A0drivers/rtc/Makefile =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/rtc/rtc-mpc5121.c | =A0408 +++++++++++++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 419 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/rtc/rtc-mpc5121.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 4e9851f..900d5b8 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -750,4 +750,14 @@ config RTC_DRV_PS3
> =A0 =A0 =A0 =A0 =A0This driver can also be built as a module. If so, the =
module
> =A0 =A0 =A0 =A0 =A0will be called rtc-ps3.
>
> +config RTC_DRV_MPC5121
> + =A0 =A0 =A0 tristate "Freescale MPC5121 built-in RTC"
> + =A0 =A0 =A0 depends on RTC_CLASS
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 If you say yes here you will get support for the
> + =A0 =A0 =A0 =A0 built-in RTC MPC5121.
> +
> + =A0 =A0 =A0 =A0 This driver can also be built as a module. If so, the m=
odule
> + =A0 =A0 =A0 =A0 will be called rtc-mpc5121.
> +
> =A0endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6c0639a..8c6d6a7 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -51,6 +51,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) =A0 =A0 =A0 =A0+=3D rtc-=
starfire.o
> =A0obj-$(CONFIG_RTC_DRV_MAX6900) =A0+=3D rtc-max6900.o
> =A0obj-$(CONFIG_RTC_DRV_MAX6902) =A0+=3D rtc-max6902.o
> =A0obj-$(CONFIG_RTC_DRV_MV) =A0 =A0 =A0 +=3D rtc-mv.o
> +obj-$(CONFIG_RTC_DRV_MPC5121) =A0+=3D rtc-mpc5121.o
> =A0obj-$(CONFIG_RTC_DRV_OMAP) =A0 =A0 +=3D rtc-omap.o
> =A0obj-$(CONFIG_RTC_DRV_PCF8563) =A0+=3D rtc-pcf8563.o
> =A0obj-$(CONFIG_RTC_DRV_PCF8583) =A0+=3D rtc-pcf8583.o
> diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
> new file mode 100644
> index 0000000..63460cb
> --- /dev/null
> +++ b/drivers/rtc/rtc-mpc5121.c
> @@ -0,0 +1,408 @@
> +/*
> + * Real-time clock driver for MPC5121
> + *
> + * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
> + * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * 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.
> + */
> +
> +/*
> + * History:
> + *
> + * Based on mpc5200_rtc.c written by Domen Puncer <domen.puncer@telargo.=
com>
> + * =A0 posted to linuxppc-embedded mailing list:
> + * =A0 =A0 http://patchwork.ozlabs.org/linuxppc-embedded/patch?id=3D1167=
5
> + * =A0 but never committed to any public tree.
> + *
> + * Author: John Rigby <jrigby@freescale.com>
> + * =A0 Converted to 5121 rtc driver.
> + *
> + * =A0 Make alarms more sane by dealing with lack of second alarm resolu=
tion.
> + *
> + * =A0 Use actual_time time register for time keeping since it is persis=
tent
> + * =A0 and the normal rtc registers are not. =A0Use target_time register=
as an
> + * =A0 offset to linux time.
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/io.h>
> +
> +struct mpc5121_rtc_regs {
> + =A0 =A0 =A0 u8 set_time; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x00 */
> + =A0 =A0 =A0 u8 hour_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x01 */
> + =A0 =A0 =A0 u8 minute_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x02 */
> + =A0 =A0 =A0 u8 second_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x03 */
> +
> + =A0 =A0 =A0 u8 set_date; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x04 */
> + =A0 =A0 =A0 u8 month_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x05 */
> + =A0 =A0 =A0 u8 weekday_set; =A0 =A0 =A0 =A0 /* RTC + 0x06 */
> + =A0 =A0 =A0 u8 date_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x07 */
> +
> + =A0 =A0 =A0 u8 write_sw; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x08 */
> + =A0 =A0 =A0 u8 sw_set; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x09 */
> + =A0 =A0 =A0 u16 year_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x0a */
> +
> + =A0 =A0 =A0 u8 alm_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0c */
> + =A0 =A0 =A0 u8 alm_hour_set; =A0 =A0 =A0 =A0/* RTC + 0x0d */
> + =A0 =A0 =A0 u8 alm_min_set; =A0 =A0 =A0 =A0 /* RTC + 0x0e */
> + =A0 =A0 =A0 u8 int_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0f */
> +
> + =A0 =A0 =A0 u8 reserved1;
> + =A0 =A0 =A0 u8 hour; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x11 */
> + =A0 =A0 =A0 u8 minute; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x12 */
> + =A0 =A0 =A0 u8 second; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x13 */
> +
> + =A0 =A0 =A0 u8 month; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x14 */
> + =A0 =A0 =A0 u8 wday_mday; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x15 */
> + =A0 =A0 =A0 u16 year; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x16 */
> +
> + =A0 =A0 =A0 u8 int_alm; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x18 */
> + =A0 =A0 =A0 u8 int_sw; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x19 */
> + =A0 =A0 =A0 u8 alm_status; =A0 =A0 =A0 =A0 =A0/* RTC + 0x1a */
> + =A0 =A0 =A0 u8 sw_minute; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1b */
> +
> + =A0 =A0 =A0 u8 bus_error_1; =A0 =A0 =A0 =A0 /* RTC + 0x1c */
> + =A0 =A0 =A0 u8 int_day; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1d */
> + =A0 =A0 =A0 u8 int_min; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1e */
> + =A0 =A0 =A0 u8 int_sec; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1f */
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* target_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0intended to be used for hibernation but hib=
ernation
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0does not work on silicon rev 1.5 so use it =
for non-volatile
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0storage of offset between the actual_time r=
egister and linux
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 target_time; =A0 =A0 =A0 =A0/* RTC + 0x20 */
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* actual_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0readonly time since VBAT_RTC was last conne=
cted
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 actual_time; =A0 =A0 =A0 =A0/* RTC + 0x24 */
> + =A0 =A0 =A0 u32 keep_alive; =A0 =A0 =A0 =A0 /* RTC + 0x28 */
> +};
> +
> +struct mpc5121_rtc_data {
> + =A0 =A0 =A0 unsigned irq;
> + =A0 =A0 =A0 unsigned irq_periodic;
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs;
> + =A0 =A0 =A0 struct rtc_device *rtc;
> + =A0 =A0 =A0 struct rtc_wkalrm wkalarm;
> +};
> +
> +/*
> + * Update second/minute/hour registers.
> + *
> + * This is just so alarm will work.
> + */
> +static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs=
,
> + =A0 =A0 =A0 struct rtc_time *tm)
> +{
> + =A0 =A0 =A0 out_8(®s->second_set, tm->tm_sec);
> + =A0 =A0 =A0 out_8(®s->minute_set, tm->tm_min);
> + =A0 =A0 =A0 out_8(®s->hour_set, tm->tm_hour);
> +
> + =A0 =A0 =A0 /* set time sequence */
> + =A0 =A0 =A0 out_8(®s->set_time, 0x1);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x3);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x1);
> + =A0 =A0 =A0 out_8(®s->set_time, 0x0);
> +}
> +
> +static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm=
)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 unsigned long now;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* linux time is actual_time plus the offset saved in tar=
get_time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 now =3D in_be32(®s->actual_time) + in_be32(®s->target=
_time);
> +
> + =A0 =A0 =A0 rtc_time_to_tm(now, tm);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int ret;
> + =A0 =A0 =A0 unsigned long now;
> +
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* The actual_time register is read only so we write the =
offset
> + =A0 =A0 =A0 =A0* between it and linux time to the target_time register.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 ret =3D rtc_tm_to_time(tm, &now);
> + =A0 =A0 =A0 if (ret =3D=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(®s->target_time, now - in_be32(=
®s->actual_time));
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm =
*alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 *alarm =3D rtc->wkalarm;
> +
> + =A0 =A0 =A0 alarm->pending =3D in_8(®s->alm_status);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *=
alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* the alarm has no seconds so deal with it
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (alarm->time.tm_sec) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_sec =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_min >=3D 60) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_hour++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_hour >=
=3D 24)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time=
.tm_hour =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 alarm->time.tm_mday =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_mon =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_year =3D -1;
> +
> + =A0 =A0 =A0 out_8(®s->alm_min_set, alarm->time.tm_min);
> + =A0 =A0 =A0 out_8(®s->alm_hour_set, alarm->time.tm_hour);
> +
> + =A0 =A0 =A0 out_8(®s->alm_enable, alarm->enabled);
> +
> + =A0 =A0 =A0 rtc->wkalarm =3D *alarm;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(®s->int_alm)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge and clear status */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_alm, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->alm_status, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
AF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(®s->int_sec) && (in_8(®s->int_enable) & 0x1)=
) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_sec, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
UF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static int mpc5121_rtc_ioctl(struct device *dev, unsigned int cmd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned long arg)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 switch (cmd) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* alarm interrupt */
> + =A0 =A0 =A0 case RTC_AIE_ON:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->alm_enable, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc->wkalarm.enabled =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case RTC_AIE_OFF:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->alm_enable, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc->wkalarm.enabled =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* update interrupt */
> + =A0 =A0 =A0 case RTC_UIE_ON:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_enable,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (in_8(®s=
->int_enable) & ~0x8) | 0x1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case RTC_UIE_OFF:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(®s->int_enable, in_8(®s->int_en=
able) & ~0x1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* no periodic interrupts */
> + =A0 =A0 =A0 case RTC_IRQP_READ:
> + =A0 =A0 =A0 case RTC_IRQP_SET:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOTTY;
> +
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOIOCTLCMD;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static const struct rtc_class_ops mpc5121_rtc_ops =3D {
> + =A0 =A0 =A0 .read_time =3D mpc5121_rtc_read_time,
> + =A0 =A0 =A0 .set_time =3D mpc5121_rtc_set_time,
> + =A0 =A0 =A0 .read_alarm =3D mpc5121_rtc_read_alarm,
> + =A0 =A0 =A0 .set_alarm =3D mpc5121_rtc_set_alarm,
> + =A0 =A0 =A0 .ioctl =3D mpc5121_rtc_ioctl,
> +};
> +
> +static int __devinit mpc5121_rtc_probe(struct of_device *op,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc;
> + =A0 =A0 =A0 int err =3D 0;
> + =A0 =A0 =A0 u32 ka;
> +
> + =A0 =A0 =A0 rtc =3D kzalloc(sizeof(*rtc), GFP_KERNEL);
> + =A0 =A0 =A0 if (!rtc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -ENOMEM;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->regs =3D of_iomap(op->node, 0);
> +
> + =A0 =A0 =A0 if (!rtc->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "%s: couldn't map io space\=
n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -ENOSYS;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_free;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 device_init_wakeup(&op->dev, 1);
> +
> + =A0 =A0 =A0 rtc->rtc =3D rtc_device_register("mpc5121-rtc", &op->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 &mpc5121_rtc_ops, THIS_MODULE);
> + =A0 =A0 =A0 if (IS_ERR(rtc->rtc)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D PTR_ERR(rtc->rtc);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_unmap;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, rtc);
> +
> + =A0 =A0 =A0 rtc->irq =3D irq_of_parse_and_map(op->node, 1);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DIS=
ABLED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 "mpc5121-rtc", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "%s: could not request irq:=
%i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, rtc->irq);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->irq_periodic =3D irq_of_parse_and_map(op->node, 0);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq_periodic, mpc5121_rtc_handler_=
upd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0IRQF_DIS=
ABLED, "mpc5121-rtc_upd", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "%s: could not request irq:=
%i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 __func__, rtc->irq_periodic);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose2;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 ka =3D in_be32(&rtc->regs->keep_alive);
> + =A0 =A0 =A0 if (ka & 0x02) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_WARNING
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "mpc5121-rtc: Battery or os=
cillator failure!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&rtc->regs->keep_alive, ka);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 goto out;
> +
> +out_dispose2:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> +out_dispose:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> +out_unmap:
> + =A0 =A0 =A0 iounmap(rtc->regs);
> +out_free:
> + =A0 =A0 =A0 kfree(rtc);
> +out:
> + =A0 =A0 =A0 return err;
> +}
> +
> +static int __devexit mpc5121_rtc_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(&op->dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /* disable interrupt, so there are no nasty surprises */
> + =A0 =A0 =A0 out_8(®s->alm_enable, 0);
> + =A0 =A0 =A0 out_8(®s->int_enable, in_8(®s->int_enable) & ~0x1);
> +
> + =A0 =A0 =A0 rtc_device_unregister(rtc->rtc);
> + =A0 =A0 =A0 iounmap(rtc->regs);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> + =A0 =A0 =A0 free_irq(rtc->irq_periodic, &op->dev);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, NULL);
> + =A0 =A0 =A0 kfree(rtc);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static struct of_device_id mpc5121_rtc_match[] =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc5121-rtc", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver mpc5121_rtc_driver =3D {
> + =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 .name =3D "mpc5121-rtc",
> + =A0 =A0 =A0 .match_table =3D mpc5121_rtc_match,
> + =A0 =A0 =A0 .probe =3D mpc5121_rtc_probe,
> + =A0 =A0 =A0 .remove =3D mpc5121_rtc_remove,
> +};
> +
> +static int __init mpc5121_rtc_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&mpc5121_rtc_driver);
> +}
> +
> +static void __exit mpc5121_rtc_exit(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&mpc5121_rtc_driver);
> +}
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
> +
> +module_init(mpc5121_rtc_init);
> +module_exit(mpc5121_rtc_exit);
> --
> 1.6.0.6
>
>
--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
next prev parent reply other threads:[~2009-05-06 21:04 UTC|newest]
Thread overview: 87+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-06 20:15 [PATCH 00/16] Add support for MPC512x Wolfgang Denk
2009-05-06 20:15 ` [PATCH 01/12] fs_enet: Use defines to set driver tunables Wolfgang Denk
2009-05-06 20:35 ` Grant Likely
2009-05-06 22:02 ` Wolfgang Denk
2009-05-06 22:41 ` Grant Likely
2009-05-06 20:15 ` [PATCH 02/12] fs_enet: Add MPC5121 FEC support Wolfgang Denk
2009-05-06 20:33 ` Grant Likely
2009-05-06 21:08 ` Scott Wood
2009-05-06 22:01 ` Wolfgang Denk
2009-05-06 22:29 ` Grant Likely
2009-05-06 22:41 ` Wolfgang Denk
2009-05-07 14:09 ` Grant Likely
2009-05-08 2:02 ` John Rigby
2009-05-08 7:52 ` David Miller
2009-05-11 6:56 ` David Jander
2009-05-07 8:14 ` David Jander
2009-05-07 13:05 ` Kumar Gala
2009-05-06 20:40 ` David Miller
2009-05-06 22:06 ` Wolfgang Denk
2009-05-06 20:41 ` Scott Wood
2009-05-06 22:09 ` Wolfgang Denk
2009-05-06 22:39 ` Grant Likely
2009-05-14 12:38 ` Piotr Zięcik
2009-05-14 14:00 ` Grant Likely
2009-05-18 22:17 ` Benjamin Herrenschmidt
2009-05-19 11:26 ` Piotr Zięcik
2009-05-19 21:56 ` Benjamin Herrenschmidt
2009-05-21 8:34 ` Piotr Zięcik
2009-05-21 15:36 ` Grant Likely
2009-05-06 20:15 ` [PATCH 03/12] fs_enet: Add FEC TX Alignment workaround for MPC5121 Wolfgang Denk
2009-05-06 20:37 ` Grant Likely
2009-05-06 22:12 ` Wolfgang Denk
2009-05-06 22:42 ` Grant Likely
2009-05-08 2:36 ` John Rigby
2009-05-06 20:15 ` [PATCH 04/12] mpc5121: Added reset module registers representation Wolfgang Denk
2009-05-06 20:29 ` Scott Wood
2009-05-06 21:57 ` Wolfgang Denk
2009-05-06 20:39 ` Grant Likely
2009-05-06 22:14 ` Wolfgang Denk
2009-05-06 20:15 ` [PATCH 05/12] mpc5121ads: Added Reset Module node to DTS Wolfgang Denk
2009-05-06 20:40 ` Grant Likely
2009-05-06 22:16 ` Wolfgang Denk
2009-05-06 22:46 ` Grant Likely
2009-05-06 20:15 ` [PATCH 06/12] mpc5121: Added NAND Flash Controller driver Wolfgang Denk
2009-05-06 20:59 ` Grant Likely
2009-05-08 2:22 ` John Rigby
2009-05-08 3:07 ` Grant Likely
2009-05-07 8:08 ` David Jander
2009-05-08 3:30 ` John Rigby
2009-05-13 8:41 ` Piotr Zięcik
2009-05-06 20:15 ` [PATCH 07/12] mpc5121ads: Clean up and fix NAND description in mpc5121ads DTS Wolfgang Denk
2009-05-06 21:00 ` Grant Likely
2009-05-06 20:15 ` [PATCH 08/12] mpc5121: Added I2C support Wolfgang Denk
2009-05-06 21:01 ` Grant Likely
2009-05-06 22:19 ` Wolfgang Denk
2009-05-06 22:51 ` Grant Likely
2009-05-07 2:41 ` Grant Likely
2009-05-07 6:36 ` Wolfgang Grandegger
2009-05-18 13:57 ` Piotr Zięcik
2009-05-18 14:11 ` Grant Likely
2009-05-18 14:29 ` Wolfgang Grandegger
2009-05-19 7:47 ` Piotr Zięcik
2009-05-19 8:10 ` Wolfgang Grandegger
2009-05-08 2:12 ` John Rigby
2009-05-08 3:01 ` Grant Likely
2009-05-06 20:15 ` [PATCH 09/12] mpc5121ads: Added I2C RTC node to mpc5121ads DTS Wolfgang Denk
2009-05-06 21:02 ` Grant Likely
2009-05-07 6:45 ` Wolfgang Grandegger
2009-05-06 20:15 ` [PATCH 10/12] mpc5121: Add MPC5121 Real time clock driver Wolfgang Denk
2009-05-06 21:03 ` Grant Likely [this message]
2009-05-06 21:06 ` Wolfram Sang
2009-05-06 22:40 ` Grant Likely
2009-05-08 2:41 ` [rtc-linux] " John Rigby
2009-05-08 15:53 ` Grant Likely
2009-05-08 16:09 ` Alessandro Zummo
2009-05-08 19:18 ` Wolfgang Denk
2009-05-08 16:10 ` Alessandro Zummo
2009-05-06 20:15 ` [PATCH 11/12] mpc5121: Added MPC512x DMA driver Wolfgang Denk
2009-05-06 21:07 ` Grant Likely
2009-05-08 2:49 ` John Rigby
2009-05-19 1:37 ` Hongjun Chen
2009-05-19 8:03 ` Piotr Zięcik
2009-05-20 0:39 ` Hongjun Chen
2009-05-06 20:15 ` [PATCH 12/12] mpc5121: Added default config for MPC5121 Wolfgang Denk
2009-05-06 21:08 ` Grant Likely
2009-05-06 22:23 ` Wolfgang Denk
2009-05-06 22:48 ` Grant Likely
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=fa686aa40905061403v12345cacsad61c7ea95726781@mail.gmail.com \
--to=grant.likely@secretlab.ca \
--cc=jrigby@freescale.com \
--cc=kosmo@semihalf.com \
--cc=linuxppc-dev@ozlabs.org \
--cc=rtc-linux@googlegroups.com \
--cc=wd@denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).