Re: RTC: add RTC class interface to m41t00 driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 04 Aug 2006 00:21:46 +0900 (JST), Atsushi Nemoto <[email protected]> wrote:
> Hi.  I added new RTC class interface to existing m41t00 driver.  I
> used CONFIG_GEN_RTC for traditional interface and CONFIG_RTC_CLASS for
> new interface.  It should work with any platform not only for PPC32.

Oops, It can not compiled on archs which do not have asm/time.h.
Revised.


Signed-off-by: Atsushi Nemoto <[email protected]>

diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 87ee3ce..2cc48d2 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -103,7 +103,7 @@ config TPS65010
 
 config SENSORS_M41T00
 	tristate "ST M41T00 RTC chip"
-	depends on I2C && PPC32
+	depends on I2C
 	help
 	  If you say yes here you get support for the ST M41T00 RTC chip.
 
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
index 2dd0a34..9c58f59 100644
--- a/drivers/i2c/chips/m41t00.c
+++ b/drivers/i2c/chips/m41t00.c
@@ -10,7 +10,7 @@
  */
 /*
  * This i2c client/driver wedges between the drivers/char/genrtc.c RTC
- * interface and the SMBus interface of the i2c subsystem.
+ * (and/or RTC class) interface and the SMBus interface of the i2c subsystem.
  */
 
 #include <linux/kernel.h>
@@ -22,11 +22,12 @@ #include <linux/bcd.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/m41t00.h>
-#include <asm/time.h>
 #include <asm/rtc.h>
 
 static struct i2c_driver m41t00_driver;
+#if defined(CONFIG_GEN_RTC) && defined(CONFIG_GEN_RTC_MODULE)
 static struct i2c_client *save_client;
+#endif
 
 static unsigned short ignore[] = { I2C_CLIENT_END };
 static unsigned short normal_addr[] = { I2C_CLIENT_END, I2C_CLIENT_END };
@@ -96,8 +97,8 @@ static struct m41t00_chip_info m41t00_ch
 };
 static struct m41t00_chip_info *m41t00_chip;
 
