xref: /linux/drivers/rtc/rtc-x1205.c (revision d2653e92732bd3911feff6bee5e23dbf959381db)
11fec7c66SAlessandro Zummo /*
21fec7c66SAlessandro Zummo  * An i2c driver for the Xicor/Intersil X1205 RTC
31fec7c66SAlessandro Zummo  * Copyright 2004 Karen Spearel
41fec7c66SAlessandro Zummo  * Copyright 2005 Alessandro Zummo
51fec7c66SAlessandro Zummo  *
61fec7c66SAlessandro Zummo  * please send all reports to:
71fec7c66SAlessandro Zummo  * 	Karen Spearel <kas111 at gmail dot com>
81fec7c66SAlessandro Zummo  *	Alessandro Zummo <a.zummo@towertech.it>
91fec7c66SAlessandro Zummo  *
101fec7c66SAlessandro Zummo  * based on a lot of other RTC drivers.
111fec7c66SAlessandro Zummo  *
12890e0375SJean Delvare  * Information and datasheet:
13890e0375SJean Delvare  * http://www.intersil.com/cda/deviceinfo/0,1477,X1205,00.html
14890e0375SJean Delvare  *
151fec7c66SAlessandro Zummo  * This program is free software; you can redistribute it and/or modify
161fec7c66SAlessandro Zummo  * it under the terms of the GNU General Public License version 2 as
171fec7c66SAlessandro Zummo  * published by the Free Software Foundation.
181fec7c66SAlessandro Zummo  */
191fec7c66SAlessandro Zummo 
201fec7c66SAlessandro Zummo #include <linux/i2c.h>
211fec7c66SAlessandro Zummo #include <linux/bcd.h>
221fec7c66SAlessandro Zummo #include <linux/rtc.h>
231fec7c66SAlessandro Zummo #include <linux/delay.h>
241fec7c66SAlessandro Zummo 
254edac2b4SAlessandro Zummo #define DRV_VERSION "1.0.8"
261fec7c66SAlessandro Zummo 
271fec7c66SAlessandro Zummo /* offsets into CCR area */
281fec7c66SAlessandro Zummo 
291fec7c66SAlessandro Zummo #define CCR_SEC			0
301fec7c66SAlessandro Zummo #define CCR_MIN			1
311fec7c66SAlessandro Zummo #define CCR_HOUR		2
321fec7c66SAlessandro Zummo #define CCR_MDAY		3
331fec7c66SAlessandro Zummo #define CCR_MONTH		4
341fec7c66SAlessandro Zummo #define CCR_YEAR		5
351fec7c66SAlessandro Zummo #define CCR_WDAY		6
361fec7c66SAlessandro Zummo #define CCR_Y2K			7
371fec7c66SAlessandro Zummo 
381fec7c66SAlessandro Zummo #define X1205_REG_SR		0x3F	/* status register */
391fec7c66SAlessandro Zummo #define X1205_REG_Y2K		0x37
401fec7c66SAlessandro Zummo #define X1205_REG_DW		0x36
411fec7c66SAlessandro Zummo #define X1205_REG_YR		0x35
421fec7c66SAlessandro Zummo #define X1205_REG_MO		0x34
431fec7c66SAlessandro Zummo #define X1205_REG_DT		0x33
441fec7c66SAlessandro Zummo #define X1205_REG_HR		0x32
451fec7c66SAlessandro Zummo #define X1205_REG_MN		0x31
461fec7c66SAlessandro Zummo #define X1205_REG_SC		0x30
471fec7c66SAlessandro Zummo #define X1205_REG_DTR		0x13
481fec7c66SAlessandro Zummo #define X1205_REG_ATR		0x12
491fec7c66SAlessandro Zummo #define X1205_REG_INT		0x11
501fec7c66SAlessandro Zummo #define X1205_REG_0		0x10
511fec7c66SAlessandro Zummo #define X1205_REG_Y2K1		0x0F
521fec7c66SAlessandro Zummo #define X1205_REG_DWA1		0x0E
531fec7c66SAlessandro Zummo #define X1205_REG_YRA1		0x0D
541fec7c66SAlessandro Zummo #define X1205_REG_MOA1		0x0C
551fec7c66SAlessandro Zummo #define X1205_REG_DTA1		0x0B
561fec7c66SAlessandro Zummo #define X1205_REG_HRA1		0x0A
571fec7c66SAlessandro Zummo #define X1205_REG_MNA1		0x09
581fec7c66SAlessandro Zummo #define X1205_REG_SCA1		0x08
591fec7c66SAlessandro Zummo #define X1205_REG_Y2K0		0x07
601fec7c66SAlessandro Zummo #define X1205_REG_DWA0		0x06
611fec7c66SAlessandro Zummo #define X1205_REG_YRA0		0x05
621fec7c66SAlessandro Zummo #define X1205_REG_MOA0		0x04
631fec7c66SAlessandro Zummo #define X1205_REG_DTA0		0x03
641fec7c66SAlessandro Zummo #define X1205_REG_HRA0		0x02
651fec7c66SAlessandro Zummo #define X1205_REG_MNA0		0x01
661fec7c66SAlessandro Zummo #define X1205_REG_SCA0		0x00
671fec7c66SAlessandro Zummo 
681fec7c66SAlessandro Zummo #define X1205_CCR_BASE		0x30	/* Base address of CCR */
691fec7c66SAlessandro Zummo #define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
701fec7c66SAlessandro Zummo 
711fec7c66SAlessandro Zummo #define X1205_SR_RTCF		0x01	/* Clock failure */
721fec7c66SAlessandro Zummo #define X1205_SR_WEL		0x02	/* Write Enable Latch */
731fec7c66SAlessandro Zummo #define X1205_SR_RWEL		0x04	/* Register Write Enable */
741fec7c66SAlessandro Zummo 
751fec7c66SAlessandro Zummo #define X1205_DTR_DTR0		0x01
761fec7c66SAlessandro Zummo #define X1205_DTR_DTR1		0x02
771fec7c66SAlessandro Zummo #define X1205_DTR_DTR2		0x04
781fec7c66SAlessandro Zummo 
791fec7c66SAlessandro Zummo #define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
801fec7c66SAlessandro Zummo 
814edac2b4SAlessandro Zummo static struct i2c_driver x1205_driver;
821fec7c66SAlessandro Zummo 
831fec7c66SAlessandro Zummo /*
841fec7c66SAlessandro Zummo  * In the routines that deal directly with the x1205 hardware, we use
851fec7c66SAlessandro Zummo  * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
861fec7c66SAlessandro Zummo  * Epoch is initialized as 2000. Time is set to UTC.
871fec7c66SAlessandro Zummo  */
881fec7c66SAlessandro Zummo static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
891fec7c66SAlessandro Zummo 				unsigned char reg_base)
901fec7c66SAlessandro Zummo {
911fec7c66SAlessandro Zummo 	unsigned char dt_addr[2] = { 0, reg_base };
921fec7c66SAlessandro Zummo 
931fec7c66SAlessandro Zummo 	unsigned char buf[8];
941fec7c66SAlessandro Zummo 
951fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
961fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
971fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
981fec7c66SAlessandro Zummo 	};
991fec7c66SAlessandro Zummo 
1001fec7c66SAlessandro Zummo 	/* read date registers */
1011fec7c66SAlessandro Zummo 	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
1022a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
1031fec7c66SAlessandro Zummo 		return -EIO;
1041fec7c66SAlessandro Zummo 	}
1051fec7c66SAlessandro Zummo 
1061fec7c66SAlessandro Zummo 	dev_dbg(&client->dev,
1071fec7c66SAlessandro Zummo 		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
1081fec7c66SAlessandro Zummo 		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
1092a4e2b87SHarvey Harrison 		__func__,
1101fec7c66SAlessandro Zummo 		buf[0], buf[1], buf[2], buf[3],
1111fec7c66SAlessandro Zummo 		buf[4], buf[5], buf[6], buf[7]);
1121fec7c66SAlessandro Zummo 
1131fec7c66SAlessandro Zummo 	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
1141fec7c66SAlessandro Zummo 	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
1151fec7c66SAlessandro Zummo 	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
1161fec7c66SAlessandro Zummo 	tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
1171fec7c66SAlessandro Zummo 	tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
1181fec7c66SAlessandro Zummo 	tm->tm_year = BCD2BIN(buf[CCR_YEAR])
1191fec7c66SAlessandro Zummo 			+ (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
1201fec7c66SAlessandro Zummo 	tm->tm_wday = buf[CCR_WDAY];
1211fec7c66SAlessandro Zummo 
1221fec7c66SAlessandro Zummo 	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
1231fec7c66SAlessandro Zummo 		"mday=%d, mon=%d, year=%d, wday=%d\n",
1242a4e2b87SHarvey Harrison 		__func__,
1251fec7c66SAlessandro Zummo 		tm->tm_sec, tm->tm_min, tm->tm_hour,
1261fec7c66SAlessandro Zummo 		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
1271fec7c66SAlessandro Zummo 
1281fec7c66SAlessandro Zummo 	return 0;
1291fec7c66SAlessandro Zummo }
1301fec7c66SAlessandro Zummo 
1311fec7c66SAlessandro Zummo static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
1321fec7c66SAlessandro Zummo {
1331fec7c66SAlessandro Zummo 	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
1341fec7c66SAlessandro Zummo 
1351fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
1361fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
1371fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, sr },	/* read status */
1381fec7c66SAlessandro Zummo 	};
1391fec7c66SAlessandro Zummo 
1401fec7c66SAlessandro Zummo 	/* read status register */
1411fec7c66SAlessandro Zummo 	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
1422a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
1431fec7c66SAlessandro Zummo 		return -EIO;
1441fec7c66SAlessandro Zummo 	}
1451fec7c66SAlessandro Zummo 
1461fec7c66SAlessandro Zummo 	return 0;
1471fec7c66SAlessandro Zummo }
1481fec7c66SAlessandro Zummo 
1491fec7c66SAlessandro Zummo static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
1501fec7c66SAlessandro Zummo 				int datetoo, u8 reg_base)
1511fec7c66SAlessandro Zummo {
1521fec7c66SAlessandro Zummo 	int i, xfer;
1531fec7c66SAlessandro Zummo 	unsigned char buf[8];
1541fec7c66SAlessandro Zummo 
1551fec7c66SAlessandro Zummo 	static const unsigned char wel[3] = { 0, X1205_REG_SR,
1561fec7c66SAlessandro Zummo 						X1205_SR_WEL };
1571fec7c66SAlessandro Zummo 
1581fec7c66SAlessandro Zummo 	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
1591fec7c66SAlessandro Zummo 						X1205_SR_WEL | X1205_SR_RWEL };
1601fec7c66SAlessandro Zummo 
1611fec7c66SAlessandro Zummo 	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
1621fec7c66SAlessandro Zummo 
1631fec7c66SAlessandro Zummo 	dev_dbg(&client->dev,
1641fec7c66SAlessandro Zummo 		"%s: secs=%d, mins=%d, hours=%d\n",
1652a4e2b87SHarvey Harrison 		__func__,
1661fec7c66SAlessandro Zummo 		tm->tm_sec, tm->tm_min, tm->tm_hour);
1671fec7c66SAlessandro Zummo 
1681fec7c66SAlessandro Zummo 	buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
1691fec7c66SAlessandro Zummo 	buf[CCR_MIN] = BIN2BCD(tm->tm_min);
1701fec7c66SAlessandro Zummo 
1711fec7c66SAlessandro Zummo 	/* set hour and 24hr bit */
1721fec7c66SAlessandro Zummo 	buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
1731fec7c66SAlessandro Zummo 
1741fec7c66SAlessandro Zummo 	/* should we also set the date? */
1751fec7c66SAlessandro Zummo 	if (datetoo) {
1761fec7c66SAlessandro Zummo 		dev_dbg(&client->dev,
1771fec7c66SAlessandro Zummo 			"%s: mday=%d, mon=%d, year=%d, wday=%d\n",
1782a4e2b87SHarvey Harrison 			__func__,
1791fec7c66SAlessandro Zummo 			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
1801fec7c66SAlessandro Zummo 
1811fec7c66SAlessandro Zummo 		buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
1821fec7c66SAlessandro Zummo 
1831fec7c66SAlessandro Zummo 		/* month, 1 - 12 */
1841fec7c66SAlessandro Zummo 		buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
1851fec7c66SAlessandro Zummo 
1861fec7c66SAlessandro Zummo 		/* year, since the rtc epoch*/
1871fec7c66SAlessandro Zummo 		buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
1881fec7c66SAlessandro Zummo 		buf[CCR_WDAY] = tm->tm_wday & 0x07;
1891fec7c66SAlessandro Zummo 		buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
1901fec7c66SAlessandro Zummo 	}
1911fec7c66SAlessandro Zummo 
1921fec7c66SAlessandro Zummo 	/* this sequence is required to unlock the chip */
1931fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
1942a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
1951fec7c66SAlessandro Zummo 		return -EIO;
1961fec7c66SAlessandro Zummo 	}
1971fec7c66SAlessandro Zummo 
1981fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
1992a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer);
2001fec7c66SAlessandro Zummo 		return -EIO;
2011fec7c66SAlessandro Zummo 	}
2021fec7c66SAlessandro Zummo 
2031fec7c66SAlessandro Zummo 	/* write register's data */
2041fec7c66SAlessandro Zummo 	for (i = 0; i < (datetoo ? 8 : 3); i++) {
2051fec7c66SAlessandro Zummo 		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
2061fec7c66SAlessandro Zummo 
2071fec7c66SAlessandro Zummo 		xfer = i2c_master_send(client, rdata, 3);
2081fec7c66SAlessandro Zummo 		if (xfer != 3) {
2091fec7c66SAlessandro Zummo 			dev_err(&client->dev,
2101fec7c66SAlessandro Zummo 				"%s: xfer=%d addr=%02x, data=%02x\n",
2112a4e2b87SHarvey Harrison 				__func__,
2121fec7c66SAlessandro Zummo 				 xfer, rdata[1], rdata[2]);
2131fec7c66SAlessandro Zummo 			return -EIO;
2141fec7c66SAlessandro Zummo 		}
2151fec7c66SAlessandro Zummo 	};
2161fec7c66SAlessandro Zummo 
2171fec7c66SAlessandro Zummo 	/* disable further writes */
2181fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
2192a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer);
2201fec7c66SAlessandro Zummo 		return -EIO;
2211fec7c66SAlessandro Zummo 	}
2221fec7c66SAlessandro Zummo 
2231fec7c66SAlessandro Zummo 	return 0;
2241fec7c66SAlessandro Zummo }
2251fec7c66SAlessandro Zummo 
2261fec7c66SAlessandro Zummo static int x1205_fix_osc(struct i2c_client *client)
2271fec7c66SAlessandro Zummo {
2281fec7c66SAlessandro Zummo 	int err;
2291fec7c66SAlessandro Zummo 	struct rtc_time tm;
2301fec7c66SAlessandro Zummo 
2311fec7c66SAlessandro Zummo 	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
2321fec7c66SAlessandro Zummo 
2331fec7c66SAlessandro Zummo 	if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
2341fec7c66SAlessandro Zummo 		dev_err(&client->dev,
2351fec7c66SAlessandro Zummo 			"unable to restart the oscillator\n");
2361fec7c66SAlessandro Zummo 
2371fec7c66SAlessandro Zummo 	return err;
2381fec7c66SAlessandro Zummo }
2391fec7c66SAlessandro Zummo 
2401fec7c66SAlessandro Zummo static int x1205_get_dtrim(struct i2c_client *client, int *trim)
2411fec7c66SAlessandro Zummo {
2421fec7c66SAlessandro Zummo 	unsigned char dtr;
2431fec7c66SAlessandro Zummo 	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
2441fec7c66SAlessandro Zummo 
2451fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
2461fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
2471fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
2481fec7c66SAlessandro Zummo 	};
2491fec7c66SAlessandro Zummo 
2501fec7c66SAlessandro Zummo 	/* read dtr register */
2511fec7c66SAlessandro Zummo 	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
2522a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
2531fec7c66SAlessandro Zummo 		return -EIO;
2541fec7c66SAlessandro Zummo 	}
2551fec7c66SAlessandro Zummo 
2562a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __func__, dtr);
2571fec7c66SAlessandro Zummo 
2581fec7c66SAlessandro Zummo 	*trim = 0;
2591fec7c66SAlessandro Zummo 
2601fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR0)
2611fec7c66SAlessandro Zummo 		*trim += 20;
2621fec7c66SAlessandro Zummo 
2631fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR1)
2641fec7c66SAlessandro Zummo 		*trim += 10;
2651fec7c66SAlessandro Zummo 
2661fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR2)
2671fec7c66SAlessandro Zummo 		*trim = -*trim;
2681fec7c66SAlessandro Zummo 
2691fec7c66SAlessandro Zummo 	return 0;
2701fec7c66SAlessandro Zummo }
2711fec7c66SAlessandro Zummo 
2721fec7c66SAlessandro Zummo static int x1205_get_atrim(struct i2c_client *client, int *trim)
2731fec7c66SAlessandro Zummo {
2741fec7c66SAlessandro Zummo 	s8 atr;
2751fec7c66SAlessandro Zummo 	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
2761fec7c66SAlessandro Zummo 
2771fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
2781fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
2791fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
2801fec7c66SAlessandro Zummo 	};
2811fec7c66SAlessandro Zummo 
2821fec7c66SAlessandro Zummo 	/* read atr register */
2831fec7c66SAlessandro Zummo 	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
2842a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
2851fec7c66SAlessandro Zummo 		return -EIO;
2861fec7c66SAlessandro Zummo 	}
2871fec7c66SAlessandro Zummo 
2882a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw atr=%x\n", __func__, atr);
2891fec7c66SAlessandro Zummo 
2901fec7c66SAlessandro Zummo 	/* atr is a two's complement value on 6 bits,
2911fec7c66SAlessandro Zummo 	 * perform sign extension. The formula is
2921fec7c66SAlessandro Zummo 	 * Catr = (atr * 0.25pF) + 11.00pF.
2931fec7c66SAlessandro Zummo 	 */
2941fec7c66SAlessandro Zummo 	if (atr & 0x20)
2951fec7c66SAlessandro Zummo 		atr |= 0xC0;
2961fec7c66SAlessandro Zummo 
2972a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr);
2981fec7c66SAlessandro Zummo 
2991fec7c66SAlessandro Zummo 	*trim = (atr * 250) + 11000;
3001fec7c66SAlessandro Zummo 
3012a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: real=%d\n", __func__, *trim);
3021fec7c66SAlessandro Zummo 
3031fec7c66SAlessandro Zummo 	return 0;
3041fec7c66SAlessandro Zummo }
3051fec7c66SAlessandro Zummo 
3061fec7c66SAlessandro Zummo struct x1205_limit
3071fec7c66SAlessandro Zummo {
3081fec7c66SAlessandro Zummo 	unsigned char reg, mask, min, max;
3091fec7c66SAlessandro Zummo };
3101fec7c66SAlessandro Zummo 
3111fec7c66SAlessandro Zummo static int x1205_validate_client(struct i2c_client *client)
3121fec7c66SAlessandro Zummo {
3131fec7c66SAlessandro Zummo 	int i, xfer;
3141fec7c66SAlessandro Zummo 
3151fec7c66SAlessandro Zummo 	/* Probe array. We will read the register at the specified
3161fec7c66SAlessandro Zummo 	 * address and check if the given bits are zero.
3171fec7c66SAlessandro Zummo 	 */
3181fec7c66SAlessandro Zummo 	static const unsigned char probe_zero_pattern[] = {
3191fec7c66SAlessandro Zummo 		/* register, mask */
3201fec7c66SAlessandro Zummo 		X1205_REG_SR,	0x18,
3211fec7c66SAlessandro Zummo 		X1205_REG_DTR,	0xF8,
3221fec7c66SAlessandro Zummo 		X1205_REG_ATR,	0xC0,
3231fec7c66SAlessandro Zummo 		X1205_REG_INT,	0x18,
3241fec7c66SAlessandro Zummo 		X1205_REG_0,	0xFF,
3251fec7c66SAlessandro Zummo 	};
3261fec7c66SAlessandro Zummo 
3271fec7c66SAlessandro Zummo 	static const struct x1205_limit probe_limits_pattern[] = {
3281fec7c66SAlessandro Zummo 		/* register, mask, min, max */
3291fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K,	0xFF,	19,	20	},
3301fec7c66SAlessandro Zummo 		{ X1205_REG_DW,		0xFF,	0,	6	},
3311fec7c66SAlessandro Zummo 		{ X1205_REG_YR,		0xFF,	0,	99	},
3321fec7c66SAlessandro Zummo 		{ X1205_REG_MO,		0xFF,	0,	12	},
3331fec7c66SAlessandro Zummo 		{ X1205_REG_DT,		0xFF,	0,	31	},
3341fec7c66SAlessandro Zummo 		{ X1205_REG_HR,		0x7F,	0,	23	},
3351fec7c66SAlessandro Zummo 		{ X1205_REG_MN,		0xFF,	0,	59	},
3361fec7c66SAlessandro Zummo 		{ X1205_REG_SC,		0xFF,	0,	59	},
3371fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
3381fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
3391fec7c66SAlessandro Zummo 	};
3401fec7c66SAlessandro Zummo 
3411fec7c66SAlessandro Zummo 	/* check that registers have bits a 0 where expected */
3421fec7c66SAlessandro Zummo 	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
3431fec7c66SAlessandro Zummo 		unsigned char buf;
3441fec7c66SAlessandro Zummo 
3451fec7c66SAlessandro Zummo 		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
3461fec7c66SAlessandro Zummo 
3471fec7c66SAlessandro Zummo 		struct i2c_msg msgs[2] = {
3481fec7c66SAlessandro Zummo 			{ client->addr, 0, 2, addr },
3491fec7c66SAlessandro Zummo 			{ client->addr, I2C_M_RD, 1, &buf },
3501fec7c66SAlessandro Zummo 		};
3511fec7c66SAlessandro Zummo 
3521fec7c66SAlessandro Zummo 		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
353a14e1893SDavid Brownell 			dev_err(&client->dev,
3541fec7c66SAlessandro Zummo 				"%s: could not read register %x\n",
3552a4e2b87SHarvey Harrison 				__func__, probe_zero_pattern[i]);
3561fec7c66SAlessandro Zummo 
3571fec7c66SAlessandro Zummo 			return -EIO;
3581fec7c66SAlessandro Zummo 		}
3591fec7c66SAlessandro Zummo 
3601fec7c66SAlessandro Zummo 		if ((buf & probe_zero_pattern[i+1]) != 0) {
361a14e1893SDavid Brownell 			dev_err(&client->dev,
3621fec7c66SAlessandro Zummo 				"%s: register=%02x, zero pattern=%d, value=%x\n",
3632a4e2b87SHarvey Harrison 				__func__, probe_zero_pattern[i], i, buf);
3641fec7c66SAlessandro Zummo 
3651fec7c66SAlessandro Zummo 			return -ENODEV;
3661fec7c66SAlessandro Zummo 		}
3671fec7c66SAlessandro Zummo 	}
3681fec7c66SAlessandro Zummo 
3691fec7c66SAlessandro Zummo 	/* check limits (only registers with bcd values) */
3701fec7c66SAlessandro Zummo 	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
3711fec7c66SAlessandro Zummo 		unsigned char reg, value;
3721fec7c66SAlessandro Zummo 
3731fec7c66SAlessandro Zummo 		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
3741fec7c66SAlessandro Zummo 
3751fec7c66SAlessandro Zummo 		struct i2c_msg msgs[2] = {
3761fec7c66SAlessandro Zummo 			{ client->addr, 0, 2, addr },
3771fec7c66SAlessandro Zummo 			{ client->addr, I2C_M_RD, 1, &reg },
3781fec7c66SAlessandro Zummo 		};
3791fec7c66SAlessandro Zummo 
3801fec7c66SAlessandro Zummo 		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
381a14e1893SDavid Brownell 			dev_err(&client->dev,
3821fec7c66SAlessandro Zummo 				"%s: could not read register %x\n",
3832a4e2b87SHarvey Harrison 				__func__, probe_limits_pattern[i].reg);
3841fec7c66SAlessandro Zummo 
3851fec7c66SAlessandro Zummo 			return -EIO;
3861fec7c66SAlessandro Zummo 		}
3871fec7c66SAlessandro Zummo 
3881fec7c66SAlessandro Zummo 		value = BCD2BIN(reg & probe_limits_pattern[i].mask);
3891fec7c66SAlessandro Zummo 
3901fec7c66SAlessandro Zummo 		if (value > probe_limits_pattern[i].max ||
3911fec7c66SAlessandro Zummo 			value < probe_limits_pattern[i].min) {
392a14e1893SDavid Brownell 			dev_dbg(&client->dev,
3931fec7c66SAlessandro Zummo 				"%s: register=%x, lim pattern=%d, value=%d\n",
3942a4e2b87SHarvey Harrison 				__func__, probe_limits_pattern[i].reg,
3951fec7c66SAlessandro Zummo 				i, value);
3961fec7c66SAlessandro Zummo 
3971fec7c66SAlessandro Zummo 			return -ENODEV;
3981fec7c66SAlessandro Zummo 		}
3991fec7c66SAlessandro Zummo 	}
4001fec7c66SAlessandro Zummo 
4011fec7c66SAlessandro Zummo 	return 0;
4021fec7c66SAlessandro Zummo }
4031fec7c66SAlessandro Zummo 
4041fec7c66SAlessandro Zummo static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
4051fec7c66SAlessandro Zummo {
4061fec7c66SAlessandro Zummo 	return x1205_get_datetime(to_i2c_client(dev),
4071fec7c66SAlessandro Zummo 		&alrm->time, X1205_ALM0_BASE);
4081fec7c66SAlessandro Zummo }
4091fec7c66SAlessandro Zummo 
4101fec7c66SAlessandro Zummo static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
4111fec7c66SAlessandro Zummo {
4121fec7c66SAlessandro Zummo 	return x1205_set_datetime(to_i2c_client(dev),
4131fec7c66SAlessandro Zummo 		&alrm->time, 1, X1205_ALM0_BASE);
4141fec7c66SAlessandro Zummo }
4151fec7c66SAlessandro Zummo 
4161fec7c66SAlessandro Zummo static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
4171fec7c66SAlessandro Zummo {
4181fec7c66SAlessandro Zummo 	return x1205_get_datetime(to_i2c_client(dev),
4191fec7c66SAlessandro Zummo 		tm, X1205_CCR_BASE);
4201fec7c66SAlessandro Zummo }
4211fec7c66SAlessandro Zummo 
4221fec7c66SAlessandro Zummo static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
4231fec7c66SAlessandro Zummo {
4241fec7c66SAlessandro Zummo 	return x1205_set_datetime(to_i2c_client(dev),
4251fec7c66SAlessandro Zummo 		tm, 1, X1205_CCR_BASE);
4261fec7c66SAlessandro Zummo }
4271fec7c66SAlessandro Zummo 
4281fec7c66SAlessandro Zummo static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
4291fec7c66SAlessandro Zummo {
4301fec7c66SAlessandro Zummo 	int err, dtrim, atrim;
4311fec7c66SAlessandro Zummo 
4321fec7c66SAlessandro Zummo 	if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
4331fec7c66SAlessandro Zummo 		seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
4341fec7c66SAlessandro Zummo 
4351fec7c66SAlessandro Zummo 	if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
4361fec7c66SAlessandro Zummo 		seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
4371fec7c66SAlessandro Zummo 			atrim / 1000, atrim % 1000);
4381fec7c66SAlessandro Zummo 	return 0;
4391fec7c66SAlessandro Zummo }
4401fec7c66SAlessandro Zummo 
441ff8371acSDavid Brownell static const struct rtc_class_ops x1205_rtc_ops = {
4421fec7c66SAlessandro Zummo 	.proc		= x1205_rtc_proc,
4431fec7c66SAlessandro Zummo 	.read_time	= x1205_rtc_read_time,
4441fec7c66SAlessandro Zummo 	.set_time	= x1205_rtc_set_time,
4451fec7c66SAlessandro Zummo 	.read_alarm	= x1205_rtc_read_alarm,
4461fec7c66SAlessandro Zummo 	.set_alarm	= x1205_rtc_set_alarm,
4471fec7c66SAlessandro Zummo };
4481fec7c66SAlessandro Zummo 
4491fec7c66SAlessandro Zummo static ssize_t x1205_sysfs_show_atrim(struct device *dev,
4501fec7c66SAlessandro Zummo 				struct device_attribute *attr, char *buf)
4511fec7c66SAlessandro Zummo {
452015aefbbSAlessandro Zummo 	int err, atrim;
4531fec7c66SAlessandro Zummo 
454015aefbbSAlessandro Zummo 	err = x1205_get_atrim(to_i2c_client(dev), &atrim);
455015aefbbSAlessandro Zummo 	if (err)
456015aefbbSAlessandro Zummo 		return err;
457015aefbbSAlessandro Zummo 
458015aefbbSAlessandro Zummo 	return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000);
4591fec7c66SAlessandro Zummo }
4601fec7c66SAlessandro Zummo static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
4611fec7c66SAlessandro Zummo 
4621fec7c66SAlessandro Zummo static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
4631fec7c66SAlessandro Zummo 				struct device_attribute *attr, char *buf)
4641fec7c66SAlessandro Zummo {
465015aefbbSAlessandro Zummo 	int err, dtrim;
4661fec7c66SAlessandro Zummo 
467015aefbbSAlessandro Zummo 	err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
468015aefbbSAlessandro Zummo 	if (err)
469015aefbbSAlessandro Zummo 		return err;
470015aefbbSAlessandro Zummo 
4711fec7c66SAlessandro Zummo 	return sprintf(buf, "%d ppm\n", dtrim);
4721fec7c66SAlessandro Zummo }
4731fec7c66SAlessandro Zummo static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
4741fec7c66SAlessandro Zummo 
4754edac2b4SAlessandro Zummo static int x1205_sysfs_register(struct device *dev)
4761fec7c66SAlessandro Zummo {
4774edac2b4SAlessandro Zummo 	int err;
4784edac2b4SAlessandro Zummo 
4794edac2b4SAlessandro Zummo 	err = device_create_file(dev, &dev_attr_atrim);
4804edac2b4SAlessandro Zummo 	if (err)
4814edac2b4SAlessandro Zummo 		return err;
4824edac2b4SAlessandro Zummo 
4834edac2b4SAlessandro Zummo 	err = device_create_file(dev, &dev_attr_dtrim);
4844edac2b4SAlessandro Zummo 	if (err)
4854edac2b4SAlessandro Zummo 		device_remove_file(dev, &dev_attr_atrim);
4864edac2b4SAlessandro Zummo 
4874edac2b4SAlessandro Zummo 	return err;
4881fec7c66SAlessandro Zummo }
4891fec7c66SAlessandro Zummo 
4904edac2b4SAlessandro Zummo static void x1205_sysfs_unregister(struct device *dev)
4914edac2b4SAlessandro Zummo {
4924edac2b4SAlessandro Zummo 	device_remove_file(dev, &dev_attr_atrim);
4934edac2b4SAlessandro Zummo 	device_remove_file(dev, &dev_attr_dtrim);
4944edac2b4SAlessandro Zummo }
4954edac2b4SAlessandro Zummo 
4964edac2b4SAlessandro Zummo 
497*d2653e92SJean Delvare static int x1205_probe(struct i2c_client *client,
498*d2653e92SJean Delvare 			const struct i2c_device_id *id)
4991fec7c66SAlessandro Zummo {
5001fec7c66SAlessandro Zummo 	int err = 0;
5011fec7c66SAlessandro Zummo 	unsigned char sr;
5021fec7c66SAlessandro Zummo 	struct rtc_device *rtc;
5031fec7c66SAlessandro Zummo 
5044edac2b4SAlessandro Zummo 	dev_dbg(&client->dev, "%s\n", __func__);
5051fec7c66SAlessandro Zummo 
5064edac2b4SAlessandro Zummo 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
5074edac2b4SAlessandro Zummo 		return -ENODEV;
5081fec7c66SAlessandro Zummo 
5094edac2b4SAlessandro Zummo 	if (x1205_validate_client(client) < 0)
5104edac2b4SAlessandro Zummo 		return -ENODEV;
5111fec7c66SAlessandro Zummo 
5121fec7c66SAlessandro Zummo 	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
5131fec7c66SAlessandro Zummo 
5141fec7c66SAlessandro Zummo 	rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
5151fec7c66SAlessandro Zummo 				&x1205_rtc_ops, THIS_MODULE);
5161fec7c66SAlessandro Zummo 
5174edac2b4SAlessandro Zummo 	if (IS_ERR(rtc))
5184edac2b4SAlessandro Zummo 		return PTR_ERR(rtc);
5191fec7c66SAlessandro Zummo 
5201fec7c66SAlessandro Zummo 	i2c_set_clientdata(client, rtc);
5211fec7c66SAlessandro Zummo 
5221fec7c66SAlessandro Zummo 	/* Check for power failures and eventualy enable the osc */
5231fec7c66SAlessandro Zummo 	if ((err = x1205_get_status(client, &sr)) == 0) {
5241fec7c66SAlessandro Zummo 		if (sr & X1205_SR_RTCF) {
5251fec7c66SAlessandro Zummo 			dev_err(&client->dev,
5261fec7c66SAlessandro Zummo 				"power failure detected, "
5271fec7c66SAlessandro Zummo 				"please set the clock\n");
5281fec7c66SAlessandro Zummo 			udelay(50);
5291fec7c66SAlessandro Zummo 			x1205_fix_osc(client);
5301fec7c66SAlessandro Zummo 		}
5311fec7c66SAlessandro Zummo 	}
5321fec7c66SAlessandro Zummo 	else
5331fec7c66SAlessandro Zummo 		dev_err(&client->dev, "couldn't read status\n");
5341fec7c66SAlessandro Zummo 
5354edac2b4SAlessandro Zummo 	err = x1205_sysfs_register(&client->dev);
5364edac2b4SAlessandro Zummo 	if (err)
5374edac2b4SAlessandro Zummo 		goto exit_devreg;
5381fec7c66SAlessandro Zummo 
5391fec7c66SAlessandro Zummo 	return 0;
5401fec7c66SAlessandro Zummo 
54191046a8aSJeff Garzik exit_devreg:
54291046a8aSJeff Garzik 	rtc_device_unregister(rtc);
54391046a8aSJeff Garzik 
5441fec7c66SAlessandro Zummo 	return err;
5451fec7c66SAlessandro Zummo }
5461fec7c66SAlessandro Zummo 
5474edac2b4SAlessandro Zummo static int x1205_remove(struct i2c_client *client)
5481fec7c66SAlessandro Zummo {
5491fec7c66SAlessandro Zummo 	struct rtc_device *rtc = i2c_get_clientdata(client);
5501fec7c66SAlessandro Zummo 
5511fec7c66SAlessandro Zummo 	rtc_device_unregister(rtc);
5524edac2b4SAlessandro Zummo 	x1205_sysfs_unregister(&client->dev);
5531fec7c66SAlessandro Zummo 	return 0;
5541fec7c66SAlessandro Zummo }
5551fec7c66SAlessandro Zummo 
5564edac2b4SAlessandro Zummo static struct i2c_driver x1205_driver = {
5574edac2b4SAlessandro Zummo 	.driver		= {
5584edac2b4SAlessandro Zummo 		.name	= "rtc-x1205",
5594edac2b4SAlessandro Zummo 	},
5604edac2b4SAlessandro Zummo 	.probe		= x1205_probe,
5614edac2b4SAlessandro Zummo 	.remove		= x1205_remove,
5624edac2b4SAlessandro Zummo };
5634edac2b4SAlessandro Zummo 
5641fec7c66SAlessandro Zummo static int __init x1205_init(void)
5651fec7c66SAlessandro Zummo {
5661fec7c66SAlessandro Zummo 	return i2c_add_driver(&x1205_driver);
5671fec7c66SAlessandro Zummo }
5681fec7c66SAlessandro Zummo 
5691fec7c66SAlessandro Zummo static void __exit x1205_exit(void)
5701fec7c66SAlessandro Zummo {
5711fec7c66SAlessandro Zummo 	i2c_del_driver(&x1205_driver);
5721fec7c66SAlessandro Zummo }
5731fec7c66SAlessandro Zummo 
5741fec7c66SAlessandro Zummo MODULE_AUTHOR(
5751fec7c66SAlessandro Zummo 	"Karen Spearel <kas111 at gmail dot com>, "
5761fec7c66SAlessandro Zummo 	"Alessandro Zummo <a.zummo@towertech.it>");
5771fec7c66SAlessandro Zummo MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
5781fec7c66SAlessandro Zummo MODULE_LICENSE("GPL");
5791fec7c66SAlessandro Zummo MODULE_VERSION(DRV_VERSION);
5801fec7c66SAlessandro Zummo 
5811fec7c66SAlessandro Zummo module_init(x1205_init);
5821fec7c66SAlessandro Zummo module_exit(x1205_exit);
583