Commit 41684cba authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by james toy

- Call dev_set_drvdata before rtc device creation.

- Use its own spinlock instead of rtc->irq_lock.  Because pdata->rtc
  must be initialized to use the irq_lock (pdata->rtc->irq_lock).  There
  is a small window which rtc methods can be called before pdata->rtc is
  initialized.

  And there is no need use the irq_lock to protect hardware registers.
  The driver's own spinlock shoule be enough.

- Check pdata->rtc before calling rtc_update_irq.

- Use alarm_irq_enable and remove ioctl routine.

- Use devres APIs and simplify error/remove path.

These fixes are ported from ds1553 driver and just compile-tested only.
Signed-off-by: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Alessandro Zummo <alessandro.zummo@towertech.it>
Cc: Thomas Hommel <thomas.hommel@gefanuc.com>
Cc: David Brownell <david-b@pacbell.net>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent ae49f0ff
...@@ -62,7 +62,6 @@ ...@@ -62,7 +62,6 @@
struct rtc_plat_data { struct rtc_plat_data {
struct rtc_device *rtc; struct rtc_device *rtc;
void __iomem *ioaddr; void __iomem *ioaddr;
unsigned long baseaddr;
unsigned long last_jiffies; unsigned long last_jiffies;
int irq; int irq;
unsigned int irqen; unsigned int irqen;
...@@ -70,6 +69,7 @@ struct rtc_plat_data { ...@@ -70,6 +69,7 @@ struct rtc_plat_data {
int alrm_min; int alrm_min;
int alrm_hour; int alrm_hour;
int alrm_mday; int alrm_mday;
spinlock_t lock;
}; };
static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
...@@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) ...@@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
unsigned long irqflags; unsigned long irqflags;
u8 flags; u8 flags;
spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); spin_lock_irqsave(&pdata->lock, irqflags);
flags = readb(ioaddr + RTC_FLAGS); flags = readb(ioaddr + RTC_FLAGS);
writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS);
...@@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) ...@@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);
readb(ioaddr + RTC_FLAGS); /* clear interrupts */ readb(ioaddr + RTC_FLAGS); /* clear interrupts */
writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS);
spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); spin_unlock_irqrestore(&pdata->lock, irqflags);
} }
static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
...@@ -202,48 +202,45 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) ...@@ -202,48 +202,45 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
struct platform_device *pdev = dev_id; struct platform_device *pdev = dev_id;
struct rtc_plat_data *pdata = platform_get_drvdata(pdev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
void __iomem *ioaddr = pdata->ioaddr; void __iomem *ioaddr = pdata->ioaddr;
unsigned long events = RTC_IRQF; unsigned long events = 0;
spin_lock(&pdata->lock);
/* read and clear interrupt */ /* read and clear interrupt */
if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) {
return IRQ_NONE; events = RTC_IRQF;
if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80)
events |= RTC_UF; events |= RTC_UF;
else else
events |= RTC_AF; events |= RTC_AF;
rtc_update_irq(pdata->rtc, 1, events); if (likely(pdata->rtc))
return IRQ_HANDLED; rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
} }
static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, static int stk17ta8_rtc_alarm_irq_enable(struct device *dev,
unsigned long arg) unsigned int enabled)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct rtc_plat_data *pdata = platform_get_drvdata(pdev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
if (pdata->irq <= 0) if (pdata->irq <= 0)
return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ return -EINVAL;
switch (cmd) { if (enabled)
case RTC_AIE_OFF:
pdata->irqen &= ~RTC_AF;
stk17ta8_rtc_update_alarm(pdata);
break;
case RTC_AIE_ON:
pdata->irqen |= RTC_AF; pdata->irqen |= RTC_AF;
stk17ta8_rtc_update_alarm(pdata); else
break; pdata->irqen &= ~RTC_AF;
default: stk17ta8_rtc_update_alarm(pdata);
return -ENOIOCTLCMD;
}
return 0; return 0;
} }
static const struct rtc_class_ops stk17ta8_rtc_ops = { static const struct rtc_class_ops stk17ta8_rtc_ops = {
.read_time = stk17ta8_rtc_read_time, .read_time = stk17ta8_rtc_read_time,
.set_time = stk17ta8_rtc_set_time, .set_time = stk17ta8_rtc_set_time,
.read_alarm = stk17ta8_rtc_read_alarm, .read_alarm = stk17ta8_rtc_read_alarm,
.set_alarm = stk17ta8_rtc_set_alarm, .set_alarm = stk17ta8_rtc_set_alarm,
.ioctl = stk17ta8_rtc_ioctl, .alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable,
}; };
static ssize_t stk17ta8_nvram_read(struct kobject *kobj, static ssize_t stk17ta8_nvram_read(struct kobject *kobj,
...@@ -292,26 +289,22 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) ...@@ -292,26 +289,22 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
unsigned int cal; unsigned int cal;
unsigned int flags; unsigned int flags;
struct rtc_plat_data *pdata; struct rtc_plat_data *pdata;
void __iomem *ioaddr = NULL; void __iomem *ioaddr;
int ret = 0; int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
return -ENODEV; return -ENODEV;
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) if (!pdata)
return -ENOMEM; return -ENOMEM;
if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
ret = -EBUSY; pdev->name))
goto out; return -EBUSY;
} ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
pdata->baseaddr = res->start; if (!ioaddr)
ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); return -ENOMEM;
if (!ioaddr) {
ret = -ENOMEM;
goto out;
}
pdata->ioaddr = ioaddr; pdata->ioaddr = ioaddr;
pdata->irq = platform_get_irq(pdev, 0); pdata->irq = platform_get_irq(pdev, 0);
...@@ -327,9 +320,13 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) ...@@ -327,9 +320,13 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)
dev_warn(&pdev->dev, "voltage-low detected.\n"); dev_warn(&pdev->dev, "voltage-low detected.\n");
spin_lock_init(&pdata->lock);
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
if (pdata->irq > 0) { if (pdata->irq > 0) {
writeb(0, ioaddr + RTC_INTERRUPTS); writeb(0, ioaddr + RTC_INTERRUPTS);
if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, if (devm_request_irq(&pdev->dev, pdata->irq,
stk17ta8_rtc_interrupt,
IRQF_DISABLED | IRQF_SHARED, IRQF_DISABLED | IRQF_SHARED,
pdev->name, pdev) < 0) { pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n"); dev_warn(&pdev->dev, "interrupt not available.\n");
...@@ -337,30 +334,14 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) ...@@ -337,30 +334,14 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)
} }
} }
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,
&stk17ta8_rtc_ops, THIS_MODULE); &stk17ta8_rtc_ops, THIS_MODULE);
if (IS_ERR(pdata->rtc)) { if (IS_ERR(pdata->rtc))
ret = PTR_ERR(pdata->rtc); return PTR_ERR(pdata->rtc);
goto out;
}
ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
if (ret) { if (ret)
rtc_device_unregister(pdata->rtc); rtc_device_unregister(pdata->rtc);
goto out;
}
return 0;
out:
if (pdata->irq > 0)
free_irq(pdata->irq, pdev);
if (ioaddr)
iounmap(ioaddr);
if (pdata->baseaddr)
release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
kfree(pdata);
return ret; return ret;
} }
...@@ -370,13 +351,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) ...@@ -370,13 +351,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)
sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);
rtc_device_unregister(pdata->rtc); rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0) { if (pdata->irq > 0)
writeb(0, pdata->ioaddr + RTC_INTERRUPTS); writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
free_irq(pdata->irq, pdev);
}
iounmap(pdata->ioaddr);
release_mem_region(pdata->baseaddr, RTC_REG_SIZE);
kfree(pdata);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment