linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add max6902 RTC support
@ 2006-05-30 15:09 Raphael Assenat
  2006-05-30 18:32 ` Alessandro Zummo
  0 siblings, 1 reply; 9+ messages in thread
From: Raphael Assenat @ 2006-05-30 15:09 UTC (permalink / raw)
  To: a.zummo; +Cc: linux-kernel

This patch adds support for the MAX6902 SPI RTC chip. Applies on 2.6.17-rc5. Tested on a 
pxa2xx cpu.

Signed-off-by: Raphael Assenat <raph@raphnet.net>
---

--- linux-2.6.17-rc5/drivers/rtc/Kconfig	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Kconfig	2006-05-25 15:59:53.000000000 -0400
@@ -172,4 +172,14 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-test.
 
+config RTC_DRV_MAX6902
+	tristate "Maxim 6902"
+	depends on RTC_CLASS && SPI 
+	help
+	  If you say yes here you will get support for the
+	  Maxim MAX6902 spi RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max6902.
+
 endmenu
--- linux-2.6.17-rc5/drivers/rtc/Makefile	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Makefile	2006-05-25 15:58:38.000000000 -0400
@@ -20,3 +20,4 @@
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
--- linux-2.6.17-rc5/drivers/rtc/rtc-max6902.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.17-rc5-8d/drivers/rtc/rtc-max6902.c	2006-05-30 11:11:23.000000000 -0400
@@ -0,0 +1,289 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ * 
+ * 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 MAX6902 spi RTC
+ * 
+ * Changelog:
+ * 
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ *                - Major rework
+ *   				Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ *                - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+ 
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#include <asm/delay.h>
+
+#define MAX6902_REG_SECONDS		0x01
+#define MAX6902_REG_MINUTES		0x03
+#define MAX6902_REG_HOURS		0x05
+#define MAX6902_REG_DATE		0x07
+#define MAX6902_REG_MONTH		0x09
+#define MAX6902_REG_DAY			0x0B
+#define MAX6902_REG_YEAR		0x0D
+#define MAX6902_REG_CONTROL		0x0F
+#define MAX6902_REG_CENTURY		0x13
+
+
+//#define RTC_DEBUG
+
+struct max6902 {
+	struct rtc_device *rtc;
+	u8 buf[9]; /* Burst read cmd + 8 registers */
+	u8 tx_buf[2];
+	u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address, 
+														unsigned char data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	/* MSB must be '0' to write */
+	buf[0] = address & 0x7f;
+	buf[1] = data;
+	
+	spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address, unsigned char *data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	if (!data) return -EINVAL;
+
+	/* Build our spi message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));	
+	xfer.len = 2;
+	/* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+	xfer.tx_buf = chip->tx_buf;
+	xfer.rx_buf = chip->rx_buf;
+
+	/* Set MSB to indicate read */
+	chip->tx_buf[0] = address | 0x80;
+
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	*data = chip->rx_buf[1];
+	
+	return status;
+}
+ 
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+	unsigned char tmp;
+	int century;
+	int err;
+
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+	if (err)
+		return err;
+
+	/* build the message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.len = 1 + 7; /* Burst read command + 7 registers */
+	xfer.tx_buf = chip->buf;
+	xfer.rx_buf = chip->buf;
+	chip->buf[0] = 0xbf; // Burst read
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	/* The chip sends data in this order:
+	 * Seconds, Minutes, Hours, Date, Month, Day, Year */
+	dt->tm_sec	= BCD2BIN(chip->buf[1]);
+	dt->tm_min	= BCD2BIN(chip->buf[2]);
+	dt->tm_hour	= BCD2BIN(chip->buf[3]);
+	dt->tm_mday	= BCD2BIN(chip->buf[4]);
+	dt->tm_mon	= BCD2BIN(chip->buf[5] - 1);
+	dt->tm_wday	= BCD2BIN(chip->buf[6]);
+	dt->tm_year = BCD2BIN(chip->buf[7]);
+
+
+	century = BCD2BIN(tmp) * 100;
+
+	dt->tm_year += century;
+	dt->tm_year -= 1900;
+
+#ifdef RTC_DEBUG
+	printk("\n%s : Read RTC values\n",__FUNCTION__);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_year: %i\n",dt->tm_year);
+	printk("tm_mon : %i\n",dt->tm_mon);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+	return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+	dt->tm_year = dt->tm_year+1900;
+
+#ifdef RTC_DEBUG
+	printk("\n%s : Setting RTC values\n",__FUNCTION__);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+	printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+	// Remove write protection
+	max6902_set_reg(dev, 0xF, 0);
+
+	max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+	max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+	max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+	max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+	max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+	max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+	max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+	max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+	/* Compulab used a delay here. However, the datasheet
+	 * does not mention a delay being required anywhere... */
+	/* delay(2000); */
+
+	// Write protect
+	max6902_set_reg(dev, 0xF, 0x80);
+
+	return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+	.read_time	= max6902_read_time,
+	.set_time	= max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+	struct rtc_device *rtc;
+	unsigned char tmp;
+	struct max6902 *chip;
+	int res;
+
+	rtc = rtc_device_register("max6902",
+				&spi->dev, &max6902_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		return PTR_ERR(rtc);
+	}
+
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (!chip) {
+		rtc_device_unregister(rtc);
+		return -ENOMEM;
+	}
+	chip->rtc = rtc;
+	dev_set_drvdata(&spi->dev, chip);	
+	
+	res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+	if (res) {
+		rtc_device_unregister(rtc);
+		return res;
+	}
+	
+	return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+	struct max6902 *chip = platform_get_drvdata(spi);
+	struct rtc_device *rtc = chip->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return 0;
+}
+
+static struct spi_driver max6902_driver = {
+	.driver = {
+		.name 	= "max6902",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe 	= max6902_probe,
+	.remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+	printk("max6902 spi driver\n");
+	return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+	spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-30 15:09 [PATCH] Add max6902 RTC support Raphael Assenat
@ 2006-05-30 18:32 ` Alessandro Zummo
  2006-05-30 18:49   ` Raphael Assenat
  0 siblings, 1 reply; 9+ messages in thread
From: Alessandro Zummo @ 2006-05-30 18:32 UTC (permalink / raw)
  To: Raphael Assenat; +Cc: linux-kernel

On Tue, 30 May 2006 11:09:14 -0400
Raphael Assenat <raph@raphnet.net> wrote:

> +//#define RTC_DEBUG

 Please remove it or use #undef
(and maybe rename it to MAX6902_DEBUG :) )

 The driver seems fine to me, you may
 want to send it to Andrew for inclusion
 in -mm.

 thanks!


-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Turin, Italy

  http://www.towertech.it


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

* Re: [PATCH] Add max6902 RTC support
  2006-05-30 18:32 ` Alessandro Zummo
