diff options
Diffstat (limited to 'drivers/rtc/rtc-cmos.c')
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 60 |
1 files changed, 54 insertions, 6 deletions
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f14876256a4a..cae212f30d65 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c | |||
@@ -34,11 +34,11 @@ | |||
34 | #include <linux/interrupt.h> | 34 | #include <linux/interrupt.h> |
35 | #include <linux/spinlock.h> | 35 | #include <linux/spinlock.h> |
36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/mod_devicetable.h> | ||
38 | #include <linux/log2.h> | 37 | #include <linux/log2.h> |
39 | #include <linux/pm.h> | 38 | #include <linux/pm.h> |
40 | #include <linux/of.h> | 39 | #include <linux/of.h> |
41 | #include <linux/of_platform.h> | 40 | #include <linux/of_platform.h> |
41 | #include <linux/dmi.h> | ||
42 | 42 | ||
43 | /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ | 43 | /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ |
44 | #include <asm-generic/rtc.h> | 44 | #include <asm-generic/rtc.h> |
@@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) | |||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
379 | 379 | ||
380 | /* | ||
381 | * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. | ||
382 | */ | ||
383 | static bool alarm_disable_quirk; | ||
384 | |||
385 | static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) | ||
386 | { | ||
387 | alarm_disable_quirk = true; | ||
388 | pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); | ||
389 | pr_info("RTC alarms disabled\n"); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static const struct dmi_system_id rtc_quirks[] __initconst = { | ||
394 | /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ | ||
395 | { | ||
396 | .callback = set_alarm_disable_quirk, | ||
397 | .ident = "IBM Truman", | ||
398 | .matches = { | ||
399 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
400 | DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), | ||
401 | }, | ||
402 | }, | ||
403 | /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ | ||
404 | { | ||
405 | .callback = set_alarm_disable_quirk, | ||
406 | .ident = "Gigabyte GA-990XA-UD3", | ||
407 | .matches = { | ||
408 | DMI_MATCH(DMI_SYS_VENDOR, | ||
409 | "Gigabyte Technology Co., Ltd."), | ||
410 | DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), | ||
411 | }, | ||
412 | }, | ||
413 | /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ | ||
414 | { | ||
415 | .callback = set_alarm_disable_quirk, | ||
416 | .ident = "Toshiba Satellite L300", | ||
417 | .matches = { | ||
418 | DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), | ||
419 | DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), | ||
420 | }, | ||
421 | }, | ||
422 | {} | ||
423 | }; | ||
424 | |||
380 | static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) | 425 | static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) |
381 | { | 426 | { |
382 | struct cmos_rtc *cmos = dev_get_drvdata(dev); | 427 | struct cmos_rtc *cmos = dev_get_drvdata(dev); |
@@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) | |||
385 | if (!is_valid_irq(cmos->irq)) | 430 | if (!is_valid_irq(cmos->irq)) |
386 | return -EINVAL; | 431 | return -EINVAL; |
387 | 432 | ||
433 | if (alarm_disable_quirk) | ||
434 | return 0; | ||
435 | |||
388 | spin_lock_irqsave(&rtc_lock, flags); | 436 | spin_lock_irqsave(&rtc_lock, flags); |
389 | 437 | ||
390 | if (enabled) | 438 | if (enabled) |
@@ -708,11 +756,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) | |||
708 | irq_handler_t rtc_cmos_int_handler; | 756 | irq_handler_t rtc_cmos_int_handler; |
709 | 757 | ||
710 | if (is_hpet_enabled()) { | 758 | if (is_hpet_enabled()) { |
711 | int err; | ||
712 | |||
713 | rtc_cmos_int_handler = hpet_rtc_interrupt; | 759 | rtc_cmos_int_handler = hpet_rtc_interrupt; |
714 | err = hpet_register_irq_handler(cmos_interrupt); | 760 | retval = hpet_register_irq_handler(cmos_interrupt); |
715 | if (err != 0) { | 761 | if (retval) { |
716 | dev_warn(dev, "hpet_register_irq_handler " | 762 | dev_warn(dev, "hpet_register_irq_handler " |
717 | " failed in rtc_init()."); | 763 | " failed in rtc_init()."); |
718 | goto cleanup1; | 764 | goto cleanup1; |
@@ -1127,7 +1173,7 @@ static struct platform_driver cmos_platform_driver = { | |||
1127 | .remove = __exit_p(cmos_platform_remove), | 1173 | .remove = __exit_p(cmos_platform_remove), |
1128 | .shutdown = cmos_platform_shutdown, | 1174 | .shutdown = cmos_platform_shutdown, |
1129 | .driver = { | 1175 | .driver = { |
1130 | .name = (char *) driver_name, | 1176 | .name = driver_name, |
1131 | #ifdef CONFIG_PM | 1177 | #ifdef CONFIG_PM |
1132 | .pm = &cmos_pm_ops, | 1178 | .pm = &cmos_pm_ops, |
1133 | #endif | 1179 | #endif |
@@ -1157,6 +1203,8 @@ static int __init cmos_init(void) | |||
1157 | platform_driver_registered = true; | 1203 | platform_driver_registered = true; |
1158 | } | 1204 | } |
1159 | 1205 | ||
1206 | dmi_check_system(rtc_quirks); | ||
1207 | |||
1160 | if (retval == 0) | 1208 | if (retval == 0) |
1161 | return 0; | 1209 | return 0; |
1162 | 1210 | ||