linux/drivers/rtc/rtc-rs5c348.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * A SPI driver for the Ricoh RS5C348 RTC
   4 *
   5 * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
   6 *
   7 * The board specific init code should provide characteristics of this
   8 * device:
   9 *     Mode 1 (High-Active, Shift-Then-Sample), High Avtive CS
  10 */
  11
  12#include <linux/bcd.h>
  13#include <linux/delay.h>
  14#include <linux/device.h>
  15#include <linux/errno.h>
  16#include <linux/init.h>
  17#include <linux/kernel.h>
  18#include <linux/string.h>
  19#include <linux/slab.h>
  20#include <linux/rtc.h>
  21#include <linux/workqueue.h>
  22#include <linux/spi/spi.h>
  23#include <linux/module.h>
  24
  25#define RS5C348_REG_SECS        0
  26#define RS5C348_REG_MINS        1
  27#define RS5C348_REG_HOURS       2
  28#define RS5C348_REG_WDAY        3
  29#define RS5C348_REG_DAY 4
  30#define RS5C348_REG_MONTH       5
  31#define RS5C348_REG_YEAR        6
  32#define RS5C348_REG_CTL1        14
  33#define RS5C348_REG_CTL2        15
  34
  35#define RS5C348_SECS_MASK       0x7f
  36#define RS5C348_MINS_MASK       0x7f
  37#define RS5C348_HOURS_MASK      0x3f
  38#define RS5C348_WDAY_MASK       0x03
  39#define RS5C348_DAY_MASK        0x3f
  40#define RS5C348_MONTH_MASK      0x1f
  41
  42#define RS5C348_BIT_PM  0x20    /* REG_HOURS */
  43#define RS5C348_BIT_Y2K 0x80    /* REG_MONTH */
  44#define RS5C348_BIT_24H 0x20    /* REG_CTL1 */
  45#define RS5C348_BIT_XSTP        0x10    /* REG_CTL2 */
  46#define RS5C348_BIT_VDET        0x40    /* REG_CTL2 */
  47
  48#define RS5C348_CMD_W(addr)     (((addr) << 4) | 0x08)  /* single write */
  49#define RS5C348_CMD_R(addr)     (((addr) << 4) | 0x0c)  /* single read */
  50#define RS5C348_CMD_MW(addr)    (((addr) << 4) | 0x00)  /* burst write */
  51#define RS5C348_CMD_MR(addr)    (((addr) << 4) | 0x04)  /* burst read */
  52
  53struct rs5c348_plat_data {
  54        struct rtc_device *rtc;
  55        int rtc_24h;
  56};
  57
  58static int
  59rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)
  60{
  61        struct spi_device *spi = to_spi_device(dev);
  62        struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev);
  63        u8 txbuf[5+7], *txp;
  64        int ret;
  65
  66        ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
  67        if (ret < 0)
  68                return ret;
  69        if (ret & RS5C348_BIT_XSTP) {
  70                txbuf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
  71                txbuf[1] = 0;
  72                ret = spi_write_then_read(spi, txbuf, 2, NULL, 0);
  73                if (ret < 0)
  74                        return ret;
  75        }
  76
  77        /* Transfer 5 bytes before writing SEC.  This gives 31us for carry. */
  78        txp = txbuf;
  79        txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
  80        txbuf[1] = 0;   /* dummy */
  81        txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
  82        txbuf[3] = 0;   /* dummy */
  83        txbuf[4] = RS5C348_CMD_MW(RS5C348_REG_SECS); /* cmd, sec, ... */
  84        txp = &txbuf[5];
  85        txp[RS5C348_REG_SECS] = bin2bcd(tm->tm_sec);
  86        txp[RS5C348_REG_MINS] = bin2bcd(tm->tm_min);
  87        if (pdata->rtc_24h) {
  88                txp[RS5C348_REG_HOURS] = bin2bcd(tm->tm_hour);
  89        } else {
  90                /* hour 0 is AM12, noon is PM12 */
  91                txp[RS5C348_REG_HOURS] = bin2bcd((tm->tm_hour + 11) % 12 + 1) |
  92                        (tm->tm_hour >= 12 ? RS5C348_BIT_PM : 0);
  93        }
  94        txp[RS5C348_REG_WDAY] = bin2bcd(tm->tm_wday);
  95        txp[RS5C348_REG_DAY] = bin2bcd(tm->tm_mday);
  96        txp[RS5C348_REG_MONTH] = bin2bcd(tm->tm_mon + 1) |
  97                (tm->tm_year >= 100 ? RS5C348_BIT_Y2K : 0);
  98        txp[RS5C348_REG_YEAR] = bin2bcd(tm->tm_year % 100);
  99        /* write in one transfer to avoid data inconsistency */
 100        ret = spi_write_then_read(spi, txbuf, sizeof(txbuf), NULL, 0);
 101        udelay(62);     /* Tcsr 62us */
 102        return ret;
 103}
 104
 105static int
 106rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
 107{
 108        struct spi_device *spi = to_spi_device(dev);
 109        struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev);
 110        u8 txbuf[5], rxbuf[7];
 111        int ret;
 112
 113        ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL2));
 114        if (ret < 0)
 115                return ret;
 116        if (ret & RS5C348_BIT_VDET)
 117                dev_warn(&spi->dev, "voltage-low detected.\n");
 118        if (ret & RS5C348_BIT_XSTP) {
 119                dev_warn(&spi->dev, "oscillator-stop detected.\n");
 120                return -EINVAL;
 121        }
 122
 123        /* Transfer 5 byte befores reading SEC.  This gives 31us for carry. */
 124        txbuf[0] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
 125        txbuf[1] = 0;   /* dummy */
 126        txbuf[2] = RS5C348_CMD_R(RS5C348_REG_CTL2); /* cmd, ctl2 */
 127        txbuf[3] = 0;   /* dummy */
 128        txbuf[4] = RS5C348_CMD_MR(RS5C348_REG_SECS); /* cmd, sec, ... */
 129
 130        /* read in one transfer to avoid data inconsistency */
 131        ret = spi_write_then_read(spi, txbuf, sizeof(txbuf),
 132                                  rxbuf, sizeof(rxbuf));
 133        udelay(62);     /* Tcsr 62us */
 134        if (ret < 0)
 135                return ret;
 136
 137        tm->tm_sec = bcd2bin(rxbuf[RS5C348_REG_SECS] & RS5C348_SECS_MASK);
 138        tm->tm_min = bcd2bin(rxbuf[RS5C348_REG_MINS] & RS5C348_MINS_MASK);
 139        tm->tm_hour = bcd2bin(rxbuf[RS5C348_REG_HOURS] & RS5C348_HOURS_MASK);
 140        if (!pdata->rtc_24h) {
 141                if (rxbuf[RS5C348_REG_HOURS] & RS5C348_BIT_PM) {
 142                        tm->tm_hour -= 20;
 143                        tm->tm_hour %= 12;
 144                        tm->tm_hour += 12;
 145                } else
 146                        tm->tm_hour %= 12;
 147        }
 148        tm->tm_wday = bcd2bin(rxbuf[RS5C348_REG_WDAY] & RS5C348_WDAY_MASK);
 149        tm->tm_mday = bcd2bin(rxbuf[RS5C348_REG_DAY] & RS5C348_DAY_MASK);
 150        tm->tm_mon =
 151                bcd2bin(rxbuf[RS5C348_REG_MONTH] & RS5C348_MONTH_MASK) - 1;
 152        /* year is 1900 + tm->tm_year */
 153        tm->tm_year = bcd2bin(rxbuf[RS5C348_REG_YEAR]) +
 154                ((rxbuf[RS5C348_REG_MONTH] & RS5C348_BIT_Y2K) ? 100 : 0);
 155
 156        return 0;
 157}
 158
 159static const struct rtc_class_ops rs5c348_rtc_ops = {
 160        .read_time      = rs5c348_rtc_read_time,
 161        .set_time       = rs5c348_rtc_set_time,
 162};
 163
 164static int rs5c348_probe(struct spi_device *spi)
 165{
 166        int ret;
 167        struct rtc_device *rtc;
 168        struct rs5c348_plat_data *pdata;
 169
 170        pdata = devm_kzalloc(&spi->dev, sizeof(struct rs5c348_plat_data),
 171                                GFP_KERNEL);
 172        if (!pdata)
 173                return -ENOMEM;
 174        spi->dev.platform_data = pdata;
 175
 176        /* Check D7 of SECOND register */
 177        ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_SECS));
 178        if (ret < 0 || (ret & 0x80)) {
 179                dev_err(&spi->dev, "not found.\n");
 180                return ret;
 181        }
 182
 183        dev_info(&spi->dev, "spiclk %u KHz.\n",
 184                 (spi->max_speed_hz + 500) / 1000);
 185
 186        ret = spi_w8r8(spi, RS5C348_CMD_R(RS5C348_REG_CTL1));
 187        if (ret < 0)
 188                return ret;
 189        if (ret & RS5C348_BIT_24H)
 190                pdata->rtc_24h = 1;
 191
 192        rtc = devm_rtc_allocate_device(&spi->dev);
 193        if (IS_ERR(rtc))
 194                return PTR_ERR(rtc);
 195
 196        pdata->rtc = rtc;
 197
 198        rtc->ops = &rs5c348_rtc_ops;
 199
 200        return devm_rtc_register_device(rtc);
 201}
 202
 203static struct spi_driver rs5c348_driver = {
 204        .driver = {
 205                .name   = "rtc-rs5c348",
 206        },
 207        .probe  = rs5c348_probe,
 208};
 209
 210module_spi_driver(rs5c348_driver);
 211
 212MODULE_AUTHOR("Atsushi Nemoto <anemo@mba.ocn.ne.jp>");
 213MODULE_DESCRIPTION("Ricoh RS5C348 RTC driver");
 214MODULE_LICENSE("GPL");
 215MODULE_ALIAS("spi:rtc-rs5c348");
 216