146 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Driver for ST M41T94 SPI RTC4 *5 * Copyright (C) 2008 Kim B. Heino6 */7 8#include <linux/module.h>9#include <linux/kernel.h>10#include <linux/platform_device.h>11#include <linux/rtc.h>12#include <linux/spi/spi.h>13#include <linux/bcd.h>14 15#define M41T94_REG_SECONDS 0x0116#define M41T94_REG_MINUTES 0x0217#define M41T94_REG_HOURS 0x0318#define M41T94_REG_WDAY 0x0419#define M41T94_REG_DAY 0x0520#define M41T94_REG_MONTH 0x0621#define M41T94_REG_YEAR 0x0722#define M41T94_REG_HT 0x0c23 24#define M41T94_BIT_HALT 0x4025#define M41T94_BIT_STOP 0x8026#define M41T94_BIT_CB 0x4027#define M41T94_BIT_CEB 0x8028 29static int m41t94_set_time(struct device *dev, struct rtc_time *tm)30{31 struct spi_device *spi = to_spi_device(dev);32 u8 buf[8]; /* write cmd + 7 registers */33 34 dev_dbg(dev, "%s secs=%d, mins=%d, "35 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",36 "write", tm->tm_sec, tm->tm_min,37 tm->tm_hour, tm->tm_mday,38 tm->tm_mon, tm->tm_year, tm->tm_wday);39 40 buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */41 buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec);42 buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min);43 buf[M41T94_REG_HOURS] = bin2bcd(tm->tm_hour);44 buf[M41T94_REG_WDAY] = bin2bcd(tm->tm_wday + 1);45 buf[M41T94_REG_DAY] = bin2bcd(tm->tm_mday);46 buf[M41T94_REG_MONTH] = bin2bcd(tm->tm_mon + 1);47 48 buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB;49 if (tm->tm_year >= 100)50 buf[M41T94_REG_HOURS] |= M41T94_BIT_CB;51 buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100);52 53 return spi_write(spi, buf, 8);54}55 56static int m41t94_read_time(struct device *dev, struct rtc_time *tm)57{58 struct spi_device *spi = to_spi_device(dev);59 u8 buf[2];60 int ret, hour;61 62 /* clear halt update bit */63 ret = spi_w8r8(spi, M41T94_REG_HT);64 if (ret < 0)65 return ret;66 if (ret & M41T94_BIT_HALT) {67 buf[0] = 0x80 | M41T94_REG_HT;68 buf[1] = ret & ~M41T94_BIT_HALT;69 spi_write(spi, buf, 2);70 }71 72 /* clear stop bit */73 ret = spi_w8r8(spi, M41T94_REG_SECONDS);74 if (ret < 0)75 return ret;76 if (ret & M41T94_BIT_STOP) {77 buf[0] = 0x80 | M41T94_REG_SECONDS;78 buf[1] = ret & ~M41T94_BIT_STOP;79 spi_write(spi, buf, 2);80 }81 82 tm->tm_sec = bcd2bin(spi_w8r8(spi, M41T94_REG_SECONDS));83 tm->tm_min = bcd2bin(spi_w8r8(spi, M41T94_REG_MINUTES));84 hour = spi_w8r8(spi, M41T94_REG_HOURS);85 tm->tm_hour = bcd2bin(hour & 0x3f);86 tm->tm_wday = bcd2bin(spi_w8r8(spi, M41T94_REG_WDAY)) - 1;87 tm->tm_mday = bcd2bin(spi_w8r8(spi, M41T94_REG_DAY));88 tm->tm_mon = bcd2bin(spi_w8r8(spi, M41T94_REG_MONTH)) - 1;89 tm->tm_year = bcd2bin(spi_w8r8(spi, M41T94_REG_YEAR));90 if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB))91 tm->tm_year += 100;92 93 dev_dbg(dev, "%s secs=%d, mins=%d, "94 "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",95 "read", tm->tm_sec, tm->tm_min,96 tm->tm_hour, tm->tm_mday,97 tm->tm_mon, tm->tm_year, tm->tm_wday);98 99 return 0;100}101 102static const struct rtc_class_ops m41t94_rtc_ops = {103 .read_time = m41t94_read_time,104 .set_time = m41t94_set_time,105};106 107static struct spi_driver m41t94_driver;108 109static int m41t94_probe(struct spi_device *spi)110{111 struct rtc_device *rtc;112 int res;113 114 spi->bits_per_word = 8;115 spi_setup(spi);116 117 res = spi_w8r8(spi, M41T94_REG_SECONDS);118 if (res < 0) {119 dev_err(&spi->dev, "not found.\n");120 return res;121 }122 123 rtc = devm_rtc_device_register(&spi->dev, m41t94_driver.driver.name,124 &m41t94_rtc_ops, THIS_MODULE);125 if (IS_ERR(rtc))126 return PTR_ERR(rtc);127 128 spi_set_drvdata(spi, rtc);129 130 return 0;131}132 133static struct spi_driver m41t94_driver = {134 .driver = {135 .name = "rtc-m41t94",136 },137 .probe = m41t94_probe,138};139 140module_spi_driver(m41t94_driver);141 142MODULE_AUTHOR("Kim B. Heino <Kim.Heino@bluegiga.com>");143MODULE_DESCRIPTION("Driver for ST M41T94 SPI RTC");144MODULE_LICENSE("GPL");145MODULE_ALIAS("spi:rtc-m41t94");146