aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/rtc-cmos.c85
-rw-r--r--include/linux/mc146818rtc.h4
2 files changed, 64 insertions, 25 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 0963c9309c7..b0e4a3eb33c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -647,6 +647,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
int retval = 0;
unsigned char rtc_control;
unsigned address_space;
+ u32 flags = 0;
/* there can be only one ... */
if (cmos_rtc.dev)
@@ -660,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* REVISIT non-x86 systems may instead use memory space resources
* (needing ioremap etc), not i/o space resources like this ...
*/
- ports = request_region(ports->start,
- resource_size(ports),
- driver_name);
+ if (RTC_IOMAPPED)
+ ports = request_region(ports->start, resource_size(ports),
+ driver_name);
+ else
+ ports = request_mem_region(ports->start, resource_size(ports),
+ driver_name);
if (!ports) {
dev_dbg(dev, "i/o registers already in use\n");
return -EBUSY;
@@ -699,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* expect CMOS_READ and friends to handle.
*/
if (info) {
+ if (info->flags)
+ flags = info->flags;
+ if (info->address_space)
+ address_space = info->address_space;
+
if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
cmos_rtc.day_alrm = info->rtc_day_alarm;
if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
@@ -726,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_lock_irq(&rtc_lock);
- /* force periodic irq to CMOS reset default of 1024Hz;
- *
- * REVISIT it's been reported that at least one x86_64 ALI mobo
- * doesn't use 32KHz here ... for portability we might need to
- * do something about other clock frequencies.
- */
- cmos_rtc.rtc->irq_freq = 1024;
- hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) {
+ /* force periodic irq to CMOS reset default of 1024Hz;
+ *
+ * REVISIT it's been reported that at least one x86_64 ALI
+ * mobo doesn't use 32KHz here ... for portability we might
+ * need to do something about other clock frequencies.
+ */
+ cmos_rtc.rtc->irq_freq = 1024;
+ hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ }
/* disable irqs */
- cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
+ if (is_valid_irq(rtc_irq))
+ cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
rtc_control = CMOS_READ(RTC_CONTROL);
@@ -802,14 +814,18 @@ cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
cleanup0:
- release_region(ports->start, resource_size(ports));
+ if (RTC_IOMAPPED)
+ release_region(ports->start, resource_size(ports));
+ else
+ release_mem_region(ports->start, resource_size(ports));
return retval;
}
-static void cmos_do_shutdown(void)
+static void cmos_do_shutdown(int rtc_irq)
{
spin_lock_irq(&rtc_lock);
- cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
+ if (is_valid_irq(rtc_irq))
+ cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
spin_unlock_irq(&rtc_lock);
}
@@ -818,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
struct resource *ports;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
sysfs_remove_bin_file(&dev->kobj, &nvram);
@@ -831,7 +847,10 @@ static void __exit cmos_do_remove(struct device *dev)
cmos->rtc = NULL;
ports = cmos->iomem;
- release_region(ports->start, resource_size(ports));
+ if (RTC_IOMAPPED)
+ release_region(ports->start, resource_size(ports));
+ else
+ release_mem_region(ports->start, resource_size(ports));
cmos->iomem = NULL;
cmos->dev = NULL;
@@ -1065,10 +1084,13 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
static void cmos_pnp_shutdown(struct pnp_dev *pnp)
{
- if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev))
+ struct device *dev = &pnp->dev;
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
}
static const struct pnp_device_id rtc_ids[] = {
@@ -1143,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {}
static int __init cmos_platform_probe(struct platform_device *pdev)
{
+ struct resource *resource;
+ int irq;
+
cmos_of_init(pdev);
cmos_wake_setup(&pdev->dev);
- return cmos_do_probe(&pdev->dev,
- platform_get_resource(pdev, IORESOURCE_IO, 0),
- platform_get_irq(pdev, 0));
+
+ if (RTC_IOMAPPED)
+ resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ else
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ irq = -1;
+
+ return cmos_do_probe(&pdev->dev, resource, irq);
}
static int __exit cmos_platform_remove(struct platform_device *pdev)
@@ -1158,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)
static void cmos_platform_shutdown(struct platform_device *pdev)
{
- if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev))
+ struct device *dev = &pdev->dev;
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
}
/* work with hotplug and coldplug */
diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h
index 2f4e957af65..433e0c74d64 100644
--- a/include/linux/mc146818rtc.h
+++ b/include/linux/mc146818rtc.h
@@ -31,6 +31,10 @@ struct cmos_rtc_board_info {
void (*wake_on)(struct device *dev);
void (*wake_off)(struct device *dev);
+ u32 flags;
+#define CMOS_RTC_FLAGS_NOFREQ (1 << 0)
+ int address_space;
+
u8 rtc_day_alarm; /* zero, or register index */
u8 rtc_mon_alarm; /* zero, or register index */
u8 rtc_century; /* zero, or register index */