Message ID | 20081121234953.GA28067@dodger.lab.datenfreihafen.org |
---|---|
State | Superseded, archived |
Headers | show |
On Sat, 22 Nov 2008 00:49:53 +0100 Stefan Schmidt <stefan@datenfreihafen.org> wrote: > > nack, please see below. > > you might want to check http://groups.google.com/group/rtc-linux/web/checklist > > for suggestions. > > Thanks for your fast review. Updated patch inline below. I hope we addressed all > your concerns let us know if there is more. Hi Stefan, it's almost ok. Still a few comments below. Do you want me to carry this via -mm or will be going in via arm? Anyway, we'll need your Signed-off-by > diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig > index 123092d..3fc15b5 100644 > --- a/drivers/rtc/Kconfig > +++ b/drivers/rtc/Kconfig > @@ -679,4 +679,11 @@ config RTC_DRV_STARFIRE > If you say Y here you will get support for the RTC found on > Starfire systems. > > +config RTC_DRV_PCAP > + tristate "PCAP RTC" > + depends on EZX_PCAP > + help > + If you say Y here you will get support for the RTC found on > + the PCAP2 ASIC used on some Motorola phones. > + > endif # RTC_CLASS > diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile > index 6e79c91..be2f294 100644 > --- a/drivers/rtc/Makefile > +++ b/drivers/rtc/Makefile > @@ -17,6 +17,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o > > # Keep the list ordered. > > + > obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o > obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o > obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o > @@ -48,6 +49,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o > obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o > obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o > obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o > +obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o > obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o > obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o > obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o > diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c > new file mode 100644 > index 0000000..1b02eae > --- /dev/null > +++ b/drivers/rtc/rtc-pcap.c > @@ -0,0 +1,212 @@ > +/* > + * pcap rtc code for Motorola EZX phones > + * > + * Copyright (c) 2008 guiming zhuo <gmzhuo@gmail.com> > + * > + * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola > + * > + * 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/module.h> > +#include <linux/init.h> > +#include <linux/string.h> > +#include <linux/sched.h> > +#include <linux/errno.h> > +#include <linux/version.h> > +#include <linux/mfd/ezx-pcap.h> > +#include <linux/rtc.h> > +#include <linux/platform_device.h> are you sure you need all of those (string sched version ? ) > +static void pcap_rtc_irq(u32 events, void *data) > +{ > + unsigned long rtc_events = 0; > + struct rtc_device *rtc = data; > + > + if (events & PCAP_IRQ_1HZ) > + rtc_events |= RTC_IRQF | RTC_UF; > + if (events & PCAP_IRQ_TODA) > + rtc_events |= RTC_IRQF | RTC_AF; > + > + rtc_update_irq(rtc, 1, rtc_events); > + return; > +} > + > +static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) > +{ > + struct rtc_time *tm = &alrm->time; > + struct timeval tmv; > + u32 value; > + > + ezx_pcap_read(PCAP_REG_RTC_TODA, &value); > + value &= PCAP_RTC_TOD_MASK; > + tmv.tv_sec = value; > + > + ezx_pcap_read(PCAP_REG_RTC_DAYA, &value); > + value &= PCAP_RTC_DAY_MASK; > + tmv.tv_sec += value * SEC_PER_DAY; > + > + rtc_time_to_tm(tmv.tv_sec, tm); > + > + return 0; > +} why a struct timeval? also in the following routines: > + > +static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) > +{ > + struct rtc_time *tm = &alrm->time; > + unsigned long secs; > + int err; > + struct timeval tmv; ?? > + u32 value; > + > + err = rtc_tm_to_time(tm, &secs); > + tmv.tv_sec = secs; > + tmv.tv_usec = 0; > + > + ezx_pcap_read(PCAP_REG_RTC_TODA, &value); > + value &= ~PCAP_RTC_TOD_MASK; > + value |= tmv.tv_sec % SEC_PER_DAY; > + ezx_pcap_write(PCAP_REG_RTC_TODA, value); > + > + ezx_pcap_read(PCAP_REG_RTC_DAYA, &value); > + value &= ~PCAP_RTC_DAY_MASK; > + value |= tmv.tv_sec / SEC_PER_DAY; > + ezx_pcap_write(PCAP_REG_RTC_DAYA, value); > + > + return 0; > +} > + > +static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm) > +{ > + struct timeval tmv; > + u32 value; > + ?? > + ezx_pcap_read(PCAP_REG_RTC_TOD, &value); > + value &= PCAP_RTC_TOD_MASK; > + tmv.tv_sec = value; > + > + ezx_pcap_read(PCAP_REG_RTC_DAY, &value); > + value &= PCAP_RTC_DAY_MASK; > + tmv.tv_sec += value * SEC_PER_DAY; > + > + rtc_time_to_tm(tmv.tv_sec, tm); > + > + return rtc_valid_tm(tm); > +} > + > +static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs) > +{ > + u32 value; > + > + ezx_pcap_read(PCAP_REG_RTC_TOD, &value); > + value &= ~PCAP_RTC_TOD_MASK; > + value |= secs % SEC_PER_DAY; > + ezx_pcap_write(PCAP_REG_RTC_TOD, value); > + > + ezx_pcap_read(PCAP_REG_RTC_DAY, &value); > + value &= ~PCAP_RTC_DAY_MASK; > + value |= secs / SEC_PER_DAY; > + ezx_pcap_write(PCAP_REG_RTC_DAY, value); > + > + return 0; > +} > + > +static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm) > +{ > + unsigned long secs; > + > + rtc_tm_to_time(tm, &secs); > + return pcap_rtc_set_mmss(dev, secs); > +} you can omit set_time if you implement set_mmss. the latest rtc subsystem will handle it. see http://patchwork.ozlabs.org/patch/9977/ > +static int pcap_rtc_ioctl(struct device *dev, unsigned int cmd, > + unsigned long arg) > +{ > + switch (cmd) { > + case RTC_UIE_ON: > + ezx_pcap_unmask_event(PCAP_IRQ_1HZ); > + break; > + case RTC_UIE_OFF: > + ezx_pcap_mask_event(PCAP_IRQ_1HZ); > + break; > + case RTC_AIE_ON: > + ezx_pcap_unmask_event(PCAP_IRQ_TODA); > + break; > + case RTC_AIE_OFF: > + ezx_pcap_mask_event(PCAP_IRQ_TODA); > + break; > + default: > + return -ENOIOCTLCMD; > + } > + return 0; > +} irq enabling should be implemented via alarm_irq_enable and update_irq_enable . you can then omit ioctl, the rtc subsystem will handle it. see http://patchwork.ozlabs.org/patch/10039/ for details > + > +static const struct rtc_class_ops pcap_rtc_ops = { > + .read_time = pcap_rtc_read_time, > + .set_time = pcap_rtc_set_time, > + .read_alarm = pcap_rtc_read_alarm, > + .set_alarm = pcap_rtc_set_alarm, > + .set_mmss = pcap_rtc_set_mmss, > + .ioctl = pcap_rtc_ioctl, > +}; > + > +static int __init pcap_rtc_probe(struct platform_device *plat_dev) > +{ > + struct rtc_device *rtc; > + int err; > + > + rtc = rtc_device_register("pcap", &plat_dev->dev, > + &pcap_rtc_ops, THIS_MODULE); > + if (IS_ERR(rtc)) { > + err = PTR_ERR(rtc); > + goto error; > + } just return PTR_ERR(rtc) here. > + > + platform_set_drvdata(plat_dev, rtc); > + > + ezx_pcap_register_event(PCAP_IRQ_1HZ, pcap_rtc_irq, rtc, "RTC Timer"); > + ezx_pcap_register_event(PCAP_IRQ_TODA, pcap_rtc_irq, rtc, "RTC Alarm"); > + > + return 0; > + > +error: > + return err; > +} > + > +static int __exit pcap_rtc_remove(struct platform_device *plat_dev) > +{ > + struct rtc_device *rtc = platform_get_drvdata(plat_dev); > + > + ezx_pcap_unregister_event(PCAP_IRQ_1HZ | PCAP_IRQ_TODA); > + rtc_device_unregister(rtc); > + return 0; > +} > + > +static struct platform_driver pcap_rtc_driver = { > + .remove = __exit_p(pcap_rtc_remove), > + .driver = { > + .name = "rtc-pcap", > + .owner = THIS_MODULE, > + }, > +}; > + > +static int __init rtc_pcap_init(void) > +{ > + return platform_driver_probe(&pcap_rtc_driver, pcap_rtc_probe); > +} > + > +static void __exit rtc_pcap_exit(void) > +{ > + platform_driver_unregister(&pcap_rtc_driver); > +} > + > +module_init(rtc_pcap_init); > +module_exit(rtc_pcap_exit); > + > +MODULE_DESCRIPTION("Motorola pcap rtc driver"); > +MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>"); > +MODULE_LICENSE("GPL"); > -- > tg: (851b4d2..) ezx/pcap_rtc (depends on: ezx/local/pcap) > > > >
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 123092d..3fc15b5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -679,4 +679,11 @@ config RTC_DRV_STARFIRE If you say Y here you will get support for the RTC found on Starfire systems. +config RTC_DRV_PCAP + tristate "PCAP RTC" + depends on EZX_PCAP + help + If you say Y here you will get support for the RTC found on + the PCAP2 ASIC used on some Motorola phones. + endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6e79c91..be2f294 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -17,6 +17,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o # Keep the list ordered. + obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o @@ -48,6 +49,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o +obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL030) += rtc-pl030.o diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c new file mode 100644 index 0000000..1b02eae --- /dev/null +++ b/drivers/rtc/rtc-pcap.c @@ -0,0 +1,212 @@ +/* + * pcap rtc code for Motorola EZX phones + * + * Copyright (c) 2008 guiming zhuo <gmzhuo@gmail.com> + * + * Based on Motorola's rtc.c Copyright (c) 2003-2005 Motorola + * + * 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/module.h> +#include <linux/init.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/version.h> +#include <linux/mfd/ezx-pcap.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +static void pcap_rtc_irq(u32 events, void *data) +{ + unsigned long rtc_events = 0; + struct rtc_device *rtc = data; + + if (events & PCAP_IRQ_1HZ) + rtc_events |= RTC_IRQF | RTC_UF; + if (events & PCAP_IRQ_TODA) + rtc_events |= RTC_IRQF | RTC_AF; + + rtc_update_irq(rtc, 1, rtc_events); + return; +} + +static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtc_time *tm = &alrm->time; + struct timeval tmv; + u32 value; + + ezx_pcap_read(PCAP_REG_RTC_TODA, &value); + value &= PCAP_RTC_TOD_MASK; + tmv.tv_sec = value; + + ezx_pcap_read(PCAP_REG_RTC_DAYA, &value); + value &= PCAP_RTC_DAY_MASK; + tmv.tv_sec += value * SEC_PER_DAY; + + rtc_time_to_tm(tmv.tv_sec, tm); + + return 0; +} + +static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rtc_time *tm = &alrm->time; + unsigned long secs; + int err; + struct timeval tmv; + u32 value; + + err = rtc_tm_to_time(tm, &secs); + tmv.tv_sec = secs; + tmv.tv_usec = 0; + + ezx_pcap_read(PCAP_REG_RTC_TODA, &value); + value &= ~PCAP_RTC_TOD_MASK; + value |= tmv.tv_sec % SEC_PER_DAY; + ezx_pcap_write(PCAP_REG_RTC_TODA, value); + + ezx_pcap_read(PCAP_REG_RTC_DAYA, &value); + value &= ~PCAP_RTC_DAY_MASK; + value |= tmv.tv_sec / SEC_PER_DAY; + ezx_pcap_write(PCAP_REG_RTC_DAYA, value); + + return 0; +} + +static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct timeval tmv; + u32 value; + + ezx_pcap_read(PCAP_REG_RTC_TOD, &value); + value &= PCAP_RTC_TOD_MASK; + tmv.tv_sec = value; + + ezx_pcap_read(PCAP_REG_RTC_DAY, &value); + value &= PCAP_RTC_DAY_MASK; + tmv.tv_sec += value * SEC_PER_DAY; + + rtc_time_to_tm(tmv.tv_sec, tm); + + return rtc_valid_tm(tm); +} + +static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs) +{ + u32 value; + + ezx_pcap_read(PCAP_REG_RTC_TOD, &value); + value &= ~PCAP_RTC_TOD_MASK; + value |= secs % SEC_PER_DAY; + ezx_pcap_write(PCAP_REG_RTC_TOD, value); + + ezx_pcap_read(PCAP_REG_RTC_DAY, &value); + value &= ~PCAP_RTC_DAY_MASK; + value |= secs / SEC_PER_DAY; + ezx_pcap_write(PCAP_REG_RTC_DAY, value); + + return 0; +} + +static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + unsigned long secs; + + rtc_tm_to_time(tm, &secs); + return pcap_rtc_set_mmss(dev, secs); +} + +static int pcap_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case RTC_UIE_ON: + ezx_pcap_unmask_event(PCAP_IRQ_1HZ); + break; + case RTC_UIE_OFF: + ezx_pcap_mask_event(PCAP_IRQ_1HZ); + break; + case RTC_AIE_ON: + ezx_pcap_unmask_event(PCAP_IRQ_TODA); + break; + case RTC_AIE_OFF: + ezx_pcap_mask_event(PCAP_IRQ_TODA); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static const struct rtc_class_ops pcap_rtc_ops = { + .read_time = pcap_rtc_read_time, + .set_time = pcap_rtc_set_time, + .read_alarm = pcap_rtc_read_alarm, + .set_alarm = pcap_rtc_set_alarm, + .set_mmss = pcap_rtc_set_mmss, + .ioctl = pcap_rtc_ioctl, +}; + +static int __init pcap_rtc_probe(struct platform_device *plat_dev) +{ + struct rtc_device *rtc; + int err; + + rtc = rtc_device_register("pcap", &plat_dev->dev, + &pcap_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + err = PTR_ERR(rtc); + goto error; + } + + platform_set_drvdata(plat_dev, rtc); + + ezx_pcap_register_event(PCAP_IRQ_1HZ, pcap_rtc_irq, rtc, "RTC Timer"); + ezx_pcap_register_event(PCAP_IRQ_TODA, pcap_rtc_irq, rtc, "RTC Alarm"); + + return 0; + +error: + return err; +} + +static int __exit pcap_rtc_remove(struct platform_device *plat_dev) +{ + struct rtc_device *rtc = platform_get_drvdata(plat_dev); + + ezx_pcap_unregister_event(PCAP_IRQ_1HZ | PCAP_IRQ_TODA); + rtc_device_unregister(rtc); + return 0; +} + +static struct platform_driver pcap_rtc_driver = { + .remove = __exit_p(pcap_rtc_remove), + .driver = { + .name = "rtc-pcap", + .owner = THIS_MODULE, + }, +}; + +static int __init rtc_pcap_init(void) +{ + return platform_driver_probe(&pcap_rtc_driver, pcap_rtc_probe); +} + +static void __exit rtc_pcap_exit(void) +{ + platform_driver_unregister(&pcap_rtc_driver); +} + +module_init(rtc_pcap_init); +module_exit(rtc_pcap_exit); + +MODULE_DESCRIPTION("Motorola pcap rtc driver"); +MODULE_AUTHOR("guiming zhuo <gmzhuo@gmail.com>"); +MODULE_LICENSE("GPL");