All the mail mirrored from lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] 2.6 I2C epson 8564 RTC chip
@ 2004-04-29 12:02 stefan.eletzhofer
  2004-04-29 12:41 ` Ian Campbell
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: stefan.eletzhofer @ 2004-04-29 12:02 UTC (permalink / raw
  To: linux-kernel; +Cc: Andrew Morton, Greg KH

[-- Attachment #1: Type: text/plain, Size: 775 bytes --]

Hi,
this is my second try to send this patch, in the previous attempts
I goofed up somehow and mail got duplicated. That's my first patch
to LKML, so please bear with me ;)

The patch attached adds support for the Epson 8564 RTC chip. This
is a RTC chip sitting on the I2C bus. AFAIK the chip's address is
hardcoded in silicon.

This driver only does the low-level I2C stuff, the rtc misc device
driver is a separate driver module which I will send a patch for soon.

I CC Greg KH because its I2C, as Andrew Morton told me to do.

The patch is against 2.6.6-rc3, but should apply cleanly to other
2.6 kernels.

Please comment,
	Stefan E.
-- 
Eletztrick Computing - Customized Linux Development
Stefan Eletzhofer, Marktstrasse 43, DE-88214 Ravensburg
http://www.eletztrick.de

[-- Attachment #2: i2c-rtc8564.patch --]
[-- Type: text/plain, Size: 13293 bytes --]

Add support for the Epson 8564 RTC chip.

#
# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
#

--- /dev/null
+++ linux-ra_alpha-update/drivers/i2c/chips/rtc8564.c
@@ -0,0 +1,404 @@
+/*
+ *  linux/drivers/i2c/chips/rtc8564.c
+ *
+ *  Copyright (C) 2002-2004 Stefan Eletzhofer
+ *
+ *	based on linux/drivers/acron/char/pcf8583.c
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for system3's EPSON RTC 8564 chip
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/rtc.h>			/* get the user-level API */
+#include <linux/init.h>
+#include <linux/init.h>
+
+#include "rtc8564.h"
+
+#ifdef DEBUG
+# define _DBG( x, fmt, args... ) do{ if ( debug>=x ) printk( KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args ); } while(0);
+#else
+# define _DBG( x, fmt, args... ) do { } while(0);
+#endif
+
+#define _DBGRTCTM( x, rtctm ) if (debug>=x) printk( "%s: secs=%d, mins=%d, hours=%d, mday=%d, " \
+			"mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \
+			(rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \
+			(rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl );
+
+struct rtc8564_data {
+	struct i2c_client client;
+	u16 ctrl;
+};
+
+static inline u8 _rtc8564_ctrl1( struct i2c_client *client )
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	return data->ctrl & 0xff;
+}
+static inline u8 _rtc8564_ctrl2( struct i2c_client *client )
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	return (data->ctrl & 0xff00) >>8;
+}
+#define CTRL1(c) _rtc8564_ctrl1( c )
+#define CTRL2(c) _rtc8564_ctrl2( c )
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+
+static struct i2c_driver rtc8564_driver;
+
+static unsigned short ignore[] = { I2C_CLIENT_END };
+static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+	.normal_i2c	= normal_addr,
+	.normal_i2c_range = ignore,
+	.probe		= ignore,
+	.probe_range	= ignore,
+	.ignore		= ignore,
+	.ignore_range	= ignore,
+	.force		= ignore,
+};
+
+static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
+static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem);
+
+static int rtc8564_read(struct i2c_client *client, unsigned char adr, unsigned char *buf, unsigned char len)
+{
+	int ret = -EIO;
+	unsigned char addr[1] = { adr };
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0,        1, addr },
+		{ client->addr, I2C_M_RD, len, buf  }
+	};
+
+	_DBG( 1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len );
+
+	if ( !buf || !client ) {
+		ret = -EINVAL;
+		goto DONE;
+	}
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if ( ret == 2 ) {
+		ret = 0;
+	}
+
+DONE:
+	return ret;
+}
+
+static int rtc8564_write(struct i2c_client *client, unsigned char adr, unsigned char *data, unsigned char len )
+{
+	int ret = 0;
+	unsigned char _data[ 16 ];
+	struct i2c_msg wr;
+	int i;
+
+	if ( !client || !data || len>15 ) {
+		ret = -EINVAL;
+		goto DONE;
+	}
+
+	_DBG( 1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len );
+
+	_data[0]=adr;
+	for ( i=0; i<len; i++ ) {
+		_data[i+1]=data[i];
+		_DBG( 5, "data[%d] = 0x%02x (%d)", i, data[i], data[i] );
+	}
+
+	wr.addr = client->addr;
+	wr.flags = 0;
+	wr.len = len+1;
+	wr.buf=_data;
+
+	ret = i2c_transfer(client->adapter, &wr, 1);
+	if ( ret == 1 ) {
+		ret = 0;
+	}
+		
+DONE:
+	return ret;
+}
+
+static int
+rtc8564_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+	int ret;
+	struct i2c_client *new_client;
+	struct rtc8564_data *d;
+	unsigned char data[10];
+	unsigned char ad[1] = { 0 };
+	struct i2c_msg ctrl_wr[1] = {
+		{ addr, 0, 2, data  }
+	};
+	struct i2c_msg ctrl_rd[2] = {
+		{ addr, 0,        1, ad },
+		{ addr, I2C_M_RD, 2, data  }
+	};
+
+	d = kmalloc( sizeof( struct rtc8564_data), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto DONE;
+	}
+	memset( d, 0, sizeof( struct rtc8564_data) );
+	new_client = &d->client;
+
+	strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
+	i2c_set_clientdata( new_client, d );
+	new_client->id		= rtc8564_driver.id;
+	new_client->flags	= I2C_CLIENT_ALLOW_USE|I2C_DF_NOTIFY;
+	new_client->addr	= addr;
+	new_client->adapter	= adap;
+	new_client->driver	= &rtc8564_driver;
+
+	_DBG( 1, "client=%p", new_client );
+	_DBG( 1, "client.id=%d", new_client->id );
+
+	/* init ctrl1 reg */
+	data[0]=0;
+	data[1]=0;
+	ret = i2c_transfer(new_client->adapter, ctrl_wr, 1);
+	if ( ret != 1 ) {
+		printk(KERN_INFO"rtc8564: cant init ctrl1\n" );
+		ret = -ENODEV;
+		goto DONE;
+	}
+
+	/* read back ctrl1 and ctrl2 */
+	ret = i2c_transfer(new_client->adapter, ctrl_rd, 2);
+	if ( ret != 2 ) {
+		printk(KERN_INFO"rtc8564: cant read ctrl\n" );
+		ret = -ENODEV;
+		goto DONE;
+	}
+
+	d->ctrl = data[0] | (data[1] << 8);
+
+	_DBG( 1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x",
+			data[0],
+			data[1] );
+
+	ret = i2c_attach_client(new_client);
+DONE:
+	if ( ret ) {
+		if ( d ) kfree( d );
+	}
+	return ret;
+}
+
+static int
+rtc8564_probe(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, rtc8564_attach);
+}
+
+static int
+rtc8564_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static int
+rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
+{
+	int ret = -EIO;
+	unsigned char buf[15];
+
+	_DBG( 1, "client=%p, dt=%p", client, dt );
+
+	if ( !dt || !client )
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	ret = rtc8564_read(client, 0, buf, 15);
+	if ( ret )
+		return ret;
+
+	/* century stored in minute alarm reg */
+	dt->year	= BCD_TO_BIN(buf[RTC8564_REG_YEAR]);
+	dt->year	+= 100*BCD_TO_BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
+	dt->mday	= BCD_TO_BIN(buf[RTC8564_REG_DAY] & 0x3f);
+	dt->wday	= BCD_TO_BIN(buf[RTC8564_REG_WDAY] & 7);
+	dt->mon		= BCD_TO_BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
+
+	dt->secs	= BCD_TO_BIN(buf[RTC8564_REG_SEC] & 0x7f);
+	dt->vl		= (buf[RTC8564_REG_SEC] & 0x80) == 0x80;
+	dt->mins	= BCD_TO_BIN(buf[RTC8564_REG_MIN] & 0x7f);
+	dt->hours	= BCD_TO_BIN(buf[RTC8564_REG_HR] & 0x3f);
+
+	_DBGRTCTM( 2, *dt );
+
+	return 0;
+}
+
+static int
+rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
+{
+	int ret, len = 5;
+	unsigned char buf[15];
+
+	_DBG( 1, "client=%p, dt=%p", client, dt );
+
+	if ( !dt || !client )
+		return -EINVAL;
+
+	_DBGRTCTM( 2, *dt );
+
+	buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
+	buf[RTC8564_REG_CTRL2] = CTRL2(client);
+	buf[RTC8564_REG_SEC] = BIN_TO_BCD(dt->secs);
+	buf[RTC8564_REG_MIN] = BIN_TO_BCD(dt->mins);
+	buf[RTC8564_REG_HR] = BIN_TO_BCD(dt->hours);
+
+	if (datetoo) {
+		len += 5;
+		buf[RTC8564_REG_DAY] = BIN_TO_BCD(dt->mday);
+		buf[RTC8564_REG_WDAY] = BIN_TO_BCD(dt->wday);
+		buf[RTC8564_REG_MON_CENT] = BIN_TO_BCD(dt->mon)&0x1f;
+		/* century stored in minute alarm reg */
+		buf[RTC8564_REG_YEAR] = BIN_TO_BCD(dt->year%100);
+		buf[RTC8564_REG_AL_MIN] = BIN_TO_BCD(dt->year/100);
+	}
+
+	ret = rtc8564_write(client, 0, buf, len);
+	if (ret) {
+		_DBG( 1, "error writing data! %d", ret );
+	}
+
+
+	buf[RTC8564_REG_CTRL1] = CTRL1(client);
+	ret = rtc8564_write(client, 0, buf, 1);
+	if (ret) {
+		_DBG( 1, "error writing data! %d", ret );
+	}
+
+	return ret;
+}
+
+static int
+rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+
+	if ( !ctrl || !client )
+		return -1;
+
+	*ctrl = data->ctrl;
+	return 0;
+}
+
+static int
+rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	unsigned char buf[2];
+
+
+	if ( !ctrl || !client )
+		return -1;
+
+	buf[0] = *ctrl & 0xff;
+	buf[1] = (*ctrl & 0xff00) >> 8;
+	data->ctrl = *ctrl;
+
+	return rtc8564_write(client, 0, buf, 2);
+}
+
+static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
+{
+
+	if ( !mem || !client )
+		return -EINVAL;
+
+	return rtc8564_read( client, mem->loc, mem->data, mem->nr );
+}
+
+static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
+{
+
+
+	if ( !mem || !client )
+		return -EINVAL;
+
+	return rtc8564_write( client, mem->loc, mem->data, mem->nr );
+}
+
+static int
+rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+
+	_DBG( 1, "cmd=%d", cmd );
+
+	switch (cmd) {
+		case RTC_GETDATETIME:
+			return rtc8564_get_datetime(client, arg);
+
+		case RTC_SETTIME:
+			return rtc8564_set_datetime(client, arg, 0);
+
+		case RTC_SETDATETIME:
+			return rtc8564_set_datetime(client, arg, 1);
+
+		case RTC_GETCTRL:
+			return rtc8564_get_ctrl(client, arg);
+
+		case RTC_SETCTRL:
+			return rtc8564_set_ctrl(client, arg);
+
+		case MEM_READ:
+			return rtc8564_read_mem(client, arg);
+
+		case MEM_WRITE:
+			return rtc8564_write_mem(client, arg);
+
+		default:
+			return -EINVAL;
+	}
+}
+
+static struct i2c_driver rtc8564_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "RTC8564",
+	.id		= I2C_DRIVERID_RTC8564,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= rtc8564_probe,
+	.detach_client	= rtc8564_detach,
+	.command	= rtc8564_command
+};
+
+static __init int rtc8564_init(void)
+{
+	return i2c_add_driver(&rtc8564_driver);
+}
+
+static __exit void rtc8564_exit(void)
+{
+	i2c_del_driver(&rtc8564_driver);
+}
+
+MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>");
+MODULE_DESCRIPTION("EPSON RTC8564 Driver");
+MODULE_LICENSE("GPL");
+
+
+module_init(rtc8564_init);
+module_exit(rtc8564_exit);
--- /dev/null
+++ linux-ra_alpha-update/drivers/i2c/chips/rtc8564.h
@@ -0,0 +1,78 @@
+/*
+ *  linux/drivers/i2c/chips/rtc8564.h
+ *
+ *  Copyright (C) 2002-2004 Stefan Eletzhofer
+ *
+ *	based on linux/drivers/acron/char/pcf8583.h
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+struct rtc_tm {
+	unsigned char	secs;
+	unsigned char	mins;
+	unsigned char	hours;
+	unsigned char	mday;
+	unsigned char	mon;
+	unsigned short	year; /* xxxx 4 digits :) */
+	unsigned char	wday;
+	unsigned char	vl;
+};
+
+struct mem {
+	unsigned int	loc;
+	unsigned int	nr;
+	unsigned char	*data;
+};
+
+#define RTC_GETDATETIME	0
+#define RTC_SETTIME	1
+#define RTC_SETDATETIME	2
+#define RTC_GETCTRL	3
+#define RTC_SETCTRL	4
+#define MEM_READ	5
+#define MEM_WRITE	6
+
+#define RTC8564_REG_CTRL1		0x0 /* T  0 S 0 | T 0 0 0 */
+#define RTC8564_REG_CTRL2		0x1 /* 0  0 0 TI/TP | AF TF AIE TIE */
+#define RTC8564_REG_SEC			0x2 /* VL 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_MIN			0x3 /* x  4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_HR			0x4 /* x  x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_DAY			0x5 /* x  x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_WDAY		0x6 /* x  x x x | x 4 2 1 */
+#define RTC8564_REG_MON_CENT	0x7 /* C  x x 1 | 8 4 2 1 */
+#define RTC8564_REG_YEAR		0x8 /* 8  4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_MIN		0x9 /* AE 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_HR		0xa /* AE 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_DAY		0xb /* AE x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_WDAY		0xc /* AE x x x | x 4 2 1 */
+#define RTC8564_REG_CLKOUT		0xd /* FE x x x | x x FD1 FD0 */
+#define RTC8564_REG_TCTL		0xe /* TE x x x | x x FD1 FD0 */
+#define RTC8564_REG_TIMER		0xf /* 8 bit binary */
+
+/* Control reg */
+#define RTC8564_CTRL1_TEST1		(1<<3)
+#define RTC8564_CTRL1_STOP		(1<<5)
+#define RTC8564_CTRL1_TEST2		(1<<7)
+
+#define RTC8564_CTRL2_TIE		(1<<0)
+#define RTC8564_CTRL2_AIE		(1<<1)
+#define RTC8564_CTRL2_TF		(1<<2)
+#define RTC8564_CTRL2_AF		(1<<3)
+#define RTC8564_CTRL2_TI_TP		(1<<4)
+
+/* CLKOUT frequencies */
+#define RTC8564_FD_32768HZ		(0x0)
+#define RTC8564_FD_1024HZ		(0x1)
+#define RTC8564_FD_32			(0x2)
+#define RTC8564_FD_1HZ			(0x3)
+
+/* Timer CTRL */
+#define RTC8564_TD_4096HZ		(0x0)
+#define RTC8564_TD_64HZ			(0x1)
+#define RTC8564_TD_1HZ			(0x2)
+#define RTC8564_TD_1_60HZ		(0x3)
+
+#define I2C_DRIVERID_RTC8564 0xf000
--- linux-ra_alpha-update/drivers/i2c/chips/Makefile~i2c-rtc8564
+++ linux-ra_alpha-update/drivers/i2c/chips/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 
--- linux-ra_alpha-update/drivers/i2c/chips/Kconfig~i2c-rtc8564
+++ linux-ra_alpha-update/drivers/i2c/chips/Kconfig
@@ -230,4 +230,14 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8591.
 
+config SENSORS_RTC8564
+	tristate "Epson 8564 RTC chip"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for the Epson 8564 RTC chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-rtc8564.
+
 endmenu

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:02 [PATCH] 2.6 I2C epson 8564 RTC chip stefan.eletzhofer
@ 2004-04-29 12:41 ` Ian Campbell
  2004-04-29 12:54   ` Russell King
  2004-04-29 12:59 ` Ian Campbell
  2004-05-01  5:48 ` Greg KH
  2 siblings, 1 reply; 15+ messages in thread
From: Ian Campbell @ 2004-04-29 12:41 UTC (permalink / raw
  To: stefan.eletzhofer; +Cc: Linux Kernel Mailing List, Andrew Morton, Greg KH

[-- Attachment #1: Type: text/plain, Size: 1529 bytes --]

Hi Stefan,

> This driver only does the low-level I2C stuff, the rtc misc device
> driver is a separate driver module which I will send a patch for soon.

I have a patch (attached, it could do with cleaning up) for the Dallas
DS1307 I2C RTC which I ported from the 2.4 rmk patch, originally written
by Intrinsyc. Currently it includes both the I2C and the RTC bits in the
same driver.

Do you think it is realistic/possible to have the same generic RTC
driver speak to multiple I2C devices, from what I can see in your driver
the two chips seem pretty similar and the differences could probably be
abstracted away. Perhaps that is your intention from the start?

I guess I will wait until you post the RTC misc driver and try and make
the DS1307 one work with that before I submit it.

Ian.

-- 
Ian Campbell, Senior Design Engineer
                                        Web: http://www.arcom.com
Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200


_____________________________________________________________________
The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.

This message has been virus scanned by MessageLabs.

[-- Attachment #2: ds1307 --]
[-- Type: text/x-patch, Size: 18989 bytes --]

Index: linux-2.6-bkpxa/drivers/i2c/chips/Kconfig
===================================================================
--- linux-2.6-bkpxa.orig/drivers/i2c/chips/Kconfig	2004-04-26 11:00:40.000000000 +0100
+++ linux-2.6-bkpxa/drivers/i2c/chips/Kconfig	2004-04-26 11:03:03.000000000 +0100
@@ -230,4 +230,8 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8591.
 
+config DS1307
+	tristate "Dallas Semiconductor DS1307 Real-Time Clock"
+	depends on I2C
+
 endmenu
Index: linux-2.6-bkpxa/drivers/i2c/chips/Makefile
===================================================================
--- linux-2.6-bkpxa.orig/drivers/i2c/chips/Makefile	2004-04-26 11:00:40.000000000 +0100
+++ linux-2.6-bkpxa/drivers/i2c/chips/Makefile	2004-04-26 11:03:03.000000000 +0100
@@ -24,6 +24,8 @@
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 
+obj-$(CONFIG_DS1307)	 	+= ds1307.o
+
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
Index: linux-2.6-bkpxa/drivers/i2c/chips/ds1307.c
===================================================================
--- linux-2.6-bkpxa.orig/drivers/i2c/chips/ds1307.c	2004-04-26 09:37:12.000000000 +0100
+++ linux-2.6-bkpxa/drivers/i2c/chips/ds1307.c	2004-04-26 13:27:11.000000000 +0100
@@ -0,0 +1,602 @@
+/*
+ * ds1307.c
+ *
+ * Device driver for Dallas Semiconductor's Real Time Controller DS1307.
+ *
+ * Copyright (C) 2002 Intrinsyc Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/poll.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/string.h>
+#include <linux/miscdevice.h>
+#include <linux/proc_fs.h>
+
+#include "ds1307.h"
+
+#if DEBUG
+static unsigned int rtc_debug = DEBUG;
+#else
+#define rtc_debug 0	/* gcc will remove all the debug code for us */
+#endif
+
+struct ds1307_data {
+	struct semaphore lock;
+	unsigned char control;
+};
+
+/* --- /dev/rtc interface --- */
+
+static struct i2c_client *rtc_client = NULL;
+
+static int ds1307_rtc_ioctl( struct inode *, struct file *, unsigned int, unsigned long);
+static int ds1307_rtc_open(struct inode *inode, struct file *file);
+static int ds1307_rtc_release(struct inode *inode, struct file *file);
+
+static struct file_operations rtc_fops = {
+	owner:		THIS_MODULE,
+	ioctl:		ds1307_rtc_ioctl,
+	open:		ds1307_rtc_open,
+	release:	ds1307_rtc_release,
+};
+
+static struct miscdevice ds1307_rtc_miscdev = {
+	RTC_MINOR,
+	"rtc",
+	&rtc_fops
+};
+
+
+static char *
+ds1307_mon2str( unsigned int mon)
+{
+	char *mon2str[12] = {
+	  "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+	  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+	};
+	if( mon > 11) return "error";
+	else return mon2str[ mon];
+}
+
+static int
+ds1307_readram( char *buf, int len)
+{
+	struct i2c_client *client = rtc_client;
+	struct ds1307_data *data = i2c_get_clientdata(client);
+
+        unsigned long   flags;
+        unsigned char ad[1] = { 0 };
+        int ret;
+        struct i2c_msg msgs[2] = {
+                { client->addr, 0,        1, ad  },
+                { client->addr, I2C_M_RD, len, buf } };
+ 
+        spin_lock_irqsave(data->lock, flags);
+        ret = i2c_transfer(client->adapter, msgs, 2);
+        spin_unlock_irqrestore(data->lock,flags);
+ 
+        return ret;
+}
+
+static void
+ds1307_convert_to_time( struct rtc_time *dt, char *buf)
+{
+	dt->tm_sec = BCD_TO_BIN(buf[0]);
+	dt->tm_min = BCD_TO_BIN(buf[1]);
+
+	if ( TWELVE_HOUR_MODE(buf[2]) )
+	{
+		dt->tm_hour = HOURS_12(buf[2]);
+		if (HOURS_AP(buf[2])) /* PM */
+		{
+			dt->tm_hour += 12;
+		}
+	}
+	else /* 24-hour-mode */
+	{
+		dt->tm_hour = HOURS_24(buf[2]);
+	}
+
+	dt->tm_mday = BCD_TO_BIN(buf[4]);
+	/* dt->tm_mon is zero-based */
+	dt->tm_mon = BCD_TO_BIN(buf[5]) - 1;
+	/* year is 1900 + dt->tm_year */
+	dt->tm_year = BCD_TO_BIN(buf[6]) + 100;
+
+	if( rtc_debug > 2)
+	{
+		printk("ds1307_get_datetime: year = %d\n", dt->tm_year);
+		printk("ds1307_get_datetime: mon  = %d\n", dt->tm_mon);
+		printk("ds1307_get_datetime: mday = %d\n", dt->tm_mday);
+		printk("ds1307_get_datetime: hour = %d\n", dt->tm_hour);
+		printk("ds1307_get_datetime: min  = %d\n", dt->tm_min);
+		printk("ds1307_get_datetime: sec  = %d\n", dt->tm_sec);
+	}
+}
+
+static int ds1307_rtc_proc_output( char *buf)
+{
+#define CHECK(ctrl,bit) ((ctrl & bit) ? "yes" : "no")
+	unsigned char ram[DS1307_RAM_SIZE];
+	int ret;
+
+	char *p = buf;
+
+	ret = ds1307_readram( ram, DS1307_RAM_SIZE);
+	if( ret > 0)
+	{
+		int i;
+		struct rtc_time dt;
+		char text[9];
+
+		p += sprintf(p, "DS1307 (64x8 Serial Real Time Clock)\n");
+
+		ds1307_convert_to_time( &dt, ram);
+		p += sprintf(p, "Date/Time           : %02d-%s-%04d %02d:%02d:%02d\n",
+			dt.tm_mday, ds1307_mon2str(dt.tm_mon), dt.tm_year + 1900,
+			dt.tm_hour, dt.tm_min, dt.tm_sec);
+
+		p += sprintf(p, "Clock halted        : %s\n", CHECK(ram[0],0x80));
+		p += sprintf(p, "24h mode            : %s\n", CHECK(ram[2],0x40));
+		p += sprintf(p, "Square wave enabled : %s\n", CHECK(ram[7],0x10));
+		p += sprintf(p, "Freq                : ");
+
+		switch( ram[7] & 0x03)
+		{
+			case RATE_1HZ:
+				p += sprintf(p, "1Hz\n");
+				break;
+			case RATE_4096HZ:
+				p += sprintf(p, "4.096kHz\n");
+				break;
+			case RATE_8192HZ:
+				p += sprintf(p, "8.192kHz\n");
+				break;
+			case RATE_32768HZ:
+			default:
+				p += sprintf(p, "32.768kHz\n");
+				break;
+
+		}
+
+		p += sprintf(p, "RAM dump:\n");
+		text[8]='\0';
+		for( i=0; i<DS1307_RAM_SIZE; i++)
+		{
+			p += sprintf(p, "%02X ", ram[i]);
+
+			if( (ram[i] < 32) || (ram[i]>126)) ram[i]='.';
+			text[i%8] = ram[i];
+			if( (i%8) == 7) p += sprintf(p, "%s\n",text);
+		}
+		p += sprintf(p, "\n");
+	}
+	else
+	{
+		p += sprintf(p, "Failed to read RTC memory!\n");
+	}
+
+	return	p - buf;
+}
+
+static int ds1307_rtc_read_proc(char *page, char **start, off_t off,
+		int count, int *eof, void *data)
+{
+	int len = ds1307_rtc_proc_output (page);
+	if (len <= off+count) *eof = 1;
+	*start = page + off;
+	len -= off;
+	if (len>count) len = count;
+	if (len<0) len = 0;
+	return len;
+}
+
+/* --- I2C interface --- */
+// The DS1307 can only ever be present at address 0x68
+static unsigned short normal_i2c[]      = { 0x68, I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD;
+
+static int ds1307_attach_adapter(struct i2c_adapter *adapter);
+static int ds1307_detect(struct i2c_adapter *adapter, int address, int kind);
+static void ds1307_init_client(struct i2c_client *client);
+static int ds1307_detach_client(struct i2c_client *client);
+static int ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg);
+static void ds1307_enable_clock(struct i2c_client *client, int enable);
+
+struct i2c_driver ds1307_driver = {
+	.name           = "ds1307",
+	.id		= I2C_DRIVERID_DS1307,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= ds1307_attach_adapter,
+	.detach_client	= ds1307_detach_client,
+	.command        = ds1307_command
+};
+
+static int ds1307_id = 0;
+
+static void ds1307_init_client(struct i2c_client *client)
+{
+	struct ds1307_data *data = i2c_get_clientdata(client);
+	data->control = i2c_smbus_read_byte_data(client, 0x07);
+	ds1307_enable_clock(client, 1);
+}
+
+static int ds1307_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, ds1307_detect);
+}
+
+/* The `kind' parameter contains 0 if this call is due to a `force'
+   parameter, and -1 otherwise */
+static int
+ds1307_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *new_client;
+	struct ds1307_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
+				             I2C_FUNC_SMBUS_WRITE_BYTE))
+		goto exit;
+
+	if ( kind < 0 ) { 
+		if ( address != 0x68 ) /* DS1307 is always at address 0x68 */
+			goto exit;
+	}
+
+	/* OK. For now, we presume we have a valid client. We now create the
+	   client structure. */
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+				   sizeof(struct ds1307_data),
+				   GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+	memset(new_client, 0, sizeof(struct i2c_client) +
+	       sizeof(struct ds1307_data));
+	data = (struct ds1307_data *) (new_client + 1);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &ds1307_driver;
+	new_client->flags = 0;
+	
+	/* Could do any remaing detection here -- if kind < 0 */
+
+	/* Fill in remaining client fields and put it into the global list */
+	strlcpy(new_client->name, "ds1307", I2C_NAME_SIZE);
+
+	new_client->id = ds1307_id++;
+	init_MUTEX(&data->lock);
+
+	/* Tell the I2C layer a new client has arrived */
+	if ((err = i2c_attach_client(new_client)))
+		goto exit_free;
+
+	/* Initialize the DS1307 chip */
+	ds1307_init_client(new_client);
+
+	rtc_client = new_client;
+
+	return 0;
+
+      exit_free:
+	kfree(new_client);
+      exit:
+	return err;
+}
+
+static int ds1307_detach_client(struct i2c_client *client)
+{
+	int err;
+
+	ds1307_enable_clock(client, 0);
+
+	if ((err = i2c_detach_client(client))) {
+		dev_err(&client->dev,
+		        "ds1307.o: Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+	return 0;
+}
+
+static __init int ds1307_init(void)
+{
+	int retval;
+
+	retval = i2c_add_driver(&ds1307_driver);
+	if (retval==0)
+	{
+		misc_register (&ds1307_rtc_miscdev);
+		create_proc_read_entry (PROC_DS1307_NAME, 0, 0, ds1307_rtc_read_proc, NULL);
+		printk(KERN_INFO "ds1307.o: RTC driver successfully loaded.\n");
+	}
+	return retval;
+}
+
+static __exit void ds1307_exit(void)
+{
+	remove_proc_entry (PROC_DS1307_NAME, NULL);
+	misc_deregister(&ds1307_rtc_miscdev);
+	i2c_del_driver(&ds1307_driver);
+}
+
+module_init(ds1307_init);
+module_exit(ds1307_exit);
+
+MODULE_AUTHOR ("Intrinsyc Software Inc.");
+MODULE_LICENSE("GPL");
+
+/* --- CUTOFF --- */
+
+static void ds1307_enable_clock(struct i2c_client *client, int enable)
+{
+	unsigned char ctrl_info;
+
+	if( enable)
+		ctrl_info = SQW_ENABLE | RATE_32768HZ;
+	else
+		ctrl_info = SQW_DISABLE;
+
+	ds1307_command(client, DS1307_SETCTRL, &ctrl_info);
+
+	/* read addr 0 (Clock-Halt bit and second counter) */
+	u32 reg = i2c_smbus_read_byte_data(client, 0x0);
+	if (enable)
+		reg &= ~CLOCK_HALT; /* clear Clock-Halt bit */
+	else
+		reg |= CLOCK_HALT; /* set Clock-Halt bit */
+	i2c_smbus_write_byte_data(client, 0, reg);
+}
+
+static int
+ds1307_get_datetime(struct i2c_client *client, struct rtc_time *dt)
+{
+        unsigned char buf[7], addr[1] = { 0 };
+        struct i2c_msg msgs[2] = {
+                { client->addr, 0,        1, addr },
+                { client->addr, I2C_M_RD, 7, buf  }
+        };
+        int ret = -EIO;
+ 
+        memset(buf, 0, sizeof(buf));
+ 
+        ret = i2c_transfer(client->adapter, msgs, 2);
+ 
+        if (ret == 2) {
+                ds1307_convert_to_time( dt, buf);
+                ret = 0;
+        }
+        else
+                printk("ds1307_get_datetime(), i2c_transfer() returned %d\n",ret);
+ 
+        return ret;
+}
+
+static int
+ds1307_set_datetime(struct i2c_client *client, struct rtc_time *dt, int datetoo)
+{
+        unsigned char buf[8];
+        int ret, len = 4;
+ 
+        if( rtc_debug > 2)
+        {
+                printk("ds1307_set_datetime: tm_year = %d\n", dt->tm_year);
+                printk("ds1307_set_datetime: tm_mon  = %d\n", dt->tm_mon);
+                printk("ds1307_set_datetime: tm_mday = %d\n", dt->tm_mday);
+                printk("ds1307_set_datetime: tm_hour = %d\n", dt->tm_hour);
+                printk("ds1307_set_datetime: tm_min  = %d\n", dt->tm_min);
+                printk("ds1307_set_datetime: tm_sec  = %d\n", dt->tm_sec);
+        }
+ 
+        buf[0] = 0;     /* register address on DS1307 */
+        buf[1] = (BIN_TO_BCD(dt->tm_sec));
+        buf[2] = (BIN_TO_BCD(dt->tm_min));
+        buf[3] = (BIN_TO_BCD(dt->tm_hour));
+
+        if (datetoo) {
+                len = 8;
+                /* we skip buf[4] as we don't use day-of-week. */
+                buf[5] = (BIN_TO_BCD(dt->tm_mday));
+                buf[6] = (BIN_TO_BCD(dt->tm_mon + 1));
+                /* The year only ranges from 0-99, we are being passed an offset from 1900,
+                 * and the chip calulates leap years based on 2000, thus we adjust by 100.
+                 */
+                buf[7] = (BIN_TO_BCD(dt->tm_year - 100));
+        }
+        ret = i2c_master_send(client, (char *)buf, len);
+        if (ret == len)
+                ret = 0;
+        else
+                printk("ds1307_set_datetime(), i2c_master_send() returned %d\n",ret);
+
+        return ret;
+}
+
+static int
+ds1307_get_ctrl(struct i2c_client *client, unsigned char *ctrl)
+{
+	struct ds1307_data *data = i2c_get_clientdata(client);
+	*ctrl = data->control;
+	return 0;
+}
+
+static int
+ds1307_set_ctrl(struct i2c_client *client, unsigned char *cinfo)
+{
+	struct ds1307_data *data = i2c_get_clientdata(client);
+	data->control = *cinfo;
+	return i2c_smbus_write_byte_data(client, 0x07, data->control);
+}
+
+static int
+ds1307_read_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+	unsigned char addr[1];
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0,	  1, addr },
+		{ client->addr, I2C_M_RD, mem->nr, mem->data }
+	};
+
+	if ( (mem->loc < DS1307_RAM_ADDR_START) ||
+	     ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) )
+		return -EINVAL;
+
+	addr[0] = mem->loc;
+
+	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int
+ds1307_write_mem(struct i2c_client *client, struct rtc_mem *mem)
+{
+	unsigned char addr[1];
+	struct i2c_msg msgs[2] = {
+		{ client->addr, 0, 1, addr },
+		{ client->addr, 0, mem->nr, mem->data }
+	};
+
+	if ( (mem->loc < DS1307_RAM_ADDR_START) ||
+	     ((mem->loc + mem->nr -1) > DS1307_RAM_ADDR_END) )
+		return -EINVAL;
+
+	addr[0] = mem->loc;
+
+	return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO;
+}
+
+static int
+ds1307_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+	switch (cmd) {
+	case DS1307_GETDATETIME:
+		return ds1307_get_datetime(client, arg);
+
+	case DS1307_SETTIME:
+		return ds1307_set_datetime(client, arg, 0);
+
+	case DS1307_SETDATETIME:
+		return ds1307_set_datetime(client, arg, 1);
+
+	case DS1307_GETCTRL:
+		return ds1307_get_ctrl(client, arg);
+
+	case DS1307_SETCTRL:
+		return ds1307_set_ctrl(client, arg);
+
+	case DS1307_MEM_READ:
+		return ds1307_read_mem(client, arg);
+
+	case DS1307_MEM_WRITE:
+		return ds1307_write_mem(client, arg);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static int
+ds1307_rtc_open(struct inode *inode, struct file *file)
+{
+	struct i2c_client *client = rtc_client;
+	struct ds1307_data *data;
+
+	if ( client == NULL )
+		return -ENODEV;
+
+	data = i2c_get_clientdata(client);
+
+	if ( data == NULL ) 
+		return -ENODEV;
+
+	/* re-read ctrl register to ensure there really is a device
+	 * there. if we have a situation where the device is present
+	 * but incorrectly connected (or just faulty) then we may seem
+	 * to be reading/writing OK but really we are getting junk --
+	 * so lets test that the CTRL register is really what we think
+	 * it is. If it isn't then it is likely that we don't have a
+	 * valid device attached */
+	u32 reg = i2c_smbus_read_byte_data(client, 0x07);
+
+	if ( reg == -1 ) {
+		printk (KERN_DEBUG "ds1307_rtc_open: could not verify ctrl - read returned %d.\n", reg);
+		return -ENODEV;
+	} else if ( (reg&~0x20) != (data->control&~0x20) ) { /* 0x20 is OSF bit, ignore it */
+		printk(KERN_DEBUG "ds1307_rtc_open: failed to verify ctrl register. "
+		       "got 0x%02x wanted 0x%02x\n",
+		       reg, data->control);
+		return -ENODEV; 
+	}
+	return 0;
+}
+
+static int
+ds1307_rtc_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static int
+ds1307_rtc_ioctl( struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	struct i2c_client *client = rtc_client;
+	struct ds1307_data *data = i2c_get_clientdata(client);
+
+	struct rtc_time wtime;
+
+	switch (cmd) {
+		default:
+		case RTC_UIE_ON:
+		case RTC_UIE_OFF:
+		case RTC_PIE_ON:
+		case RTC_PIE_OFF:
+		case RTC_AIE_ON:
+		case RTC_AIE_OFF:
+		case RTC_ALM_SET:
+		case RTC_ALM_READ:
+		case RTC_IRQP_READ:
+		case RTC_IRQP_SET:
+		case RTC_EPOCH_READ:
+		case RTC_EPOCH_SET:
+		case RTC_WKALM_SET:
+		case RTC_WKALM_RD:
+			return -EINVAL;
+
+		case RTC_RD_TIME:
+			down(&data->lock);
+			ds1307_command(client, DS1307_GETDATETIME, &wtime);
+			up(&data->lock);
+			if( copy_to_user((void *)arg, &wtime, sizeof (struct rtc_time)))
+				return -EFAULT;
+			return 0;
+
+		case RTC_SET_TIME:
+			if (!capable(CAP_SYS_TIME))
+				return -EACCES;
+			if (copy_from_user(&wtime, (struct rtc_time *)arg, sizeof(struct rtc_time)) )
+				return -EFAULT;
+	
+			down(&data->lock);
+			ds1307_command(client, DS1307_SETDATETIME, &wtime);
+			up(&data->lock);
+			return 0;
+	}
+}
Index: linux-2.6-bkpxa/drivers/i2c/chips/ds1307.h
===================================================================
--- linux-2.6-bkpxa.orig/drivers/i2c/chips/ds1307.h	2004-04-26 09:37:12.000000000 +0100
+++ linux-2.6-bkpxa/drivers/i2c/chips/ds1307.h	2004-04-26 11:03:03.000000000 +0100
@@ -0,0 +1,52 @@
+/*
+ * ds1307.h
+ *
+ * Copyright (C) 2002 Intrinsyc Software Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#ifndef DS1307_H
+#define DS1307_H
+
+#define DS1307_RAM_ADDR_START	0x08
+#define DS1307_RAM_ADDR_END	0x3F
+#define DS1307_RAM_SIZE 0x40
+
+#define PROC_DS1307_NAME	"driver/ds1307"
+
+struct rtc_mem {
+	unsigned int	loc;
+	unsigned int	nr;
+	unsigned char	*data;
+};
+
+#define DS1307_GETDATETIME	0
+#define DS1307_SETTIME		1
+#define DS1307_SETDATETIME	2
+#define DS1307_GETCTRL		3
+#define DS1307_SETCTRL		4
+#define DS1307_MEM_READ		5
+#define DS1307_MEM_WRITE	6
+
+#define SQW_ENABLE	0x10	/* Square Wave Enable */
+#define SQW_DISABLE	0x00	/* Square Wave disable */
+
+#define RATE_32768HZ	0x03	/* Rate Select 32.768KHz */
+#define RATE_8192HZ	0x02	/* Rate Select 8.192KHz */
+#define RATE_4096HZ	0x01	/* Rate Select 4.096KHz */
+#define RATE_1HZ	0x00	/* Rate Select 1Hz */
+
+#define CLOCK_HALT	0x80	/* Clock Halt */
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+
+#define TWELVE_HOUR_MODE(n)	(((n)>>6)&1)
+#define HOURS_AP(n)		(((n)>>5)&1)
+#define HOURS_12(n)		BCD_TO_BIN((n)&0x1F)
+#define HOURS_24(n)		BCD_TO_BIN((n)&0x3F)
+
+#endif

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:41 ` Ian Campbell
@ 2004-04-29 12:54   ` Russell King
  2004-04-29 13:58     ` stefan.eletzhofer
  2004-04-29 22:40     ` Tom Rini
  0 siblings, 2 replies; 15+ messages in thread
From: Russell King @ 2004-04-29 12:54 UTC (permalink / raw
  To: Ian Campbell
  Cc: stefan.eletzhofer, Linux Kernel Mailing List, Andrew Morton,
	Greg KH

On Thu, Apr 29, 2004 at 01:41:23PM +0100, Ian Campbell wrote:
> Hi Stefan,
> 
> > This driver only does the low-level I2C stuff, the rtc misc device
> > driver is a separate driver module which I will send a patch for soon.
> 
> I have a patch (attached, it could do with cleaning up) for the Dallas
> DS1307 I2C RTC which I ported from the 2.4 rmk patch, originally written
> by Intrinsyc. Currently it includes both the I2C and the RTC bits in the
> same driver.

Have a look at drivers/acorn/char/{i2c,pcf8583}.[ch]

> Do you think it is realistic/possible to have the same generic RTC
> driver speak to multiple I2C devices, from what I can see in your driver
> the two chips seem pretty similar and the differences could probably be
> abstracted away. Perhaps that is your intention from the start?
> 
> I guess I will wait until you post the RTC misc driver and try and make
> the DS1307 one work with that before I submit it.

If you look at the last 2.6-rmk patch, you'll notice that it contains
an abstracted RTC driver - I got peed off with writing the same code
to support the user interfaces to the variety of RTCs over and over
again.  (Ones which are simple 32-bit second counters with alarms
through to ones which return D/M/Y H:M:S.C format.)

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 PCMCIA      - http://pcmcia.arm.linux.org.uk/
                 2.6 Serial core

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:02 [PATCH] 2.6 I2C epson 8564 RTC chip stefan.eletzhofer
  2004-04-29 12:41 ` Ian Campbell
@ 2004-04-29 12:59 ` Ian Campbell
  2004-04-29 13:55   ` stefan.eletzhofer
  2004-05-01  5:48 ` Greg KH
  2 siblings, 1 reply; 15+ messages in thread
From: Ian Campbell @ 2004-04-29 12:59 UTC (permalink / raw
  To: stefan.eletzhofer; +Cc: Linux Kernel Mailing List, Andrew Morton, Greg KH

On Thu, 2004-04-29 at 13:02, stefan.eletzhofer@eletztrick.de wrote:
> This driver only does the low-level I2C stuff, the rtc misc device
> driver is a separate driver module which I will send a patch for soon.

By the way -- I notice you have said you need i2c_get_client for your
RTC driver to locate the i2c chip it wants to work with. 

Just a thought -- perhaps it would make sense to reverse the roles and
for the rtc driver to export a 'register_rtc_device' type call which the
specific i2c chip driver could then call to hook itself up to /dev/rtc

Ian.

-- 
Ian Campbell, Senior Design Engineer
                                        Web: http://www.arcom.com
Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200


_____________________________________________________________________
The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.

This message has been virus scanned by MessageLabs.

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:59 ` Ian Campbell
@ 2004-04-29 13:55   ` stefan.eletzhofer
  0 siblings, 0 replies; 15+ messages in thread
From: stefan.eletzhofer @ 2004-04-29 13:55 UTC (permalink / raw
  To: Linux Kernel Mailing List; +Cc: Russell King - ARM Linux, Ian Campbell, Greg KH

On Thu, Apr 29, 2004 at 01:59:40PM +0100, Ian Campbell wrote:
> On Thu, 2004-04-29 at 13:02, stefan.eletzhofer@eletztrick.de wrote:
> > This driver only does the low-level I2C stuff, the rtc misc device
> > driver is a separate driver module which I will send a patch for soon.
> 
> By the way -- I notice you have said you need i2c_get_client for your
> RTC driver to locate the i2c chip it wants to work with. 

Correct. I'll send a patch which re-adds this call to 2.6.6-rcx.

> 
> Just a thought -- perhaps it would make sense to reverse the roles and
> for the rtc driver to export a 'register_rtc_device' type call which the
> specific i2c chip driver could then call to hook itself up to /dev/rtc

The problem with this approach is IHMO that you need the i2c_client struct in
I2C chrip driver as well (to call the i2c access primitives). You'd need to
store the pointer to the client somewhere in the driver itself. What if we have
more than one client per driver?

IMHO the call i2c_get_client() is nice and clean. One could wish another call like
  int i2c_command( struct i2c_client *c, long cmd, void *arg );
whcih does a
  client->driver->command( client, cmd, arg );
internally.

> 
> Ian.
> 
> -- 
> Ian Campbell, Senior Design Engineer
>                                         Web: http://www.arcom.com
> Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
> Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200
> 
> 
> _____________________________________________________________________
> The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.
> 
> This message has been virus scanned by MessageLabs.
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Eletztrick Computing - Customized Linux Development
Stefan Eletzhofer, Marktstrasse 43, DE-88214 Ravensburg
http://www.eletztrick.de

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:54   ` Russell King
@ 2004-04-29 13:58     ` stefan.eletzhofer
  2004-04-29 14:14       ` Ian Campbell
  2004-04-29 22:40     ` Tom Rini
  1 sibling, 1 reply; 15+ messages in thread
From: stefan.eletzhofer @ 2004-04-29 13:58 UTC (permalink / raw
  To: Linux Kernel Mailing List; +Cc: Ian Campbell, Russell King - ARM Linux

On Thu, Apr 29, 2004 at 01:54:08PM +0100, Russell King wrote:
> On Thu, Apr 29, 2004 at 01:41:23PM +0100, Ian Campbell wrote:
> > Hi Stefan,
> > 
> > > This driver only does the low-level I2C stuff, the rtc misc device
> > > driver is a separate driver module which I will send a patch for soon.
> > 
> > I have a patch (attached, it could do with cleaning up) for the Dallas
> > DS1307 I2C RTC which I ported from the 2.4 rmk patch, originally written
> > by Intrinsyc. Currently it includes both the I2C and the RTC bits in the
> > same driver.
> 
> Have a look at drivers/acorn/char/{i2c,pcf8583}.[ch]
> 
> > Do you think it is realistic/possible to have the same generic RTC
> > driver speak to multiple I2C devices, from what I can see in your driver
> > the two chips seem pretty similar and the differences could probably be
> > abstracted away. Perhaps that is your intention from the start?
> > 
> > I guess I will wait until you post the RTC misc driver and try and make
> > the DS1307 one work with that before I submit it.
> 
> If you look at the last 2.6-rmk patch, you'll notice that it contains
> an abstracted RTC driver - I got peed off with writing the same code
> to support the user interfaces to the variety of RTCs over and over
> again.  (Ones which are simple 32-bit second counters with alarms
> through to ones which return D/M/Y H:M:S.C format.)

Oh, I wasn't aware of that. I assume that one is not in linus bk tree already?

> 
> -- 
> Russell King
>  Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
>  maintainer of:  2.6 PCMCIA      - http://pcmcia.arm.linux.org.uk/
>                  2.6 Serial core
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Eletztrick Computing - Customized Linux Development
Stefan Eletzhofer, Marktstrasse 43, DE-88214 Ravensburg
http://www.eletztrick.de

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 13:58     ` stefan.eletzhofer
@ 2004-04-29 14:14       ` Ian Campbell
  2004-04-29 14:28         ` stefan.eletzhofer
  0 siblings, 1 reply; 15+ messages in thread
From: Ian Campbell @ 2004-04-29 14:14 UTC (permalink / raw
  To: stefan.eletzhofer; +Cc: Linux Kernel Mailing List, Russell King - ARM Linux

On Thu, 2004-04-29 at 14:58, stefan.eletzhofer@eletztrick.de wrote:
> On Thu, Apr 29, 2004 at 01:54:08PM +0100, Russell King wrote:
> > If you look at the last 2.6-rmk patch, you'll notice that it contains
> > an abstracted RTC driver - I got peed off with writing the same code
> > to support the user interfaces to the variety of RTCs over and over
> > again.  (Ones which are simple 32-bit second counters with alarms
> > through to ones which return D/M/Y H:M:S.C format.)
> 
> Oh, I wasn't aware of that. I assume that one is not in linus bk tree already?

I don't think so. I found it in patch-2.6.0-test9-rmk1. In particular
arch/arm/common/rtctime.c and include/asm-arm/rtc.h which implement the
generic RTC bit. drivers/char/sa1100-rtc.c and
linux/arch/arm/mach-integrator/time.c have been ported to use it.

It looks very useful, and it would be pretty easy to make an i2c RTC use
it as well.

Ian.
-- 
Ian Campbell, Senior Design Engineer
                                        Web: http://www.arcom.com
Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200


_____________________________________________________________________
The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.

This message has been virus scanned by MessageLabs.

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 14:14       ` Ian Campbell
@ 2004-04-29 14:28         ` stefan.eletzhofer
  0 siblings, 0 replies; 15+ messages in thread
From: stefan.eletzhofer @ 2004-04-29 14:28 UTC (permalink / raw
  To: Linux Kernel Mailing List

On Thu, Apr 29, 2004 at 03:14:24PM +0100, Ian Campbell wrote:
> On Thu, 2004-04-29 at 14:58, stefan.eletzhofer@eletztrick.de wrote:
> > On Thu, Apr 29, 2004 at 01:54:08PM +0100, Russell King wrote:
> > > If you look at the last 2.6-rmk patch, you'll notice that it contains
> > > an abstracted RTC driver - I got peed off with writing the same code
> > > to support the user interfaces to the variety of RTCs over and over
> > > again.  (Ones which are simple 32-bit second counters with alarms
> > > through to ones which return D/M/Y H:M:S.C format.)
> > 
> > Oh, I wasn't aware of that. I assume that one is not in linus bk tree already?
> 
> I don't think so. I found it in patch-2.6.0-test9-rmk1. In particular
> arch/arm/common/rtctime.c and include/asm-arm/rtc.h which implement the
> generic RTC bit. drivers/char/sa1100-rtc.c and
> linux/arch/arm/mach-integrator/time.c have been ported to use it.
> 
> It looks very useful, and it would be pretty easy to make an i2c RTC use
> it as well.

Ah, haven't had a look at 2.6.0-test9 for some time now. I'll try to check
these and maybe I'll port my rtc driver over to it. Maybe these files
sould be moved out of the arm tree, though? It may well be that other platforms
are interested it (at last I've found a drivers/char/genrtc.c ...).

> 
> Ian.
> -- 
> Ian Campbell, Senior Design Engineer
>                                         Web: http://www.arcom.com
> Arcom, Clifton Road, 			Direct: +44 (0)1223 403 465
> Cambridge CB1 7EA, United Kingdom	Phone:  +44 (0)1223 411 200
> 
> 
> _____________________________________________________________________
> The message in this transmission is sent in confidence for the attention of the addressee only and should not be disclosed to any other party. Unauthorised recipients are requested to preserve this confidentiality. Please advise the sender if the addressee is not resident at the receiving end.  Email to and from Arcom is automatically monitored for operational and lawful business reasons.
> 
> This message has been virus scanned by MessageLabs.
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Eletztrick Computing - Customized Linux Development
Stefan Eletzhofer, Marktstrasse 43, DE-88214 Ravensburg
http://www.eletztrick.de

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:54   ` Russell King
  2004-04-29 13:58     ` stefan.eletzhofer
@ 2004-04-29 22:40     ` Tom Rini
  2004-04-29 22:49       ` Russell King
  1 sibling, 1 reply; 15+ messages in thread
From: Tom Rini @ 2004-04-29 22:40 UTC (permalink / raw
  To: Ian Campbell, stefan.eletzhofer, Linux Kernel Mailing List,
	Andrew Morton, Greg KH

On Thu, Apr 29, 2004 at 01:54:08PM +0100, Russell King wrote:
> On Thu, Apr 29, 2004 at 01:41:23PM +0100, Ian Campbell wrote:
> > Hi Stefan,
> > 
> > > This driver only does the low-level I2C stuff, the rtc misc device
> > > driver is a separate driver module which I will send a patch for soon.
> > 
> > I have a patch (attached, it could do with cleaning up) for the Dallas
> > DS1307 I2C RTC which I ported from the 2.4 rmk patch, originally written
> > by Intrinsyc. Currently it includes both the I2C and the RTC bits in the
> > same driver.
> 
> Have a look at drivers/acorn/char/{i2c,pcf8583}.[ch]
> 
> > Do you think it is realistic/possible to have the same generic RTC
> > driver speak to multiple I2C devices, from what I can see in your driver
> > the two chips seem pretty similar and the differences could probably be
> > abstracted away. Perhaps that is your intention from the start?
> > 
> > I guess I will wait until you post the RTC misc driver and try and make
> > the DS1307 one work with that before I submit it.
> 
> If you look at the last 2.6-rmk patch, you'll notice that it contains
> an abstracted RTC driver - I got peed off with writing the same code
> to support the user interfaces to the variety of RTCs over and over
> again.  (Ones which are simple 32-bit second counters with alarms
> through to ones which return D/M/Y H:M:S.C format.)

A generic one for i2c rtcs or another generic rtc driver?  There's
already drivers/char/genrtc.c...

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 22:40     ` Tom Rini
@ 2004-04-29 22:49       ` Russell King
  2004-04-29 22:52         ` Tom Rini
  0 siblings, 1 reply; 15+ messages in thread
From: Russell King @ 2004-04-29 22:49 UTC (permalink / raw
  To: Tom Rini
  Cc: Ian Campbell, stefan.eletzhofer, Linux Kernel Mailing List,
	Andrew Morton, Greg KH

On Thu, Apr 29, 2004 at 03:40:07PM -0700, Tom Rini wrote:
> A generic one for i2c rtcs or another generic rtc driver?  There's
> already drivers/char/genrtc.c...

genrtc.c lacks several features ARM needs, the big one being wakeup
timers.  It also only provides either (configurable) emulation or no
support of various RTC features, rather than allowing a real RTC to
provide them if it can - and you need to know the details of your RTC
at kernel configuration time.

It provides no support for translating "RTC" time into seconds and
vice versa which is needed for second-counter based RTCs found in
PXA, StrongARM, and other ARM SoC platforms.

IOW, its fairly restrictive in what it provides and what it allows
architectures to provide.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 PCMCIA      - http://pcmcia.arm.linux.org.uk/
                 2.6 Serial core

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 22:49       ` Russell King
@ 2004-04-29 22:52         ` Tom Rini
  2004-04-29 23:07           ` Russell King
  0 siblings, 1 reply; 15+ messages in thread
From: Tom Rini @ 2004-04-29 22:52 UTC (permalink / raw
  To: Ian Campbell, stefan.eletzhofer, Linux Kernel Mailing List,
	Andrew Morton, Greg KH

On Thu, Apr 29, 2004 at 11:49:45PM +0100, Russell King wrote:
> On Thu, Apr 29, 2004 at 03:40:07PM -0700, Tom Rini wrote:
> > A generic one for i2c rtcs or another generic rtc driver?  There's
> > already drivers/char/genrtc.c...
> 
> genrtc.c lacks several features ARM needs, the big one being wakeup
> timers.  It also only provides either (configurable) emulation or no
> support of various RTC features, rather than allowing a real RTC to
> provide them if it can - and you need to know the details of your RTC
> at kernel configuration time.

Having hacked at this, and just not having had the time to clean it up a
bit more yet, did you try adding it to genrtc at least?

> It provides no support for translating "RTC" time into seconds and
> vice versa which is needed for second-counter based RTCs found in
> PXA, StrongARM, and other ARM SoC platforms.

It couldn't be added in?

> IOW, its fairly restrictive in what it provides and what it allows
> architectures to provide.

Either way, I'd like to not have 2 generic rtc drivers if at all
possible...

-- 
Tom Rini
http://gate.crashing.org/~trini/

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 22:52         ` Tom Rini
@ 2004-04-29 23:07           ` Russell King
  0 siblings, 0 replies; 15+ messages in thread
From: Russell King @ 2004-04-29 23:07 UTC (permalink / raw
  To: Tom Rini
  Cc: Ian Campbell, stefan.eletzhofer, Linux Kernel Mailing List,
	Andrew Morton, Greg KH

On Thu, Apr 29, 2004 at 03:52:38PM -0700, Tom Rini wrote:
> Either way, I'd like to not have 2 generic rtc drivers if at all
> possible...

So would I...

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 PCMCIA      - http://pcmcia.arm.linux.org.uk/
                 2.6 Serial core

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-04-29 12:02 [PATCH] 2.6 I2C epson 8564 RTC chip stefan.eletzhofer
  2004-04-29 12:41 ` Ian Campbell
  2004-04-29 12:59 ` Ian Campbell
@ 2004-05-01  5:48 ` Greg KH
  2004-05-01  9:26   ` stefan.eletzhofer
  2 siblings, 1 reply; 15+ messages in thread
From: Greg KH @ 2004-05-01  5:48 UTC (permalink / raw
  To: stefan.eletzhofer, linux-kernel, Andrew Morton

On Thu, Apr 29, 2004 at 02:02:50PM +0200, stefan.eletzhofer@eletztrick.de wrote:
> +	if ( !buf || !client ) {

Can you clean up your exuberant use of spaces in 'if' statements, and
function calls?  It's not the proper kernel style.

> +DONE:

Lowercase please

> +	if ( ret ) {
> +		if ( d ) kfree( d );

No need to check a pointer before sending it to kfree.

thanks,

greg k-h

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-05-01  5:48 ` Greg KH
@ 2004-05-01  9:26   ` stefan.eletzhofer
  2004-05-02  5:51     ` Greg KH
  0 siblings, 1 reply; 15+ messages in thread
From: stefan.eletzhofer @ 2004-05-01  9:26 UTC (permalink / raw
  To: linux-kernel; +Cc: Greg KH, Andrew Morton

[-- Attachment #1: Type: text/plain, Size: 1092 bytes --]

On Fri, Apr 30, 2004 at 10:48:04PM -0700, Greg KH wrote:
> On Thu, Apr 29, 2004 at 02:02:50PM +0200, stefan.eletzhofer@eletztrick.de wrote:
> > +	if ( !buf || !client ) {
> 
> Can you clean up your exuberant use of spaces in 'if' statements, and
> function calls?  It's not the proper kernel style.
> 
> > +DONE:
> 
> Lowercase please
> 
> > +	if ( ret ) {
> > +		if ( d ) kfree( d );
> 
> No need to check a pointer before sending it to kfree.

Ok, that should be it. I've also ran the source through Lindent,
which fixed some further things. I've reverted the indention change
for labels, though. I think labels should be at level zero, should
they?

thanks,
 Stefan E.

> 
> thanks,
> 
> greg k-h
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

-- 
Eletztrick Computing - Customized Linux Development
Stefan Eletzhofer, Marktstrasse 43, DE-88214 Ravensburg
http://www.eletztrick.de

[-- Attachment #2: i2c-rtc8564.patch --]
[-- Type: text/plain, Size: 13176 bytes --]

Add support for the Epson 8564 RTC chip.

#
# Patch managed by http://www.mn-logistik.de/unsupported/pxa250/patcher
#

--- /dev/null
+++ linux-ra_alpha-update/drivers/i2c/chips/rtc8564.c
@@ -0,0 +1,396 @@
+/*
+ *  linux/drivers/i2c/chips/rtc8564.c
+ *
+ *  Copyright (C) 2002-2004 Stefan Eletzhofer
+ *
+ *	based on linux/drivers/acron/char/pcf8583.c
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Driver for system3's EPSON RTC 8564 chip
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/rtc.h>		/* get the user-level API */
+#include <linux/init.h>
+#include <linux/init.h>
+
+#include "rtc8564.h"
+
+#ifdef DEBUG
+# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0);
+#else
+# define _DBG(x, fmt, args...) do { } while(0);
+#endif
+
+#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \
+			"mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \
+			(rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \
+			(rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl);
+
+struct rtc8564_data {
+	struct i2c_client client;
+	u16 ctrl;
+};
+
+static inline u8 _rtc8564_ctrl1(struct i2c_client *client)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	return data->ctrl & 0xff;
+}
+static inline u8 _rtc8564_ctrl2(struct i2c_client *client)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	return (data->ctrl & 0xff00) >> 8;
+}
+
+#define CTRL1(c) _rtc8564_ctrl1(c)
+#define CTRL2(c) _rtc8564_ctrl2(c)
+
+#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)
+#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)
+
+static int debug = 0;
+MODULE_PARM(debug, "i");
+
+static struct i2c_driver rtc8564_driver;
+
+static unsigned short ignore[] = { I2C_CLIENT_END };
+static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+	.normal_i2c		= normal_addr,
+	.normal_i2c_range	= ignore,
+	.probe			= ignore,
+	.probe_range		= ignore,
+	.ignore			= ignore,
+	.ignore_range		= ignore,
+	.force			= ignore,
+};
+
+static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
+static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem);
+
+static int rtc8564_read(struct i2c_client *client, unsigned char adr,
+			unsigned char *buf, unsigned char len)
+{
+	int ret = -EIO;
+	unsigned char addr[1] = { adr };
+	struct i2c_msg msgs[2] = {
+		{client->addr, 0, 1, addr},
+		{client->addr, I2C_M_RD, len, buf}
+	};
+
+	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len);
+
+	if (!buf || !client) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	if (ret == 2) {
+		ret = 0;
+	}
+
+done:
+	return ret;
+}
+
+static int rtc8564_write(struct i2c_client *client, unsigned char adr,
+			 unsigned char *data, unsigned char len)
+{
+	int ret = 0;
+	unsigned char _data[16];
+	struct i2c_msg wr;
+	int i;
+
+	if (!client || !data || len > 15) {
+		ret = -EINVAL;
+		goto done;
+	}
+
+	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len);
+
+	_data[0] = adr;
+	for (i = 0; i < len; i++) {
+		_data[i + 1] = data[i];
+		_DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]);
+	}
+
+	wr.addr = client->addr;
+	wr.flags = 0;
+	wr.len = len + 1;
+	wr.buf = _data;
+
+	ret = i2c_transfer(client->adapter, &wr, 1);
+	if (ret == 1) {
+		ret = 0;
+	}
+
+done:
+	return ret;
+}
+
+static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+	int ret;
+	struct i2c_client *new_client;
+	struct rtc8564_data *d;
+	unsigned char data[10];
+	unsigned char ad[1] = { 0 };
+	struct i2c_msg ctrl_wr[1] = {
+		{addr, 0, 2, data}
+	};
+	struct i2c_msg ctrl_rd[2] = {
+		{addr, 0, 1, ad},
+		{addr, I2C_M_RD, 2, data}
+	};
+
+	d = kmalloc(sizeof(struct rtc8564_data), GFP_KERNEL);
+	if (!d) {
+		ret = -ENOMEM;
+		goto done;
+	}
+	memset(d, 0, sizeof(struct rtc8564_data));
+	new_client = &d->client;
+
+	strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
+	i2c_set_clientdata(new_client, d);
+	new_client->id = rtc8564_driver.id;
+	new_client->flags = I2C_CLIENT_ALLOW_USE | I2C_DF_NOTIFY;
+	new_client->addr = addr;
+	new_client->adapter = adap;
+	new_client->driver = &rtc8564_driver;
+
+	_DBG(1, "client=%p", new_client);
+	_DBG(1, "client.id=%d", new_client->id);
+
+	/* init ctrl1 reg */
+	data[0] = 0;
+	data[1] = 0;
+	ret = i2c_transfer(new_client->adapter, ctrl_wr, 1);
+	if (ret != 1) {
+		printk(KERN_INFO "rtc8564: cant init ctrl1\n");
+		ret = -ENODEV;
+		goto done;
+	}
+
+	/* read back ctrl1 and ctrl2 */
+	ret = i2c_transfer(new_client->adapter, ctrl_rd, 2);
+	if (ret != 2) {
+		printk(KERN_INFO "rtc8564: cant read ctrl\n");
+		ret = -ENODEV;
+		goto done;
+	}
+
+	d->ctrl = data[0] | (data[1] << 8);
+
+	_DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x",
+	     data[0], data[1]);
+
+	ret = i2c_attach_client(new_client);
+done:
+	if (ret) {
+		kfree(d);
+	}
+	return ret;
+}
+
+static int rtc8564_probe(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, rtc8564_attach);
+}
+
+static int rtc8564_detach(struct i2c_client *client)
+{
+	i2c_detach_client(client);
+	kfree(i2c_get_clientdata(client));
+	return 0;
+}
+
+static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
+{
+	int ret = -EIO;
+	unsigned char buf[15];
+
+	_DBG(1, "client=%p, dt=%p", client, dt);
+
+	if (!dt || !client)
+		return -EINVAL;
+
+	memset(buf, 0, sizeof(buf));
+
+	ret = rtc8564_read(client, 0, buf, 15);
+	if (ret)
+		return ret;
+
+	/* century stored in minute alarm reg */
+	dt->year = BCD_TO_BIN(buf[RTC8564_REG_YEAR]);
+	dt->year += 100 * BCD_TO_BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
+	dt->mday = BCD_TO_BIN(buf[RTC8564_REG_DAY] & 0x3f);
+	dt->wday = BCD_TO_BIN(buf[RTC8564_REG_WDAY] & 7);
+	dt->mon = BCD_TO_BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
+
+	dt->secs = BCD_TO_BIN(buf[RTC8564_REG_SEC] & 0x7f);
+	dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80;
+	dt->mins = BCD_TO_BIN(buf[RTC8564_REG_MIN] & 0x7f);
+	dt->hours = BCD_TO_BIN(buf[RTC8564_REG_HR] & 0x3f);
+
+	_DBGRTCTM(2, *dt);
+
+	return 0;
+}
+
+static int
+rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
+{
+	int ret, len = 5;
+	unsigned char buf[15];
+
+	_DBG(1, "client=%p, dt=%p", client, dt);
+
+	if (!dt || !client)
+		return -EINVAL;
+
+	_DBGRTCTM(2, *dt);
+
+	buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
+	buf[RTC8564_REG_CTRL2] = CTRL2(client);
+	buf[RTC8564_REG_SEC] = BIN_TO_BCD(dt->secs);
+	buf[RTC8564_REG_MIN] = BIN_TO_BCD(dt->mins);
+	buf[RTC8564_REG_HR] = BIN_TO_BCD(dt->hours);
+
+	if (datetoo) {
+		len += 5;
+		buf[RTC8564_REG_DAY] = BIN_TO_BCD(dt->mday);
+		buf[RTC8564_REG_WDAY] = BIN_TO_BCD(dt->wday);
+		buf[RTC8564_REG_MON_CENT] = BIN_TO_BCD(dt->mon) & 0x1f;
+		/* century stored in minute alarm reg */
+		buf[RTC8564_REG_YEAR] = BIN_TO_BCD(dt->year % 100);
+		buf[RTC8564_REG_AL_MIN] = BIN_TO_BCD(dt->year / 100);
+	}
+
+	ret = rtc8564_write(client, 0, buf, len);
+	if (ret) {
+		_DBG(1, "error writing data! %d", ret);
+	}
+
+	buf[RTC8564_REG_CTRL1] = CTRL1(client);
+	ret = rtc8564_write(client, 0, buf, 1);
+	if (ret) {
+		_DBG(1, "error writing data! %d", ret);
+	}
+
+	return ret;
+}
+
+static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+
+	if (!ctrl || !client)
+		return -1;
+
+	*ctrl = data->ctrl;
+	return 0;
+}
+
+static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl)
+{
+	struct rtc8564_data *data = i2c_get_clientdata(client);
+	unsigned char buf[2];
+
+	if (!ctrl || !client)
+		return -1;
+
+	buf[0] = *ctrl & 0xff;
+	buf[1] = (*ctrl & 0xff00) >> 8;
+	data->ctrl = *ctrl;
+
+	return rtc8564_write(client, 0, buf, 2);
+}
+
+static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
+{
+
+	if (!mem || !client)
+		return -EINVAL;
+
+	return rtc8564_read(client, mem->loc, mem->data, mem->nr);
+}
+
+static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
+{
+
+	if (!mem || !client)
+		return -EINVAL;
+
+	return rtc8564_write(client, mem->loc, mem->data, mem->nr);
+}
+
+static int
+rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+
+	_DBG(1, "cmd=%d", cmd);
+
+	switch (cmd) {
+	case RTC_GETDATETIME:
+		return rtc8564_get_datetime(client, arg);
+
+	case RTC_SETTIME:
+		return rtc8564_set_datetime(client, arg, 0);
+
+	case RTC_SETDATETIME:
+		return rtc8564_set_datetime(client, arg, 1);
+
+	case RTC_GETCTRL:
+		return rtc8564_get_ctrl(client, arg);
+
+	case RTC_SETCTRL:
+		return rtc8564_set_ctrl(client, arg);
+
+	case MEM_READ:
+		return rtc8564_read_mem(client, arg);
+
+	case MEM_WRITE:
+		return rtc8564_write_mem(client, arg);
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct i2c_driver rtc8564_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "RTC8564",
+	.id		= I2C_DRIVERID_RTC8564,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter = rtc8564_probe,
+	.detach_client	= rtc8564_detach,
+	.command	= rtc8564_command
+};
+
+static __init int rtc8564_init(void)
+{
+	return i2c_add_driver(&rtc8564_driver);
+}
+
+static __exit void rtc8564_exit(void)
+{
+	i2c_del_driver(&rtc8564_driver);
+}
+
+MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>");
+MODULE_DESCRIPTION("EPSON RTC8564 Driver");
+MODULE_LICENSE("GPL");
+
+module_init(rtc8564_init);
+module_exit(rtc8564_exit);
--- /dev/null
+++ linux-ra_alpha-update/drivers/i2c/chips/rtc8564.h
@@ -0,0 +1,78 @@
+/*
+ *  linux/drivers/i2c/chips/rtc8564.h
+ *
+ *  Copyright (C) 2002-2004 Stefan Eletzhofer
+ *
+ *	based on linux/drivers/acron/char/pcf8583.h
+ *  Copyright (C) 2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+struct rtc_tm {
+	unsigned char	secs;
+	unsigned char	mins;
+	unsigned char	hours;
+	unsigned char	mday;
+	unsigned char	mon;
+	unsigned short	year; /* xxxx 4 digits :) */
+	unsigned char	wday;
+	unsigned char	vl;
+};
+
+struct mem {
+	unsigned int	loc;
+	unsigned int	nr;
+	unsigned char	*data;
+};
+
+#define RTC_GETDATETIME	0
+#define RTC_SETTIME	1
+#define RTC_SETDATETIME	2
+#define RTC_GETCTRL	3
+#define RTC_SETCTRL	4
+#define MEM_READ	5
+#define MEM_WRITE	6
+
+#define RTC8564_REG_CTRL1		0x0 /* T  0 S 0 | T 0 0 0 */
+#define RTC8564_REG_CTRL2		0x1 /* 0  0 0 TI/TP | AF TF AIE TIE */
+#define RTC8564_REG_SEC			0x2 /* VL 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_MIN			0x3 /* x  4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_HR			0x4 /* x  x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_DAY			0x5 /* x  x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_WDAY		0x6 /* x  x x x | x 4 2 1 */
+#define RTC8564_REG_MON_CENT	0x7 /* C  x x 1 | 8 4 2 1 */
+#define RTC8564_REG_YEAR		0x8 /* 8  4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_MIN		0x9 /* AE 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_HR		0xa /* AE 4 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_DAY		0xb /* AE x 2 1 | 8 4 2 1 */
+#define RTC8564_REG_AL_WDAY		0xc /* AE x x x | x 4 2 1 */
+#define RTC8564_REG_CLKOUT		0xd /* FE x x x | x x FD1 FD0 */
+#define RTC8564_REG_TCTL		0xe /* TE x x x | x x FD1 FD0 */
+#define RTC8564_REG_TIMER		0xf /* 8 bit binary */
+
+/* Control reg */
+#define RTC8564_CTRL1_TEST1		(1<<3)
+#define RTC8564_CTRL1_STOP		(1<<5)
+#define RTC8564_CTRL1_TEST2		(1<<7)
+
+#define RTC8564_CTRL2_TIE		(1<<0)
+#define RTC8564_CTRL2_AIE		(1<<1)
+#define RTC8564_CTRL2_TF		(1<<2)
+#define RTC8564_CTRL2_AF		(1<<3)
+#define RTC8564_CTRL2_TI_TP		(1<<4)
+
+/* CLKOUT frequencies */
+#define RTC8564_FD_32768HZ		(0x0)
+#define RTC8564_FD_1024HZ		(0x1)
+#define RTC8564_FD_32			(0x2)
+#define RTC8564_FD_1HZ			(0x3)
+
+/* Timer CTRL */
+#define RTC8564_TD_4096HZ		(0x0)
+#define RTC8564_TD_64HZ			(0x1)
+#define RTC8564_TD_1HZ			(0x2)
+#define RTC8564_TD_1_60HZ		(0x3)
+
+#define I2C_DRIVERID_RTC8564 0xf000
--- linux-ra_alpha-update/drivers/i2c/chips/Makefile~i2c-rtc8564
+++ linux-ra_alpha-update/drivers/i2c/chips/Makefile
@@ -21,6 +21,7 @@
 obj-$(CONFIG_SENSORS_LM90)	+= lm90.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
 obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 
