From 9cc704b6854e094a3cf5e977a4e2fd1938d25e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= Date: Tue, 10 Nov 2009 18:22:19 +0100 Subject: linux-2.6.31: cleanup boc01 RTC driver --- .../linux-2.6.31/boc01/005-091103-isl12024.patch | 511 --------------------- .../linux-2.6.31/boc01/005-091110-isl12024.patch | 509 ++++++++++++++++++++ recipes/linux/linux_2.6.31.bb | 2 +- 3 files changed, 510 insertions(+), 512 deletions(-) delete mode 100644 recipes/linux/linux-2.6.31/boc01/005-091103-isl12024.patch create mode 100644 recipes/linux/linux-2.6.31/boc01/005-091110-isl12024.patch diff --git a/recipes/linux/linux-2.6.31/boc01/005-091103-isl12024.patch b/recipes/linux/linux-2.6.31/boc01/005-091103-isl12024.patch deleted file mode 100644 index 9daab5acaa..0000000000 --- a/recipes/linux/linux-2.6.31/boc01/005-091103-isl12024.patch +++ /dev/null @@ -1,511 +0,0 @@ -Support for the ISL12024 RTC, EEPROM and unique ID. - -Signed-off-by: Jeremy Laine - -Index: linux-2.6.31/drivers/misc/eeprom/at24.c -=================================================================== ---- linux-2.6.31.orig/drivers/misc/eeprom/at24.c 2009-09-10 00:13:59.000000000 +0200 -+++ linux-2.6.31/drivers/misc/eeprom/at24.c 2009-11-03 11:17:22.000000000 +0100 -@@ -115,6 +115,8 @@ - { "spd", AT24_DEVICE_MAGIC(2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, - { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, -+ /* Intersil isl12024 eeprom */ -+ { "isl12024-eeprom", AT24_DEVICE_MAGIC(4096 / 8, AT24_FLAG_ADDR16) }, - /* 24rf08 quirk is handled at i2c-core */ - { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, - { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, -Index: linux-2.6.31/drivers/rtc/Kconfig -=================================================================== ---- linux-2.6.31.orig/drivers/rtc/Kconfig 2009-09-10 00:13:59.000000000 +0200 -+++ linux-2.6.31/drivers/rtc/Kconfig 2009-11-03 11:13:42.000000000 +0100 -@@ -193,6 +193,15 @@ - This driver can also be built as a module. If so, the module - will be called rtc-isl1208. - -+config RTC_DRV_ISL12024 -+ tristate "Intersil 12024" -+ help -+ If you say yes here you get support for the Intersil ISL12024 -+ RTC chip. This driver also exposes the chip's unique ID. -+ -+ This driver can also be built as a module. If so, the module -+ will be called rtc-isl12024. -+ - config RTC_DRV_X1205 - tristate "Xicor/Intersil X1205" - help -Index: linux-2.6.31/drivers/rtc/Makefile -=================================================================== ---- linux-2.6.31.orig/drivers/rtc/Makefile 2009-09-10 00:13:59.000000000 +0200 -+++ linux-2.6.31/drivers/rtc/Makefile 2009-11-03 11:13:42.000000000 +0100 -@@ -40,6 +40,7 @@ - obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o - obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o - obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o -+obj-$(CONFIG_RTC_DRV_ISL12024) += rtc-isl12024.o - obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o - obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o - obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o -Index: linux-2.6.31/drivers/rtc/rtc-isl12024.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.31/drivers/rtc/rtc-isl12024.c 2009-11-03 11:14:33.000000000 +0100 -@@ -0,0 +1,457 @@ -+/* -+ * Intersil ISL12024 rtc class driver -+ * -+ * Copyright (C) 2007, CenoSYS (www.cenosys.com). -+ * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu). -+ * -+ * Guillaume Ligneul -+ * Sylvain Giroudon -+ * Jeremy Laine -+ * -+ * Based on rtc-x1205. -+ * -+ * 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 -+#include -+#include -+#include -+#include -+ -+#define DRV_VERSION "0.3" -+ -+/* offsets into CCR area */ -+ -+#define CCR_SEC 0 -+#define CCR_MIN 1 -+#define CCR_HOUR 2 -+#define CCR_MDAY 3 -+#define CCR_MONTH 4 -+#define CCR_YEAR 5 -+#define CCR_WDAY 6 -+#define CCR_Y2K 7 -+ -+/* alarm0 section */ -+#define ISL12024_REG_ALARM0 0x08 /* Base address of ALARM0 */ -+ -+/* device id section */ -+#define ISL12024_REG_ID 0x20 -+#define ISL12024_ID_SECTION_LEN 8 -+ -+/* rtc section */ -+#define ISL12024_REG_RTC 0x30 /* Base address of RTC */ -+#define ISL12024_REG_HR_MIL (1<<7) /* 24h/12h mode */ -+#define ISL12024_REG_HR_PM (1<<5) /* AM/PM bit in 12h mode */ -+#define ISL12024_RTC_SECTION_LEN 8 -+ -+/* control/status section */ -+#define ISL12024_REG_SR 0x3F -+#define ISL12024_REG_SR_BAT (1<<7) /* battery */ -+#define ISL12024_REG_SR_AL1 (1<<6) /* alarm 0 */ -+#define ISL12024_REG_SR_AL0 (1<<5) /* alarm 1 */ -+#define ISL12024_REG_SR_OSCF (1<<4) /* oscillator fail */ -+#define ISL12024_REG_SR_RWEL (1<<2) /* register write enable latch */ -+#define ISL12024_REG_SR_WEL (1<<1) /* write enable latch */ -+#define ISL12024_REG_SR_RTCF (1<<0) /* rtc fail */ -+#define ISL12024_REG_INT 0x11 -+ -+#define ISL12024_INT_AL0E 0x20 /* Alarm 0 enable */ -+ -+static struct i2c_driver isl12024_driver; -+ -+static int -+isl12024_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], -+ unsigned len) -+{ -+ int ret; -+ u8 dt_addr[2]; -+ -+ struct i2c_msg msgs[2] = { -+ { -+ .addr = client->addr, -+ .flags = 0, -+ .len = 2, -+ .buf = dt_addr, -+ }, -+ { -+ .addr = client->addr, -+ .flags = I2C_M_RD, -+ .len = len, -+ .buf = buf, -+ }, -+ }; -+ -+ dt_addr[0] = 0; -+ dt_addr[1] = reg; -+ -+ ret = i2c_transfer(client->adapter, msgs, 2); -+ if (ret < 0) { -+ dev_err(&client->dev, "read error (%i)\n", ret); -+ return ret; -+ } -+ return 0; -+} -+ -+static int -+isl12024_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], -+ unsigned len) -+{ -+ int ret; -+ u8 i2c_buf[10]; -+ -+ i2c_buf[0] = 0; -+ i2c_buf[1] = reg; -+ memcpy(&i2c_buf[2], &buf[0], len); -+ -+ ret = i2c_master_send(client, i2c_buf, len + 2); -+ if (ret != len + 2) { -+ dev_err(&client->dev, "write error (%d)\n", ret); -+ return -EIO; -+ } -+ return 0; -+} -+ -+static int isl12024_read_time(struct i2c_client *client, -+ struct rtc_time *tm, u8 reg_base) -+{ -+ unsigned char sr; -+ int err; -+ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; -+ -+ if (isl12024_i2c_read_regs(client, ISL12024_REG_SR, &sr, -+ sizeof(sr)) < 0) { -+ dev_err(&client->dev, "reading SR failed\n"); -+ return -EIO; -+ } -+ -+ err = isl12024_i2c_read_regs(client, reg_base, regs, -+ ISL12024_RTC_SECTION_LEN); -+ -+ if (err < 0) { -+ dev_err(&client->dev, "reading RTC section failed\n"); -+ return err; -+ } -+ -+ tm->tm_sec = bcd2bin(regs[0]); -+ tm->tm_min = bcd2bin(regs[1]); -+ -+ /* HR field has a more complex interpretation */ -+ if (regs[2] & ISL12024_REG_HR_MIL) { -+ /* 24h format */ -+ tm->tm_hour = bcd2bin(regs[2] & 0x3f); -+ } else { -+ /* 12h format */ -+ tm->tm_hour = bcd2bin(regs[2] & 0x1f); -+ if (regs[2] & ISL12024_REG_HR_PM) /* PM flag set */ -+ tm->tm_hour += 12; -+ } -+ -+ tm->tm_mday = bcd2bin(regs[3]); -+ tm->tm_mon = bcd2bin(regs[4]); -+ tm->tm_year = bcd2bin(regs[5]) + 100; -+ tm->tm_wday = bcd2bin(regs[6]); -+ -+ return rtc_valid_tm(tm); -+} -+ -+static int isl12024_set_datetime(struct i2c_client *client, struct rtc_time *tm, -+ int datetoo, u8 reg_base, -+ unsigned char alm_enable) -+{ -+ int i, xfer, nbytes; -+ unsigned char buf[8]; -+ -+ static const unsigned char wel[3] = { 0, ISL12024_REG_SR, -+ ISL12024_REG_SR_WEL }; -+ -+ static const unsigned char rwel[3] = { 0, ISL12024_REG_SR, -+ ISL12024_REG_SR_WEL | ISL12024_REG_SR_RWEL }; -+ -+ static const unsigned char diswe[3] = { 0, ISL12024_REG_SR, 0 }; -+ -+ dev_dbg(&client->dev, -+ "%s: secs=%d, mins=%d, hours=%d\n", -+ __func__, -+ tm->tm_sec, tm->tm_min, tm->tm_hour); -+ -+ buf[CCR_SEC] = bin2bcd(tm->tm_sec); -+ buf[CCR_MIN] = bin2bcd(tm->tm_min); -+ -+ /* set hour and 24hr bit */ -+ buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | ISL12024_REG_HR_MIL; -+ -+ /* should we also set the date? */ -+ if (datetoo) { -+ dev_dbg(&client->dev, -+ "%s: mday=%d, mon=%d, year=%d, wday=%d\n", -+ __func__, -+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); -+ -+ buf[CCR_MDAY] = bin2bcd(tm->tm_mday); -+ -+ /* month, 1 - 12 */ -+ buf[CCR_MONTH] = bin2bcd(tm->tm_mon); -+ -+ /* year, since the rtc epoch*/ -+ buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); -+ buf[CCR_WDAY] = tm->tm_wday & 0x07; -+ buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100); -+ } -+ -+ /* If writing alarm registers, set compare bits on registers 0-4 */ -+ if (reg_base == ISL12024_REG_ALARM0) -+ for (i = 0; i <= 4; i++) -+ buf[i] |= 0x80; -+ -+ /* this sequence is required to unlock the chip */ -+ xfer = i2c_master_send(client, wel, 3); -+ if (xfer != 3) { -+ dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); -+ return -EIO; -+ } -+ -+ xfer = i2c_master_send(client, rwel, 3); -+ if (xfer != 3) { -+ dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); -+ return -EIO; -+ } -+ -+ /* write register's data */ -+ if (datetoo) -+ nbytes = 8; -+ else -+ nbytes = 3; -+ xfer = isl12024_i2c_set_regs(client, reg_base, buf, nbytes); -+ if (xfer < 0) -+ return xfer; -+ -+ /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/ -+ if (reg_base == ISL12024_REG_ALARM0) { -+ unsigned char al0e[3] = { 0, ISL12024_REG_INT, 0 }; -+ -+ msleep(10); -+ -+ /* ...and set or clear the AL0E bit in the INT register */ -+ -+ /* Need to set RWEL again as the write has cleared it */ -+ xfer = i2c_master_send(client, rwel, 3); -+ if (xfer != 3) { -+ dev_err(&client->dev, -+ "%s: al0e rwel - %d\n", -+ __func__, -+ xfer); -+ return -EIO; -+ } -+ -+ if (alm_enable) -+ al0e[2] = ISL12024_INT_AL0E; -+ -+ xfer = i2c_master_send(client, al0e, 3); -+ if (xfer != 3) { -+ dev_err(&client->dev, -+ "%s: al0e - %d\n", -+ __func__, -+ xfer); -+ return -EIO; -+ } -+ -+ /* and wait 10msec again for this write to complete */ -+ msleep(10); -+ } -+ -+ /* disable further writes */ -+ xfer = i2c_master_send(client, diswe, 3); -+ if (xfer != 3) { -+ dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+static int isl12024_fix_osc(struct i2c_client *client) -+{ -+ int err; -+ struct rtc_time tm; -+ -+ tm.tm_hour = tm.tm_min = tm.tm_sec = 0; -+ -+ err = isl12024_set_datetime(client, &tm, 0, ISL12024_REG_RTC, 0); -+ if (err < 0) -+ dev_err(&client->dev, -+ "unable to restart the oscillator (%d)\n", err); -+ -+ return err; -+} -+ -+static int isl12024_rtc_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ return isl12024_read_time(to_i2c_client(dev), tm, -+ ISL12024_REG_RTC); -+} -+ -+static int isl12024_rtc_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ return isl12024_set_datetime(to_i2c_client(dev), tm, 1, -+ ISL12024_REG_RTC, 0); -+} -+ -+static int isl12024_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ unsigned char intr; -+ int err; -+ struct i2c_client *client = to_i2c_client(dev); -+ -+ err = isl12024_i2c_read_regs(client, ISL12024_REG_INT, &intr, -+ sizeof(intr)); -+ if (err < 0) -+ return err; -+ alrm->enabled = (intr & ISL12024_INT_AL0E) ? 1 : 0; -+ -+ return isl12024_read_time(client, &alrm->time, ISL12024_REG_ALARM0); -+} -+ -+static int isl12024_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -+{ -+ return isl12024_set_datetime(to_i2c_client(dev), &alrm->time, 1, -+ ISL12024_REG_ALARM0, alrm->enabled); -+} -+ -+static int -+isl12024_rtc_proc(struct device *dev, struct seq_file *seq) -+{ -+ /* Nothing to do */ -+ return 0; -+} -+ -+static const struct rtc_class_ops isl12024_rtc_ops = { -+ .proc = isl12024_rtc_proc, -+ .read_time = isl12024_rtc_read_time, -+ .set_time = isl12024_rtc_set_time, -+ .read_alarm = isl12024_rtc_read_alarm, -+ .set_alarm = isl12024_rtc_set_alarm, -+}; -+ -+static ssize_t isl12024_show_id(struct device *dev, -+ struct device_attribute *attr, -+ char *buf) -+{ -+ struct i2c_client *client = to_i2c_client(dev); -+ int err; -+ ssize_t len = 0; -+ int i; -+ u8 id_buffer[ISL12024_ID_SECTION_LEN]; -+ -+ /* Read unique id from eeprom */ -+ err = isl12024_i2c_read_regs(client, ISL12024_REG_ID, id_buffer, -+ sizeof(id_buffer)); -+ if (err < 0) { -+ dev_err(&client->dev, "reading RTC section failed\n"); -+ return err; -+ } -+ -+ /* Print hexadecimal */ -+ for (i = 0; i < sizeof(id_buffer); i++) -+ len += sprintf(buf + len, "%02X", id_buffer[i]); -+ len += sprintf(buf + len, "\n"); -+ return len; -+} -+ -+static DEVICE_ATTR(id, S_IRUGO, isl12024_show_id, NULL); -+ -+static int -+isl12024_probe(struct i2c_client *client, const struct i2c_device_id *id) -+{ -+ int rc = 0; -+ unsigned char sr; -+ struct rtc_device *rtc = NULL; -+ -+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) -+ return -ENODEV; -+ -+ dev_info(&client->dev, -+ "chip found, driver version " DRV_VERSION "\n"); -+ -+ rtc = rtc_device_register(isl12024_driver.driver.name, -+ &client->dev, &isl12024_rtc_ops, -+ THIS_MODULE); -+ if (IS_ERR(rtc)) -+ return PTR_ERR(rtc); -+ -+ i2c_set_clientdata(client, rtc); -+ -+ rc = isl12024_i2c_read_regs(client, ISL12024_REG_SR, &sr, sizeof(sr)); -+ if (rc < 0) { -+ dev_err(&client->dev, "reading status failed\n"); -+ goto exit_unregister; -+ } -+ -+ /* Check for power failures and enable the osc */ -+ if (sr & ISL12024_REG_SR_RTCF) { -+ dev_warn(&client->dev, "rtc power failure detected, " -+ "please set clock.\n"); -+ udelay(50); -+ isl12024_fix_osc(client); -+ } -+ -+ /* Register sysfs hooks */ -+ rc = device_create_file(&client->dev, &dev_attr_id); -+ if (rc < 0) -+ goto exit_unregister; -+ -+ return 0; -+ -+exit_unregister: -+ rtc_device_unregister(rtc); -+ -+ return rc; -+} -+ -+static int -+isl12024_remove(struct i2c_client *client) -+{ -+ struct rtc_device *rtc = i2c_get_clientdata(client); -+ -+ rtc_device_unregister(rtc); -+ device_remove_file(&client->dev, &dev_attr_id); -+ -+ return 0; -+} -+ -+static const struct i2c_device_id isl12024_id[] = { -+ { "isl12024", 0 }, -+ { } -+}; -+MODULE_DEVICE_TABLE(i2c, isl12024_id); -+ -+static struct i2c_driver isl12024_driver = { -+ .driver = { -+ .name = "rtc-isl12024", -+ }, -+ .probe = isl12024_probe, -+ .remove = isl12024_remove, -+ .id_table = isl12024_id, -+}; -+ -+/* module init/exit */ -+ -+static int __init isl12024_init(void) -+{ -+ return i2c_add_driver(&isl12024_driver); -+} -+ -+static void __exit isl12024_exit(void) -+{ -+ i2c_del_driver(&isl12024_driver); -+} -+ -+MODULE_AUTHOR("Guillaume Ligneul "); -+MODULE_DESCRIPTION("Intersil ISL12024 driver"); -+MODULE_LICENSE("GPL"); -+MODULE_VERSION(DRV_VERSION); -+ -+module_init(isl12024_init); -+module_exit(isl12024_exit); diff --git a/recipes/linux/linux-2.6.31/boc01/005-091110-isl12024.patch b/recipes/linux/linux-2.6.31/boc01/005-091110-isl12024.patch new file mode 100644 index 0000000000..0d0f5c42c0 --- /dev/null +++ b/recipes/linux/linux-2.6.31/boc01/005-091110-isl12024.patch @@ -0,0 +1,509 @@ +Support for the ISL12024 RTC, EEPROM and unique ID. + +Signed-off-by: Jeremy Laine + +Index: linux-2.6.31/drivers/misc/eeprom/at24.c +=================================================================== +--- linux-2.6.31.orig/drivers/misc/eeprom/at24.c 2009-11-10 17:20:53.000000000 +0100 ++++ linux-2.6.31/drivers/misc/eeprom/at24.c 2009-11-10 17:54:17.000000000 +0100 +@@ -115,6 +115,8 @@ + { "spd", AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, + { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, ++ /* Intersil isl12024 eeprom */ ++ { "isl12024-eeprom", AT24_DEVICE_MAGIC(4096 / 8, AT24_FLAG_ADDR16) }, + /* 24rf08 quirk is handled at i2c-core */ + { "24c08", AT24_DEVICE_MAGIC(8192 / 8, 0) }, + { "24c16", AT24_DEVICE_MAGIC(16384 / 8, 0) }, +Index: linux-2.6.31/drivers/rtc/Kconfig +=================================================================== +--- linux-2.6.31.orig/drivers/rtc/Kconfig 2009-11-10 17:20:53.000000000 +0100 ++++ linux-2.6.31/drivers/rtc/Kconfig 2009-11-10 17:54:17.000000000 +0100 +@@ -193,6 +193,15 @@ + This driver can also be built as a module. If so, the module + will be called rtc-isl1208. + ++config RTC_DRV_ISL12024 ++ tristate "Intersil ISL12024" ++ help ++ If you say yes here you get support for the Intersil ISL12024 ++ RTC chip. This driver also exposes the chip's unique ID. ++ ++ This driver can also be built as a module. If so, the module ++ will be called rtc-isl12024. ++ + config RTC_DRV_X1205 + tristate "Xicor/Intersil X1205" + help +Index: linux-2.6.31/drivers/rtc/Makefile +=================================================================== +--- linux-2.6.31.orig/drivers/rtc/Makefile 2009-11-10 17:20:53.000000000 +0100 ++++ linux-2.6.31/drivers/rtc/Makefile 2009-11-10 17:54:17.000000000 +0100 +@@ -40,6 +40,7 @@ + obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o + obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o + obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o ++obj-$(CONFIG_RTC_DRV_ISL12024) += rtc-isl12024.o + obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o + obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o + obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o +Index: linux-2.6.31/drivers/rtc/rtc-isl12024.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.31/drivers/rtc/rtc-isl12024.c 2009-11-10 17:54:31.000000000 +0100 +@@ -0,0 +1,455 @@ ++/* ++ * Intersil ISL12024 rtc class driver ++ * ++ * Copyright (C) 2007, CenoSYS (www.cenosys.com). ++ * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu). ++ * ++ * Guillaume Ligneul ++ * Sylvain Giroudon ++ * Jeremy Laine ++ * ++ * Based on rtc-x1205. ++ * ++ * 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 ++#include ++#include ++#include ++#include ++ ++#define DRV_VERSION "0.3" ++ ++/* offsets into CCR area */ ++ ++#define CCR_SEC 0 ++#define CCR_MIN 1 ++#define CCR_HOUR 2 ++#define CCR_MDAY 3 ++#define CCR_MONTH 4 ++#define CCR_YEAR 5 ++#define CCR_WDAY 6 ++#define CCR_Y2K 7 ++ ++/* alarm0 section */ ++#define ISL12024_REG_ALARM0 0x08 /* Base address of ALARM0 */ ++ ++/* device id section */ ++#define ISL12024_REG_ID 0x20 ++#define ISL12024_ID_SECTION_LEN 8 ++ ++/* rtc section */ ++#define ISL12024_REG_RTC 0x30 /* Base address of RTC */ ++#define ISL12024_REG_HR_MIL (1<<7) /* 24h/12h mode */ ++#define ISL12024_REG_HR_PM (1<<5) /* AM/PM bit in 12h mode */ ++#define ISL12024_RTC_SECTION_LEN 8 ++ ++/* status section */ ++#define ISL12024_REG_SR 0x3F ++#define ISL12024_REG_SR_BAT (1<<7) /* battery */ ++#define ISL12024_REG_SR_AL1 (1<<6) /* alarm 0 */ ++#define ISL12024_REG_SR_AL0 (1<<5) /* alarm 1 */ ++#define ISL12024_REG_SR_OSCF (1<<4) /* oscillator fail */ ++#define ISL12024_REG_SR_RWEL (1<<2) /* register write enable latch */ ++#define ISL12024_REG_SR_WEL (1<<1) /* write enable latch */ ++#define ISL12024_REG_SR_RTCF (1<<0) /* rtc fail */ ++ ++/* control section */ ++#define ISL12024_REG_INT 0x11 ++#define ISL12024_INT_AL0E (1<<5) /* Alarm 0 enable */ ++ ++static struct i2c_driver isl12024_driver; ++ ++static int ++isl12024_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], ++ unsigned len) ++{ ++ int ret; ++ u8 dt_addr[2]; ++ ++ struct i2c_msg msgs[2] = { ++ { ++ .addr = client->addr, ++ .flags = 0, ++ .len = 2, ++ .buf = dt_addr, ++ }, ++ { ++ .addr = client->addr, ++ .flags = I2C_M_RD, ++ .len = len, ++ .buf = buf, ++ }, ++ }; ++ ++ dt_addr[0] = 0; ++ dt_addr[1] = reg; ++ ++ ret = i2c_transfer(client->adapter, msgs, 2); ++ if (ret != 2) { ++ dev_err(&client->dev, "read error (%i)\n", ret); ++ return (ret < 0) ? ret : -EIO; ++ } ++ return 0; ++} ++ ++static int ++isl12024_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], ++ unsigned len) ++{ ++ int ret; ++ u8 i2c_buf[10]; ++ ++ i2c_buf[0] = 0; ++ i2c_buf[1] = reg; ++ memcpy(&i2c_buf[2], &buf[0], len); ++ ++ ret = i2c_master_send(client, i2c_buf, len + 2); ++ if (ret != len + 2) { ++ dev_err(&client->dev, "write error (%d)\n", ret); ++ return (ret < 0) ? ret : -EIO; ++ } ++ return 0; ++} ++ ++static int isl12024_read_time(struct i2c_client *client, ++ struct rtc_time *tm, u8 reg_base) ++{ ++ unsigned char sr; ++ int err; ++ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; ++ ++ if (isl12024_i2c_read_regs(client, ISL12024_REG_SR, &sr, ++ sizeof(sr)) < 0) { ++ dev_err(&client->dev, "reading SR failed\n"); ++ return -EIO; ++ } ++ ++ err = isl12024_i2c_read_regs(client, reg_base, regs, ++ ISL12024_RTC_SECTION_LEN); ++ ++ if (err < 0) { ++ dev_err(&client->dev, "reading RTC section failed\n"); ++ return err; ++ } ++ ++ tm->tm_sec = bcd2bin(regs[CCR_SEC]); ++ tm->tm_min = bcd2bin(regs[CCR_MIN]); ++ ++ /* HR field has a more complex interpretation */ ++ if (regs[CCR_HOUR] & ISL12024_REG_HR_MIL) { ++ /* 24h format */ ++ tm->tm_hour = bcd2bin(regs[CCR_HOUR] & 0x3f); ++ } else { ++ /* 12h format */ ++ tm->tm_hour = bcd2bin(regs[CCR_HOUR] & 0x1f); ++ if (regs[CCR_HOUR] & ISL12024_REG_HR_PM) /* PM flag set */ ++ tm->tm_hour += 12; ++ } ++ ++ tm->tm_mday = bcd2bin(regs[CCR_MDAY]); ++ tm->tm_mon = bcd2bin(regs[CCR_MONTH]) - 1; ++ tm->tm_year = bcd2bin(regs[CCR_YEAR]) ++ + (bcd2bin(regs[CCR_Y2K]) * 100) - 1900; ++ tm->tm_wday = bcd2bin(regs[CCR_WDAY]); ++ ++ return rtc_valid_tm(tm); ++} ++ ++static int isl12024_set_datetime(struct i2c_client *client, struct rtc_time *tm, ++ int datetoo, u8 reg_base, ++ unsigned char alm_enable) ++{ ++ int i, xfer, nbytes; ++ unsigned char buf[8]; ++ ++ static const unsigned char wel[3] = { 0, ISL12024_REG_SR, ++ ISL12024_REG_SR_WEL }; ++ ++ static const unsigned char rwel[3] = { 0, ISL12024_REG_SR, ++ ISL12024_REG_SR_WEL | ISL12024_REG_SR_RWEL }; ++ ++ static const unsigned char diswe[3] = { 0, ISL12024_REG_SR, 0 }; ++ ++ dev_dbg(&client->dev, ++ "%s: secs=%d, mins=%d, hours=%d\n", ++ __func__, ++ tm->tm_sec, tm->tm_min, tm->tm_hour); ++ ++ buf[CCR_SEC] = bin2bcd(tm->tm_sec); ++ buf[CCR_MIN] = bin2bcd(tm->tm_min); ++ ++ /* set hour and 24hr bit */ ++ buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | ISL12024_REG_HR_MIL; ++ ++ /* should we also set the date? */ ++ if (datetoo) { ++ dev_dbg(&client->dev, ++ "%s: mday=%d, mon=%d, year=%d, wday=%d\n", ++ __func__, ++ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); ++ ++ buf[CCR_MDAY] = bin2bcd(tm->tm_mday); ++ ++ /* month, 1 - 12 */ ++ buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); ++ ++ /* year, since the rtc epoch*/ ++ buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); ++ buf[CCR_WDAY] = tm->tm_wday & 0x07; ++ buf[CCR_Y2K] = bin2bcd(19 + tm->tm_year / 100); ++ } ++ ++ /* If writing alarm registers, set compare bits on registers 0-4 */ ++ if (reg_base == ISL12024_REG_ALARM0) ++ for (i = 0; i <= 4; i++) ++ buf[i] |= 0x80; ++ ++ /* this sequence is required to unlock the chip */ ++ xfer = i2c_master_send(client, wel, 3); ++ if (xfer != 3) { ++ dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); ++ return -EIO; ++ } ++ ++ xfer = i2c_master_send(client, rwel, 3); ++ if (xfer != 3) { ++ dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); ++ return -EIO; ++ } ++ ++ /* write register's data */ ++ if (datetoo) ++ nbytes = 8; ++ else ++ nbytes = 3; ++ xfer = isl12024_i2c_set_regs(client, reg_base, buf, nbytes); ++ if (xfer < 0) ++ return xfer; ++ ++ /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/ ++ if (reg_base == ISL12024_REG_ALARM0) { ++ unsigned char al0e[3] = { 0, ISL12024_REG_INT, 0 }; ++ ++ msleep(10); ++ ++ /* ...and set or clear the AL0E bit in the INT register */ ++ ++ /* Need to set RWEL again as the write has cleared it */ ++ xfer = i2c_master_send(client, rwel, 3); ++ if (xfer != 3) { ++ dev_err(&client->dev, "%s: al0e rwel - %d\n", ++ __func__, xfer); ++ return -EIO; ++ } ++ ++ if (alm_enable) ++ al0e[2] = ISL12024_INT_AL0E; ++ ++ xfer = i2c_master_send(client, al0e, 3); ++ if (xfer != 3) { ++ dev_err(&client->dev, "%s: al0e - %d\n", ++ __func__, xfer); ++ return -EIO; ++ } ++ ++ /* and wait 10msec again for this write to complete */ ++ msleep(10); ++ } ++ ++ /* disable further writes */ ++ xfer = i2c_master_send(client, diswe, 3); ++ if (xfer != 3) { ++ dev_err(&client->dev, "%s: diswe - %d\n", __func__, xfer); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++static int isl12024_fix_osc(struct i2c_client *client) ++{ ++ int err; ++ struct rtc_time tm; ++ ++ tm.tm_hour = tm.tm_min = tm.tm_sec = 0; ++ ++ err = isl12024_set_datetime(client, &tm, 0, ISL12024_REG_RTC, 0); ++ if (err < 0) ++ dev_err(&client->dev, ++ "unable to restart the oscillator (%d)\n", err); ++ ++ return err; ++} ++ ++static int isl12024_rtc_read_time(struct device *dev, struct rtc_time *tm) ++{ ++ return isl12024_read_time(to_i2c_client(dev), tm, ++ ISL12024_REG_RTC); ++} ++ ++static int isl12024_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ return isl12024_set_datetime(to_i2c_client(dev), tm, 1, ++ ISL12024_REG_RTC, 0); ++} ++ ++static int isl12024_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ unsigned char intr; ++ int err; ++ struct i2c_client *client = to_i2c_client(dev); ++ ++ err = isl12024_i2c_read_regs(client, ISL12024_REG_INT, &intr, ++ sizeof(intr)); ++ if (err < 0) ++ return err; ++ alrm->enabled = (intr & ISL12024_INT_AL0E) ? 1 : 0; ++ ++ return isl12024_read_time(client, &alrm->time, ISL12024_REG_ALARM0); ++} ++ ++static int isl12024_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ++{ ++ return isl12024_set_datetime(to_i2c_client(dev), &alrm->time, 1, ++ ISL12024_REG_ALARM0, alrm->enabled); ++} ++ ++static int ++isl12024_rtc_proc(struct device *dev, struct seq_file *seq) ++{ ++ /* Nothing to do */ ++ return 0; ++} ++ ++static const struct rtc_class_ops isl12024_rtc_ops = { ++ .proc = isl12024_rtc_proc, ++ .read_time = isl12024_rtc_read_time, ++ .set_time = isl12024_rtc_set_time, ++ .read_alarm = isl12024_rtc_read_alarm, ++ .set_alarm = isl12024_rtc_set_alarm, ++}; ++ ++static ssize_t isl12024_show_id(struct device *dev, ++ struct device_attribute *attr, ++ char *buf) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ int err; ++ ssize_t len = 0; ++ int i; ++ u8 id_buffer[ISL12024_ID_SECTION_LEN]; ++ ++ /* Read unique id from eeprom */ ++ err = isl12024_i2c_read_regs(client, ISL12024_REG_ID, id_buffer, ++ sizeof(id_buffer)); ++ if (err < 0) { ++ dev_err(&client->dev, "reading ID section failed\n"); ++ return err; ++ } ++ ++ /* Print hexadecimal */ ++ for (i = 0; i < sizeof(id_buffer); i++) ++ len += sprintf(buf + len, "%02X", id_buffer[i]); ++ len += sprintf(buf + len, "\n"); ++ return len; ++} ++ ++static DEVICE_ATTR(id, S_IRUGO, isl12024_show_id, NULL); ++ ++static int ++isl12024_probe(struct i2c_client *client, const struct i2c_device_id *id) ++{ ++ int rc = 0; ++ unsigned char sr; ++ struct rtc_device *rtc = NULL; ++ ++ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ++ return -ENODEV; ++ ++ dev_info(&client->dev, ++ "chip found, driver version " DRV_VERSION "\n"); ++ ++ rtc = rtc_device_register(isl12024_driver.driver.name, ++ &client->dev, &isl12024_rtc_ops, ++ THIS_MODULE); ++ if (IS_ERR(rtc)) ++ return PTR_ERR(rtc); ++ ++ i2c_set_clientdata(client, rtc); ++ ++ rc = isl12024_i2c_read_regs(client, ISL12024_REG_SR, &sr, sizeof(sr)); ++ if (rc < 0) { ++ dev_err(&client->dev, "reading status failed\n"); ++ goto exit_unregister; ++ } ++ ++ /* Check for power failures and enable the osc */ ++ if (sr & ISL12024_REG_SR_RTCF) { ++ dev_warn(&client->dev, "rtc power failure detected, " ++ "please set clock.\n"); ++ udelay(50); ++ isl12024_fix_osc(client); ++ } ++ ++ /* Register sysfs hooks */ ++ rc = device_create_file(&client->dev, &dev_attr_id); ++ if (rc < 0) ++ goto exit_unregister; ++ ++ return 0; ++ ++exit_unregister: ++ rtc_device_unregister(rtc); ++ ++ return rc; ++} ++ ++static int ++isl12024_remove(struct i2c_client *client) ++{ ++ struct rtc_device *rtc = i2c_get_clientdata(client); ++ ++ rtc_device_unregister(rtc); ++ device_remove_file(&client->dev, &dev_attr_id); ++ ++ return 0; ++} ++ ++static const struct i2c_device_id isl12024_id[] = { ++ { "isl12024", 0 }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, isl12024_id); ++ ++static struct i2c_driver isl12024_driver = { ++ .driver = { ++ .name = "rtc-isl12024", ++ }, ++ .probe = isl12024_probe, ++ .remove = isl12024_remove, ++ .id_table = isl12024_id, ++}; ++ ++/* module init/exit */ ++ ++static int __init isl12024_init(void) ++{ ++ return i2c_add_driver(&isl12024_driver); ++} ++ ++static void __exit isl12024_exit(void) ++{ ++ i2c_del_driver(&isl12024_driver); ++} ++ ++MODULE_AUTHOR("Guillaume Ligneul "); ++MODULE_DESCRIPTION("Intersil ISL12024 driver"); ++MODULE_LICENSE("GPL"); ++MODULE_VERSION(DRV_VERSION); ++ ++module_init(isl12024_init); ++module_exit(isl12024_exit); diff --git a/recipes/linux/linux_2.6.31.bb b/recipes/linux/linux_2.6.31.bb index 21ebe2cc95..845909c76c 100644 --- a/recipes/linux/linux_2.6.31.bb +++ b/recipes/linux/linux_2.6.31.bb @@ -26,7 +26,7 @@ SRC_URI_append_boc01 = "\ file://boc01.dts \ file://boc01.dts.v1 \ file://004-081205-usb.patch;patch=1 \ - file://005-091103-isl12024.patch;patch=1 \ + file://005-091110-isl12024.patch;patch=1 \ file://007-091005-lm73.patch;patch=1 \ file://011-091028-gpio.patch;patch=1 \ file://012-091019-capsense.patch;patch=1 \ -- cgit v1.2.3