root/drivers/rtc/rtc-m48t86.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. m48t86_readb
  2. m48t86_writeb
  3. m48t86_rtc_read_time
  4. m48t86_rtc_set_time
  5. m48t86_rtc_proc
  6. m48t86_nvram_read
  7. m48t86_nvram_write
  8. m48t86_verify_chip
  9. m48t86_rtc_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * ST M48T86 / Dallas DS12887 RTC driver
   4  * Copyright (c) 2006 Tower Technologies
   5  *
   6  * Author: Alessandro Zummo <a.zummo@towertech.it>
   7  *
   8  * This drivers only supports the clock running in BCD and 24H mode.
   9  * If it will be ever adapted to binary and 12H mode, care must be taken
  10  * to not introduce bugs.
  11  */
  12 
  13 #include <linux/module.h>
  14 #include <linux/rtc.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/bcd.h>
  17 #include <linux/io.h>
  18 
  19 #define M48T86_SEC              0x00
  20 #define M48T86_SECALRM          0x01
  21 #define M48T86_MIN              0x02
  22 #define M48T86_MINALRM          0x03
  23 #define M48T86_HOUR             0x04
  24 #define M48T86_HOURALRM         0x05
  25 #define M48T86_DOW              0x06 /* 1 = sunday */
  26 #define M48T86_DOM              0x07
  27 #define M48T86_MONTH            0x08 /* 1 - 12 */
  28 #define M48T86_YEAR             0x09 /* 0 - 99 */
  29 #define M48T86_A                0x0a
  30 #define M48T86_B                0x0b
  31 #define M48T86_B_SET            BIT(7)
  32 #define M48T86_B_DM             BIT(2)
  33 #define M48T86_B_H24            BIT(1)
  34 #define M48T86_C                0x0c
  35 #define M48T86_D                0x0d
  36 #define M48T86_D_VRT            BIT(7)
  37 #define M48T86_NVRAM(x)         (0x0e + (x))
  38 #define M48T86_NVRAM_LEN        114
  39 
  40 struct m48t86_rtc_info {
  41         void __iomem *index_reg;
  42         void __iomem *data_reg;
  43         struct rtc_device *rtc;
  44 };
  45 
  46 static unsigned char m48t86_readb(struct device *dev, unsigned long addr)
  47 {
  48         struct m48t86_rtc_info *info = dev_get_drvdata(dev);
  49         unsigned char value;
  50 
  51         writeb(addr, info->index_reg);
  52         value = readb(info->data_reg);
  53 
  54         return value;
  55 }
  56 
  57 static void m48t86_writeb(struct device *dev,
  58                           unsigned char value, unsigned long addr)
  59 {
  60         struct m48t86_rtc_info *info = dev_get_drvdata(dev);
  61 
  62         writeb(addr, info->index_reg);
  63         writeb(value, info->data_reg);
  64 }
  65 
  66 static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
  67 {
  68         unsigned char reg;
  69 
  70         reg = m48t86_readb(dev, M48T86_B);
  71 
  72         if (reg & M48T86_B_DM) {
  73                 /* data (binary) mode */
  74                 tm->tm_sec      = m48t86_readb(dev, M48T86_SEC);
  75                 tm->tm_min      = m48t86_readb(dev, M48T86_MIN);
  76                 tm->tm_hour     = m48t86_readb(dev, M48T86_HOUR) & 0x3f;
  77                 tm->tm_mday     = m48t86_readb(dev, M48T86_DOM);
  78                 /* tm_mon is 0-11 */
  79                 tm->tm_mon      = m48t86_readb(dev, M48T86_MONTH) - 1;
  80                 tm->tm_year     = m48t86_readb(dev, M48T86_YEAR) + 100;
  81                 tm->tm_wday     = m48t86_readb(dev, M48T86_DOW);
  82         } else {
  83                 /* bcd mode */
  84                 tm->tm_sec      = bcd2bin(m48t86_readb(dev, M48T86_SEC));
  85                 tm->tm_min      = bcd2bin(m48t86_readb(dev, M48T86_MIN));
  86                 tm->tm_hour     = bcd2bin(m48t86_readb(dev, M48T86_HOUR) &
  87                                           0x3f);
  88                 tm->tm_mday     = bcd2bin(m48t86_readb(dev, M48T86_DOM));
  89                 /* tm_mon is 0-11 */
  90                 tm->tm_mon      = bcd2bin(m48t86_readb(dev, M48T86_MONTH)) - 1;
  91                 tm->tm_year     = bcd2bin(m48t86_readb(dev, M48T86_YEAR)) + 100;
  92                 tm->tm_wday     = bcd2bin(m48t86_readb(dev, M48T86_DOW));
  93         }
  94 
  95         /* correct the hour if the clock is in 12h mode */
  96         if (!(reg & M48T86_B_H24))
  97                 if (m48t86_readb(dev, M48T86_HOUR) & 0x80)
  98                         tm->tm_hour += 12;
  99 
 100         return 0;
 101 }
 102 
 103 static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
 104 {
 105         unsigned char reg;
 106 
 107         reg = m48t86_readb(dev, M48T86_B);
 108 
 109         /* update flag and 24h mode */
 110         reg |= M48T86_B_SET | M48T86_B_H24;
 111         m48t86_writeb(dev, reg, M48T86_B);
 112 
 113         if (reg & M48T86_B_DM) {
 114                 /* data (binary) mode */
 115                 m48t86_writeb(dev, tm->tm_sec, M48T86_SEC);
 116                 m48t86_writeb(dev, tm->tm_min, M48T86_MIN);
 117                 m48t86_writeb(dev, tm->tm_hour, M48T86_HOUR);
 118                 m48t86_writeb(dev, tm->tm_mday, M48T86_DOM);
 119                 m48t86_writeb(dev, tm->tm_mon + 1, M48T86_MONTH);
 120                 m48t86_writeb(dev, tm->tm_year % 100, M48T86_YEAR);
 121                 m48t86_writeb(dev, tm->tm_wday, M48T86_DOW);
 122         } else {
 123                 /* bcd mode */
 124                 m48t86_writeb(dev, bin2bcd(tm->tm_sec), M48T86_SEC);
 125                 m48t86_writeb(dev, bin2bcd(tm->tm_min), M48T86_MIN);
 126                 m48t86_writeb(dev, bin2bcd(tm->tm_hour), M48T86_HOUR);
 127                 m48t86_writeb(dev, bin2bcd(tm->tm_mday), M48T86_DOM);
 128                 m48t86_writeb(dev, bin2bcd(tm->tm_mon + 1), M48T86_MONTH);
 129                 m48t86_writeb(dev, bin2bcd(tm->tm_year % 100), M48T86_YEAR);
 130                 m48t86_writeb(dev, bin2bcd(tm->tm_wday), M48T86_DOW);
 131         }
 132 
 133         /* update ended */
 134         reg &= ~M48T86_B_SET;
 135         m48t86_writeb(dev, reg, M48T86_B);
 136 
 137         return 0;
 138 }
 139 
 140 static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
 141 {
 142         unsigned char reg;
 143 
 144         reg = m48t86_readb(dev, M48T86_B);
 145 
 146         seq_printf(seq, "mode\t\t: %s\n",
 147                    (reg & M48T86_B_DM) ? "binary" : "bcd");
 148 
 149         reg = m48t86_readb(dev, M48T86_D);
 150 
 151         seq_printf(seq, "battery\t\t: %s\n",
 152                    (reg & M48T86_D_VRT) ? "ok" : "exhausted");
 153 
 154         return 0;
 155 }
 156 
 157 static const struct rtc_class_ops m48t86_rtc_ops = {
 158         .read_time      = m48t86_rtc_read_time,
 159         .set_time       = m48t86_rtc_set_time,
 160         .proc           = m48t86_rtc_proc,
 161 };
 162 
 163 static int m48t86_nvram_read(void *priv, unsigned int off, void *buf,
 164                              size_t count)
 165 {
 166         struct device *dev = priv;
 167         unsigned int i;
 168 
 169         for (i = 0; i < count; i++)
 170                 ((u8 *)buf)[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
 171 
 172         return 0;
 173 }
 174 
 175 static int m48t86_nvram_write(void *priv, unsigned int off, void *buf,
 176                               size_t count)
 177 {
 178         struct device *dev = priv;
 179         unsigned int i;
 180 
 181         for (i = 0; i < count; i++)
 182                 m48t86_writeb(dev, ((u8 *)buf)[i], M48T86_NVRAM(off + i));
 183 
 184         return 0;
 185 }
 186 
 187 /*
 188  * The RTC is an optional feature at purchase time on some Technologic Systems
 189  * boards. Verify that it actually exists by checking if the last two bytes
 190  * of the NVRAM can be changed.
 191  *
 192  * This is based on the method used in their rtc7800.c example.
 193  */
 194 static bool m48t86_verify_chip(struct platform_device *pdev)
 195 {
 196         unsigned int offset0 = M48T86_NVRAM(M48T86_NVRAM_LEN - 2);
 197         unsigned int offset1 = M48T86_NVRAM(M48T86_NVRAM_LEN - 1);
 198         unsigned char tmp0, tmp1;
 199 
 200         tmp0 = m48t86_readb(&pdev->dev, offset0);
 201         tmp1 = m48t86_readb(&pdev->dev, offset1);
 202 
 203         m48t86_writeb(&pdev->dev, 0x00, offset0);
 204         m48t86_writeb(&pdev->dev, 0x55, offset1);
 205         if (m48t86_readb(&pdev->dev, offset1) == 0x55) {
 206                 m48t86_writeb(&pdev->dev, 0xaa, offset1);
 207                 if (m48t86_readb(&pdev->dev, offset1) == 0xaa &&
 208                     m48t86_readb(&pdev->dev, offset0) == 0x00) {
 209                         m48t86_writeb(&pdev->dev, tmp0, offset0);
 210                         m48t86_writeb(&pdev->dev, tmp1, offset1);
 211 
 212                         return true;
 213                 }
 214         }
 215         return false;
 216 }
 217 
 218 static int m48t86_rtc_probe(struct platform_device *pdev)
 219 {
 220         struct m48t86_rtc_info *info;
 221         struct resource *res;
 222         unsigned char reg;
 223         int err;
 224         struct nvmem_config m48t86_nvmem_cfg = {
 225                 .name = "m48t86_nvram",
 226                 .word_size = 1,
 227                 .stride = 1,
 228                 .size = M48T86_NVRAM_LEN,
 229                 .reg_read = m48t86_nvram_read,
 230                 .reg_write = m48t86_nvram_write,
 231                 .priv = &pdev->dev,
 232         };
 233 
 234         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 235         if (!info)
 236                 return -ENOMEM;
 237 
 238         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 239         if (!res)
 240                 return -ENODEV;
 241         info->index_reg = devm_ioremap_resource(&pdev->dev, res);
 242         if (IS_ERR(info->index_reg))
 243                 return PTR_ERR(info->index_reg);
 244 
 245         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 246         if (!res)
 247                 return -ENODEV;
 248         info->data_reg = devm_ioremap_resource(&pdev->dev, res);
 249         if (IS_ERR(info->data_reg))
 250                 return PTR_ERR(info->data_reg);
 251 
 252         dev_set_drvdata(&pdev->dev, info);
 253 
 254         if (!m48t86_verify_chip(pdev)) {
 255                 dev_info(&pdev->dev, "RTC not present\n");
 256                 return -ENODEV;
 257         }
 258 
 259         info->rtc = devm_rtc_allocate_device(&pdev->dev);
 260         if (IS_ERR(info->rtc))
 261                 return PTR_ERR(info->rtc);
 262 
 263         info->rtc->ops = &m48t86_rtc_ops;
 264         info->rtc->nvram_old_abi = true;
 265 
 266         err = rtc_register_device(info->rtc);
 267         if (err)
 268                 return err;
 269 
 270         rtc_nvmem_register(info->rtc, &m48t86_nvmem_cfg);
 271 
 272         /* read battery status */
 273         reg = m48t86_readb(&pdev->dev, M48T86_D);
 274         dev_info(&pdev->dev, "battery %s\n",
 275                  (reg & M48T86_D_VRT) ? "ok" : "exhausted");
 276 
 277         return 0;
 278 }
 279 
 280 static struct platform_driver m48t86_rtc_platform_driver = {
 281         .driver         = {
 282                 .name   = "rtc-m48t86",
 283         },
 284         .probe          = m48t86_rtc_probe,
 285 };
 286 
 287 module_platform_driver(m48t86_rtc_platform_driver);
 288 
 289 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
 290 MODULE_DESCRIPTION("M48T86 RTC driver");
 291 MODULE_LICENSE("GPL");
 292 MODULE_ALIAS("platform:rtc-m48t86");

/* [<][>][^][v][top][bottom][index][help] */