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 <[email protected]>
---
 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 <[email protected]>
+ *
+ *  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 <[email protected]");
+MODULE_DESCRIPTION("IDT 1338 RTC driver");
+MODULE_LICENSE("GPL");
+
+module_init(idt1338_init);
+module_exit(idt1338_exit);
-- 
1.7.4.1

_______________________________________________
Devel mailing list
[email protected]
http://lists.laptop.org/listinfo/devel

Reply via email to