diff mbox

[12/14] PCAP2 RTC driver

Message ID 20081121160523.623809888@dodger.lab.datenfreihafen.org
State Superseded, archived
Headers show

Commit Message

Stefan Schmidt Nov. 21, 2008, 4:04 p.m. UTC
RTC driver based on the PCAP2 multi function device

Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
Signed-off-by: guiming zhuo <gmzhuo@gmail.com>

---
 drivers/rtc/Kconfig    |    7 ++
 drivers/rtc/Makefile   |    2 +
 drivers/rtc/rtc-pcap.c |  213 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 222 insertions(+), 0 deletions(-)

Comments

Alessandro Zummo Nov. 21, 2008, 4:14 p.m. UTC | #1
On Fri, 21 Nov 2008 17:04:15 +0100
stefan@datenfreihafen.org wrote:

> 
> RTC driver based on the PCAP2 multi function device
> 
> Signed-off-by: Daniel Ribeiro <drwyrm@gmail.com>
> Signed-off-by: guiming zhuo <gmzhuo@gmail.com>

 nack, please see below.
 you might want to check http://groups.google.com/group/rtc-linux/web/checklist
 for suggestions.

> ---
>  drivers/rtc/Kconfig    |    7 ++
>  drivers/rtc/Makefile   |    2 +
>  drivers/rtc/rtc-pcap.c |  213 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 222 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 123092d..0198321 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
> +	   pcap.

 Please be more descriptive.

