- rtc-rtc-class-driver-for-the-ds1374.patch removed from -mm tree

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

 



The patch titled
     rtc: RTC class driver for the ds1374
has been removed from the -mm tree.  Its filename was
     rtc-rtc-class-driver-for-the-ds1374.patch

This patch was dropped because it doesn't compile in the current tree

------------------------------------------------------
Subject: rtc: RTC class driver for the ds1374
From: Scott Wood <scottwood@xxxxxxxxxxxxx>

Add an RTC class driver for the Maxim/Dallas 1374 RTC chip, based on
drivers/i2c/chips/ds1374.c.  It uses new-style device enumeration and supports
alarm functionality.

Signed-off-by: Scott Wood <scottwood@xxxxxxxxxxxxx>
Acked-by: Alessandro Zummo <a.zummo@xxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxx>
---

 drivers/rtc/Kconfig      |   11 
 drivers/rtc/Makefile     |    1 
 drivers/rtc/rtc-ds1374.c |  439 +++++++++++++++++++++++++++++++++++++
 3 files changed, 451 insertions(+)

diff -puN drivers/rtc/Kconfig~rtc-rtc-class-driver-for-the-ds1374 drivers/rtc/Kconfig
--- a/drivers/rtc/Kconfig~rtc-rtc-class-driver-for-the-ds1374
+++ a/drivers/rtc/Kconfig
@@ -123,6 +123,17 @@ config RTC_DRV_DS1307
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1307.
 
+config RTC_DRV_DS1374
+	tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock"
+	depends on RTC_CLASS && I2C && !SENSORS_DS1374
+	help
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS1374 real-time clock chips.  If an interrupt is associated
+	  with the device, the alarm functionality is supported.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called rtc-ds1374.
+
 config RTC_DRV_DS1553
 	tristate "Dallas DS1553"
 	depends on RTC_CLASS
diff -puN drivers/rtc/Makefile~rtc-rtc-class-driver-for-the-ds1374 drivers/rtc/Makefile
--- a/drivers/rtc/Makefile~rtc-rtc-class-driver-for-the-ds1374
+++ a/drivers/rtc/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205
 obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1374)	+= rtc-ds1374.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
