^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * A driver for the RTC embedded in the Cirrus Logic EP93XX processors
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2006 Tower Technologies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Author: Alessandro Zummo <a.zummo@towertech.it>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/rtc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/gfp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define EP93XX_RTC_DATA 0x000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define EP93XX_RTC_MATCH 0x004
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #define EP93XX_RTC_STATUS 0x008
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define EP93XX_RTC_STATUS_INTR BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define EP93XX_RTC_LOAD 0x00C
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define EP93XX_RTC_CONTROL 0x010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define EP93XX_RTC_CONTROL_MIE BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define EP93XX_RTC_SWCOMP 0x108
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define EP93XX_RTC_SWCOMP_DEL_MASK 0x001f0000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define EP93XX_RTC_SWCOMP_DEL_SHIFT 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define EP93XX_RTC_SWCOMP_INT_MASK 0x0000ffff
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define EP93XX_RTC_SWCOMP_INT_SHIFT 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct ep93xx_rtc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) void __iomem *mmio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct rtc_device *rtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) unsigned short *delete)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) unsigned long comp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) comp = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) if (preload)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) *preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) >> EP93XX_RTC_SWCOMP_INT_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (delete)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) >> EP93XX_RTC_SWCOMP_DEL_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) unsigned long time;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) rtc_time64_to_tm(time, tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct ep93xx_rtc *ep93xx_rtc = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned long secs = rtc_tm_to_time64(tm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) unsigned short preload, delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ep93xx_rtc_get_swcomp(dev, &preload, &delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) seq_printf(seq, "preload\t\t: %d\n", preload);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) seq_printf(seq, "delete\t\t: %d\n", delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static const struct rtc_class_ops ep93xx_rtc_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) .read_time = ep93xx_rtc_read_time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) .set_time = ep93xx_rtc_set_time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) .proc = ep93xx_rtc_proc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static ssize_t comp_preload_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) unsigned short preload;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ep93xx_rtc_get_swcomp(dev->parent, &preload, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return sprintf(buf, "%d\n", preload);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static DEVICE_ATTR_RO(comp_preload);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static ssize_t comp_delete_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) unsigned short delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ep93xx_rtc_get_swcomp(dev->parent, NULL, &delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return sprintf(buf, "%d\n", delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static DEVICE_ATTR_RO(comp_delete);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) static struct attribute *ep93xx_rtc_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) &dev_attr_comp_preload.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) &dev_attr_comp_delete.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static const struct attribute_group ep93xx_rtc_sysfs_files = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .attrs = ep93xx_rtc_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int ep93xx_rtc_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct ep93xx_rtc *ep93xx_rtc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) if (!ep93xx_rtc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ep93xx_rtc->mmio_base = devm_platform_ioremap_resource(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (IS_ERR(ep93xx_rtc->mmio_base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return PTR_ERR(ep93xx_rtc->mmio_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) platform_set_drvdata(pdev, ep93xx_rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) ep93xx_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (IS_ERR(ep93xx_rtc->rtc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return PTR_ERR(ep93xx_rtc->rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ep93xx_rtc->rtc->ops = &ep93xx_rtc_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) ep93xx_rtc->rtc->range_max = U32_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) err = rtc_add_group(ep93xx_rtc->rtc, &ep93xx_rtc_sysfs_files);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) return rtc_register_device(ep93xx_rtc->rtc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static struct platform_driver ep93xx_rtc_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) .name = "ep93xx-rtc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .probe = ep93xx_rtc_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) module_platform_driver(ep93xx_rtc_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) MODULE_DESCRIPTION("EP93XX RTC driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) MODULE_ALIAS("platform:ep93xx-rtc");