>  endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 6e79c91..1e93d12 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -17,6 +17,8 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
>  
>  # Keep the list ordered.
>  
> +
> +obj-$(CONFIG_RTC_DRV_PCAP)	+= rtc-pcap.o
>  obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
>  obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
>  obj-$(CONFIG_RTC_DRV_AT91SAM9)	+= rtc-at91sam9.o
> diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
> new file mode 100644
> index 0000000..a7bd8e8
> --- /dev/null
> +++ b/drivers/rtc/rtc-pcap.c
> @@ -0,0 +1,213 @@
> +/*
> + *  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 struct rtc_device *rtc;

 please avoid globals



> +static void pcap_alarm_irq(struct work_struct *unused)
> +{
> +	rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
> +	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 0;
> +}

 return rtc_valid_tm(tm);


> +
> +static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct timeval tmv;
> +	u32 value;
> +	rtc_tm_to_time(tm, &tmv.tv_sec);
> +
> +	if (tmv.tv_usec > 500000)
> +		tmv.tv_sec++;
> +
> +	ezx_pcap_read(PCAP_REG_RTC_TOD, &value);
> +	value &= ~PCAP_RTC_TOD_MASK;
> +	value |= tmv.tv_sec % 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 |= tmv.tv_sec / SEC_PER_DAY;
> +	ezx_pcap_write(PCAP_REG_RTC_DAY, value);
> +
> +	return 0;
> +}
> +
> +static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs)
> +{
> +	return 0;
> +}

 you should be implementing only set_mmss, not set_time with
 this kind of rtc


> +
> +static int pcap_rtc_proc(struct device *dev, struct seq_file *seq)
> +{
> +	struct platform_device *plat_dev = to_platform_device(dev);
> +
> +	seq_printf(seq, "pcap\t\t: yes\n");
> +	seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
> +
> +	return 0;
> +}

 is this really necessary? /proc will go away sooner
 or later

> +
> +static int pcap_rtc_ioctl(struct device *dev, unsigned int cmd,
> +			  unsigned long arg)
> +{
> +	switch (cmd) {
> +	case RTC_PIE_ON:
> +	case RTC_PIE_OFF:
> +	case RTC_UIE_ON:
> +	case RTC_UIE_OFF:
> +	case RTC_AIE_ON:
> +	case RTC_AIE_OFF:
> +		return 0;
> +
> +	default:
> +		return -ENOIOCTLCMD;
> +	}
> +
> +}

 this function makes no sense the way it is. you shold 
 implement the proper irq hooks


> +static const struct rtc_class_ops pcap_rtc_ops = {
> +	.proc = pcap_rtc_proc,
> +	.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 pcap_rtc_probe(struct platform_device *plat_dev)
> +{
> +	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_TODA, pcap_alarm_irq, "PCAP alarm");
> +
> +	return 0;
> +
> +error:
> +	rtc_device_unregister(rtc);

 wrong! rtc won't be valid here


> +	return err;
> +}
> +
> +static int __devexit pcap_rtc_remove(struct platform_device *plat_dev)
> +{
> +	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
> +	ezx_pcap_unregister_event(PCAP_IRQ_TODA);
> +	rtc_device_unregister(rtc);
> +	return 0;
> +}
> +
> +static struct platform_driver pcap_rtc_driver = {
> +	.probe  = pcap_rtc_probe,
> +	.remove = __devexit_p(pcap_rtc_remove),
> +	.driver = {
> +		.name  = "rtc-pcap",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static int __init rtc_pcap_init(void)
> +{
> +	return platform_driver_register(&pcap_rtc_driver);
> +}

 you might want to use platform_driver_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: (f978d9c..) ezx/pcap_rtc (depends on: ezx/local/pcap)
>
diff mbox

Patch

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 123092d..0198321 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
+	   pcap.
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e79c91..1e93d12 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -17,6 +17,8 @@  rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
 
 # Keep the list ordered.
 
+
+obj-$(CONFIG_RTC_DRV_PCAP)	+= rtc-pcap.o
 obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_AT91SAM9)	+= rtc-at91sam9.o
diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c
new file mode 100644
index 0000000..a7bd8e8
--- /dev/null
+++ b/drivers/rtc/rtc-pcap.c
@@ -0,0 +1,213 @@ 
+/*
+ *  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 struct rtc_device *rtc;
+
+static void pcap_alarm_irq(struct work_struct *unused)
+{
+	rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+	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 0;
+}
+
+static int pcap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct timeval tmv;
+	u32 value;
+	rtc_tm_to_time(tm, &tmv.tv_sec);
+
+	if (tmv.tv_usec > 500000)
+		tmv.tv_sec++;
+
+	ezx_pcap_read(PCAP_REG_RTC_TOD, &value);
+	value &= ~PCAP_RTC_TOD_MASK;
+	value |= tmv.tv_sec % 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 |= tmv.tv_sec / SEC_PER_DAY;
+	ezx_pcap_write(PCAP_REG_RTC_DAY, value);
+
+	return 0;
+}
+
+static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	return 0;
+}
+
+static int pcap_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+
+	seq_printf(seq, "pcap\t\t: yes\n");
+	seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
+
+	return 0;
+}
+
+static int pcap_rtc_ioctl(struct device *dev, unsigned int cmd,
+			  unsigned long arg)
+{
+	switch (cmd) {
+	case RTC_PIE_ON:
+	case RTC_PIE_OFF:
+	case RTC_UIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_AIE_OFF:
+		return 0;
+
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+}
+
+static const struct rtc_class_ops pcap_rtc_ops = {
+	.proc = pcap_rtc_proc,
+	.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 pcap_rtc_probe(struct platform_device *plat_dev)
+{
+	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_TODA, pcap_alarm_irq, "PCAP alarm");
+
+	return 0;
+
+error:
+	rtc_device_unregister(rtc);
+	return err;
+}
+
+static int __devexit pcap_rtc_remove(struct platform_device *plat_dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
+	ezx_pcap_unregister_event(PCAP_IRQ_TODA);
+	rtc_device_unregister(rtc);
+	return 0;
+}
+
+static struct platform_driver pcap_rtc_driver = {
+	.probe  = pcap_rtc_probe,
+	.remove = __devexit_p(pcap_rtc_remove),
+	.driver = {
+		.name  = "rtc-pcap",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init rtc_pcap_init(void)
+{
+	return platform_driver_register(&pcap_rtc_driver);
+}
+
+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");