--- linux-ra_alpha-update/drivers/i2c/chips/Kconfig~i2c-rtc8564
+++ linux-ra_alpha-update/drivers/i2c/chips/Kconfig
@@ -230,4 +230,14 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8591.
 
+config SENSORS_RTC8564
+	tristate "Epson 8564 RTC chip"
+	depends on I2C && EXPERIMENTAL
+	select I2C_SENSOR
+	help
+	  If you say yes here you get support for the Epson 8564 RTC chip.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-rtc8564.
+
 endmenu

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

* Re: [PATCH] 2.6 I2C epson 8564 RTC chip
  2004-05-01  9:26   ` stefan.eletzhofer
@ 2004-05-02  5:51     ` Greg KH
  0 siblings, 0 replies; 15+ messages in thread
From: Greg KH @ 2004-05-02  5:51 UTC (permalink / raw
  To: stefan.eletzhofer, linux-kernel, Andrew Morton

On Sat, May 01, 2004 at 11:26:04AM +0200, stefan.eletzhofer@eletztrick.de wrote:
> On Fri, Apr 30, 2004 at 10:48:04PM -0700, Greg KH wrote:
> > On Thu, Apr 29, 2004 at 02:02:50PM +0200, stefan.eletzhofer@eletztrick.de wrote:
> > > +	if ( !buf || !client ) {
> > 
> > Can you clean up your exuberant use of spaces in 'if' statements, and
> > function calls?  It's not the proper kernel style.
> > 
> > > +DONE:
> > 
> > Lowercase please
> > 
> > > +	if ( ret ) {
> > > +		if ( d ) kfree( d );
> > 
> > No need to check a pointer before sending it to kfree.
> 
> Ok, that should be it. I've also ran the source through Lindent,
> which fixed some further things. I've reverted the indention change
> for labels, though. I think labels should be at level zero, should
> they?

Looks good, applied, thanks.

greg k-h

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

end of thread, other threads:[~2004-05-02  6:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-04-29 12:02 [PATCH] 2.6 I2C epson 8564 RTC chip stefan.eletzhofer
2004-04-29 12:41 ` Ian Campbell
2004-04-29 12:54   ` Russell King
2004-04-29 13:58     ` stefan.eletzhofer
2004-04-29 14:14       ` Ian Campbell
2004-04-29 14:28         ` stefan.eletzhofer
2004-04-29 22:40     ` Tom Rini
2004-04-29 22:49       ` Russell King
2004-04-29 22:52         ` Tom Rini
2004-04-29 23:07           ` Russell King
2004-04-29 12:59 ` Ian Campbell
2004-04-29 13:55   ` stefan.eletzhofer
2004-05-01  5:48 ` Greg KH
2004-05-01  9:26   ` stefan.eletzhofer
2004-05-02  5:51     ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.