|
From: Giuseppe C. <pep...@gm...> - 2008-03-05 15:17:11
|
Angelo,
I'm using periodic without any problems.
Cheers,
Peppe
On 05/03/2008, Angelo CASTELLO <ang...@st...> wrote:
>
> Hi Paul,
> this patch adds missing features in rtc-sh driver (e.g Periodic IRQs).
> Code tested at user level using the classic example provided within
> Documentation/rtc.txt on sh4 core.
>
> Let me know.
> Regards.
> Angelo
>
> Giuseppe Cavallaro wrote:
>
>
> ---------- Forwarded message ----------
> From: Paul Mundt <pau...@re...>
> Date: 20 Feb 2008 03:20
> Subject: Re: SH4 RTC periodic mode
> To: Giuseppe Cavallaro <pep...@gm...>
> Cc: lin...@vg...
>
> On Mon, Feb 18, 2008 at 04:21:08PM +0100, Giuseppe Cavallaro wrote:
> > I wonder why the sh4 rtc driver (drivers/rtc/rtc-sh.c) doesn't implement
> the
> > periodic ioctls (RTC_IRQP_SET...) currently implemented in other
> drivers.
> > Is there a specific reason?
>
>
> These are trivially added. There is no particular reason why they are
> unimplemented in the current driver, I just havent gotten around to
> adding them. Feel free to submit a patch.
>
>
> Mainly its contains the Periodic IRQs support, both Alarm routine
> fixes and Kernel/User level interface updating.
>
> Signed-off-by: Angelo Castello <ang...@st...>
> Signed-off-by: Giuseppe Cavallaro <pep...@st...>
>
> diff -Naur linux-2.6.23.16/drivers/rtc/rtc-sh.c linux-2.6.23.16-rtc-sh
> /drivers/rtc/rtc-sh.c
> --- linux-2.6.23.16/drivers/rtc/rtc-sh.c 2008-03-05 15:10:
> 51.551251064 +0100
> +++ linux-2.6.23.16-rtc-sh/drivers/rtc/rtc-sh.c 2008-03-05 14:48:
> 06.727735776 +0100
> @@ -1,6 +1,14 @@
> /*
> * SuperH On-Chip RTC Support
> *
> + * Copyright (C) 2008 Angelo Castello <ang...@st...>
> + * Changes from 0.1.3 to 0.1.4 are:
> + * Added Periodic IRQs support emulating 8,32,128Hz yet.
> + * Fixed Alarm routine.
> + * Added Kernel/user level support.
> + *
> + * Updating from latest released by:
> + *
> * Copyright (C) 2006, 2007 Paul Mundt
> * Copyright (C) 2006 Jamie Lenehan
> *
> @@ -26,7 +34,7 @@
> #include <asm/rtc.h>
>
> #define DRV_NAME "sh-rtc"
> -#define DRV_VERSION "0.1.3"
> +#define DRV_VERSION "0.1.4"
>
> #ifdef CONFIG_CPU_SH3
> #define rtc_reg_size sizeof(u16)
> @@ -61,6 +69,13 @@
> /* ALARM Bits - or with BCD encoded value */
> #define AR_ENB 0x80 /* Enable for alarm cmp */
>
> +/* Period Bits */
> +#define PF_HP 0x100 /* Enable Half Period to support
> 8,32,128Hz */
> +#define PF_COUNT 0x200 /* Half periodic counter */
> +#define PF_OXS 0x400 /* Periodic One x Second */
> +#define PF_KOU 0x800 /* Kernel or User periodic request
> 1=kernel */
> +#define PF_MASK 0xf00
> +
> /* RCR1 Bits */
> #define RCR1_CF 0x80 /* Carry Flag */
> #define RCR1_CIE 0x10 /* Carry Interrupt Enable */
> @@ -82,33 +97,24 @@
> unsigned int alarm_irq, periodic_irq, carry_irq;
> struct rtc_device *rtc_dev;
> spinlock_t lock;
> - int rearm_aie;
> unsigned long capabilities; /* See asm-sh/rtc.h for cap bits */
> + unsigned short periodic_freq;
> };
>
> static irqreturn_t sh_rtc_interrupt(int irq, void *dev_id)
> {
> - struct platform_device *pdev = to_platform_device(dev_id);
> - struct sh_rtc *rtc = platform_get_drvdata(pdev);
> - unsigned int tmp, events = 0;
> + struct sh_rtc *rtc = (struct sh_rtc *)dev_id;
> + unsigned int tmp;
>
> spin_lock(&rtc->lock);
>
> tmp = readb(rtc->regbase + RCR1);
> tmp &= ~RCR1_CF;
> -
> - if (rtc->rearm_aie) {
> - if (tmp & RCR1_AF)
> - tmp &= ~RCR1_AF; /* try to clear AF again
> */
> - else {
> - tmp |= RCR1_AIE; /* AF has cleared, rearm
> IRQ */
> - rtc->rearm_aie = 0;
> - }
> - }
> -
> writeb(tmp, rtc->regbase + RCR1);
>
> - rtc_update_irq(rtc->rtc_dev, 1, events);
> + /* Users have requested One x Second IRQ */
> + if (rtc->periodic_freq & PF_OXS)
> + rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF);
>
> spin_unlock(&rtc->lock);
>
> @@ -117,47 +123,49 @@
>
> static irqreturn_t sh_rtc_alarm(int irq, void *dev_id)
> {
> - struct platform_device *pdev = to_platform_device(dev_id);
> - struct sh_rtc *rtc = platform_get_drvdata(pdev);
> - unsigned int tmp, events = 0;
> + struct sh_rtc *rtc = (struct sh_rtc *)dev_id;
> + unsigned int tmp;
>
> spin_lock(&rtc->lock);
>
> tmp = readb(rtc->regbase + RCR1);
> + tmp &= ~(RCR1_AF | RCR1_AIE);
> + writeb(tmp, rtc->regbase + RCR1);
>
> - /*
> - * If AF is set then the alarm has triggered. If we clear AF while
> - * the alarm time still matches the RTC time then AF will
> - * immediately be set again, and if AIE is enabled then the alarm
> - * interrupt will immediately be retrigger. So we clear AIE here
> - * and use rtc->rearm_aie so that the carry interrupt will keep
> - * trying to clear AF and once it stays cleared it'll re-enable
> - * AIE.
> - */
> - if (tmp & RCR1_AF) {
> - events |= RTC_AF | RTC_IRQF;
> -
> - tmp &= ~(RCR1_AF|RCR1_AIE);
> -
> - writeb(tmp, rtc->regbase + RCR1);
> -
> - rtc->rearm_aie = 1;
> -
> - rtc_update_irq(rtc->rtc_dev, 1, events);
> - }
> + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
>
> spin_unlock(&rtc->lock);
> +
> return IRQ_HANDLED;
> }
>
> static irqreturn_t sh_rtc_periodic(int irq, void *dev_id)
> {
> - struct platform_device *pdev = to_platform_device(dev_id);
> - struct sh_rtc *rtc = platform_get_drvdata(pdev);
> + struct sh_rtc *rtc = (struct sh_rtc *)dev_id;
> + struct rtc_device *rtc_dev = rtc->rtc_dev;
> + unsigned int tmp;
>
> spin_lock(&rtc->lock);
>
> - rtc_update_irq(rtc->rtc_dev, 1, RTC_PF | RTC_IRQF);
> + tmp = readb(rtc->regbase + RCR2);
> + tmp &= ~RCR2_PEF;
> + writeb(tmp, rtc->regbase + RCR2);
> +
> + /* Half period enabled than one skipped and the next notified */
> + if ((rtc->periodic_freq & PF_HP) && (rtc->periodic_freq &
> PF_COUNT))
> + rtc->periodic_freq &= ~PF_COUNT;
> + else {
> + if (rtc->periodic_freq & PF_HP)
> + rtc->periodic_freq |= PF_COUNT;
> + if (rtc->periodic_freq & PF_KOU) {
> + spin_lock(&rtc_dev->irq_task_lock);
> + if (rtc_dev->irq_task)
> +
> rtc_dev->irq_task->func(rtc_dev->irq_task->
> + private_data);
> + spin_unlock(&rtc_dev->irq_task_lock);
> + } else
> + rtc_update_irq(rtc->rtc_dev, 1, RTC_PF |
> RTC_IRQF);
> + }
>
> spin_unlock(&rtc->lock);
>
> @@ -174,8 +182,8 @@
> tmp = readb(rtc->regbase + RCR2);
>
> if (enable) {
> - tmp &= ~RCR2_PESMASK;
> - tmp |= RCR2_PEF | (2 << 4);
> + tmp &= ~RCR2_PEF; /* Clear PES bit */
> + tmp |= (rtc->periodic_freq & ~PF_HP); /* Set PES2-0 */
> } else
> tmp &= ~(RCR2_PESMASK | RCR2_PEF);
>
> @@ -184,82 +192,90 @@
> spin_unlock_irq(&rtc->lock);
> }
>
> -static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
> +static inline int sh_rtc_setfreq(struct device *dev, unsigned int freq)
> {
> struct sh_rtc *rtc = dev_get_drvdata(dev);
> - unsigned int tmp;
> + int tmp, ret = 0;
>
> spin_lock_irq(&rtc->lock);
> + tmp = rtc->periodic_freq & PF_MASK;
>
> - tmp = readb(rtc->regbase + RCR1);
> -
> - if (!enable) {
> - tmp &= ~RCR1_AIE;
> - rtc->rearm_aie = 0;
> - } else if (rtc->rearm_aie == 0)
> - tmp |= RCR1_AIE;
> + switch (freq) {
> + case 0:
> + rtc->periodic_freq = 0x00;
> + break;
> + case 1:
> + rtc->periodic_freq = 0x60;
> + break;
> + case 2:
> + rtc->periodic_freq = 0x50;
> + break;
> + case 4:
> + rtc->periodic_freq = 0x40;
> + break;
> + case 8:
> + rtc->periodic_freq = 0x30 | PF_HP;
> + break;
> + case 16:
> + rtc->periodic_freq = 0x30;
> + break;
> + case 32:
> + rtc->periodic_freq = 0x20 | PF_HP;
> + break;
> + case 64:
> + rtc->periodic_freq = 0x20;
> + break;
> + case 128:
> + rtc->periodic_freq = 0x10 | PF_HP;
> + break;
> + case 256:
> + rtc->periodic_freq = 0x10;
> + break;
> + default:
> + ret = -ENOTSUPP;
> + }
>
> - writeb(tmp, rtc->regbase + RCR1);
> + if (ret == 0) {
> + rtc->periodic_freq |= tmp;
> + rtc->rtc_dev->irq_freq = freq;
> + }
>
> spin_unlock_irq(&rtc->lock);
> + return ret;
> }
>
> -static int sh_rtc_open(struct device *dev)
> +static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
> {
> struct sh_rtc *rtc = dev_get_drvdata(dev);
> unsigned int tmp;
> - int ret;
> +
> + spin_lock_irq(&rtc->lock);
>
> tmp = readb(rtc->regbase + RCR1);
> - tmp &= ~RCR1_CF;
> - tmp |= RCR1_CIE;
> - writeb(tmp, rtc->regbase + RCR1);
>
> - ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
> IRQF_DISABLED,
> - "sh-rtc period", dev);
> - if (unlikely(ret)) {
> - dev_err(dev, "request period IRQ failed with %d, IRQ
> %d\n",
> - ret, rtc->periodic_irq);
> - return ret;
> - }
> + if (!enable)
> + tmp &= ~RCR1_AIE;
> + else
> + tmp |= RCR1_AIE;
>
> - ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
> - "sh-rtc carry", dev);
> - if (unlikely(ret)) {
> - dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n",
> - ret, rtc->carry_irq);
> - free_irq(rtc->periodic_irq, dev);
> - goto err_bad_carry;
> - }
> + writeb(tmp, rtc->regbase + RCR1);
>
> - ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
> - "sh-rtc alarm", dev);
> - if (unlikely(ret)) {
> - dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
> - ret, rtc->alarm_irq);
> - goto err_bad_alarm;
> - }
> + spin_unlock_irq(&rtc->lock);
> +}
>
> +static int sh_rtc_open(struct device *dev)
> +{
> + /* the rtc-dev interface keeps the lock as long as the device
> + * is in use and return immediately if busy. That means only one
> + * RTC instance can be avilable.
> + */
> return 0;
> -
> -err_bad_alarm:
> - free_irq(rtc->carry_irq, dev);
> -err_bad_carry:
> - free_irq(rtc->periodic_irq, dev);
> -
> - return ret;
> }
>
> static void sh_rtc_release(struct device *dev)
> {
> - struct sh_rtc *rtc = dev_get_drvdata(dev);
> -
> sh_rtc_setpie(dev, 0);
> sh_rtc_setaie(dev, 0);
> -
> - free_irq(rtc->periodic_irq, dev);
> - free_irq(rtc->carry_irq, dev);
> - free_irq(rtc->alarm_irq, dev);
> }
>
> static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
> @@ -268,31 +284,44 @@
> unsigned int tmp;
>
> tmp = readb(rtc->regbase + RCR1);
> - seq_printf(seq, "carry_IRQ\t: %s\n",
> - (tmp & RCR1_CIE) ? "yes" : "no");
> + seq_printf(seq, "carry_IRQ\t: %s\n", (tmp & RCR1_CIE) ? "yes" :
> "no");
>
> tmp = readb(rtc->regbase + RCR2);
> seq_printf(seq, "periodic_IRQ\t: %s\n",
> - (tmp & RCR2_PEF) ? "yes" : "no");
> + (tmp & RCR2_PESMASK) ? "yes" : "no");
>
> return 0;
> }
>
> static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned
> long arg)
> {
> - unsigned int ret = -ENOIOCTLCMD;
> + struct sh_rtc *rtc = dev_get_drvdata(dev);
> + unsigned int ret = 0;
>
> switch (cmd) {
> case RTC_PIE_OFF:
> case RTC_PIE_ON:
> sh_rtc_setpie(dev, cmd == RTC_PIE_ON);
> - ret = 0;
> break;
> case RTC_AIE_OFF:
> case RTC_AIE_ON:
> sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
> - ret = 0;
> break;
> + case RTC_UIE_OFF:
> + rtc->periodic_freq &= ~PF_OXS;
> + break;
> + case RTC_UIE_ON:
> + rtc->periodic_freq |= PF_OXS;
> + break;
> + case RTC_IRQP_READ:
> + ret = put_user(rtc->rtc_dev->irq_freq,
> + (unsigned long __user *)arg);
> + break;
> + case RTC_IRQP_SET:
> + ret = sh_rtc_setfreq(dev, arg);
> + break;
> + default:
> + ret = -ENOIOCTLCMD;
> }
>
> return ret;
> @@ -310,25 +339,25 @@
> spin_lock_irq(&rtc->lock);
>
> tmp = readb(rtc->regbase + RCR1);
> - tmp &= ~RCR1_CF; /* Clear CF-bit */
> + tmp &= ~RCR1_CF; /* Clear CF-bit */
> tmp |= RCR1_CIE;
> writeb(tmp, rtc->regbase + RCR1);
>
> sec128 = readb(rtc->regbase + R64CNT);
>
> - tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
> - tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
> - tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
> - tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
> - tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
> - tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) -
> 1;
> + tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
> + tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
> + tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
> + tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
> + tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
> + tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT)) - 1;
>
> if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
> - yr = readw(rtc->regbase + RYRCNT);
> + yr = readw(rtc->regbase + RYRCNT);
> yr100 = BCD2BIN(yr >> 8);
> yr &= 0xff;
> } else {
> - yr = readb(rtc->regbase + RYRCNT);
> + yr = readb(rtc->regbase + RYRCNT);
> yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
> }
>
> @@ -372,8 +401,8 @@
> tmp &= ~RCR2_START;
> writeb(tmp, rtc->regbase + RCR2);
>
> - writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
> - writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
> + writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
> + writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
> writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
> writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
> writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
> @@ -381,7 +410,7 @@
>
> if (rtc->capabilities & RTC_CAP_4_DIGIT_YEAR) {
> year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
> - BIN2BCD(tm->tm_year % 100);
> + BIN2BCD(tm->tm_year % 100);
> writew(year, rtc->regbase + RYRCNT);
> } else {
> year = tm->tm_year % 100;
> @@ -417,19 +446,19 @@
> {
> struct platform_device *pdev = to_platform_device(dev);
> struct sh_rtc *rtc = platform_get_drvdata(pdev);
> - struct rtc_time* tm = &wkalrm->time;
> + struct rtc_time *tm = &wkalrm->time;
>
> spin_lock_irq(&rtc->lock);
>
> - tm->tm_sec = sh_rtc_read_alarm_value(rtc, RSECAR);
> - tm->tm_min = sh_rtc_read_alarm_value(rtc, RMINAR);
> - tm->tm_hour = sh_rtc_read_alarm_value(rtc, RHRAR);
> - tm->tm_wday = sh_rtc_read_alarm_value(rtc, RWKAR);
> - tm->tm_mday = sh_rtc_read_alarm_value(rtc, RDAYAR);
> - tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR);
> + tm->tm_sec = sh_rtc_read_alarm_value(rtc, RSECAR);
> + tm->tm_min = sh_rtc_read_alarm_value(rtc, RMINAR);
> + tm->tm_hour = sh_rtc_read_alarm_value(rtc, RHRAR);
> + tm->tm_wday = sh_rtc_read_alarm_value(rtc, RWKAR);
> + tm->tm_mday = sh_rtc_read_alarm_value(rtc, RDAYAR);
> + tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR);
> if (tm->tm_mon > 0)
> - tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
> - tm->tm_year = 0xffff;
> + tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
> + tm->tm_year = 0xffff;
>
> wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;
>
> @@ -445,10 +474,10 @@
> if (value < 0)
> writeb(0, rtc->regbase + reg_off);
> else
> - writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off);
> + writeb(BIN2BCD(value) | AR_ENB, rtc->regbase + reg_off);
> }
>
> -static int sh_rtc_check_alarm(struct rtc_time* tm)
> +static int sh_rtc_check_alarm(struct rtc_time *tm)
> {
> /*
> * The original rtc says anything > 0xc0 is "don't care" or "match
> @@ -472,12 +501,10 @@
> tm->tm_sec = -1;
>
> if (tm->tm_year > 9999 ||
> - tm->tm_mon >= 12 ||
> - tm->tm_mday == 0 || tm->tm_mday >= 32 ||
> - tm->tm_wday >= 7 ||
> - tm->tm_hour >= 24 ||
> - tm->tm_min >= 60 ||
> - tm->tm_sec >= 60)
> + tm->tm_mon >= 12 ||
> + tm->tm_mday == 0 || tm->tm_mday >= 32 ||
> + tm->tm_wday >= 7 ||
> + tm->tm_hour >= 24 || tm->tm_min >= 60 || tm->tm_sec >= 60)
> return -EINVAL;
>
> return 0;
> @@ -499,14 +526,12 @@
>
> /* disable alarm interrupt and clear the alarm flag */
> rcr1 = readb(rtc->regbase + RCR1);
> - rcr1 &= ~(RCR1_AF|RCR1_AIE);
> + rcr1 &= ~(RCR1_AF | RCR1_AIE);
> writeb(rcr1, rtc->regbase + RCR1);
>
> - rtc->rearm_aie = 0;
> -
> /* set alarm time */
> - sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR);
> - sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR);
> + sh_rtc_write_alarm_value(rtc, tm->tm_sec, RSECAR);
> + sh_rtc_write_alarm_value(rtc, tm->tm_min, RMINAR);
> sh_rtc_write_alarm_value(rtc, tm->tm_hour, RHRAR);
> sh_rtc_write_alarm_value(rtc, tm->tm_wday, RWKAR);
> sh_rtc_write_alarm_value(rtc, tm->tm_mday, RDAYAR);
> @@ -525,15 +550,36 @@
> return 0;
> }
>
> +static int sh_rtc_irq_set_state(struct device *dev, int enabled)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct sh_rtc *rtc = platform_get_drvdata(pdev);
> +
> + if (enabled) {
> + rtc->periodic_freq |= PF_KOU;
> + return sh_rtc_ioctl(dev, RTC_PIE_ON, 0);
> + } else {
> + rtc->periodic_freq &= ~PF_KOU;
> + return sh_rtc_ioctl(dev, RTC_PIE_OFF, 0);
> + }
> +}
> +
> +static int sh_rtc_irq_set_freq(struct device *dev, int freq)
> +{
> + return sh_rtc_ioctl(dev, RTC_IRQP_SET, freq);
> +}
> +
> static struct rtc_class_ops sh_rtc_ops = {
> - .open = sh_rtc_open,
> - .release = sh_rtc_release,
> - .ioctl = sh_rtc_ioctl,
> - .read_time = sh_rtc_read_time,
> - .set_time = sh_rtc_set_time,
> - .read_alarm = sh_rtc_read_alarm,
> - .set_alarm = sh_rtc_set_alarm,
> - .proc = sh_rtc_proc,
> + .open = sh_rtc_open,
> + .release = sh_rtc_release,
> + .ioctl = sh_rtc_ioctl,
> + .read_time = sh_rtc_read_time,
> + .set_time = sh_rtc_set_time,
> + .read_alarm = sh_rtc_read_alarm,
> + .set_alarm = sh_rtc_set_alarm,
> + .irq_set_state = sh_rtc_irq_set_state,
> + .irq_set_freq = sh_rtc_irq_set_freq,
> + .proc = sh_rtc_proc,
> };
>
> static int __devinit sh_rtc_probe(struct platform_device *pdev)
> @@ -541,6 +587,7 @@
> struct sh_rtc *rtc;
> struct resource *res;
> int ret = -ENOENT;
> + unsigned int tmp;
>
> rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
> if (unlikely(!rtc))
> @@ -548,6 +595,7 @@
>
> spin_lock_init(&rtc->lock);
>
> + /* get periodic/carry/alarm irqs */
> rtc->periodic_irq = platform_get_irq(pdev, 0);
> if (unlikely(rtc->periodic_irq < 0)) {
> dev_err(&pdev->dev, "No IRQ for period\n");
> @@ -604,15 +652,54 @@
> rtc->capabilities |= pinfo->capabilities;
> }
>
> + rtc->rtc_dev->max_user_freq = 256;
> + rtc->rtc_dev->irq_freq = 1;
> + rtc->periodic_freq = 0x60;
> +
> platform_set_drvdata(pdev, rtc);
>
> + /* register periodic/carry/alarm irqs */
> + ret = request_irq(rtc->periodic_irq, sh_rtc_periodic,
> IRQF_DISABLED,
> + "sh-rtc period", rtc);
> + if (unlikely(ret)) {
> + dev_err(&pdev->dev,
> + "request period IRQ failed with %d, IRQ %d\n",
> ret,
> + rtc->periodic_irq);
> + goto err_badmap;
> + }
> +
> + ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
> + "sh-rtc carry", rtc);
> + if (unlikely(ret)) {
> + dev_err(&pdev->dev,
> + "request carry IRQ failed with %d, IRQ %d\n", ret,
> + rtc->carry_irq);
> + free_irq(rtc->periodic_irq, rtc);
> + goto err_badmap;
> + }
> +
> + ret = request_irq(rtc->alarm_irq, sh_rtc_alarm, IRQF_DISABLED,
> + "sh-rtc alarm", rtc);
> + if (unlikely(ret)) {
> + dev_err(&pdev->dev,
> + "request alarm IRQ failed with %d, IRQ %d\n", ret,
> + rtc->alarm_irq);
> + free_irq(rtc->carry_irq, rtc);
> + free_irq(rtc->periodic_irq, rtc);
> + goto err_badmap;
> + }
> +
> + tmp = readb(rtc->regbase + RCR1);
> + tmp &= ~RCR1_CF;
> + tmp |= RCR1_CIE;
> + writeb(tmp, rtc->regbase + RCR1);
> +
> return 0;
>
> -err_badmap:
> + err_badmap:
> release_resource(rtc->res);
> -err_badres:
> + err_badres:
> kfree(rtc);
> -
> return ret;
> }
>
> @@ -626,6 +713,9 @@
> sh_rtc_setpie(&pdev->dev, 0);
> sh_rtc_setaie(&pdev->dev, 0);
>
> + free_irq(rtc->carry_irq, rtc);
> + free_irq(rtc->periodic_irq, rtc);
> + free_irq(rtc->alarm_irq, rtc);
> release_resource(rtc->res);
>
> platform_set_drvdata(pdev, NULL);
> @@ -635,12 +725,12 @@
> return 0;
> }
> static struct platform_driver sh_rtc_platform_driver = {
> - .driver = {
> - .name = DRV_NAME,
> - .owner = THIS_MODULE,
> - },
> - .probe = sh_rtc_probe,
> - .remove = __devexit_p(sh_rtc_remove),
> + .driver = {
> + .name = DRV_NAME,
> + .owner = THIS_MODULE,
> + },
> + .probe = sh_rtc_probe,
> + .remove = __devexit_p(sh_rtc_remove),
> };
>
> static int __init sh_rtc_init(void)
> @@ -659,4 +749,5 @@
> MODULE_DESCRIPTION("SuperH on-chip RTC driver");
> MODULE_VERSION(DRV_VERSION);
> MODULE_AUTHOR("Paul Mundt <le...@li...>, Jamie Lenehan <
> le...@tw...>");
> +MODULE_AUTHOR("Angelo Castello <ang...@st...>");
> MODULE_LICENSE("GPL");
>
>
|