From 68b54f477fae4f50a4010a1b5019bd185d452fa7 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 10 Feb 2017 11:11:55 -0700 Subject: rtc: m48t86: shorten register name defines For aesthetics. Shorten all the register names by removing '_REG' from all of them. This helps fix all the checkpatch.pl issues. Signed-off-by: H Hartley Sweeten Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 127 +++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 64 deletions(-) (limited to 'drivers/rtc/rtc-m48t86.c') diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 0eeb5714c00f..30648ea9e8e0 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -19,25 +19,24 @@ #include #include -#define M48T86_REG_SEC 0x00 -#define M48T86_REG_SECALRM 0x01 -#define M48T86_REG_MIN 0x02 -#define M48T86_REG_MINALRM 0x03 -#define M48T86_REG_HOUR 0x04 -#define M48T86_REG_HOURALRM 0x05 -#define M48T86_REG_DOW 0x06 /* 1 = sunday */ -#define M48T86_REG_DOM 0x07 -#define M48T86_REG_MONTH 0x08 /* 1 - 12 */ -#define M48T86_REG_YEAR 0x09 /* 0 - 99 */ -#define M48T86_REG_A 0x0A -#define M48T86_REG_B 0x0B -#define M48T86_REG_C 0x0C -#define M48T86_REG_D 0x0D - -#define M48T86_REG_B_H24 (1 << 1) -#define M48T86_REG_B_DM (1 << 2) -#define M48T86_REG_B_SET (1 << 7) -#define M48T86_REG_D_VRT (1 << 7) +#define M48T86_SEC 0x00 +#define M48T86_SECALRM 0x01 +#define M48T86_MIN 0x02 +#define M48T86_MINALRM 0x03 +#define M48T86_HOUR 0x04 +#define M48T86_HOURALRM 0x05 +#define M48T86_DOW 0x06 /* 1 = sunday */ +#define M48T86_DOM 0x07 +#define M48T86_MONTH 0x08 /* 1 - 12 */ +#define M48T86_YEAR 0x09 /* 0 - 99 */ +#define M48T86_A 0x0a +#define M48T86_B 0x0b +#define M48T86_B_SET BIT(7) +#define M48T86_B_DM BIT(2) +#define M48T86_B_H24 BIT(1) +#define M48T86_C 0x0c +#define M48T86_D 0x0d +#define M48T86_D_VRT BIT(7) static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) { @@ -45,33 +44,33 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) struct platform_device *pdev = to_platform_device(dev); struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_REG_B); + reg = ops->readbyte(M48T86_B); - if (reg & M48T86_REG_B_DM) { + if (reg & M48T86_B_DM) { /* data (binary) mode */ - tm->tm_sec = ops->readbyte(M48T86_REG_SEC); - tm->tm_min = ops->readbyte(M48T86_REG_MIN); - tm->tm_hour = ops->readbyte(M48T86_REG_HOUR) & 0x3F; - tm->tm_mday = ops->readbyte(M48T86_REG_DOM); + tm->tm_sec = ops->readbyte(M48T86_SEC); + tm->tm_min = ops->readbyte(M48T86_MIN); + tm->tm_hour = ops->readbyte(M48T86_HOUR) & 0x3f; + tm->tm_mday = ops->readbyte(M48T86_DOM); /* tm_mon is 0-11 */ - tm->tm_mon = ops->readbyte(M48T86_REG_MONTH) - 1; - tm->tm_year = ops->readbyte(M48T86_REG_YEAR) + 100; - tm->tm_wday = ops->readbyte(M48T86_REG_DOW); + tm->tm_mon = ops->readbyte(M48T86_MONTH) - 1; + tm->tm_year = ops->readbyte(M48T86_YEAR) + 100; + tm->tm_wday = ops->readbyte(M48T86_DOW); } else { /* bcd mode */ - tm->tm_sec = bcd2bin(ops->readbyte(M48T86_REG_SEC)); - tm->tm_min = bcd2bin(ops->readbyte(M48T86_REG_MIN)); - tm->tm_hour = bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F); - tm->tm_mday = bcd2bin(ops->readbyte(M48T86_REG_DOM)); + tm->tm_sec = bcd2bin(ops->readbyte(M48T86_SEC)); + tm->tm_min = bcd2bin(ops->readbyte(M48T86_MIN)); + tm->tm_hour = bcd2bin(ops->readbyte(M48T86_HOUR) & 0x3f); + tm->tm_mday = bcd2bin(ops->readbyte(M48T86_DOM)); /* tm_mon is 0-11 */ - tm->tm_mon = bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1; - tm->tm_year = bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100; - tm->tm_wday = bcd2bin(ops->readbyte(M48T86_REG_DOW)); + tm->tm_mon = bcd2bin(ops->readbyte(M48T86_MONTH)) - 1; + tm->tm_year = bcd2bin(ops->readbyte(M48T86_YEAR)) + 100; + tm->tm_wday = bcd2bin(ops->readbyte(M48T86_DOW)); } /* correct the hour if the clock is in 12h mode */ - if (!(reg & M48T86_REG_B_H24)) - if (ops->readbyte(M48T86_REG_HOUR) & 0x80) + if (!(reg & M48T86_B_H24)) + if (ops->readbyte(M48T86_HOUR) & 0x80) tm->tm_hour += 12; return rtc_valid_tm(tm); @@ -83,35 +82,35 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) struct platform_device *pdev = to_platform_device(dev); struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_REG_B); + reg = ops->readbyte(M48T86_B); /* update flag and 24h mode */ - reg |= M48T86_REG_B_SET | M48T86_REG_B_H24; - ops->writebyte(reg, M48T86_REG_B); + reg |= M48T86_B_SET | M48T86_B_H24; + ops->writebyte(reg, M48T86_B); - if (reg & M48T86_REG_B_DM) { + if (reg & M48T86_B_DM) { /* data (binary) mode */ - ops->writebyte(tm->tm_sec, M48T86_REG_SEC); - ops->writebyte(tm->tm_min, M48T86_REG_MIN); - ops->writebyte(tm->tm_hour, M48T86_REG_HOUR); - ops->writebyte(tm->tm_mday, M48T86_REG_DOM); - ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH); - ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR); - ops->writebyte(tm->tm_wday, M48T86_REG_DOW); + ops->writebyte(tm->tm_sec, M48T86_SEC); + ops->writebyte(tm->tm_min, M48T86_MIN); + ops->writebyte(tm->tm_hour, M48T86_HOUR); + ops->writebyte(tm->tm_mday, M48T86_DOM); + ops->writebyte(tm->tm_mon + 1, M48T86_MONTH); + ops->writebyte(tm->tm_year % 100, M48T86_YEAR); + ops->writebyte(tm->tm_wday, M48T86_DOW); } else { /* bcd mode */ - ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC); - ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN); - ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR); - ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM); - ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH); - ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR); - ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW); + ops->writebyte(bin2bcd(tm->tm_sec), M48T86_SEC); + ops->writebyte(bin2bcd(tm->tm_min), M48T86_MIN); + ops->writebyte(bin2bcd(tm->tm_hour), M48T86_HOUR); + ops->writebyte(bin2bcd(tm->tm_mday), M48T86_DOM); + ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_MONTH); + ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_YEAR); + ops->writebyte(bin2bcd(tm->tm_wday), M48T86_DOW); } /* update ended */ - reg &= ~M48T86_REG_B_SET; - ops->writebyte(reg, M48T86_REG_B); + reg &= ~M48T86_B_SET; + ops->writebyte(reg, M48T86_B); return 0; } @@ -122,15 +121,15 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) struct platform_device *pdev = to_platform_device(dev); struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_REG_B); + reg = ops->readbyte(M48T86_B); seq_printf(seq, "mode\t\t: %s\n", - (reg & M48T86_REG_B_DM) ? "binary" : "bcd"); + (reg & M48T86_B_DM) ? "binary" : "bcd"); - reg = ops->readbyte(M48T86_REG_D); + reg = ops->readbyte(M48T86_D); seq_printf(seq, "battery\t\t: %s\n", - (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); + (reg & M48T86_D_VRT) ? "ok" : "exhausted"); return 0; } @@ -148,7 +147,7 @@ static int m48t86_rtc_probe(struct platform_device *dev) struct rtc_device *rtc; rtc = devm_rtc_device_register(&dev->dev, "m48t86", - &m48t86_rtc_ops, THIS_MODULE); + &m48t86_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); @@ -156,9 +155,9 @@ static int m48t86_rtc_probe(struct platform_device *dev) platform_set_drvdata(dev, rtc); /* read battery status */ - reg = ops->readbyte(M48T86_REG_D); + reg = ops->readbyte(M48T86_D); dev_info(&dev->dev, "battery %s\n", - (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted"); + (reg & M48T86_D_VRT) ? "ok" : "exhausted"); return 0; } -- cgit From 8057c86d43a6579421c97b00c6df1ab0bc5e51a0 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 10 Feb 2017 11:11:56 -0700 Subject: rtc: m48t86: allow driver to manage its resources Allow this driver to, optionally, manage it's own resources and do the read/write operations if the platform does not provide them. Signed-off-by: H Hartley Sweeten Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 153 +++++++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 51 deletions(-) (limited to 'drivers/rtc/rtc-m48t86.c') diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 30648ea9e8e0..4dcdbd2a2408 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -18,6 +18,7 @@ #include #include #include +#include #define M48T86_SEC 0x00 #define M48T86_SECALRM 0x01 @@ -38,39 +39,72 @@ #define M48T86_D 0x0d #define M48T86_D_VRT BIT(7) +struct m48t86_rtc_info { + void __iomem *index_reg; + void __iomem *data_reg; + struct rtc_device *rtc; + struct m48t86_ops *ops; +}; + +static unsigned char m48t86_readb(struct device *dev, unsigned long addr) +{ + struct m48t86_rtc_info *info = dev_get_drvdata(dev); + unsigned char value; + + if (info->ops) { + value = info->ops->readbyte(addr); + } else { + writeb(addr, info->index_reg); + value = readb(info->data_reg); + } + return value; +} + +static void m48t86_writeb(struct device *dev, + unsigned char value, unsigned long addr) +{ + struct m48t86_rtc_info *info = dev_get_drvdata(dev); + + if (info->ops) { + info->ops->writebyte(value, addr); + } else { + writeb(addr, info->index_reg); + writeb(value, info->data_reg); + } +} + static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_B); + reg = m48t86_readb(dev, M48T86_B); if (reg & M48T86_B_DM) { /* data (binary) mode */ - tm->tm_sec = ops->readbyte(M48T86_SEC); - tm->tm_min = ops->readbyte(M48T86_MIN); - tm->tm_hour = ops->readbyte(M48T86_HOUR) & 0x3f; - tm->tm_mday = ops->readbyte(M48T86_DOM); + tm->tm_sec = m48t86_readb(dev, M48T86_SEC); + tm->tm_min = m48t86_readb(dev, M48T86_MIN); + tm->tm_hour = m48t86_readb(dev, M48T86_HOUR) & 0x3f; + tm->tm_mday = m48t86_readb(dev, M48T86_DOM); /* tm_mon is 0-11 */ - tm->tm_mon = ops->readbyte(M48T86_MONTH) - 1; - tm->tm_year = ops->readbyte(M48T86_YEAR) + 100; - tm->tm_wday = ops->readbyte(M48T86_DOW); + tm->tm_mon = m48t86_readb(dev, M48T86_MONTH) - 1; + tm->tm_year = m48t86_readb(dev, M48T86_YEAR) + 100; + tm->tm_wday = m48t86_readb(dev, M48T86_DOW); } else { /* bcd mode */ - tm->tm_sec = bcd2bin(ops->readbyte(M48T86_SEC)); - tm->tm_min = bcd2bin(ops->readbyte(M48T86_MIN)); - tm->tm_hour = bcd2bin(ops->readbyte(M48T86_HOUR) & 0x3f); - tm->tm_mday = bcd2bin(ops->readbyte(M48T86_DOM)); + tm->tm_sec = bcd2bin(m48t86_readb(dev, M48T86_SEC)); + tm->tm_min = bcd2bin(m48t86_readb(dev, M48T86_MIN)); + tm->tm_hour = bcd2bin(m48t86_readb(dev, M48T86_HOUR) & + 0x3f); + tm->tm_mday = bcd2bin(m48t86_readb(dev, M48T86_DOM)); /* tm_mon is 0-11 */ - tm->tm_mon = bcd2bin(ops->readbyte(M48T86_MONTH)) - 1; - tm->tm_year = bcd2bin(ops->readbyte(M48T86_YEAR)) + 100; - tm->tm_wday = bcd2bin(ops->readbyte(M48T86_DOW)); + tm->tm_mon = bcd2bin(m48t86_readb(dev, M48T86_MONTH)) - 1; + tm->tm_year = bcd2bin(m48t86_readb(dev, M48T86_YEAR)) + 100; + tm->tm_wday = bcd2bin(m48t86_readb(dev, M48T86_DOW)); } /* correct the hour if the clock is in 12h mode */ if (!(reg & M48T86_B_H24)) - if (ops->readbyte(M48T86_HOUR) & 0x80) + if (m48t86_readb(dev, M48T86_HOUR) & 0x80) tm->tm_hour += 12; return rtc_valid_tm(tm); @@ -79,38 +113,36 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_B); + reg = m48t86_readb(dev, M48T86_B); /* update flag and 24h mode */ reg |= M48T86_B_SET | M48T86_B_H24; - ops->writebyte(reg, M48T86_B); + m48t86_writeb(dev, reg, M48T86_B); if (reg & M48T86_B_DM) { /* data (binary) mode */ - ops->writebyte(tm->tm_sec, M48T86_SEC); - ops->writebyte(tm->tm_min, M48T86_MIN); - ops->writebyte(tm->tm_hour, M48T86_HOUR); - ops->writebyte(tm->tm_mday, M48T86_DOM); - ops->writebyte(tm->tm_mon + 1, M48T86_MONTH); - ops->writebyte(tm->tm_year % 100, M48T86_YEAR); - ops->writebyte(tm->tm_wday, M48T86_DOW); + m48t86_writeb(dev, tm->tm_sec, M48T86_SEC); + m48t86_writeb(dev, tm->tm_min, M48T86_MIN); + m48t86_writeb(dev, tm->tm_hour, M48T86_HOUR); + m48t86_writeb(dev, tm->tm_mday, M48T86_DOM); + m48t86_writeb(dev, tm->tm_mon + 1, M48T86_MONTH); + m48t86_writeb(dev, tm->tm_year % 100, M48T86_YEAR); + m48t86_writeb(dev, tm->tm_wday, M48T86_DOW); } else { /* bcd mode */ - ops->writebyte(bin2bcd(tm->tm_sec), M48T86_SEC); - ops->writebyte(bin2bcd(tm->tm_min), M48T86_MIN); - ops->writebyte(bin2bcd(tm->tm_hour), M48T86_HOUR); - ops->writebyte(bin2bcd(tm->tm_mday), M48T86_DOM); - ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_MONTH); - ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_YEAR); - ops->writebyte(bin2bcd(tm->tm_wday), M48T86_DOW); + m48t86_writeb(dev, bin2bcd(tm->tm_sec), M48T86_SEC); + m48t86_writeb(dev, bin2bcd(tm->tm_min), M48T86_MIN); + m48t86_writeb(dev, bin2bcd(tm->tm_hour), M48T86_HOUR); + m48t86_writeb(dev, bin2bcd(tm->tm_mday), M48T86_DOM); + m48t86_writeb(dev, bin2bcd(tm->tm_mon + 1), M48T86_MONTH); + m48t86_writeb(dev, bin2bcd(tm->tm_year % 100), M48T86_YEAR); + m48t86_writeb(dev, bin2bcd(tm->tm_wday), M48T86_DOW); } /* update ended */ reg &= ~M48T86_B_SET; - ops->writebyte(reg, M48T86_B); + m48t86_writeb(dev, reg, M48T86_B); return 0; } @@ -118,15 +150,13 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm) static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) { unsigned char reg; - struct platform_device *pdev = to_platform_device(dev); - struct m48t86_ops *ops = dev_get_platdata(&pdev->dev); - reg = ops->readbyte(M48T86_B); + reg = m48t86_readb(dev, M48T86_B); seq_printf(seq, "mode\t\t: %s\n", (reg & M48T86_B_DM) ? "binary" : "bcd"); - reg = ops->readbyte(M48T86_D); + reg = m48t86_readb(dev, M48T86_D); seq_printf(seq, "battery\t\t: %s\n", (reg & M48T86_D_VRT) ? "ok" : "exhausted"); @@ -140,23 +170,44 @@ static const struct rtc_class_ops m48t86_rtc_ops = { .proc = m48t86_rtc_proc, }; -static int m48t86_rtc_probe(struct platform_device *dev) +static int m48t86_rtc_probe(struct platform_device *pdev) { + struct m48t86_rtc_info *info; unsigned char reg; - struct m48t86_ops *ops = dev_get_platdata(&dev->dev); - struct rtc_device *rtc; - rtc = devm_rtc_device_register(&dev->dev, "m48t86", - &m48t86_rtc_ops, THIS_MODULE); + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->ops = dev_get_platdata(&pdev->dev); + if (!info->ops) { + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + info->index_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->index_reg)) + return PTR_ERR(info->index_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + info->data_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->data_reg)) + return PTR_ERR(info->data_reg); + } - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + dev_set_drvdata(&pdev->dev, info); - platform_set_drvdata(dev, rtc); + info->rtc = devm_rtc_device_register(&pdev->dev, "m48t86", + &m48t86_rtc_ops, THIS_MODULE); + if (IS_ERR(info->rtc)) + return PTR_ERR(info->rtc); /* read battery status */ - reg = ops->readbyte(M48T86_D); - dev_info(&dev->dev, "battery %s\n", + reg = m48t86_readb(&pdev->dev, M48T86_D); + dev_info(&pdev->dev, "battery %s\n", (reg & M48T86_D_VRT) ? "ok" : "exhausted"); return 0; -- cgit From b180cf8b0bce3e0e1eb9c5d78bfc9ef2559a0b22 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Fri, 10 Feb 2017 11:11:57 -0700 Subject: rtc: m48t86: add NVRAM support This RTC has 114 bytes of NVRAM. Provide access to it via a binary sysfs 'nvram' attribute file. Signed-off-by: H Hartley Sweeten Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'drivers/rtc/rtc-m48t86.c') diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 4dcdbd2a2408..4dc4af41c03d 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -38,6 +38,8 @@ #define M48T86_C 0x0c #define M48T86_D 0x0d #define M48T86_D_VRT BIT(7) +#define M48T86_NVRAM(x) (0x0e + (x)) +#define M48T86_NVRAM_LEN 114 struct m48t86_rtc_info { void __iomem *index_reg; @@ -170,6 +172,35 @@ static const struct rtc_class_ops m48t86_rtc_ops = { .proc = m48t86_rtc_proc, }; +static ssize_t m48t86_nvram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + unsigned int i; + + for (i = 0; i < count; i++) + buf[i] = m48t86_readb(dev, M48T86_NVRAM(off + i)); + + return count; +} + +static ssize_t m48t86_nvram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + unsigned int i; + + for (i = 0; i < count; i++) + m48t86_writeb(dev, buf[i], M48T86_NVRAM(off + i)); + + return count; +} + +static BIN_ATTR(nvram, 0644, m48t86_nvram_read, m48t86_nvram_write, + M48T86_NVRAM_LEN); + static int m48t86_rtc_probe(struct platform_device *pdev) { struct m48t86_rtc_info *info; @@ -210,6 +241,15 @@ static int m48t86_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "battery %s\n", (reg & M48T86_D_VRT) ? "ok" : "exhausted"); + if (device_create_bin_file(&pdev->dev, &bin_attr_nvram)) + dev_err(&pdev->dev, "failed to create nvram sysfs entry\n"); + + return 0; +} + +static int m48t86_rtc_remove(struct platform_device *pdev) +{ + device_remove_bin_file(&pdev->dev, &bin_attr_nvram); return 0; } @@ -218,6 +258,7 @@ static struct platform_driver m48t86_rtc_platform_driver = { .name = "rtc-m48t86", }, .probe = m48t86_rtc_probe, + .remove = m48t86_rtc_remove, }; module_platform_driver(m48t86_rtc_platform_driver); -- cgit From 3ea07127d9367250321df33bf9fee2ada362400c Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 15 Feb 2017 09:35:23 -0700 Subject: rtc: m48t86: verify that the RTC is actually present The RTC is an optional feature at purchase time on some Technologic Systems boards. Verify that it actually exists by checking if the last two bytes of the NVRAM can be changed. Signed-off-by: H Hartley Sweeten Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/rtc/rtc-m48t86.c') diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 4dc4af41c03d..491e8e4b300b 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -201,6 +201,37 @@ static ssize_t m48t86_nvram_write(struct file *filp, struct kobject *kobj, static BIN_ATTR(nvram, 0644, m48t86_nvram_read, m48t86_nvram_write, M48T86_NVRAM_LEN); +/* + * The RTC is an optional feature at purchase time on some Technologic Systems + * boards. Verify that it actually exists by checking if the last two bytes + * of the NVRAM can be changed. + * + * This is based on the method used in their rtc7800.c example. + */ +static bool m48t86_verify_chip(struct platform_device *pdev) +{ + unsigned int offset0 = M48T86_NVRAM(M48T86_NVRAM_LEN - 2); + unsigned int offset1 = M48T86_NVRAM(M48T86_NVRAM_LEN - 1); + unsigned char tmp0, tmp1; + + tmp0 = m48t86_readb(&pdev->dev, offset0); + tmp1 = m48t86_readb(&pdev->dev, offset1); + + m48t86_writeb(&pdev->dev, 0x00, offset0); + m48t86_writeb(&pdev->dev, 0x55, offset1); + if (m48t86_readb(&pdev->dev, offset1) == 0x55) { + m48t86_writeb(&pdev->dev, 0xaa, offset1); + if (m48t86_readb(&pdev->dev, offset1) == 0xaa && + m48t86_readb(&pdev->dev, offset0) == 0x00) { + m48t86_writeb(&pdev->dev, tmp0, offset0); + m48t86_writeb(&pdev->dev, tmp1, offset1); + + return true; + } + } + return false; +} + static int m48t86_rtc_probe(struct platform_device *pdev) { struct m48t86_rtc_info *info; @@ -231,6 +262,11 @@ static int m48t86_rtc_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, info); + if (!m48t86_verify_chip(pdev)) { + dev_info(&pdev->dev, "RTC not present\n"); + return -ENODEV; + } + info->rtc = devm_rtc_device_register(&pdev->dev, "m48t86", &m48t86_rtc_ops, THIS_MODULE); if (IS_ERR(info->rtc)) -- cgit From 0500ce589aa7b5325af161d3c992ffb6be138ff9 Mon Sep 17 00:00:00 2001 From: H Hartley Sweeten Date: Wed, 15 Feb 2017 09:35:27 -0700 Subject: rtc: m48t86: remove unused platform_data All users of this driver have been updated to allow the driver to manage it's own resources and do the read/write operations internally. The m48t86_ops are no longer used. Remove the platform_data header and the support code in the driver. Signed-off-by: H Hartley Sweeten Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t86.c | 51 ++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) (limited to 'drivers/rtc/rtc-m48t86.c') diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 491e8e4b300b..02af045305dd 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -45,7 +44,6 @@ struct m48t86_rtc_info { void __iomem *index_reg; void __iomem *data_reg; struct rtc_device *rtc; - struct m48t86_ops *ops; }; static unsigned char m48t86_readb(struct device *dev, unsigned long addr) @@ -53,12 +51,9 @@ static unsigned char m48t86_readb(struct device *dev, unsigned long addr) struct m48t86_rtc_info *info = dev_get_drvdata(dev); unsigned char value; - if (info->ops) { - value = info->ops->readbyte(addr); - } else { - writeb(addr, info->index_reg); - value = readb(info->data_reg); - } + writeb(addr, info->index_reg); + value = readb(info->data_reg); + return value; } @@ -67,12 +62,8 @@ static void m48t86_writeb(struct device *dev, { struct m48t86_rtc_info *info = dev_get_drvdata(dev); - if (info->ops) { - info->ops->writebyte(value, addr); - } else { - writeb(addr, info->index_reg); - writeb(value, info->data_reg); - } + writeb(addr, info->index_reg); + writeb(value, info->data_reg); } static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -235,30 +226,26 @@ static bool m48t86_verify_chip(struct platform_device *pdev) static int m48t86_rtc_probe(struct platform_device *pdev) { struct m48t86_rtc_info *info; + struct resource *res; unsigned char reg; info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - info->ops = dev_get_platdata(&pdev->dev); - if (!info->ops) { - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - info->index_reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(info->index_reg)) - return PTR_ERR(info->index_reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res) - return -ENODEV; - info->data_reg = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(info->data_reg)) - return PTR_ERR(info->data_reg); - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + info->index_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->index_reg)) + return PTR_ERR(info->index_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) + return -ENODEV; + info->data_reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(info->data_reg)) + return PTR_ERR(info->data_reg); dev_set_drvdata(&pdev->dev, info); -- cgit