@ 2006-05-30 18:49   ` Raphael Assenat
  2006-05-30 22:01     ` Andrew Morton
  0 siblings, 1 reply; 9+ messages in thread
From: Raphael Assenat @ 2006-05-30 18:49 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: linux-kernel, akpm

This is the second version of my patch to add
support for the MAX6902 SPI RTC chip. Renamed RTC_DEBUG
to MAX6902_DEBUG and use #undef instead of a comment, as
suggested by Alessandro Zummo.

Applies on 2.6.17-rc5. Tested on a pxa2xx cpu.

Signed-off-by: Raphael Assenat <raph@raphnet.net>
---

--- linux-2.6.17-rc5/drivers/rtc/Kconfig	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Kconfig	2006-05-25 15:59:53.000000000 -0400
@@ -172,4 +172,14 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-test.
 
+config RTC_DRV_MAX6902
+	tristate "Maxim 6902"
+	depends on RTC_CLASS && SPI 
+	help
+	  If you say yes here you will get support for the
+	  Maxim MAX6902 spi RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max6902.
+
 endmenu
--- linux-2.6.17-rc5/drivers/rtc/Makefile	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Makefile	2006-05-25 15:58:38.000000000 -0400
@@ -20,3 +20,4 @@
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
--- linux-2.6.17-rc5/drivers/rtc/rtc-max6902.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.17-rc5-8d/drivers/rtc/rtc-max6902.c	2006-05-30 14:38:10.000000000 -0400
@@ -0,0 +1,289 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ * 
+ * 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 MAX6902 spi RTC
+ * 
+ * Changelog:
+ * 
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ *                - Major rework
+ *   				Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ *                - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+ 
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#include <asm/delay.h>
+
+#define MAX6902_REG_SECONDS		0x01
+#define MAX6902_REG_MINUTES		0x03
+#define MAX6902_REG_HOURS		0x05
+#define MAX6902_REG_DATE		0x07
+#define MAX6902_REG_MONTH		0x09
+#define MAX6902_REG_DAY			0x0B
+#define MAX6902_REG_YEAR		0x0D
+#define MAX6902_REG_CONTROL		0x0F
+#define MAX6902_REG_CENTURY		0x13
+
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+	struct rtc_device *rtc;
+	u8 buf[9]; /* Burst read cmd + 8 registers */
+	u8 tx_buf[2];
+	u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address, 
+														unsigned char data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	/* MSB must be '0' to write */
+	buf[0] = address & 0x7f;
+	buf[1] = data;
+	
+	spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address, unsigned char *data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	if (!data) return -EINVAL;
+
+	/* Build our spi message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));	
+	xfer.len = 2;
+	/* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+	xfer.tx_buf = chip->tx_buf;
+	xfer.rx_buf = chip->rx_buf;
+
+	/* Set MSB to indicate read */
+	chip->tx_buf[0] = address | 0x80;
+
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	*data = chip->rx_buf[1];
+	
+	return status;
+}
+ 
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+	unsigned char tmp;
+	int century;
+	int err;
+
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+	if (err)
+		return err;
+
+	/* build the message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.len = 1 + 7; /* Burst read command + 7 registers */
+	xfer.tx_buf = chip->buf;
+	xfer.rx_buf = chip->buf;
+	chip->buf[0] = 0xbf; // Burst read
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	/* The chip sends data in this order:
+	 * Seconds, Minutes, Hours, Date, Month, Day, Year */
+	dt->tm_sec	= BCD2BIN(chip->buf[1]);
+	dt->tm_min	= BCD2BIN(chip->buf[2]);
+	dt->tm_hour	= BCD2BIN(chip->buf[3]);
+	dt->tm_mday	= BCD2BIN(chip->buf[4]);
+	dt->tm_mon	= BCD2BIN(chip->buf[5] - 1);
+	dt->tm_wday	= BCD2BIN(chip->buf[6]);
+	dt->tm_year = BCD2BIN(chip->buf[7]);
+
+
+	century = BCD2BIN(tmp) * 100;
+
+	dt->tm_year += century;
+	dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Read RTC values\n",__FUNCTION__);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_year: %i\n",dt->tm_year);
+	printk("tm_mon : %i\n",dt->tm_mon);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+	return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+	dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Setting RTC values\n",__FUNCTION__);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+	printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+	// Remove write protection
+	max6902_set_reg(dev, 0xF, 0);
+
+	max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+	max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+	max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+	max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+	max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+	max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+	max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+	max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+	/* Compulab used a delay here. However, the datasheet
+	 * does not mention a delay being required anywhere... */
+	/* delay(2000); */
+
+	// Write protect
+	max6902_set_reg(dev, 0xF, 0x80);
+
+	return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+	.read_time	= max6902_read_time,
+	.set_time	= max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+	struct rtc_device *rtc;
+	unsigned char tmp;
+	struct max6902 *chip;
+	int res;
+
+	rtc = rtc_device_register("max6902",
+				&spi->dev, &max6902_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		return PTR_ERR(rtc);
+	}
+
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (!chip) {
+		rtc_device_unregister(rtc);
+		return -ENOMEM;
+	}
+	chip->rtc = rtc;
+	dev_set_drvdata(&spi->dev, chip);	
+	
+	res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+	if (res) {
+		rtc_device_unregister(rtc);
+		return res;
+	}
+	
+	return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+	struct max6902 *chip = platform_get_drvdata(spi);
+	struct rtc_device *rtc = chip->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return 0;
+}
+
+static struct spi_driver max6902_driver = {
+	.driver = {
+		.name 	= "max6902",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe 	= max6902_probe,
+	.remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+	printk("max6902 spi driver\n");
+	return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+	spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-30 18:49   ` Raphael Assenat
@ 2006-05-30 22:01     ` Andrew Morton
  2006-05-31  6:32       ` Ian Campbell
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2006-05-30 22:01 UTC (permalink / raw)
  To: Raphael Assenat; +Cc: alessandro.zummo, linux-kernel

On Tue, 30 May 2006 14:49:49 -0400
Raphael Assenat <raph@raphnet.net> wrote:

> + * Changelog:
> + * 
> + * 24-May-2006: Raphael Assenat <raph@8d.com>
> + *                - Major rework
> + *   				Converted to rtc_device and uses the SPI layer.
> + *
> + * ??-???-2005: Someone at Compulab
> + *                - Initial driver creation.

That's a problem.  According to the Developer's Certificate of Origin
process we'd need "Someone at Compulab" to send us a Signed-off-by:, along
with the assertions which that carries.

I mean, maybe you've finally found that code wot we stole from sco ;)

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-30 22:01     ` Andrew Morton
@ 2006-05-31  6:32       ` Ian Campbell
  2006-05-31  6:55         ` Andrew Morton
  0 siblings, 1 reply; 9+ messages in thread
From: Ian Campbell @ 2006-05-31  6:32 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Raphael Assenat, alessandro.zummo, linux-kernel

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

On Tue, 2006-05-30 at 15:01 -0700, Andrew Morton wrote:
> That's a problem.  According to the Developer's Certificate of Origin
> process we'd need "Someone at Compulab" to send us a Signed-off-by:, along
> with the assertions which that carries.

Don't clauses (a) and/or (b) include provisions that mean Raphael takes
on this responsibility if he believes that CompuLab released the patch
under a suitable open source license? In particular the "to the best of
my knowledge, is covered under an appropriate open source license" bit
in (b).

        (a) The contribution was created in whole or in part by me and I
        have the right to submit it under the open source license
        indicated in the file; or
        
        (b) The contribution is based upon previous work that, to the
        best of my knowledge, is covered under an appropriate open
        source license and I have the right under that license to submit
        that work with modifications, whether created in whole or in
        part by me, under the same open source license (unless I am
        permitted to submit under a different license), as indicated in
        the file; or
        
        ...

Ian.
-- 
Ian Campbell

zeal, n.:
	Quality seen in new graduates -- if you're quick.

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-31  6:32       ` Ian Campbell
@ 2006-05-31  6:55         ` Andrew Morton
  2006-05-31 12:43           ` Raphael Assenat
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2006-05-31  6:55 UTC (permalink / raw)
  To: Ian Campbell; +Cc: raph, alessandro.zummo, linux-kernel

On Wed, 31 May 2006 07:32:11 +0100
Ian Campbell <ijc@hellion.org.uk> wrote:

> On Tue, 2006-05-30 at 15:01 -0700, Andrew Morton wrote:
> > That's a problem.  According to the Developer's Certificate of Origin
> > process we'd need "Someone at Compulab" to send us a Signed-off-by:, along
> > with the assertions which that carries.
> 
> Don't clauses (a) and/or (b) include provisions that mean Raphael takes
> on this responsibility if he believes that CompuLab released the patch
> under a suitable open source license? In particular the "to the best of
> my knowledge, is covered under an appropriate open source license" bit
> in (b).

hm, sometimes it helps to read things.

>         (a) The contribution was created in whole or in part by me and I
>         have the right to submit it under the open source license
>         indicated in the file; or
>         
>         (b) The contribution is based upon previous work that, to the
>         best of my knowledge, is covered under an appropriate open
>         source license and I have the right under that license to submit
>         that work with modifications, whether created in whole or in
>         part by me, under the same open source license (unless I am
>         permitted to submit under a different license), as indicated in
>         the file; or

Yes, I think that would work, if Rafael is prepared to make that assertion.

If so, please send along a few words describing where the Compulab code
came from and some substantiation of your belief that it was appropriately
licensed.  (It probably had some license words at the top of the file..)

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-31  6:55         ` Andrew Morton
@ 2006-05-31 12:43           ` Raphael Assenat
  2006-05-31 17:13             ` Andrew Morton
  0 siblings, 1 reply; 9+ messages in thread
From: Raphael Assenat @ 2006-05-31 12:43 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Ian Campbell, alessandro.zummo, linux-kernel

On Tue, May 30, 2006 at 11:55:00PM -0700, Andrew Morton wrote:
> Ian Campbell <ijc@hellion.org.uk> wrote:
> > On Tue, 2006-05-30 at 15:01 -0700, Andrew Morton wrote:
...
> >         (a) The contribution was created in whole or in part by me and I
> >         have the right to submit it under the open source license
> >         indicated in the file; or
> >         
> >         (b) The contribution is based upon previous work that, to the
> >         best of my knowledge, is covered under an appropriate open
> >         source license and I have the right under that license to submit
> >         that work with modifications, whether created in whole or in
> >         part by me, under the same open source license (unless I am
> >         permitted to submit under a different license), as indicated in
> >         the file; or
> 
> Yes, I think that would work, if Rafael is prepared to make that assertion.
> 
> If so, please send along a few words describing where the Compulab code
> came from and some substantiation of your belief that it was appropriately
> licensed.  (It probably had some license words at the top of the file..)
The compulab code comes from the kernel patch the produce for their
cn-x255 board. (inside a zip file on the 
http://www.compulab.co.il/x255/html/x255-developer.htm)

The original file (drivers/char/max6902.c) was GPL, which is of course
an appropriate licence:

/*
 * max6902.c
 *
 * Driver for MAX6902 RTC
 *
 * Copyright (C) 2004 Compulab Ltd.
 *
 * 
 * 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.
 *
 *
 */

For reference, you can get the original file here:
http://raph.people.8d.com/misc/max6902.c

Regards,
Raphael Assenat


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

* Re: [PATCH] Add max6902 RTC support
  2006-05-31 12:43           ` Raphael Assenat
@ 2006-05-31 17:13             ` Andrew Morton
  2006-06-02 16:38               ` Raphael Assenat
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2006-05-31 17:13 UTC (permalink / raw)
  To: Raphael Assenat; +Cc: ijc, alessandro.zummo, linux-kernel

On Wed, 31 May 2006 08:43:34 -0400
Raphael Assenat <raph@raphnet.net> wrote:

> The compulab code comes from the kernel patch the produce for their
> cn-x255 board. (inside a zip file on the 
> http://www.compulab.co.il/x255/html/x255-developer.htm)
> 
> The original file (drivers/char/max6902.c) was GPL, which is of course
> an appropriate licence:
> 
> /*
>  * max6902.c
>  *
>  * Driver for MAX6902 RTC
>  *
>  * Copyright (C) 2004 Compulab Ltd.
>  *
>  * 
>  * 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.
>  *
>  *
>  */
> 
> For reference, you can get the original file here:
> http://raph.people.8d.com/misc/max6902.c

Wonderful, thanks.

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

* Re: [PATCH] Add max6902 RTC support
  2006-05-31 17:13             ` Andrew Morton
@ 2006-06-02 16:38               ` Raphael Assenat
  0 siblings, 0 replies; 9+ messages in thread
From: Raphael Assenat @ 2006-06-02 16:38 UTC (permalink / raw)
  To: Andrew Morton; +Cc: ijc, alessandro.zummo, linux-kernel

I just discovered I forgot to call kfree on the struct max6902 I
allocate in max6902_probe. An updated version of the patch follows. If
you prefer a patch which applies on top of the previous one, let me
know.

--- linux-2.6.17-rc5/drivers/rtc/Kconfig	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Kconfig	2006-05-25 15:59:53.000000000 -0400
@@ -172,4 +172,14 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-test.
 
+config RTC_DRV_MAX6902
+	tristate "Maxim 6902"
+	depends on RTC_CLASS && SPI 
+	help
+	  If you say yes here you will get support for the
+	  Maxim MAX6902 spi RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-max6902.
+
 endmenu
--- linux-2.6.17-rc5/drivers/rtc/Makefile	2006-05-24 21:50:17.000000000 -0400
+++ linux-2.6.17-rc5-8d/drivers/rtc/Makefile	2006-05-25 15:58:38.000000000 -0400
@@ -20,3 +20,4 @@
 obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
 obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o
+obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
diff -Nru -X linux-2.6.17-rc5/Documentation/dontdiff linux-2.6.17-rc5/drivers/rtc/rtc-max6902.c linux-2.6.17-rc5-8d/drivers/rtc/rtc-max6902.c
--- linux-2.6.17-rc5/drivers/rtc/rtc-max6902.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.17-rc5-8d/drivers/rtc/rtc-max6902.c	2006-06-01 11:55:28.000000000 -0400
@@ -0,0 +1,291 @@
+/* drivers/char/max6902.c
+ *
+ * Copyright (C) 2006 8D Technologies inc.
+ * Copyright (C) 2004 Compulab Ltd.
+ * 
+ * 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 MAX6902 spi RTC
+ * 
+ * Changelog:
+ * 
+ * 24-May-2006: Raphael Assenat <raph@8d.com>
+ *                - Major rework
+ *   				Converted to rtc_device and uses the SPI layer.
+ *
+ * ??-???-2005: Someone at Compulab
+ *                - Initial driver creation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+ 
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#include <asm/delay.h>
+
+#define MAX6902_REG_SECONDS		0x01
+#define MAX6902_REG_MINUTES		0x03
+#define MAX6902_REG_HOURS		0x05
+#define MAX6902_REG_DATE		0x07
+#define MAX6902_REG_MONTH		0x09
+#define MAX6902_REG_DAY			0x0B
+#define MAX6902_REG_YEAR		0x0D
+#define MAX6902_REG_CONTROL		0x0F
+#define MAX6902_REG_CENTURY		0x13
+
+
+#undef MAX6902_DEBUG
+
+struct max6902 {
+	struct rtc_device *rtc;
+	u8 buf[9]; /* Burst read cmd + 8 registers */
+	u8 tx_buf[2];
+	u8 rx_buf[2];
+};
+
+static void max6902_set_reg(struct device *dev, unsigned char address, 
+														unsigned char data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	unsigned char buf[2];
+
+	/* MSB must be '0' to write */
+	buf[0] = address & 0x7f;
+	buf[1] = data;
+	
+	spi_write(spi, buf, 2);
+}
+
+static int max6902_get_reg(struct device *dev, unsigned char address, unsigned char *data)
+{
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	if (!data) return -EINVAL;
+
+	/* Build our spi message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));	
+	xfer.len = 2;
+	/* Can tx_buf and rx_buf be equal? The doc in spi.h is not sure... */
+	xfer.tx_buf = chip->tx_buf;
+	xfer.rx_buf = chip->rx_buf;
+
+	/* Set MSB to indicate read */
+	chip->tx_buf[0] = address | 0x80;
+
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	*data = chip->rx_buf[1];
+	
+	return status;
+}
+ 
+static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+	unsigned char tmp;
+	int century;
+	int err;
+
+	struct spi_device	*spi = to_spi_device(dev);
+	struct max6902 *chip = dev_get_drvdata(dev);
+	struct spi_message message;
+	struct spi_transfer xfer;
+	int status;
+
+	err = max6902_get_reg(dev, MAX6902_REG_CENTURY, &tmp);
+	if (err)
+		return err;
+
+	/* build the message */
+	spi_message_init(&message);
+	memset(&xfer, 0, sizeof(xfer));
+	xfer.len = 1 + 7; /* Burst read command + 7 registers */
+	xfer.tx_buf = chip->buf;
+	xfer.rx_buf = chip->buf;
+	chip->buf[0] = 0xbf; // Burst read
+	spi_message_add_tail(&xfer, &message);
+	
+	/* do the i/o */
+	status = spi_sync(spi, &message);
+	if (status == 0) {
+		status = message.status;
+	}
+	else
+		return status;
+
+	/* The chip sends data in this order:
+	 * Seconds, Minutes, Hours, Date, Month, Day, Year */
+	dt->tm_sec	= BCD2BIN(chip->buf[1]);
+	dt->tm_min	= BCD2BIN(chip->buf[2]);
+	dt->tm_hour	= BCD2BIN(chip->buf[3]);
+	dt->tm_mday	= BCD2BIN(chip->buf[4]);
+	dt->tm_mon	= BCD2BIN(chip->buf[5] - 1);
+	dt->tm_wday	= BCD2BIN(chip->buf[6]);
+	dt->tm_year = BCD2BIN(chip->buf[7]);
+
+
+	century = BCD2BIN(tmp) * 100;
+
+	dt->tm_year += century;
+	dt->tm_year -= 1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Read RTC values\n",__FUNCTION__);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_year: %i\n",dt->tm_year);
+	printk("tm_mon : %i\n",dt->tm_mon);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+#endif
+
+	return 0;
+}
+
+static int max6902_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+	dt->tm_year = dt->tm_year+1900;
+
+#ifdef MAX6902_DEBUG
+	printk("\n%s : Setting RTC values\n",__FUNCTION__);
+	printk("tm_sec : %i\n",dt->tm_sec);
+	printk("tm_min : %i\n",dt->tm_min);
+	printk("tm_hour: %i\n",dt->tm_hour);
+	printk("tm_mday: %i\n",dt->tm_mday);
+	printk("tm_wday: %i\n",dt->tm_wday);
+	printk("tm_year: %i\n",dt->tm_year);
+#endif
+
+	// Remove write protection
+	max6902_set_reg(dev, 0xF, 0);
+
+	max6902_set_reg(dev, 0x01, BIN2BCD(dt->tm_sec));
+	max6902_set_reg(dev, 0x03, BIN2BCD(dt->tm_min));
+	max6902_set_reg(dev, 0x05, BIN2BCD(dt->tm_hour));
+
+	max6902_set_reg(dev, 0x07, BIN2BCD(dt->tm_mday));
+	max6902_set_reg(dev, 0x09, BIN2BCD(dt->tm_mon+1));
+	max6902_set_reg(dev, 0x0B, BIN2BCD(dt->tm_wday));
+	max6902_set_reg(dev, 0x0D, BIN2BCD(dt->tm_year%100));
+	max6902_set_reg(dev, 0x13, BIN2BCD(dt->tm_year/100));
+
+	/* Compulab used a delay here. However, the datasheet
+	 * does not mention a delay being required anywhere... */
+	/* delay(2000); */
+
+	// Write protect
+	max6902_set_reg(dev, 0xF, 0x80);
+
+	return 0;
+}
+
+static int max6902_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_get_datetime(dev, tm);
+}
+
+static int max6902_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return max6902_set_datetime(dev, tm);
+}
+
+static struct rtc_class_ops max6902_rtc_ops = {
+	.read_time	= max6902_read_time,
+	.set_time	= max6902_set_time,
+};
+
+static int __devinit max6902_probe(struct spi_device *spi)
+{
+	struct rtc_device *rtc;
+	unsigned char tmp;
+	struct max6902 *chip;
+	int res;
+
+	rtc = rtc_device_register("max6902",
+				&spi->dev, &max6902_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		return PTR_ERR(rtc);
+	}
+
+	spi->mode = SPI_MODE_3;
+	spi->bits_per_word = 8;
+	spi_setup(spi);
+
+	chip = kzalloc(sizeof *chip, GFP_KERNEL);
+	if (!chip) {
+		rtc_device_unregister(rtc);
+		return -ENOMEM;
+	}
+	chip->rtc = rtc;
+	dev_set_drvdata(&spi->dev, chip);	
+	
+	res = max6902_get_reg(&spi->dev, MAX6902_REG_SECONDS, &tmp);
+	if (res) {
+		rtc_device_unregister(rtc);
+		return res;
+	}
+	
+	return 0;
+}
+
+static int __devexit max6902_remove(struct spi_device *spi)
+{
+	struct max6902 *chip = platform_get_drvdata(spi);
+	struct rtc_device *rtc = chip->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	kfree(chip);
+	
+	return 0;
+}
+
+static struct spi_driver max6902_driver = {
+	.driver = {
+		.name 	= "max6902",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe 	= max6902_probe,
+	.remove = __devexit_p(max6902_remove),
+};
+
+static __init int max6902_init(void)
+{
+	printk("max6902 spi driver\n");
+	return spi_register_driver(&max6902_driver);
+}
+module_init(max6902_init);
+
+static __exit void max6902_exit(void)
+{
+	spi_unregister_driver(&max6902_driver);
+}
+module_exit(max6902_exit);
+
+MODULE_DESCRIPTION ("max6902 spi RTC driver");
+MODULE_AUTHOR ("Raphael Assenat");
+MODULE_LICENSE ("GPL");




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

end of thread, other threads:[~2006-06-02 16:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-05-30 15:09 [PATCH] Add max6902 RTC support Raphael Assenat
2006-05-30 18:32 ` Alessandro Zummo
2006-05-30 18:49   ` Raphael Assenat
2006-05-30 22:01     ` Andrew Morton
2006-05-31  6:32       ` Ian Campbell
2006-05-31  6:55         ` Andrew Morton
2006-05-31 12:43           ` Raphael Assenat
2006-05-31 17:13             ` Andrew Morton
2006-06-02 16:38               ` Raphael Assenat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).