174d34d4bSVoss, Nikolaus /* 274d34d4bSVoss, Nikolaus * 374d34d4bSVoss, Nikolaus * Driver for ST M41T93 SPI RTC 474d34d4bSVoss, Nikolaus * 574d34d4bSVoss, Nikolaus * (c) 2010 Nikolaus Voss, Weinmann Medical GmbH 674d34d4bSVoss, Nikolaus * 774d34d4bSVoss, Nikolaus * This program is free software; you can redistribute it and/or modify 874d34d4bSVoss, Nikolaus * it under the terms of the GNU General Public License version 2 as 974d34d4bSVoss, Nikolaus * published by the Free Software Foundation. 1074d34d4bSVoss, Nikolaus */ 1174d34d4bSVoss, Nikolaus 1274d34d4bSVoss, Nikolaus #include <linux/bcd.h> 1374d34d4bSVoss, Nikolaus #include <linux/kernel.h> 1474d34d4bSVoss, Nikolaus #include <linux/module.h> 1574d34d4bSVoss, Nikolaus #include <linux/platform_device.h> 1674d34d4bSVoss, Nikolaus #include <linux/rtc.h> 1774d34d4bSVoss, Nikolaus #include <linux/spi/spi.h> 1874d34d4bSVoss, Nikolaus 1974d34d4bSVoss, Nikolaus #define M41T93_REG_SSEC 0 2074d34d4bSVoss, Nikolaus #define M41T93_REG_ST_SEC 1 2174d34d4bSVoss, Nikolaus #define M41T93_REG_MIN 2 2274d34d4bSVoss, Nikolaus #define M41T93_REG_CENT_HOUR 3 2374d34d4bSVoss, Nikolaus #define M41T93_REG_WDAY 4 2474d34d4bSVoss, Nikolaus #define M41T93_REG_DAY 5 2574d34d4bSVoss, Nikolaus #define M41T93_REG_MON 6 2674d34d4bSVoss, Nikolaus #define M41T93_REG_YEAR 7 2774d34d4bSVoss, Nikolaus 2874d34d4bSVoss, Nikolaus 2974d34d4bSVoss, Nikolaus #define M41T93_REG_ALM_HOUR_HT 0xc 3074d34d4bSVoss, Nikolaus #define M41T93_REG_FLAGS 0xf 3174d34d4bSVoss, Nikolaus 3274d34d4bSVoss, Nikolaus #define M41T93_FLAG_ST (1 << 7) 3374d34d4bSVoss, Nikolaus #define M41T93_FLAG_OF (1 << 2) 3474d34d4bSVoss, Nikolaus #define M41T93_FLAG_BL (1 << 4) 3574d34d4bSVoss, Nikolaus #define M41T93_FLAG_HT (1 << 6) 3674d34d4bSVoss, Nikolaus 3774d34d4bSVoss, Nikolaus static inline int m41t93_set_reg(struct spi_device *spi, u8 addr, u8 data) 3874d34d4bSVoss, Nikolaus { 3974d34d4bSVoss, Nikolaus u8 buf[2]; 4074d34d4bSVoss, Nikolaus 4174d34d4bSVoss, Nikolaus /* MSB must be '1' to write */ 4274d34d4bSVoss, Nikolaus buf[0] = addr | 0x80; 4374d34d4bSVoss, Nikolaus buf[1] = data; 4474d34d4bSVoss, Nikolaus 4574d34d4bSVoss, Nikolaus return spi_write(spi, buf, sizeof(buf)); 4674d34d4bSVoss, Nikolaus } 4774d34d4bSVoss, Nikolaus 4874d34d4bSVoss, Nikolaus static int m41t93_set_time(struct device *dev, struct rtc_time *tm) 4974d34d4bSVoss, Nikolaus { 5074d34d4bSVoss, Nikolaus struct spi_device *spi = to_spi_device(dev); 51bcffb10fSNikolaus Voss int tmp; 5274d34d4bSVoss, Nikolaus u8 buf[9] = {0x80}; /* write cmd + 8 data bytes */ 5374d34d4bSVoss, Nikolaus u8 * const data = &buf[1]; /* ptr to first data byte */ 5474d34d4bSVoss, Nikolaus 5574d34d4bSVoss, Nikolaus dev_dbg(dev, "%s secs=%d, mins=%d, " 5674d34d4bSVoss, Nikolaus "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", 5774d34d4bSVoss, Nikolaus "write", tm->tm_sec, tm->tm_min, 5874d34d4bSVoss, Nikolaus tm->tm_hour, tm->tm_mday, 5974d34d4bSVoss, Nikolaus tm->tm_mon, tm->tm_year, tm->tm_wday); 6074d34d4bSVoss, Nikolaus 6174d34d4bSVoss, Nikolaus if (tm->tm_year < 100) { 6274d34d4bSVoss, Nikolaus dev_warn(&spi->dev, "unsupported date (before 2000-01-01).\n"); 6374d34d4bSVoss, Nikolaus return -EINVAL; 6474d34d4bSVoss, Nikolaus } 6574d34d4bSVoss, Nikolaus 66bcffb10fSNikolaus Voss tmp = spi_w8r8(spi, M41T93_REG_FLAGS); 67bcffb10fSNikolaus Voss if (tmp < 0) 68bcffb10fSNikolaus Voss return tmp; 69bcffb10fSNikolaus Voss 70bcffb10fSNikolaus Voss if (tmp & M41T93_FLAG_OF) { 71bcffb10fSNikolaus Voss dev_warn(&spi->dev, "OF bit is set, resetting.\n"); 72bcffb10fSNikolaus Voss m41t93_set_reg(spi, M41T93_REG_FLAGS, tmp & ~M41T93_FLAG_OF); 73bcffb10fSNikolaus Voss 74bcffb10fSNikolaus Voss tmp = spi_w8r8(spi, M41T93_REG_FLAGS); 75bcffb10fSNikolaus Voss if (tmp < 0) { 76bcffb10fSNikolaus Voss return tmp; 77bcffb10fSNikolaus Voss } else if (tmp & M41T93_FLAG_OF) { 78bcffb10fSNikolaus Voss /* OF cannot be immediately reset: oscillator has to be 79bcffb10fSNikolaus Voss * restarted. */ 80bcffb10fSNikolaus Voss u8 reset_osc = buf[M41T93_REG_ST_SEC] | M41T93_FLAG_ST; 81bcffb10fSNikolaus Voss 82bcffb10fSNikolaus Voss dev_warn(&spi->dev, 83bcffb10fSNikolaus Voss "OF bit is still set, kickstarting clock.\n"); 84bcffb10fSNikolaus Voss m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); 85bcffb10fSNikolaus Voss reset_osc &= ~M41T93_FLAG_ST; 86bcffb10fSNikolaus Voss m41t93_set_reg(spi, M41T93_REG_ST_SEC, reset_osc); 87bcffb10fSNikolaus Voss } 88bcffb10fSNikolaus Voss } 89bcffb10fSNikolaus Voss 9074d34d4bSVoss, Nikolaus data[M41T93_REG_SSEC] = 0; 9174d34d4bSVoss, Nikolaus data[M41T93_REG_ST_SEC] = bin2bcd(tm->tm_sec); 9274d34d4bSVoss, Nikolaus data[M41T93_REG_MIN] = bin2bcd(tm->tm_min); 9374d34d4bSVoss, Nikolaus data[M41T93_REG_CENT_HOUR] = bin2bcd(tm->tm_hour) | 9474d34d4bSVoss, Nikolaus ((tm->tm_year/100-1) << 6); 9574d34d4bSVoss, Nikolaus data[M41T93_REG_DAY] = bin2bcd(tm->tm_mday); 9674d34d4bSVoss, Nikolaus data[M41T93_REG_WDAY] = bin2bcd(tm->tm_wday + 1); 9774d34d4bSVoss, Nikolaus data[M41T93_REG_MON] = bin2bcd(tm->tm_mon + 1); 9874d34d4bSVoss, Nikolaus data[M41T93_REG_YEAR] = bin2bcd(tm->tm_year % 100); 9974d34d4bSVoss, Nikolaus 10074d34d4bSVoss, Nikolaus return spi_write(spi, buf, sizeof(buf)); 10174d34d4bSVoss, Nikolaus } 10274d34d4bSVoss, Nikolaus 10374d34d4bSVoss, Nikolaus 10474d34d4bSVoss, Nikolaus static int m41t93_get_time(struct device *dev, struct rtc_time *tm) 10574d34d4bSVoss, Nikolaus { 10674d34d4bSVoss, Nikolaus struct spi_device *spi = to_spi_device(dev); 10774d34d4bSVoss, Nikolaus const u8 start_addr = 0; 10874d34d4bSVoss, Nikolaus u8 buf[8]; 10974d34d4bSVoss, Nikolaus int century_after_1900; 11074d34d4bSVoss, Nikolaus int tmp; 11174d34d4bSVoss, Nikolaus int ret = 0; 11274d34d4bSVoss, Nikolaus 11374d34d4bSVoss, Nikolaus /* Check status of clock. Two states must be considered: 11474d34d4bSVoss, Nikolaus 1. halt bit (HT) is set: the clock is running but update of readout 11574d34d4bSVoss, Nikolaus registers has been disabled due to power failure. This is normal 11674d34d4bSVoss, Nikolaus case after poweron. Time is valid after resetting HT bit. 117bcffb10fSNikolaus Voss 2. oscillator fail bit (OF) is set: time is invalid. 11874d34d4bSVoss, Nikolaus */ 11974d34d4bSVoss, Nikolaus tmp = spi_w8r8(spi, M41T93_REG_ALM_HOUR_HT); 12074d34d4bSVoss, Nikolaus if (tmp < 0) 12174d34d4bSVoss, Nikolaus return tmp; 12274d34d4bSVoss, Nikolaus 12374d34d4bSVoss, Nikolaus if (tmp & M41T93_FLAG_HT) { 12474d34d4bSVoss, Nikolaus dev_dbg(&spi->dev, "HT bit is set, reenable clock update.\n"); 12574d34d4bSVoss, Nikolaus m41t93_set_reg(spi, M41T93_REG_ALM_HOUR_HT, 12674d34d4bSVoss, Nikolaus tmp & ~M41T93_FLAG_HT); 12774d34d4bSVoss, Nikolaus } 12874d34d4bSVoss, Nikolaus 12974d34d4bSVoss, Nikolaus tmp = spi_w8r8(spi, M41T93_REG_FLAGS); 13074d34d4bSVoss, Nikolaus if (tmp < 0) 13174d34d4bSVoss, Nikolaus return tmp; 13274d34d4bSVoss, Nikolaus 13374d34d4bSVoss, Nikolaus if (tmp & M41T93_FLAG_OF) { 13474d34d4bSVoss, Nikolaus ret = -EINVAL; 135bcffb10fSNikolaus Voss dev_warn(&spi->dev, "OF bit is set, write time to restart.\n"); 13674d34d4bSVoss, Nikolaus } 13774d34d4bSVoss, Nikolaus 13874d34d4bSVoss, Nikolaus if (tmp & M41T93_FLAG_BL) 13974d34d4bSVoss, Nikolaus dev_warn(&spi->dev, "BL bit is set, replace battery.\n"); 14074d34d4bSVoss, Nikolaus 14174d34d4bSVoss, Nikolaus /* read actual time/date */ 14274d34d4bSVoss, Nikolaus tmp = spi_write_then_read(spi, &start_addr, 1, buf, sizeof(buf)); 14374d34d4bSVoss, Nikolaus if (tmp < 0) 14474d34d4bSVoss, Nikolaus return tmp; 14574d34d4bSVoss, Nikolaus 14674d34d4bSVoss, Nikolaus tm->tm_sec = bcd2bin(buf[M41T93_REG_ST_SEC]); 14774d34d4bSVoss, Nikolaus tm->tm_min = bcd2bin(buf[M41T93_REG_MIN]); 14874d34d4bSVoss, Nikolaus tm->tm_hour = bcd2bin(buf[M41T93_REG_CENT_HOUR] & 0x3f); 14974d34d4bSVoss, Nikolaus tm->tm_mday = bcd2bin(buf[M41T93_REG_DAY]); 15074d34d4bSVoss, Nikolaus tm->tm_mon = bcd2bin(buf[M41T93_REG_MON]) - 1; 15174d34d4bSVoss, Nikolaus tm->tm_wday = bcd2bin(buf[M41T93_REG_WDAY] & 0x0f) - 1; 15274d34d4bSVoss, Nikolaus 15374d34d4bSVoss, Nikolaus century_after_1900 = (buf[M41T93_REG_CENT_HOUR] >> 6) + 1; 15474d34d4bSVoss, Nikolaus tm->tm_year = bcd2bin(buf[M41T93_REG_YEAR]) + century_after_1900 * 100; 15574d34d4bSVoss, Nikolaus 15674d34d4bSVoss, Nikolaus dev_dbg(dev, "%s secs=%d, mins=%d, " 15774d34d4bSVoss, Nikolaus "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n", 15874d34d4bSVoss, Nikolaus "read", tm->tm_sec, tm->tm_min, 15974d34d4bSVoss, Nikolaus tm->tm_hour, tm->tm_mday, 16074d34d4bSVoss, Nikolaus tm->tm_mon, tm->tm_year, tm->tm_wday); 16174d34d4bSVoss, Nikolaus 162*3d809cedSAlexandre Belloni return ret; 16374d34d4bSVoss, Nikolaus } 16474d34d4bSVoss, Nikolaus 16574d34d4bSVoss, Nikolaus 16674d34d4bSVoss, Nikolaus static const struct rtc_class_ops m41t93_rtc_ops = { 16774d34d4bSVoss, Nikolaus .read_time = m41t93_get_time, 16874d34d4bSVoss, Nikolaus .set_time = m41t93_set_time, 16974d34d4bSVoss, Nikolaus }; 17074d34d4bSVoss, Nikolaus 17174d34d4bSVoss, Nikolaus static struct spi_driver m41t93_driver; 17274d34d4bSVoss, Nikolaus 1735a167f45SGreg Kroah-Hartman static int m41t93_probe(struct spi_device *spi) 17474d34d4bSVoss, Nikolaus { 17574d34d4bSVoss, Nikolaus struct rtc_device *rtc; 17674d34d4bSVoss, Nikolaus int res; 17774d34d4bSVoss, Nikolaus 17874d34d4bSVoss, Nikolaus spi->bits_per_word = 8; 17974d34d4bSVoss, Nikolaus spi_setup(spi); 18074d34d4bSVoss, Nikolaus 18174d34d4bSVoss, Nikolaus res = spi_w8r8(spi, M41T93_REG_WDAY); 18274d34d4bSVoss, Nikolaus if (res < 0 || (res & 0xf8) != 0) { 18374d34d4bSVoss, Nikolaus dev_err(&spi->dev, "not found 0x%x.\n", res); 18474d34d4bSVoss, Nikolaus return -ENODEV; 18574d34d4bSVoss, Nikolaus } 18674d34d4bSVoss, Nikolaus 1870166fcd0SJingoo Han rtc = devm_rtc_device_register(&spi->dev, m41t93_driver.driver.name, 1880166fcd0SJingoo Han &m41t93_rtc_ops, THIS_MODULE); 18974d34d4bSVoss, Nikolaus if (IS_ERR(rtc)) 19074d34d4bSVoss, Nikolaus return PTR_ERR(rtc); 19174d34d4bSVoss, Nikolaus 192b6c4e71aSJingoo Han spi_set_drvdata(spi, rtc); 19374d34d4bSVoss, Nikolaus 19474d34d4bSVoss, Nikolaus return 0; 19574d34d4bSVoss, Nikolaus } 19674d34d4bSVoss, Nikolaus 19774d34d4bSVoss, Nikolaus static struct spi_driver m41t93_driver = { 19874d34d4bSVoss, Nikolaus .driver = { 19974d34d4bSVoss, Nikolaus .name = "rtc-m41t93", 20074d34d4bSVoss, Nikolaus }, 20174d34d4bSVoss, Nikolaus .probe = m41t93_probe, 20274d34d4bSVoss, Nikolaus }; 20374d34d4bSVoss, Nikolaus 204109e9418SAxel Lin module_spi_driver(m41t93_driver); 20574d34d4bSVoss, Nikolaus 20674d34d4bSVoss, Nikolaus MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>"); 20774d34d4bSVoss, Nikolaus MODULE_DESCRIPTION("Driver for ST M41T93 SPI RTC"); 20874d34d4bSVoss, Nikolaus MODULE_LICENSE("GPL"); 20974d34d4bSVoss, Nikolaus MODULE_ALIAS("spi:rtc-m41t93"); 210