-ulong
-m41t00_get_rtc_time(void)
+static int
+m41t00_get_time(struct i2c_client *client, struct rtc_time *tm)
 {
 	s32 sec, min, hour, day, mon, year;
 	s32 sec1, min1, hour1, day1, mon1, year1;
@@ -105,13 +106,13 @@ m41t00_get_rtc_time(void)
 	u8 buf[8], msgbuf[1] = { 0 }; /* offset into rtc's regs */
 	struct i2c_msg msgs[] = {
 		{
-			.addr	= save_client->addr,
+			.addr	= client->addr,
 			.flags	= 0,
 			.len	= 1,
 			.buf	= msgbuf,
 		},
 		{
-			.addr	= save_client->addr,
+			.addr	= client->addr,
 			.flags	= I2C_M_RD,
 			.len	= 8,
 			.buf	= buf,
@@ -121,7 +122,7 @@ m41t00_get_rtc_time(void)
 	sec = min = hour = day = mon = year = 0;
 
 	do {
-		if (i2c_transfer(save_client->adapter, msgs, 2) < 0)
+		if (i2c_transfer(client->adapter, msgs, 2) < 0)
 			goto read_err;
 
 		sec1 = sec;
@@ -146,61 +147,68 @@ m41t00_get_rtc_time(void)
 			|| (year != year1)))
 		goto read_err;
 
-	sec = BCD2BIN(sec);
-	min = BCD2BIN(min);
-	hour = BCD2BIN(hour);
-	day = BCD2BIN(day);
-	mon = BCD2BIN(mon);
-	year = BCD2BIN(year);
+	tm->tm_sec = BCD2BIN(sec);
+	tm->tm_min = BCD2BIN(min);
+	tm->tm_hour = BCD2BIN(hour);
+	tm->tm_mday = BCD2BIN(day);
+	tm->tm_mon = BCD2BIN(mon) - 1;
+	tm->tm_year = BCD2BIN(year);
 
-	year += 1900;
-	if (year < 1970)
-		year += 100;
+	if (tm->tm_year + 1900 < 1970)
+		tm->tm_year += 100;
 
-	return mktime(year, mon, day, hour, min, sec);
+	return 0;
 
 read_err:
-	dev_err(&save_client->dev, "m41t00_get_rtc_time: Read error\n");
-	return 0;
+	dev_err(&client->dev, "m41t00_get_rtc_time: Read error\n");
+	return -EIO;
 }
-EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
 
-static void
-m41t00_set(void *arg)
+#if defined(CONFIG_GEN_RTC) && defined(CONFIG_GEN_RTC_MODULE)
+ulong
+m41t00_get_rtc_time(void)
 {
 	struct rtc_time	tm;
-	int nowtime = *(int *)arg;
+
+	if (m41t00_get_time(&save_client, &tm))
+		return 0;
+	return mktime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+		      tm.tm_hour, tm.tm_min, tm.tm_sec);
+}
+EXPORT_SYMBOL_GPL(m41t00_get_rtc_time);
+#endif
+
+static int
+m41t00_set_time(struct i2c_client *client, struct rtc_time *tm)
+{
 	s32 sec, min, hour, day, mon, year;
 	u8 wbuf[9], *buf = &wbuf[1], msgbuf[1] = { 0 };
 	struct i2c_msg msgs[] = {
 		{
-			.addr	= save_client->addr,
+			.addr	= client->addr,
 			.flags	= 0,
 			.len	= 1,
 			.buf	= msgbuf,
 		},
 		{
-			.addr	= save_client->addr,
+			.addr	= client->addr,
 			.flags	= I2C_M_RD,
 			.len	= 8,
 			.buf	= buf,
 		},
 	};
 
-	to_tm(nowtime, &tm);
-	tm.tm_year = (tm.tm_year - 1900) % 100;
-
-	sec = BIN2BCD(tm.tm_sec);
-	min = BIN2BCD(tm.tm_min);
-	hour = BIN2BCD(tm.tm_hour);
-	day = BIN2BCD(tm.tm_mday);
-	mon = BIN2BCD(tm.tm_mon);
-	year = BIN2BCD(tm.tm_year);
+	sec = BIN2BCD(tm->tm_sec);
+	min = BIN2BCD(tm->tm_min);
+	hour = BIN2BCD(tm->tm_hour);
+	day = BIN2BCD(tm->tm_mday);
+	mon = BIN2BCD(tm->tm_mon + 1);
+	year = BIN2BCD(tm->tm_year % 100);
 
 	/* Read reg values into buf[0..7]/wbuf[1..8] */
-	if (i2c_transfer(save_client->adapter, msgs, 2) < 0) {
-		dev_err(&save_client->dev, "m41t00_set: Read error\n");
-		return;
+	if (i2c_transfer(client->adapter, msgs, 2) < 0) {
+		dev_err(&client->dev, "m41t00_set: Read error\n");
+		return -EIO;
 	}
 
 	wbuf[0] = 0; /* offset into rtc's regs */
@@ -210,8 +218,24 @@ m41t00_set(void *arg)
 	buf[m41t00_chip->day] = (buf[m41t00_chip->day] & ~0x3f) | (day & 0x3f);
 	buf[m41t00_chip->mon] = (buf[m41t00_chip->mon] & ~0x1f) | (mon & 0x1f);
 
-	if (i2c_master_send(save_client, wbuf, 9) < 0)
-		dev_err(&save_client->dev, "m41t00_set: Write error\n");
+	if (i2c_master_send(client, wbuf, 9) < 0) {
+		dev_err(&client->dev, "m41t00_set: Write error\n");
+		return -EIO;
+	}
+	return 0;
+}
+
+#if defined(CONFIG_GEN_RTC) && defined(CONFIG_GEN_RTC_MODULE)
+static void
+m41t00_set(void *arg)
+{
+	struct rtc_time	tm;
+	int nowtime = *(int *)arg;
+
+	to_tm(nowtime, &tm);
+	tm.tm_year -= 1900;
+	tm.tm_mon -= 1;
+	m41t00_set_time(&save_client, &tm);
 }
 
 static ulong new_time;
@@ -231,6 +255,7 @@ m41t00_set_rtc_time(ulong nowtime)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
+#endif
 
 /*
  *****************************************************************************
@@ -273,6 +298,23 @@ static struct platform_driver m41t00_pla
 	},
 };
 
+#if defined(CONFIG_RTC_CLASS) || defined(CONFIG_RTC_CLASS_MODULE)
+static int m41t00_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return m41t00_get_time(to_i2c_client(dev), tm);
+}
+
+static int m41t00_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return m41t00_set_time(to_i2c_client(dev), tm);
+}
+
+static struct rtc_class_ops m41t00_rtc_ops = {
+	.read_time	= m41t00_rtc_read_time,
+	.set_time	= m41t00_rtc_set_time,
+};
+#endif
+
 /*
  *****************************************************************************
  *
@@ -284,6 +326,9 @@ static int
 m41t00_probe(struct i2c_adapter *adap, int addr, int kind)
 {
 	struct i2c_client *client;
+#if defined(CONFIG_RTC_CLASS) || defined(CONFIG_RTC_CLASS_MODULE)
+	struct rtc_device *rtc;
+#endif
 	int rc;
 
 	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
@@ -336,8 +381,21 @@ m41t00_probe(struct i2c_adapter *adap, i
 				rc & ~0x80)) < 0)
 			goto st_err;
 
+#if defined(CONFIG_RTC_CLASS) || defined(CONFIG_RTC_CLASS_MODULE)
+	rtc = rtc_device_register(m41t00_driver.driver.name, &client->dev,
+				  &m41t00_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		rc = PTR_ERR(rtc);
+		goto attach_err;
+	}
+	i2c_set_clientdata(client, rtc);
+#endif
+
+#if defined(CONFIG_GEN_RTC) && defined(CONFIG_GEN_RTC_MODULE)
 	m41t00_wq = create_singlethread_workqueue(m41t00_chip->name);
 	save_client = client;
+#endif
 	return 0;
 
 st_err:
@@ -363,10 +421,17 @@ static int
 m41t00_detach(struct i2c_client *client)
 {
 	int rc;
+#if defined(CONFIG_RTC_CLASS) || defined(CONFIG_RTC_CLASS_MODULE)
+	struct rtc_device *rtc = i2c_get_clientdata(client);
 
+	if (rtc)
+		rtc_device_unregister(rtc);
+#endif
 	if ((rc = i2c_detach_client(client)) == 0) {
 		kfree(client);
+#if defined(CONFIG_GEN_RTC) && defined(CONFIG_GEN_RTC_MODULE)
 		destroy_workqueue(m41t00_wq);
+#endif
 	}
 	return rc;
 }
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux