public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: RTC: add RTC class interface to m41t00 driver
@ 2006-08-05  2:33 David Brownell
  2006-08-05 16:29 ` Atsushi Nemoto
  0 siblings, 1 reply; 15+ messages in thread
From: David Brownell @ 2006-08-05  2:33 UTC (permalink / raw)
  To: anemo, ab, mgreer; +Cc: Linux Kernel list

Actually, it'd be worth trying drivers/rtc/rtc-ds1307.c ... the M41T00 is
one of a family of mostly-compatible RTC chips, and the ds1307 driver
should be pretty much the least-common-denominator there.  They all use
the same I2C address, and the same register layout for the calendar/time
function.

I'd expect rtc-ds1307 to handle the m41t00 already, or with at most minor
tweaks to recognize whatever's different.  It should already be ignoring
the bits in the clock/calendar registers that vary, as well as the SRAM
and (for some other chips) the alarm.  (Not that I2C has ways to tell us
what IRQ the alarm would use, but that's a different tale!)

- Dave

^ permalink raw reply	[flat|nested] 15+ messages in thread
* RTC: add RTC class interface to m41t00 driver
@ 2006-08-03 15:21 Atsushi Nemoto
  2006-08-03 15:42 ` Atsushi Nemoto
  0 siblings, 1 reply; 15+ messages in thread
From: Atsushi Nemoto @ 2006-08-03 15:21 UTC (permalink / raw)
  To: linux-kernel; +Cc: mgreer, a.zummo, khali, akpm

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.

Is this a right direction?  Or should I create an another rtc-m41t00
driver in drivers/rtc/ directory?


Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>

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..b58f2f0 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>
@@ -26,7 +26,9 @@ #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 +98,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 +107,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 +123,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 +148,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 +219,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 +256,7 @@ m41t00_set_rtc_time(ulong nowtime)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(m41t00_set_rtc_time);
+#endif
 
 /*
  *****************************************************************************
@@ -273,6 +299,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 +327,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 +382,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 +422,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;
 }

^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2006-08-07 15:01 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-05  2:33 RTC: add RTC class interface to m41t00 driver David Brownell
2006-08-05 16:29 ` Atsushi Nemoto
2006-08-05 17:43   ` Alexander Bigga
2006-08-05 20:23     ` David Brownell
2006-08-07 15:01       ` Alexander Bigga
2006-08-05 19:13   ` David Brownell
2006-08-06 17:09     ` Atsushi Nemoto
2006-08-07 14:55       ` Alexander Bigga
  -- strict thread matches above, loose matches on Subject: below --
2006-08-03 15:21 Atsushi Nemoto
2006-08-03 15:42 ` Atsushi Nemoto
2006-08-04  0:21   ` Mark A. Greer
2006-08-04 14:01     ` Alexander Bigga
2006-08-04 16:03       ` Atsushi Nemoto
2006-08-04 22:57       ` Andrew Morton
2006-08-05 13:28         ` Atsushi Nemoto

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox