Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
0004  *
0005  * Copyright (C) 2000 Silicon Graphics, Inc.
0006  * Written by Ulf Carlsson (ulfc@engr.sgi.com)
0007  *
0008  * Copyright (C) 2008 Thomas Bogendoerfer
0009  *
0010  * Based on code written by Paul Gortmaker.
0011  */
0012 
0013 #include <linux/module.h>
0014 #include <linux/rtc.h>
0015 #include <linux/slab.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/bcd.h>
0018 #include <linux/io.h>
0019 #include <linux/err.h>
0020 
0021 struct m48t35_rtc {
0022     u8  pad[0x7ff8];    /* starts at 0x7ff8 */
0023 #ifdef CONFIG_SGI_IP27
0024     u8  hour;
0025     u8  min;
0026     u8  sec;
0027     u8  control;
0028     u8  year;
0029     u8  month;
0030     u8  date;
0031     u8  day;
0032 #else
0033     u8  control;
0034     u8  sec;
0035     u8  min;
0036     u8  hour;
0037     u8  day;
0038     u8  date;
0039     u8  month;
0040     u8  year;
0041 #endif
0042 };
0043 
0044 #define M48T35_RTC_SET      0x80
0045 #define M48T35_RTC_READ     0x40
0046 
0047 struct m48t35_priv {
0048     struct rtc_device *rtc;
0049     struct m48t35_rtc __iomem *reg;
0050     size_t size;
0051     unsigned long baseaddr;
0052     spinlock_t lock;
0053 };
0054 
0055 static int m48t35_read_time(struct device *dev, struct rtc_time *tm)
0056 {
0057     struct m48t35_priv *priv = dev_get_drvdata(dev);
0058     u8 control;
0059 
0060     /*
0061      * Only the values that we read from the RTC are set. We leave
0062      * tm_wday, tm_yday and tm_isdst untouched. Even though the
0063      * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
0064      * by the RTC when initially set to a non-zero value.
0065      */
0066     spin_lock_irq(&priv->lock);
0067     control = readb(&priv->reg->control);
0068     writeb(control | M48T35_RTC_READ, &priv->reg->control);
0069     tm->tm_sec = readb(&priv->reg->sec);
0070     tm->tm_min = readb(&priv->reg->min);
0071     tm->tm_hour = readb(&priv->reg->hour);
0072     tm->tm_mday = readb(&priv->reg->date);
0073     tm->tm_mon = readb(&priv->reg->month);
0074     tm->tm_year = readb(&priv->reg->year);
0075     writeb(control, &priv->reg->control);
0076     spin_unlock_irq(&priv->lock);
0077 
0078     tm->tm_sec = bcd2bin(tm->tm_sec);
0079     tm->tm_min = bcd2bin(tm->tm_min);
0080     tm->tm_hour = bcd2bin(tm->tm_hour);
0081     tm->tm_mday = bcd2bin(tm->tm_mday);
0082     tm->tm_mon = bcd2bin(tm->tm_mon);
0083     tm->tm_year = bcd2bin(tm->tm_year);
0084 
0085     /*
0086      * Account for differences between how the RTC uses the values
0087      * and how they are defined in a struct rtc_time;
0088      */
0089     tm->tm_year += 70;
0090     if (tm->tm_year <= 69)
0091         tm->tm_year += 100;
0092 
0093     tm->tm_mon--;
0094     return 0;
0095 }
0096 
0097 static int m48t35_set_time(struct device *dev, struct rtc_time *tm)
0098 {
0099     struct m48t35_priv *priv = dev_get_drvdata(dev);
0100     unsigned char mon, day, hrs, min, sec;
0101     unsigned int yrs;
0102     u8 control;
0103 
0104     yrs = tm->tm_year + 1900;
0105     mon = tm->tm_mon + 1;   /* tm_mon starts at zero */
0106     day = tm->tm_mday;
0107     hrs = tm->tm_hour;
0108     min = tm->tm_min;
0109     sec = tm->tm_sec;
0110 
0111     if (yrs < 1970)
0112         return -EINVAL;
0113 
0114     yrs -= 1970;
0115     if (yrs > 255)    /* They are unsigned */
0116         return -EINVAL;
0117 
0118     if (yrs > 169)
0119         return -EINVAL;
0120 
0121     if (yrs >= 100)
0122         yrs -= 100;
0123 
0124     sec = bin2bcd(sec);
0125     min = bin2bcd(min);
0126     hrs = bin2bcd(hrs);
0127     day = bin2bcd(day);
0128     mon = bin2bcd(mon);
0129     yrs = bin2bcd(yrs);
0130 
0131     spin_lock_irq(&priv->lock);
0132     control = readb(&priv->reg->control);
0133     writeb(control | M48T35_RTC_SET, &priv->reg->control);
0134     writeb(yrs, &priv->reg->year);
0135     writeb(mon, &priv->reg->month);
0136     writeb(day, &priv->reg->date);
0137     writeb(hrs, &priv->reg->hour);
0138     writeb(min, &priv->reg->min);
0139     writeb(sec, &priv->reg->sec);
0140     writeb(control, &priv->reg->control);
0141     spin_unlock_irq(&priv->lock);
0142     return 0;
0143 }
0144 
0145 static const struct rtc_class_ops m48t35_ops = {
0146     .read_time  = m48t35_read_time,
0147     .set_time   = m48t35_set_time,
0148 };
0149 
0150 static int m48t35_probe(struct platform_device *pdev)
0151 {
0152     struct resource *res;
0153     struct m48t35_priv *priv;
0154 
0155     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0156     if (!res)
0157         return -ENODEV;
0158     priv = devm_kzalloc(&pdev->dev, sizeof(struct m48t35_priv), GFP_KERNEL);
0159     if (!priv)
0160         return -ENOMEM;
0161 
0162     priv->size = resource_size(res);
0163     if (!devm_request_mem_region(&pdev->dev, res->start, priv->size,
0164                      pdev->name))
0165         return -EBUSY;
0166 
0167     priv->baseaddr = res->start;
0168     priv->reg = devm_ioremap(&pdev->dev, priv->baseaddr, priv->size);
0169     if (!priv->reg)
0170         return -ENOMEM;
0171 
0172     spin_lock_init(&priv->lock);
0173 
0174     platform_set_drvdata(pdev, priv);
0175 
0176     priv->rtc = devm_rtc_device_register(&pdev->dev, "m48t35",
0177                   &m48t35_ops, THIS_MODULE);
0178     return PTR_ERR_OR_ZERO(priv->rtc);
0179 }
0180 
0181 static struct platform_driver m48t35_platform_driver = {
0182     .driver     = {
0183         .name   = "rtc-m48t35",
0184     },
0185     .probe      = m48t35_probe,
0186 };
0187 
0188 module_platform_driver(m48t35_platform_driver);
0189 
0190 MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
0191 MODULE_DESCRIPTION("M48T35 RTC driver");
0192 MODULE_LICENSE("GPL");
0193 MODULE_ALIAS("platform:rtc-m48t35");