diff -puN /dev/null drivers/rtc/rtc-ds1374.c
--- /dev/null
+++ a/drivers/rtc/rtc-ds1374.c
@@ -0,0 +1,439 @@
+/*
+ * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C
+ *
+ * Based on drivers/i2c/chips/ds1374.c by Randy Vinson <rvinson@xxxxxxxxxx>,
+ * which was based on the m41t00.c by Mark Greer <mgreer@xxxxxxxxxx>.
+ *
+ * Copyright (C) 2006 Freescale Semiconductor
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+/*
+ * It would be more efficient to use i2c msgs/i2c_transfer directly but, as
+ * recommened in .../Documentation/i2c/writing-clients section
+ * "Sending and receiving", using SMBus level communication is preferred.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/workqueue.h>
+
+#define DS1374_REG_TOD0		0x00 /* Time of Day */
+#define DS1374_REG_TOD1		0x01
+#define DS1374_REG_TOD2		0x02
+#define DS1374_REG_TOD3		0x03
+#define DS1374_REG_WDALM0	0x04 /* Watchdog/Alarm */
+#define DS1374_REG_WDALM1	0x05
+#define DS1374_REG_WDALM2	0x06
+#define DS1374_REG_CR		0x07 /* Control */
+#define DS1374_REG_CR_AIE	0x01 /* Alarm Int. Enable */
+#define DS1374_REG_CR_WDALM	0x20 /* 1=Watchdog, 0=Alarm */
+#define DS1374_REG_CR_WACE	0x40 /* WD/Alarm counter enable */
+#define DS1374_REG_SR		0x08 /* Status */
+#define DS1374_REG_SR_OSF	0x80 /* Oscillator Stop Flag */
+#define DS1374_REG_SR_AF	0x01 /* Alarm Flag */
+#define DS1374_REG_TCR		0x09 /* Trickle Charge */
+
+#define	DS1374_DRV_NAME		"ds1374"
+
+struct ds1374 {
+	struct rtc_device *rtc;
+	struct work_struct work;
+	struct mutex mutex;
+	spinlock_t lock;
+	int have_irq;
+};
+
+static struct i2c_driver ds1374_driver;
+
+static u8 read_reg(struct i2c_client *client, int reg, int *err)
+{
+	s32 val = i2c_smbus_read_byte_data(client, reg);
+
+	if (val < 0) {
+		dev_warn(&client->dev, "read from I2C register %d failed\n",
+		         reg);
+
+		if (err)
+			*err = -EIO;
+
+		return 0;
+	}
+
+	return val;
+}
+
+static void write_reg(struct i2c_client *client, int reg, u8 val, int *err)
+{
+	if (i2c_smbus_write_byte_data(client, reg, val) < 0) {
+		dev_warn(&client->dev, "write to I2C register %d failed\n",
+		         reg);
+
+		if (err)
+			*err = -EIO;
+	}
+}
+
+static int ds1374_read_rtc(struct i2c_client *client, ulong *time,
+                           int from, int to)
+{
+	int reg, ret = 0;
+	*time = 0;
+
+	for (reg = to; reg >= from; reg--)
+		*time = (*time << 8) | read_reg(client, reg, &ret);
+
+	return ret;
+}
+
+static int ds1374_write_rtc(struct i2c_client *client, ulong time,
+                            int from, int to)
+{
+	int reg, ret = 0;
+
+	for (reg = from; reg <= to; reg++) {
+		write_reg(client, reg, time & 0xff, &ret);
+		time = time >> 8;
+	}
+
+	return ret;
+}
+
+static int ds1374_check_rtc_status(struct i2c_client *client)
+{
+	int ret = 0;
+	u8 stat = read_reg(client, DS1374_REG_SR, &ret);
+	u8 control;
+
+	if (ret == 0) {
+		if (stat & DS1374_REG_SR_OSF)
+			dev_warn(&client->dev,
+			         "oscillator discontinuity flagged, "
+			         "time unreliable\n");
+
+		stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);
+		write_reg(client, DS1374_REG_SR, stat, &ret);
+	}
+
+	/* If the alarm is pending, clear it before requesting
+	 * the interrupt, so an interrupt event isn't reported
+	 * before everything is initialized.
+	 */
+
+	control = read_reg(client, DS1374_REG_CR, &ret);
+
+	if (ret == 0) {
+		control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
+		write_reg(client, DS1374_REG_CR, control, &ret);
+	}
+
+	return ret;
+}
+
+static int ds1374_read_rtc_retry(struct device *dev, ulong *time,
+                                 int from, int to)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	ulong time2;
+	int limit = 10;		/* arbitrary retry limit */
+	int ret;
+
+	/*
+	 * Since the reads are being performed one byte at a time using
+	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+	 * carry will occur during the read. To detect this, 2 reads are
+	 * performed and compared.
+	 */
+	do {
+		ret = ds1374_read_rtc(client, time, from, to);
+		if (ret)
+			return ret;
+
+		ret = ds1374_read_rtc(client, &time2, from, to);
+		if (ret)
+			return ret;
+	} while (*time != time2 && limit--);
+
+	if (*time != time2) {
+		dev_warn(dev, "can't get consistent time from rtc chip\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ds1374_write_rtc_retry(struct device *dev, ulong time,
+                                  int from, int to)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	ulong time2;
+	int limit = 10;		/* arbitrary retry limit */
+	int ret;
+
+	/*
+	 * Since the writes are being performed one byte at a time using
+	 * the SMBus vs a 4-byte i2c transfer, there is a chance that a
+	 * carry will occur during the write. To detect this, the write
+	 * value is read back and compared.
+	 */
+	do {
+		ds1374_write_rtc(client, time, from, to);
+
+		ret = ds1374_read_rtc(client, &time2, from, to);
+		if (ret)
+			return ret;
+	} while (time != time2 && limit--);
+
+	if (time != time2) {
+		dev_warn(dev, "can't confirm time set from rtc chip\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ds1374_read_time(struct device *dev, struct rtc_time *time)
+{
+	ulong itime;
+
+	int ret = ds1374_read_rtc_retry(dev, &itime,
+	                                DS1374_REG_TOD0,
+	                                DS1374_REG_TOD3);
+
+	if (!ret)
+		rtc_time_to_tm(itime, time);
+
+	return ret;
+}
+
+static int ds1374_set_time(struct device *dev, struct rtc_time *time)
+{
+	ulong itime;
+	rtc_tm_to_time(time, &itime);
+
+	return ds1374_write_rtc_retry(dev, itime,
+	                              DS1374_REG_TOD0,
+	                              DS1374_REG_TOD3);
+}
+
+/* The ds1374 has a decrementer for an alarm, rather than a comparator.
+ * If the time of day is changed, then the alarm will need to be
+ * reset.
+ */
+static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	ulong now, cur_alarm;
+	u8 cr, sr;
+	int ret = 0;
+
+	cr = read_reg(client, DS1374_REG_CR, &ret);
+	sr = read_reg(client, DS1374_REG_SR, &ret);
+	if (ret)
+		return ret;
+
+	ret = ds1374_read_rtc_retry(dev, &now,
+	                            DS1374_REG_TOD0, DS1374_REG_TOD3);
+	if (ret)
+		return ret;
+
+	ret = ds1374_read_rtc_retry(dev, &cur_alarm,
+	                            DS1374_REG_WDALM0, DS1374_REG_WDALM2);
+	if (ret)
+		return ret;
+
+	rtc_time_to_tm(now + cur_alarm, &alarm->time);
+	alarm->enabled = !!(cr & DS1374_REG_CR_WACE);
+	alarm->pending = !!(sr & DS1374_REG_SR_AF);
+
+	return 0;
+}
+
+static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ds1374 *ds1374 = i2c_get_clientdata(client);
+	struct rtc_time now;
+	ulong new_alarm, itime;
+	u8 cr;
+	int ret = 0;
+
+	if (!ds1374->have_irq)
+		return -EINVAL;
+
+	cr = read_reg(client, DS1374_REG_CR, &ret);
+	if (ret)
+		return ret;
+
+	ret = ds1374_read_time(dev, &now);
+	if (ret)
+		return ret;
+
+	rtc_merge_alarm(&now, &alarm->time);
+	rtc_tm_to_time(&alarm->time, &new_alarm);
+	rtc_tm_to_time(&now, &itime);
+
+	new_alarm -= itime;
+
+	/* This should only happen due to races, or if the full date
+	 * up to the year was specified (and is in the past).  Partial
+	 * dates in the past are interpreted into the future by
+	 * rtc_merge_alarm().
+	 */
+	if (new_alarm <= 0)
+		new_alarm = 1;
+
+	mutex_lock(&ds1374->mutex);
+
+	ret = ds1374_write_rtc_retry(dev, new_alarm,
+	                             DS1374_REG_WDALM0,
+	                             DS1374_REG_WDALM2);
+
+	if (alarm->enabled) {
+		cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE;
+		cr &= ~DS1374_REG_CR_WDALM;
+
+		write_reg(client, DS1374_REG_CR, cr, &ret);
+	}
+
+	mutex_unlock(&ds1374->mutex);
+	return ret;
+}
+
+static irqreturn_t ds1374_irq(int irq, void *dev_id)
+{
+	struct i2c_client *client = dev_id;
+	struct ds1374 *ds1374 = i2c_get_clientdata(client);
+	irqreturn_t ret = IRQ_NONE;
+
+	spin_lock_irq(&ds1374->lock);
+
+	if (ds1374->have_irq) {
+		disable_irq_nosync(irq);
+		schedule_work(&ds1374->work);
+		ret = IRQ_HANDLED;
+	}
+
+	spin_unlock_irq(&ds1374->lock);
+	return ret;
+}
+
+static void ds1374_work(void *arg)
+{
+	struct i2c_client *client = arg;
+	struct ds1374 *ds1374 = i2c_get_clientdata(client);
+	u8 stat, control;
+
+	mutex_lock(&ds1374->mutex);
+
+	stat = read_reg(client, DS1374_REG_SR, NULL);
+
+	if (stat & DS1374_REG_SR_AF) {
+		stat &= ~DS1374_REG_SR_AF;
+		write_reg(client, DS1374_REG_SR, stat, NULL);
+
+		control = read_reg(client, DS1374_REG_CR, NULL);
+		control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);
+		write_reg(client, DS1374_REG_CR, control, NULL);
+
+		rtc_update_irq(&ds1374->rtc->class_dev, 1, RTC_AF | RTC_IRQF);
+	}
+
+	mutex_unlock(&ds1374->mutex);
+
+	enable_irq(client->irq);
+}
+
+static const struct rtc_class_ops ds1374_rtc_ops = {
+	.read_time = ds1374_read_time,
+	.set_time = ds1374_set_time,
+	.read_alarm = ds1374_read_alarm,
+	.set_alarm = ds1374_set_alarm,
+};
+
+static int ds1374_probe(struct i2c_client *client)
+{
+	struct ds1374 *ds1374;
+	int ret;
+
+	ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL);
+	if (!ds1374)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, ds1374);
+
+	INIT_WORK(&ds1374->work, ds1374_work, client);
+	spin_lock_init(&ds1374->lock);
+	mutex_init(&ds1374->mutex);
+
+	ret = ds1374_check_rtc_status(client);
+	if (ret)
+		return ret;
+
+	if (client->irq != -1 &&
+	    !request_irq(client->irq, ds1374_irq, 0, DS1374_DRV_NAME, client))
+		ds1374->have_irq = 1;
+
+	ds1374->rtc = rtc_device_register(client->name, &client->dev,
+	                                  &ds1374_rtc_ops, THIS_MODULE);
+	if (IS_ERR(ds1374->rtc)) {
+		ret = PTR_ERR(ds1374->rtc);
+		dev_err(&client->dev, "unable to register the class device\n");
+		kfree(ds1374);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int __devexit ds1374_remove(struct i2c_client *client)
+{
+	struct ds1374 *ds1374 = i2c_get_clientdata(client);
+
+	if (ds1374->have_irq) {
+		spin_lock_irq(&ds1374->lock);
+		ds1374->have_irq = 0;
+		spin_unlock_irq(&ds1374->lock);
+
+		flush_scheduled_work();
+		free_irq(client->irq, client);
+	}
+
+	rtc_device_unregister(ds1374->rtc);
+	kfree(ds1374);
+	return 0;
+}
+
+static struct i2c_driver ds1374_driver = {
+	.driver = {
+		.name	= DS1374_DRV_NAME,
+		.owner = THIS_MODULE,
+	},
+	.id = I2C_DRIVERID_DS1374,
+	.probe = ds1374_probe,
+	.remove = __devexit_p(ds1374_remove),
+};
+
+static int __init ds1374_init(void)
+{
+	return i2c_add_driver(&ds1374_driver);
+}
+
+static void __exit ds1374_exit(void)
+{
+	i2c_del_driver(&ds1374_driver);
+}
+
+module_init(ds1374_init);
+module_exit(ds1374_exit);
+
+MODULE_AUTHOR("Scott Wood <scottwood@xxxxxxxxxxxxx>");
+MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver");
+MODULE_LICENSE("GPL");
_

Patches currently in -mm which might be from scottwood@xxxxxxxxxxxxx are

origin.patch
rtc-add-rtc_merge_alarm.patch
rtc-rtc-class-driver-for-the-ds1374.patch

-
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Kernel Newbies FAQ]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Photo]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux