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"); > > |