[PATCH 1/3] rtc: driver for idt1338 chip
Saadia Baloch
saadia at laptop.org
Fri May 13 13:50:34 EDT 2011
OLPC is using this chip in the XO 1.75 A2 boards.
This chip provides a clock tick but no alarms or interrupts.
Signed-off-by: Saadia Baloch <saadia at laptop.org>
---
drivers/rtc/Kconfig | 9 +++
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-idt1338.c | 176 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 186 insertions(+), 0 deletions(-)
create mode 100644 drivers/rtc/rtc-idt1338.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e187887..bd63df1 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -994,5 +994,14 @@ config RTC_DRV_TEGRA
This drive can also be built as a module. If so, the module
will be called rtc-tegra.
+config RTC_DRV_IDT1338
+ tristate "IDT 1338 RTC driver"
+ depends on RTC_CLASS && ARCH_MMP
+ help
+ If you say yes here you get support for the
+ IDT 1338 RTC module.
+
+ This drive can also be built as a module. If so, the module
+ will be called rtc-idt1338
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index ca91c3c..84aa595 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -100,3 +100,4 @@ obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_IDT1338) += rtc-idt1338.o
diff --git a/drivers/rtc/rtc-idt1338.c b/drivers/rtc/rtc-idt1338.c
new file mode 100644
index 0000000..1d81320
--- /dev/null
+++ b/drivers/rtc/rtc-idt1338.c
@@ -0,0 +1,176 @@
+/*
+ * IDT1338 rtc class driver
+ *
+ * Copyright 2011 Saadia Husain Baloch <saadia at laptop.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/slab.h>
+
+#define RTC_SECONDS 0
+#define RTC_MINUTES 1
+#define RTC_HOURS 2
+#define RTC_DAY_OF_WEEK 3
+#define RTC_DATE 4
+#define RTC_MONTH 5
+#define RTC_YEAR 6
+#define BYTE_NUM 7
+
+static const struct i2c_device_id idt1338_id[] = {
+ { "rtc_idt1338", 0 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(i2c, idt1338_id);
+
+struct idt1338 {
+ struct rtc_device *rtc;
+};
+
+static int idt1338_get_time(struct i2c_client *client, struct rtc_time *tm)
+{
+ unsigned int year, month, date, hour, minute, second, week;
+ u8 buf[BYTE_NUM] = {0};
+ int err = 0;
+
+ err = i2c_master_send(client, buf, 1); /* Send 0 */
+ if (err < 0)
+ return (err);
+ err = i2c_master_recv(client, buf, BYTE_NUM);
+
+ second = buf[RTC_SECONDS] & 0x7f;
+ minute = buf[RTC_MINUTES];
+ hour = buf[RTC_HOURS] & 0xbf;
+ week = buf[RTC_DAY_OF_WEEK] & 0x07;
+ date = buf[RTC_DATE] & 0x3f;
+ month = buf[RTC_MONTH];
+ year = buf[RTC_YEAR];
+
+ tm->tm_sec = bcd2bin(second);
+ tm->tm_min = bcd2bin(minute);
+ tm->tm_hour = bcd2bin(hour);
+ tm->tm_wday = bcd2bin(week);
+ tm->tm_mday = bcd2bin(date);
+ tm->tm_mon = bcd2bin(month) - 1; /* read in 1-12 range */
+ tm->tm_year = 100 + bcd2bin(year); /* read delta from 2000 */
+
+ err = rtc_valid_tm(tm);
+ if (err < 0)
+ rtc_time_to_tm(0, tm);
+
+ return err;
+}
+
+static int idt1338_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return idt1338_get_time(to_i2c_client(dev), tm);
+}
+
+static int idt1338_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 buf[BYTE_NUM] = {0};
+ int err = 0;
+
+ err = i2c_master_send(client, buf, 1); /* Send 0 */
+ if (err < 0)
+ return (err);
+
+ buf[RTC_SECONDS] = bin2bcd(tm->tm_sec) & 0x7f;
+ buf[RTC_MINUTES] = bin2bcd(tm->tm_min) & 0x7f;
+ /* Retain 24 hour mode by keeping bit 6 of HOURS register low */
+ buf[RTC_HOURS] = bin2bcd(tm->tm_hour) & 0x3f;
+ buf[RTC_DAY_OF_WEEK] = bin2bcd(tm->tm_wday) & 0x07;
+ buf[RTC_DATE] = bin2bcd(tm->tm_mday) & 0x3f;
+ buf[RTC_MONTH] = bin2bcd(tm->tm_mon + 1) & 0x1f;
+ buf[RTC_YEAR] = bin2bcd((tm->tm_year > 100)?
+ tm->tm_year-100:tm->tm_year);
+
+ err = i2c_master_send(client, (char *)buf, BYTE_NUM);
+ return err;
+}
+
+static const struct rtc_class_ops idt1338_ops = {
+ .read_time = idt1338_read_time,
+ .set_time = idt1338_set_time,
+};
+
+static struct i2c_driver idt1338_driver;
+
+static int __devinit idt1338_probe(struct i2c_client *client,
+ const struct i2c_device_id *idp)
+{
+ struct idt1338 *idt1338;
+ int err = 0;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+
+ idt1338 = kzalloc(sizeof(struct idt1338), GFP_KERNEL);
+ if (!idt1338)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, idt1338);
+
+ idt1338->rtc = rtc_device_register(idt1338_driver.driver.name,
+ &client->dev, &idt1338_ops,
+ THIS_MODULE);
+ if (IS_ERR(idt1338->rtc)) {
+ err = PTR_ERR(idt1338->rtc);
+ kfree (idt1338);
+ return err;
+ }
+ return 0;
+}
+
+static int idt1338_remove(struct i2c_client *client)
+{
+ struct idt1338 *idt1338 = i2c_get_clientdata(client);
+ if (idt1338->rtc)
+ rtc_device_unregister(idt1338->rtc);
+
+ kfree(idt1338);
+ return 0;
+}
+
+static struct i2c_driver idt1338_driver = {
+ .driver = {
+ .name = "rtc_idt1338",
+ },
+ .probe = idt1338_probe,
+ .remove = __devexit_p(idt1338_remove),
+ .id_table = idt1338_id,
+};
+
+static int __init idt1338_init(void)
+{
+ int err;
+
+ err = i2c_add_driver(&idt1338_driver);
+ if (err)
+ printk(KERN_ERR "IDT1338 RTC init err=%d\n", err);
+ return err;
+}
+
+static void __exit idt1338_exit(void)
+{
+ i2c_del_driver(&idt1338_driver);
+}
+
+MODULE_AUTHOR("Saadia Baloch <saadia at laptop.org");
+MODULE_DESCRIPTION("IDT 1338 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(idt1338_init);
+module_exit(idt1338_exit);
--
1.7.4.1
More information about the Devel
mailing list