diff options
| -rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ep93xx.c | 162 |
3 files changed, 174 insertions, 1 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 609f55593459..b399259784e2 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
| @@ -117,6 +117,17 @@ config RTC_DRV_RS5C372 | |||
| 117 | This driver can also be built as a module. If so, the module | 117 | This driver can also be built as a module. If so, the module |
| 118 | will be called rtc-rs5c372. | 118 | will be called rtc-rs5c372. |
| 119 | 119 | ||
| 120 | config RTC_DRV_EP93XX | ||
| 121 | tristate "Cirrus Logic EP93XX" | ||
| 122 | depends on RTC_CLASS && ARCH_EP93XX | ||
| 123 | help | ||
| 124 | If you say yes here you get support for the | ||
| 125 | RTC embedded in the Cirrus Logic EP93XX processors. | ||
| 126 | |||
| 127 | This driver can also be built as a module. If so, the module | ||
| 128 | will be called rtc-ep93xx. | ||
| 129 | |||
| 130 | |||
| 120 | config RTC_DRV_TEST | 131 | config RTC_DRV_TEST |
| 121 | tristate "Test driver/device" | 132 | tristate "Test driver/device" |
| 122 | depends on RTC_CLASS | 133 | depends on RTC_CLASS |
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d2b4b1735598..38b4d87939e1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile | |||
| @@ -16,4 +16,4 @@ obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o | |||
| 16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o | 16 | obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o |
| 17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o | 17 | obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o |
| 18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o | 18 | obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o |
| 19 | 19 | obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o | |
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c new file mode 100644 index 000000000000..0dd80ea686a9 --- /dev/null +++ b/drivers/rtc/rtc-ep93xx.c | |||
| @@ -0,0 +1,162 @@ | |||
| 1 | /* | ||
| 2 | * A driver for the RTC embedded in the Cirrus Logic EP93XX processors | ||
| 3 | * Copyright (c) 2006 Tower Technologies | ||
| 4 | * | ||
| 5 | * Author: Alessandro Zummo <a.zummo@towertech.it> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/rtc.h> | ||
| 14 | #include <linux/platform_device.h> | ||
| 15 | #include <asm/hardware.h> | ||
| 16 | |||
| 17 | #define EP93XX_RTC_REG(x) (EP93XX_RTC_BASE + (x)) | ||
| 18 | #define EP93XX_RTC_DATA EP93XX_RTC_REG(0x0000) | ||
| 19 | #define EP93XX_RTC_LOAD EP93XX_RTC_REG(0x000C) | ||
| 20 | #define EP93XX_RTC_SWCOMP EP93XX_RTC_REG(0x0108) | ||
| 21 | |||
| 22 | #define DRV_VERSION "0.2" | ||
| 23 | |||
| 24 | static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, | ||
| 25 | unsigned short *delete) | ||
| 26 | { | ||
| 27 | unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); | ||
| 28 | |||
| 29 | if (preload) | ||
| 30 | *preload = comp & 0xffff; | ||
| 31 | |||
| 32 | if (delete) | ||
| 33 | *delete = (comp >> 16) & 0x1f; | ||
| 34 | |||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) | ||
| 39 | { | ||
| 40 | unsigned long time = __raw_readl(EP93XX_RTC_DATA); | ||
| 41 | |||
| 42 | rtc_time_to_tm(time, tm); | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs) | ||
| 47 | { | ||
| 48 | __raw_writel(secs + 1, EP93XX_RTC_LOAD); | ||
| 49 | return 0; | ||
| 50 | } | ||
| 51 | |||
| 52 | static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm) | ||
| 53 | { | ||
| 54 | int err; | ||
| 55 | unsigned long secs; | ||
| 56 | |||
| 57 | err = rtc_tm_to_time(tm, &secs); | ||
| 58 | if (err != 0) | ||
| 59 | return err; | ||
| 60 | |||
| 61 | return ep93xx_rtc_set_mmss(dev, secs); | ||
| 62 | } | ||
| 63 | |||
| 64 | static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) | ||
| 65 | { | ||
| 66 | unsigned short preload, delete; | ||
| 67 | |||
| 68 | ep93xx_get_swcomp(dev, &preload, &delete); | ||
| 69 | |||
| 70 | seq_printf(seq, "24hr\t\t: yes\n"); | ||
| 71 | seq_printf(seq, "preload\t\t: %d\n", preload); | ||
| 72 | seq_printf(seq, "delete\t\t: %d\n", delete); | ||
| 73 | |||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | static struct rtc_class_ops ep93xx_rtc_ops = { | ||
| 78 | .read_time = ep93xx_rtc_read_time, | ||
| 79 | .set_time = ep93xx_rtc_set_time, | ||
| 80 | .set_mmss = ep93xx_rtc_set_mmss, | ||
| 81 | .proc = ep93xx_rtc_proc, | ||
| 82 | }; | ||
| 83 | |||
| 84 | static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, | ||
| 85 | struct device_attribute *attr, char *buf) | ||
| 86 | { | ||
| 87 | unsigned short preload; | ||
| 88 | |||
| 89 | ep93xx_get_swcomp(dev, &preload, NULL); | ||
| 90 | |||
| 91 | return sprintf(buf, "%d\n", preload); | ||
| 92 | } | ||
| 93 | static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); | ||
| 94 | |||
| 95 | static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, | ||
| 96 | struct device_attribute *attr, char *buf) | ||
| 97 | { | ||
| 98 | unsigned short delete; | ||
| 99 | |||
| 100 | ep93xx_get_swcomp(dev, NULL, &delete); | ||
| 101 | |||
| 102 | return sprintf(buf, "%d\n", delete); | ||
| 103 | } | ||
| 104 | static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); | ||
| 105 | |||
| 106 | |||
| 107 | static int __devinit ep93xx_rtc_probe(struct platform_device *dev) | ||
| 108 | { | ||
| 109 | struct rtc_device *rtc = rtc_device_register("ep93xx", | ||
| 110 | &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); | ||
| 111 | |||
| 112 | if (IS_ERR(rtc)) { | ||
| 113 | dev_err(&dev->dev, "unable to register\n"); | ||
| 114 | return PTR_ERR(rtc); | ||
| 115 | } | ||
| 116 | |||
| 117 | platform_set_drvdata(dev, rtc); | ||
| 118 | |||
| 119 | device_create_file(&dev->dev, &dev_attr_comp_preload); | ||
| 120 | device_create_file(&dev->dev, &dev_attr_comp_delete); | ||
| 121 | |||
| 122 | return 0; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int __devexit ep93xx_rtc_remove(struct platform_device *dev) | ||
| 126 | { | ||
| 127 | struct rtc_device *rtc = platform_get_drvdata(dev); | ||
| 128 | |||
| 129 | if (rtc) | ||
| 130 | rtc_device_unregister(rtc); | ||
| 131 | |||
| 132 | platform_set_drvdata(dev, NULL); | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | |||
| 137 | static struct platform_driver ep93xx_rtc_platform_driver = { | ||
| 138 | .driver = { | ||
| 139 | .name = "ep93xx-rtc", | ||
| 140 | .owner = THIS_MODULE, | ||
| 141 | }, | ||
| 142 | .probe = ep93xx_rtc_probe, | ||
| 143 | .remove = __devexit_p(ep93xx_rtc_remove), | ||
| 144 | }; | ||
| 145 | |||
| 146 | static int __init ep93xx_rtc_init(void) | ||
| 147 | { | ||
| 148 | return platform_driver_register(&ep93xx_rtc_platform_driver); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void __exit ep93xx_rtc_exit(void) | ||
| 152 | { | ||
| 153 | platform_driver_unregister(&ep93xx_rtc_platform_driver); | ||
| 154 | } | ||
| 155 | |||
| 156 | MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); | ||
| 157 | MODULE_DESCRIPTION("EP93XX RTC driver"); | ||
| 158 | MODULE_LICENSE("GPL"); | ||
| 159 | MODULE_VERSION(DRV_VERSION); | ||
| 160 | |||
| 161 | module_init(ep93xx_rtc_init); | ||
| 162 | module_exit(ep93xx_rtc_exit); | ||
