xref: /linux/drivers/rtc/rtc-x1205.c (revision fe20ba70abf7d6e5855c3dacc729490b3d0d077f)
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 */
74471d47e3SMichael Hamel #define X1205_SR_AL0		0x20	/* Alarm 0 match */
751fec7c66SAlessandro Zummo 
761fec7c66SAlessandro Zummo #define X1205_DTR_DTR0		0x01
771fec7c66SAlessandro Zummo #define X1205_DTR_DTR1		0x02
781fec7c66SAlessandro Zummo #define X1205_DTR_DTR2		0x04
791fec7c66SAlessandro Zummo 
801fec7c66SAlessandro Zummo #define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
811fec7c66SAlessandro Zummo 
82471d47e3SMichael Hamel #define X1205_INT_AL0E		0x20	/* Alarm 0 enable */
83471d47e3SMichael Hamel 
844edac2b4SAlessandro Zummo static struct i2c_driver x1205_driver;
851fec7c66SAlessandro Zummo 
861fec7c66SAlessandro Zummo /*
871fec7c66SAlessandro Zummo  * In the routines that deal directly with the x1205 hardware, we use
881fec7c66SAlessandro Zummo  * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
891fec7c66SAlessandro Zummo  * Epoch is initialized as 2000. Time is set to UTC.
901fec7c66SAlessandro Zummo  */
911fec7c66SAlessandro Zummo static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
921fec7c66SAlessandro Zummo 				unsigned char reg_base)
931fec7c66SAlessandro Zummo {
941fec7c66SAlessandro Zummo 	unsigned char dt_addr[2] = { 0, reg_base };
951fec7c66SAlessandro Zummo 	unsigned char buf[8];
96471d47e3SMichael Hamel 	int i;
971fec7c66SAlessandro Zummo 
981fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
991fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
1001fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
1011fec7c66SAlessandro Zummo 	};
1021fec7c66SAlessandro Zummo 
1031fec7c66SAlessandro Zummo 	/* read date registers */
104471d47e3SMichael Hamel 	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
1052a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
1061fec7c66SAlessandro Zummo 		return -EIO;
1071fec7c66SAlessandro Zummo 	}
1081fec7c66SAlessandro Zummo 
1091fec7c66SAlessandro Zummo 	dev_dbg(&client->dev,
1101fec7c66SAlessandro Zummo 		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
1111fec7c66SAlessandro Zummo 		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
1122a4e2b87SHarvey Harrison 		__func__,
1131fec7c66SAlessandro Zummo 		buf[0], buf[1], buf[2], buf[3],
1141fec7c66SAlessandro Zummo 		buf[4], buf[5], buf[6], buf[7]);
1151fec7c66SAlessandro Zummo 
116471d47e3SMichael Hamel 	/* Mask out the enable bits if these are alarm registers */
117471d47e3SMichael Hamel 	if (reg_base < X1205_CCR_BASE)
118471d47e3SMichael Hamel 		for (i = 0; i <= 4; i++)
119471d47e3SMichael Hamel 			buf[i] &= 0x7F;
120471d47e3SMichael Hamel 
121*fe20ba70SAdrian Bunk 	tm->tm_sec = bcd2bin(buf[CCR_SEC]);
122*fe20ba70SAdrian Bunk 	tm->tm_min = bcd2bin(buf[CCR_MIN]);
123*fe20ba70SAdrian Bunk 	tm->tm_hour = bcd2bin(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
124*fe20ba70SAdrian Bunk 	tm->tm_mday = bcd2bin(buf[CCR_MDAY]);
125*fe20ba70SAdrian Bunk 	tm->tm_mon = bcd2bin(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
126*fe20ba70SAdrian Bunk 	tm->tm_year = bcd2bin(buf[CCR_YEAR])
127*fe20ba70SAdrian Bunk 			+ (bcd2bin(buf[CCR_Y2K]) * 100) - 1900;
1281fec7c66SAlessandro Zummo 	tm->tm_wday = buf[CCR_WDAY];
1291fec7c66SAlessandro Zummo 
1301fec7c66SAlessandro Zummo 	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
1311fec7c66SAlessandro Zummo 		"mday=%d, mon=%d, year=%d, wday=%d\n",
1322a4e2b87SHarvey Harrison 		__func__,
1331fec7c66SAlessandro Zummo 		tm->tm_sec, tm->tm_min, tm->tm_hour,
1341fec7c66SAlessandro Zummo 		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
1351fec7c66SAlessandro Zummo 
1361fec7c66SAlessandro Zummo 	return 0;
1371fec7c66SAlessandro Zummo }
1381fec7c66SAlessandro Zummo 
1391fec7c66SAlessandro Zummo static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
1401fec7c66SAlessandro Zummo {
1411fec7c66SAlessandro Zummo 	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
1421fec7c66SAlessandro Zummo 
1431fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
1441fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
1451fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, sr },	/* read status */
1461fec7c66SAlessandro Zummo 	};
1471fec7c66SAlessandro Zummo 
1481fec7c66SAlessandro Zummo 	/* read status register */
149471d47e3SMichael Hamel 	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
1502a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
1511fec7c66SAlessandro Zummo 		return -EIO;
1521fec7c66SAlessandro Zummo 	}
1531fec7c66SAlessandro Zummo 
1541fec7c66SAlessandro Zummo 	return 0;
1551fec7c66SAlessandro Zummo }
1561fec7c66SAlessandro Zummo 
1571fec7c66SAlessandro Zummo static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
158471d47e3SMichael Hamel 			int datetoo, u8 reg_base, unsigned char alm_enable)
1591fec7c66SAlessandro Zummo {
160471d47e3SMichael Hamel 	int i, xfer, nbytes;
1611fec7c66SAlessandro Zummo 	unsigned char buf[8];
162471d47e3SMichael Hamel 	unsigned char rdata[10] = { 0, reg_base };
1631fec7c66SAlessandro Zummo 
1641fec7c66SAlessandro Zummo 	static const unsigned char wel[3] = { 0, X1205_REG_SR,
1651fec7c66SAlessandro Zummo 						X1205_SR_WEL };
1661fec7c66SAlessandro Zummo 
1671fec7c66SAlessandro Zummo 	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
1681fec7c66SAlessandro Zummo 						X1205_SR_WEL | X1205_SR_RWEL };
1691fec7c66SAlessandro Zummo 
1701fec7c66SAlessandro Zummo 	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
1711fec7c66SAlessandro Zummo 
1721fec7c66SAlessandro Zummo 	dev_dbg(&client->dev,
1731fec7c66SAlessandro Zummo 		"%s: secs=%d, mins=%d, hours=%d\n",
1742a4e2b87SHarvey Harrison 		__func__,
1751fec7c66SAlessandro Zummo 		tm->tm_sec, tm->tm_min, tm->tm_hour);
1761fec7c66SAlessandro Zummo 
177*fe20ba70SAdrian Bunk 	buf[CCR_SEC] = bin2bcd(tm->tm_sec);
178*fe20ba70SAdrian Bunk 	buf[CCR_MIN] = bin2bcd(tm->tm_min);
1791fec7c66SAlessandro Zummo 
1801fec7c66SAlessandro Zummo 	/* set hour and 24hr bit */
181*fe20ba70SAdrian Bunk 	buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL;
1821fec7c66SAlessandro Zummo 
1831fec7c66SAlessandro Zummo 	/* should we also set the date? */
1841fec7c66SAlessandro Zummo 	if (datetoo) {
1851fec7c66SAlessandro Zummo 		dev_dbg(&client->dev,
1861fec7c66SAlessandro Zummo 			"%s: mday=%d, mon=%d, year=%d, wday=%d\n",
1872a4e2b87SHarvey Harrison 			__func__,
1881fec7c66SAlessandro Zummo 			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
1891fec7c66SAlessandro Zummo 
190*fe20ba70SAdrian Bunk 		buf[CCR_MDAY] = bin2bcd(tm->tm_mday);
1911fec7c66SAlessandro Zummo 
1921fec7c66SAlessandro Zummo 		/* month, 1 - 12 */
193*fe20ba70SAdrian Bunk 		buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1);
1941fec7c66SAlessandro Zummo 
1951fec7c66SAlessandro Zummo 		/* year, since the rtc epoch*/
196*fe20ba70SAdrian Bunk 		buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100);
1971fec7c66SAlessandro Zummo 		buf[CCR_WDAY] = tm->tm_wday & 0x07;
198*fe20ba70SAdrian Bunk 		buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100);
1991fec7c66SAlessandro Zummo 	}
2001fec7c66SAlessandro Zummo 
201471d47e3SMichael Hamel 	/* If writing alarm registers, set compare bits on registers 0-4 */
202471d47e3SMichael Hamel 	if (reg_base < X1205_CCR_BASE)
203471d47e3SMichael Hamel 		for (i = 0; i <= 4; i++)
204471d47e3SMichael Hamel 			buf[i] |= 0x80;
205471d47e3SMichael Hamel 
2061fec7c66SAlessandro Zummo 	/* this sequence is required to unlock the chip */
2071fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
2082a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
2091fec7c66SAlessandro Zummo 		return -EIO;
2101fec7c66SAlessandro Zummo 	}
2111fec7c66SAlessandro Zummo 
2121fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
2132a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer);
2141fec7c66SAlessandro Zummo 		return -EIO;
2151fec7c66SAlessandro Zummo 	}
2161fec7c66SAlessandro Zummo 
2171fec7c66SAlessandro Zummo 
218471d47e3SMichael Hamel 	/* write register's data */
219471d47e3SMichael Hamel 	if (datetoo)
220471d47e3SMichael Hamel 		nbytes = 8;
221471d47e3SMichael Hamel 	else
222471d47e3SMichael Hamel 		nbytes = 3;
223471d47e3SMichael Hamel 	for (i = 0; i < nbytes; i++)
224471d47e3SMichael Hamel 		rdata[2+i] = buf[i];
225471d47e3SMichael Hamel 
226471d47e3SMichael Hamel 	xfer = i2c_master_send(client, rdata, nbytes+2);
227471d47e3SMichael Hamel 	if (xfer != nbytes+2) {
2281fec7c66SAlessandro Zummo 		dev_err(&client->dev,
229471d47e3SMichael Hamel 			"%s: result=%d addr=%02x, data=%02x\n",
2302a4e2b87SHarvey Harrison 			__func__,
2311fec7c66SAlessandro Zummo 			 xfer, rdata[1], rdata[2]);
2321fec7c66SAlessandro Zummo 		return -EIO;
2331fec7c66SAlessandro Zummo 	}
234471d47e3SMichael Hamel 
235471d47e3SMichael Hamel 	/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
236471d47e3SMichael Hamel 	if (reg_base < X1205_CCR_BASE) {
237471d47e3SMichael Hamel 		unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
238471d47e3SMichael Hamel 
239471d47e3SMichael Hamel 		msleep(10);
240471d47e3SMichael Hamel 
241471d47e3SMichael Hamel 		/* ...and set or clear the AL0E bit in the INT register */
242471d47e3SMichael Hamel 
243471d47e3SMichael Hamel 		/* Need to set RWEL again as the write has cleared it */
244471d47e3SMichael Hamel 		xfer = i2c_master_send(client, rwel, 3);
245471d47e3SMichael Hamel 		if (xfer != 3) {
246471d47e3SMichael Hamel 			dev_err(&client->dev,
247471d47e3SMichael Hamel 				"%s: aloe rwel - %d\n",
248471d47e3SMichael Hamel 				__func__,
249471d47e3SMichael Hamel 				xfer);
250471d47e3SMichael Hamel 			return -EIO;
251471d47e3SMichael Hamel 		}
252471d47e3SMichael Hamel 
253471d47e3SMichael Hamel 		if (alm_enable)
254471d47e3SMichael Hamel 			al0e[2] = X1205_INT_AL0E;
255471d47e3SMichael Hamel 
256471d47e3SMichael Hamel 		xfer = i2c_master_send(client, al0e, 3);
257471d47e3SMichael Hamel 		if (xfer != 3) {
258471d47e3SMichael Hamel 			dev_err(&client->dev,
259471d47e3SMichael Hamel 				"%s: al0e - %d\n",
260471d47e3SMichael Hamel 				__func__,
261471d47e3SMichael Hamel 				xfer);
262471d47e3SMichael Hamel 			return -EIO;
263471d47e3SMichael Hamel 		}
264471d47e3SMichael Hamel 
265471d47e3SMichael Hamel 		/* and wait 10msec again for this write to complete */
266471d47e3SMichael Hamel 		msleep(10);
267471d47e3SMichael Hamel 	}
2681fec7c66SAlessandro Zummo 
2691fec7c66SAlessandro Zummo 	/* disable further writes */
2701fec7c66SAlessandro Zummo 	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
2712a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer);
2721fec7c66SAlessandro Zummo 		return -EIO;
2731fec7c66SAlessandro Zummo 	}
2741fec7c66SAlessandro Zummo 
2751fec7c66SAlessandro Zummo 	return 0;
2761fec7c66SAlessandro Zummo }
2771fec7c66SAlessandro Zummo 
2781fec7c66SAlessandro Zummo static int x1205_fix_osc(struct i2c_client *client)
2791fec7c66SAlessandro Zummo {
2801fec7c66SAlessandro Zummo 	int err;
2811fec7c66SAlessandro Zummo 	struct rtc_time tm;
2821fec7c66SAlessandro Zummo 
2831fec7c66SAlessandro Zummo 	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
2841fec7c66SAlessandro Zummo 
285471d47e3SMichael Hamel 	err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
286471d47e3SMichael Hamel 	if (err < 0)
287471d47e3SMichael Hamel 		dev_err(&client->dev, "unable to restart the oscillator\n");
2881fec7c66SAlessandro Zummo 
2891fec7c66SAlessandro Zummo 	return err;
2901fec7c66SAlessandro Zummo }
2911fec7c66SAlessandro Zummo 
2921fec7c66SAlessandro Zummo static int x1205_get_dtrim(struct i2c_client *client, int *trim)
2931fec7c66SAlessandro Zummo {
2941fec7c66SAlessandro Zummo 	unsigned char dtr;
2951fec7c66SAlessandro Zummo 	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
2961fec7c66SAlessandro Zummo 
2971fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
2981fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
2991fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
3001fec7c66SAlessandro Zummo 	};
3011fec7c66SAlessandro Zummo 
3021fec7c66SAlessandro Zummo 	/* read dtr register */
303471d47e3SMichael Hamel 	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
3042a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
3051fec7c66SAlessandro Zummo 		return -EIO;
3061fec7c66SAlessandro Zummo 	}
3071fec7c66SAlessandro Zummo 
3082a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __func__, dtr);
3091fec7c66SAlessandro Zummo 
3101fec7c66SAlessandro Zummo 	*trim = 0;
3111fec7c66SAlessandro Zummo 
3121fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR0)
3131fec7c66SAlessandro Zummo 		*trim += 20;
3141fec7c66SAlessandro Zummo 
3151fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR1)
3161fec7c66SAlessandro Zummo 		*trim += 10;
3171fec7c66SAlessandro Zummo 
3181fec7c66SAlessandro Zummo 	if (dtr & X1205_DTR_DTR2)
3191fec7c66SAlessandro Zummo 		*trim = -*trim;
3201fec7c66SAlessandro Zummo 
3211fec7c66SAlessandro Zummo 	return 0;
3221fec7c66SAlessandro Zummo }
3231fec7c66SAlessandro Zummo 
3241fec7c66SAlessandro Zummo static int x1205_get_atrim(struct i2c_client *client, int *trim)
3251fec7c66SAlessandro Zummo {
3261fec7c66SAlessandro Zummo 	s8 atr;
3271fec7c66SAlessandro Zummo 	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
3281fec7c66SAlessandro Zummo 
3291fec7c66SAlessandro Zummo 	struct i2c_msg msgs[] = {
3301fec7c66SAlessandro Zummo 		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
3311fec7c66SAlessandro Zummo 		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
3321fec7c66SAlessandro Zummo 	};
3331fec7c66SAlessandro Zummo 
3341fec7c66SAlessandro Zummo 	/* read atr register */
335471d47e3SMichael Hamel 	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
3362a4e2b87SHarvey Harrison 		dev_err(&client->dev, "%s: read error\n", __func__);
3371fec7c66SAlessandro Zummo 		return -EIO;
3381fec7c66SAlessandro Zummo 	}
3391fec7c66SAlessandro Zummo 
3402a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw atr=%x\n", __func__, atr);
3411fec7c66SAlessandro Zummo 
3421fec7c66SAlessandro Zummo 	/* atr is a two's complement value on 6 bits,
3431fec7c66SAlessandro Zummo 	 * perform sign extension. The formula is
3441fec7c66SAlessandro Zummo 	 * Catr = (atr * 0.25pF) + 11.00pF.
3451fec7c66SAlessandro Zummo 	 */
3461fec7c66SAlessandro Zummo 	if (atr & 0x20)
3471fec7c66SAlessandro Zummo 		atr |= 0xC0;
3481fec7c66SAlessandro Zummo 
3492a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __func__, atr, atr);
3501fec7c66SAlessandro Zummo 
3511fec7c66SAlessandro Zummo 	*trim = (atr * 250) + 11000;
3521fec7c66SAlessandro Zummo 
3532a4e2b87SHarvey Harrison 	dev_dbg(&client->dev, "%s: real=%d\n", __func__, *trim);
3541fec7c66SAlessandro Zummo 
3551fec7c66SAlessandro Zummo 	return 0;
3561fec7c66SAlessandro Zummo }
3571fec7c66SAlessandro Zummo 
3581fec7c66SAlessandro Zummo struct x1205_limit
3591fec7c66SAlessandro Zummo {
3601fec7c66SAlessandro Zummo 	unsigned char reg, mask, min, max;
3611fec7c66SAlessandro Zummo };
3621fec7c66SAlessandro Zummo 
3631fec7c66SAlessandro Zummo static int x1205_validate_client(struct i2c_client *client)
3641fec7c66SAlessandro Zummo {
3651fec7c66SAlessandro Zummo 	int i, xfer;
3661fec7c66SAlessandro Zummo 
3671fec7c66SAlessandro Zummo 	/* Probe array. We will read the register at the specified
3681fec7c66SAlessandro Zummo 	 * address and check if the given bits are zero.
3691fec7c66SAlessandro Zummo 	 */
3701fec7c66SAlessandro Zummo 	static const unsigned char probe_zero_pattern[] = {
3711fec7c66SAlessandro Zummo 		/* register, mask */
3721fec7c66SAlessandro Zummo 		X1205_REG_SR,	0x18,
3731fec7c66SAlessandro Zummo 		X1205_REG_DTR,	0xF8,
3741fec7c66SAlessandro Zummo 		X1205_REG_ATR,	0xC0,
3751fec7c66SAlessandro Zummo 		X1205_REG_INT,	0x18,
3761fec7c66SAlessandro Zummo 		X1205_REG_0,	0xFF,
3771fec7c66SAlessandro Zummo 	};
3781fec7c66SAlessandro Zummo 
3791fec7c66SAlessandro Zummo 	static const struct x1205_limit probe_limits_pattern[] = {
3801fec7c66SAlessandro Zummo 		/* register, mask, min, max */
3811fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K,	0xFF,	19,	20	},
3821fec7c66SAlessandro Zummo 		{ X1205_REG_DW,		0xFF,	0,	6	},
3831fec7c66SAlessandro Zummo 		{ X1205_REG_YR,		0xFF,	0,	99	},
3841fec7c66SAlessandro Zummo 		{ X1205_REG_MO,		0xFF,	0,	12	},
3851fec7c66SAlessandro Zummo 		{ X1205_REG_DT,		0xFF,	0,	31	},
3861fec7c66SAlessandro Zummo 		{ X1205_REG_HR,		0x7F,	0,	23	},
3871fec7c66SAlessandro Zummo 		{ X1205_REG_MN,		0xFF,	0,	59	},
3881fec7c66SAlessandro Zummo 		{ X1205_REG_SC,		0xFF,	0,	59	},
3891fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
3901fec7c66SAlessandro Zummo 		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
3911fec7c66SAlessandro Zummo 	};
3921fec7c66SAlessandro Zummo 
3931fec7c66SAlessandro Zummo 	/* check that registers have bits a 0 where expected */
3941fec7c66SAlessandro Zummo 	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
3951fec7c66SAlessandro Zummo 		unsigned char buf;
3961fec7c66SAlessandro Zummo 
3971fec7c66SAlessandro Zummo 		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
3981fec7c66SAlessandro Zummo 
3991fec7c66SAlessandro Zummo 		struct i2c_msg msgs[2] = {
4001fec7c66SAlessandro Zummo 			{ client->addr, 0, 2, addr },
4011fec7c66SAlessandro Zummo 			{ client->addr, I2C_M_RD, 1, &buf },
4021fec7c66SAlessandro Zummo 		};
4031fec7c66SAlessandro Zummo 
4041fec7c66SAlessandro Zummo 		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
405a14e1893SDavid Brownell 			dev_err(&client->dev,
4061fec7c66SAlessandro Zummo 				"%s: could not read register %x\n",
4072a4e2b87SHarvey Harrison 				__func__, probe_zero_pattern[i]);
4081fec7c66SAlessandro Zummo 
4091fec7c66SAlessandro Zummo 			return -EIO;
4101fec7c66SAlessandro Zummo 		}
4111fec7c66SAlessandro Zummo 
4121fec7c66SAlessandro Zummo 		if ((buf & probe_zero_pattern[i+1]) != 0) {
413a14e1893SDavid Brownell 			dev_err(&client->dev,
4141fec7c66SAlessandro Zummo 				"%s: register=%02x, zero pattern=%d, value=%x\n",
4152a4e2b87SHarvey Harrison 				__func__, probe_zero_pattern[i], i, buf);
4161fec7c66SAlessandro Zummo 
4171fec7c66SAlessandro Zummo 			return -ENODEV;
4181fec7c66SAlessandro Zummo 		}
4191fec7c66SAlessandro Zummo 	}
4201fec7c66SAlessandro Zummo 
4211fec7c66SAlessandro Zummo 	/* check limits (only registers with bcd values) */
4221fec7c66SAlessandro Zummo 	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
4231fec7c66SAlessandro Zummo 		unsigned char reg, value;
4241fec7c66SAlessandro Zummo 
4251fec7c66SAlessandro Zummo 		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
4261fec7c66SAlessandro Zummo 
4271fec7c66SAlessandro Zummo 		struct i2c_msg msgs[2] = {
4281fec7c66SAlessandro Zummo 			{ client->addr, 0, 2, addr },
4291fec7c66SAlessandro Zummo 			{ client->addr, I2C_M_RD, 1, &reg },
4301fec7c66SAlessandro Zummo 		};
4311fec7c66SAlessandro Zummo 
4321fec7c66SAlessandro Zummo 		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
433a14e1893SDavid Brownell 			dev_err(&client->dev,
4341fec7c66SAlessandro Zummo 				"%s: could not read register %x\n",
4352a4e2b87SHarvey Harrison 				__func__, probe_limits_pattern[i].reg);
4361fec7c66SAlessandro Zummo 
4371fec7c66SAlessandro Zummo 			return -EIO;
4381fec7c66SAlessandro Zummo 		}
4391fec7c66SAlessandro Zummo 
440*fe20ba70SAdrian Bunk 		value = bcd2bin(reg & probe_limits_pattern[i].mask);
4411fec7c66SAlessandro Zummo 
4421fec7c66SAlessandro Zummo 		if (value > probe_limits_pattern[i].max ||
4431fec7c66SAlessandro Zummo 			value < probe_limits_pattern[i].min) {
444a14e1893SDavid Brownell 			dev_dbg(&client->dev,
4451fec7c66SAlessandro Zummo 				"%s: register=%x, lim pattern=%d, value=%d\n",
4462a4e2b87SHarvey Harrison 				__func__, probe_limits_pattern[i].reg,
4471fec7c66SAlessandro Zummo 				i, value);
4481fec7c66SAlessandro Zummo 
4491fec7c66SAlessandro Zummo 			return -ENODEV;
4501fec7c66SAlessandro Zummo 		}
4511fec7c66SAlessandro Zummo 	}
4521fec7c66SAlessandro Zummo 
4531fec7c66SAlessandro Zummo 	return 0;
4541fec7c66SAlessandro Zummo }
4551fec7c66SAlessandro Zummo 
4561fec7c66SAlessandro Zummo static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
4571fec7c66SAlessandro Zummo {
458471d47e3SMichael Hamel 	int err;
459471d47e3SMichael Hamel 	unsigned char intreg, status;
460471d47e3SMichael Hamel 	static unsigned char int_addr[2] = { 0, X1205_REG_INT };
461471d47e3SMichael Hamel 	struct i2c_client *client = to_i2c_client(dev);
462471d47e3SMichael Hamel 	struct i2c_msg msgs[] = {
463471d47e3SMichael Hamel 		{ client->addr, 0, 2, int_addr },        /* setup read ptr */
464471d47e3SMichael Hamel 		{ client->addr, I2C_M_RD, 1, &intreg },  /* read INT register */
465471d47e3SMichael Hamel 	};
466471d47e3SMichael Hamel 
467471d47e3SMichael Hamel 	/* read interrupt register and status register */
468471d47e3SMichael Hamel 	if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
469471d47e3SMichael Hamel 		dev_err(&client->dev, "%s: read error\n", __func__);
470471d47e3SMichael Hamel 		return -EIO;
471471d47e3SMichael Hamel 	}
472471d47e3SMichael Hamel 	err = x1205_get_status(client, &status);
473471d47e3SMichael Hamel 	if (err == 0) {
474471d47e3SMichael Hamel 		alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
475471d47e3SMichael Hamel 		alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
476471d47e3SMichael Hamel 		err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
477471d47e3SMichael Hamel 	}
478471d47e3SMichael Hamel 	return err;
4791fec7c66SAlessandro Zummo }
4801fec7c66SAlessandro Zummo 
4811fec7c66SAlessandro Zummo static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
4821fec7c66SAlessandro Zummo {
4831fec7c66SAlessandro Zummo 	return x1205_set_datetime(to_i2c_client(dev),
484471d47e3SMichael Hamel 		&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
4851fec7c66SAlessandro Zummo }
4861fec7c66SAlessandro Zummo 
4871fec7c66SAlessandro Zummo static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
4881fec7c66SAlessandro Zummo {
4891fec7c66SAlessandro Zummo 	return x1205_get_datetime(to_i2c_client(dev),
4901fec7c66SAlessandro Zummo 		tm, X1205_CCR_BASE);
4911fec7c66SAlessandro Zummo }
4921fec7c66SAlessandro Zummo 
4931fec7c66SAlessandro Zummo static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
4941fec7c66SAlessandro Zummo {
4951fec7c66SAlessandro Zummo 	return x1205_set_datetime(to_i2c_client(dev),
496471d47e3SMichael Hamel 		tm, 1, X1205_CCR_BASE, 0);
4971fec7c66SAlessandro Zummo }
4981fec7c66SAlessandro Zummo 
4991fec7c66SAlessandro Zummo static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
5001fec7c66SAlessandro Zummo {
5011fec7c66SAlessandro Zummo 	int err, dtrim, atrim;
5021fec7c66SAlessandro Zummo 
5031fec7c66SAlessandro Zummo 	if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
5041fec7c66SAlessandro Zummo 		seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
5051fec7c66SAlessandro Zummo 
5061fec7c66SAlessandro Zummo 	if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
5071fec7c66SAlessandro Zummo 		seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
5081fec7c66SAlessandro Zummo 			atrim / 1000, atrim % 1000);
5091fec7c66SAlessandro Zummo 	return 0;
5101fec7c66SAlessandro Zummo }
5111fec7c66SAlessandro Zummo 
512ff8371acSDavid Brownell static const struct rtc_class_ops x1205_rtc_ops = {
5131fec7c66SAlessandro Zummo 	.proc		= x1205_rtc_proc,
5141fec7c66SAlessandro Zummo 	.read_time	= x1205_rtc_read_time,
5151fec7c66SAlessandro Zummo 	.set_time	= x1205_rtc_set_time,
5161fec7c66SAlessandro Zummo 	.read_alarm	= x1205_rtc_read_alarm,
5171fec7c66SAlessandro Zummo 	.set_alarm	= x1205_rtc_set_alarm,
5181fec7c66SAlessandro Zummo };
5191fec7c66SAlessandro Zummo 
5201fec7c66SAlessandro Zummo static ssize_t x1205_sysfs_show_atrim(struct device *dev,
5211fec7c66SAlessandro Zummo 				struct device_attribute *attr, char *buf)
5221fec7c66SAlessandro Zummo {
523015aefbbSAlessandro Zummo 	int err, atrim;
5241fec7c66SAlessandro Zummo 
525015aefbbSAlessandro Zummo 	err = x1205_get_atrim(to_i2c_client(dev), &atrim);
526015aefbbSAlessandro Zummo 	if (err)
527015aefbbSAlessandro Zummo 		return err;
528015aefbbSAlessandro Zummo 
529015aefbbSAlessandro Zummo 	return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000);
5301fec7c66SAlessandro Zummo }
5311fec7c66SAlessandro Zummo static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
5321fec7c66SAlessandro Zummo 
5331fec7c66SAlessandro Zummo static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
5341fec7c66SAlessandro Zummo 				struct device_attribute *attr, char *buf)
5351fec7c66SAlessandro Zummo {
536015aefbbSAlessandro Zummo 	int err, dtrim;
5371fec7c66SAlessandro Zummo 
538015aefbbSAlessandro Zummo 	err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
539015aefbbSAlessandro Zummo 	if (err)
540015aefbbSAlessandro Zummo 		return err;
541015aefbbSAlessandro Zummo 
5421fec7c66SAlessandro Zummo 	return sprintf(buf, "%d ppm\n", dtrim);
5431fec7c66SAlessandro Zummo }
5441fec7c66SAlessandro Zummo static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
5451fec7c66SAlessandro Zummo 
5464edac2b4SAlessandro Zummo static int x1205_sysfs_register(struct device *dev)
5471fec7c66SAlessandro Zummo {
5484edac2b4SAlessandro Zummo 	int err;
5494edac2b4SAlessandro Zummo 
5504edac2b4SAlessandro Zummo 	err = device_create_file(dev, &dev_attr_atrim);
5514edac2b4SAlessandro Zummo 	if (err)
5524edac2b4SAlessandro Zummo 		return err;
5534edac2b4SAlessandro Zummo 
5544edac2b4SAlessandro Zummo 	err = device_create_file(dev, &dev_attr_dtrim);
5554edac2b4SAlessandro Zummo 	if (err)
5564edac2b4SAlessandro Zummo 		device_remove_file(dev, &dev_attr_atrim);
5574edac2b4SAlessandro Zummo 
5584edac2b4SAlessandro Zummo 	return err;
5591fec7c66SAlessandro Zummo }
5601fec7c66SAlessandro Zummo 
5614edac2b4SAlessandro Zummo static void x1205_sysfs_unregister(struct device *dev)
5624edac2b4SAlessandro Zummo {
5634edac2b4SAlessandro Zummo 	device_remove_file(dev, &dev_attr_atrim);
5644edac2b4SAlessandro Zummo 	device_remove_file(dev, &dev_attr_dtrim);
5654edac2b4SAlessandro Zummo }
5664edac2b4SAlessandro Zummo 
5674edac2b4SAlessandro Zummo 
568d2653e92SJean Delvare static int x1205_probe(struct i2c_client *client,
569d2653e92SJean Delvare 			const struct i2c_device_id *id)
5701fec7c66SAlessandro Zummo {
5711fec7c66SAlessandro Zummo 	int err = 0;
5721fec7c66SAlessandro Zummo 	unsigned char sr;
5731fec7c66SAlessandro Zummo 	struct rtc_device *rtc;
5741fec7c66SAlessandro Zummo 
5754edac2b4SAlessandro Zummo 	dev_dbg(&client->dev, "%s\n", __func__);
5761fec7c66SAlessandro Zummo 
5774edac2b4SAlessandro Zummo 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
5784edac2b4SAlessandro Zummo 		return -ENODEV;
5791fec7c66SAlessandro Zummo 
5804edac2b4SAlessandro Zummo 	if (x1205_validate_client(client) < 0)
5814edac2b4SAlessandro Zummo 		return -ENODEV;
5821fec7c66SAlessandro Zummo 
5831fec7c66SAlessandro Zummo 	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
5841fec7c66SAlessandro Zummo 
5851fec7c66SAlessandro Zummo 	rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
5861fec7c66SAlessandro Zummo 				&x1205_rtc_ops, THIS_MODULE);
5871fec7c66SAlessandro Zummo 
5884edac2b4SAlessandro Zummo 	if (IS_ERR(rtc))
5894edac2b4SAlessandro Zummo 		return PTR_ERR(rtc);
5901fec7c66SAlessandro Zummo 
5911fec7c66SAlessandro Zummo 	i2c_set_clientdata(client, rtc);
5921fec7c66SAlessandro Zummo 
5931fec7c66SAlessandro Zummo 	/* Check for power failures and eventualy enable the osc */
5941fec7c66SAlessandro Zummo 	if ((err = x1205_get_status(client, &sr)) == 0) {
5951fec7c66SAlessandro Zummo 		if (sr & X1205_SR_RTCF) {
5961fec7c66SAlessandro Zummo 			dev_err(&client->dev,
5971fec7c66SAlessandro Zummo 				"power failure detected, "
5981fec7c66SAlessandro Zummo 				"please set the clock\n");
5991fec7c66SAlessandro Zummo 			udelay(50);
6001fec7c66SAlessandro Zummo 			x1205_fix_osc(client);
6011fec7c66SAlessandro Zummo 		}
6021fec7c66SAlessandro Zummo 	}
6031fec7c66SAlessandro Zummo 	else
6041fec7c66SAlessandro Zummo 		dev_err(&client->dev, "couldn't read status\n");
6051fec7c66SAlessandro Zummo 
6064edac2b4SAlessandro Zummo 	err = x1205_sysfs_register(&client->dev);
6074edac2b4SAlessandro Zummo 	if (err)
6084edac2b4SAlessandro Zummo 		goto exit_devreg;
6091fec7c66SAlessandro Zummo 
6101fec7c66SAlessandro Zummo 	return 0;
6111fec7c66SAlessandro Zummo 
61291046a8aSJeff Garzik exit_devreg:
61391046a8aSJeff Garzik 	rtc_device_unregister(rtc);
61491046a8aSJeff Garzik 
6151fec7c66SAlessandro Zummo 	return err;
6161fec7c66SAlessandro Zummo }
6171fec7c66SAlessandro Zummo 
6184edac2b4SAlessandro Zummo static int x1205_remove(struct i2c_client *client)
6191fec7c66SAlessandro Zummo {
6201fec7c66SAlessandro Zummo 	struct rtc_device *rtc = i2c_get_clientdata(client);
6211fec7c66SAlessandro Zummo 
6221fec7c66SAlessandro Zummo 	rtc_device_unregister(rtc);
6234edac2b4SAlessandro Zummo 	x1205_sysfs_unregister(&client->dev);
6241fec7c66SAlessandro Zummo 	return 0;
6251fec7c66SAlessandro Zummo }
6261fec7c66SAlessandro Zummo 
6273760f736SJean Delvare static const struct i2c_device_id x1205_id[] = {
6283760f736SJean Delvare 	{ "x1205", 0 },
6293760f736SJean Delvare 	{ }
6303760f736SJean Delvare };
6313760f736SJean Delvare MODULE_DEVICE_TABLE(i2c, x1205_id);
6323760f736SJean Delvare 
6334edac2b4SAlessandro Zummo static struct i2c_driver x1205_driver = {
6344edac2b4SAlessandro Zummo 	.driver		= {
6354edac2b4SAlessandro Zummo 		.name	= "rtc-x1205",
6364edac2b4SAlessandro Zummo 	},
6374edac2b4SAlessandro Zummo 	.probe		= x1205_probe,
6384edac2b4SAlessandro Zummo 	.remove		= x1205_remove,
6393760f736SJean Delvare 	.id_table	= x1205_id,
6404edac2b4SAlessandro Zummo };
6414edac2b4SAlessandro Zummo 
6421fec7c66SAlessandro Zummo static int __init x1205_init(void)
6431fec7c66SAlessandro Zummo {
6441fec7c66SAlessandro Zummo 	return i2c_add_driver(&x1205_driver);
6451fec7c66SAlessandro Zummo }
6461fec7c66SAlessandro Zummo 
6471fec7c66SAlessandro Zummo static void __exit x1205_exit(void)
6481fec7c66SAlessandro Zummo {
6491fec7c66SAlessandro Zummo 	i2c_del_driver(&x1205_driver);
6501fec7c66SAlessandro Zummo }
6511fec7c66SAlessandro Zummo 
6521fec7c66SAlessandro Zummo MODULE_AUTHOR(
6531fec7c66SAlessandro Zummo 	"Karen Spearel <kas111 at gmail dot com>, "
6541fec7c66SAlessandro Zummo 	"Alessandro Zummo <a.zummo@towertech.it>");
6551fec7c66SAlessandro Zummo MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
6561fec7c66SAlessandro Zummo MODULE_LICENSE("GPL");
6571fec7c66SAlessandro Zummo MODULE_VERSION(DRV_VERSION);
6581fec7c66SAlessandro Zummo 
6591fec7c66SAlessandro Zummo module_init(x1205_init);
6601fec7c66SAlessandro Zummo module_exit(x1205_exit);
661