From 08f02468d5a3963cf0114285835f46cf0249b944 Mon Sep 17 00:00:00 2001 From: Jeremy Lainé Date: Tue, 24 Mar 2009 17:30:03 +0100 Subject: linux-2.6.27: update patches for boc01 --- .../linux-2.6.27/boc01/005-090217-isl12024.patch | 669 ------------ .../linux-2.6.27/boc01/005-090226-isl12024.patch | 693 +++++++++++++ .../linux-2.6.27/boc01/012-090219-capsense.patch | 20 +- .../linux/linux-2.6.27/boc01/013-090209-lcd.patch | 933 ----------------- .../linux/linux-2.6.27/boc01/013-090306-lcd.patch | 1090 ++++++++++++++++++++ .../linux-2.6.27/boc01/014-090209-pm-wakeup.patch | 195 ---- recipes/linux/linux-2.6.27/boc01/defconfig | 31 +- recipes/linux/linux_2.6.27.bb | 7 +- 8 files changed, 1833 insertions(+), 1805 deletions(-) delete mode 100644 recipes/linux/linux-2.6.27/boc01/005-090217-isl12024.patch create mode 100644 recipes/linux/linux-2.6.27/boc01/005-090226-isl12024.patch delete mode 100644 recipes/linux/linux-2.6.27/boc01/013-090209-lcd.patch create mode 100644 recipes/linux/linux-2.6.27/boc01/013-090306-lcd.patch delete mode 100644 recipes/linux/linux-2.6.27/boc01/014-090209-pm-wakeup.patch diff --git a/recipes/linux/linux-2.6.27/boc01/005-090217-isl12024.patch b/recipes/linux/linux-2.6.27/boc01/005-090217-isl12024.patch deleted file mode 100644 index 672e405de0..0000000000 --- a/recipes/linux/linux-2.6.27/boc01/005-090217-isl12024.patch +++ /dev/null @@ -1,669 +0,0 @@ -Index: linux-2.6.27/drivers/rtc/Kconfig -=================================================================== ---- linux-2.6.27.orig/drivers/rtc/Kconfig -+++ linux-2.6.27/drivers/rtc/Kconfig -@@ -124,6 +124,12 @@ comment "I2C RTC drivers" - - if I2C - -+config RTC_DRV_ISL12024 -+ tristate "Intersil 12024 RTC/ UniqueID" -+ help -+ If you say yes .... -+ This driver can also be built as a module. -+ - config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" - help -Index: linux-2.6.27/drivers/rtc/Makefile -=================================================================== ---- linux-2.6.27.orig/drivers/rtc/Makefile -+++ linux-2.6.27/drivers/rtc/Makefile -@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds17 - 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_M48T59) += rtc-m48t59.o -Index: linux-2.6.27/drivers/rtc/rtc-isl12024.c -=================================================================== ---- /dev/null -+++ linux-2.6.27/drivers/rtc/rtc-isl12024.c -@@ -0,0 +1,517 @@ -+/* -+ * Intersil ISL12024 class driver -+ * -+ * -+ * Copyright (C) 2007, CenoSYS (www.cenosys.com). -+ * Guillaume Ligneul -+ * Guillaume.ligneul@gmail.com -+ * -+ * This software program is licensed subject to the GNU General Public License -+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "isl12024.h" -+ -+ -+#define DBG 1 -+#undef DBG -+ -+static u8 buf_id[ISL12024_RTC_SECTION_LEN] = { 0 ,}; -+ -+#define DRV_NAME "isl12024" -+#define DRV_VERSION "0.1" -+ -+/* i2c configuration */ -+ -+static const unsigned short normal_i2c[] = { -+ ISL12024_I2C_ADDR >>1, I2C_CLIENT_END -+}; -+I2C_CLIENT_INSMOD; -+ -+/* Procfs management */ -+static struct proc_dir_entry * root_proc = NULL; -+static struct proc_dir_entry * entry_proc = NULL; -+static int read_proc (char * page, char ** start, off_t off, int count, int * eof, void * data); -+ -+static int isl12024_get_status(struct i2c_client *client, unsigned char *sr); -+static int isl12024_fix_osc(struct i2c_client *client); -+ -+ -+static int isl12024_attach_adapter(struct i2c_adapter *adapter); -+static int isl12024_detach_client(struct i2c_client *client); -+ -+// To debug (may be add in includ/linux/i2c-id.h) -+#define I2C_DRIVERID_ISL12024 97 -+ -+static struct i2c_driver isl12024_driver = { -+ .driver = { -+ .name = DRV_NAME, -+ }, -+ .id = I2C_DRIVERID_ISL12024, -+ .attach_adapter = &isl12024_attach_adapter, -+ .detach_client = &isl12024_detach_client, -+}; -+ -+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\n"); -+ return -EIO; -+ } -+ return ret; -+} -+ -+EXPORT_SYMBOL(isl12024_i2c_read_regs); -+ -+ -+int -+isl12024_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], -+ unsigned len) -+{ -+ int ret; -+ u8 i2c_buf[10]; -+ -+ struct i2c_msg msgs[1] = { -+ { -+ .addr = client->addr, -+ .flags = 0, -+ .len = len+2, -+ .buf = i2c_buf, -+ }, -+ }; -+ -+ i2c_buf[0] = 0; -+ i2c_buf[1] = reg; -+ -+ -+ memcpy(&i2c_buf[2], &buf[0], len ); -+ -+ -+ ret = i2c_transfer(client->adapter, msgs, 1); -+ printk(KERN_INFO "i2c_transfer %d\n",ret); -+ return ret; -+} -+ -+EXPORT_SYMBOL(isl12024_i2c_set_regs); -+ -+static int isl12024_i2c_validate_client(struct i2c_client *client) -+{ -+ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; -+ u8 zero_mask[ISL12024_RTC_SECTION_LEN] = { -+ 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8, 0xc6 -+ }; -+ -+ int i; -+ int ret; -+ -+ ret = isl12024_i2c_read_regs(client, ISL12024_REG_SC, regs, ISL12024_RTC_SECTION_LEN); -+ -+ if (ret < 0) -+ return ret; -+ -+ for (i = 0; i < ISL12024_RTC_SECTION_LEN; ++i) { -+ if (regs[i] & zero_mask[i]) /* check if bits are cleared */ -+ return -ENODEV; -+ -+ } -+ -+ return 0; -+} -+ -+static int isl12024_read_time(struct i2c_client *client, -+ struct rtc_time *tm) -+{ -+ unsigned char sr; -+ int err; -+ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; -+ -+ printk(KERN_INFO "%s\n ",__FUNCTION__ ); -+ -+ -+ if (isl12024_get_status(client, &sr) < 0) { -+ dev_err(&client->dev, "%s: reading SR failed\n", __func__); -+ return -EIO; -+ } -+ -+ err = isl12024_i2c_read_regs(client, ISL12024_REG_SC, regs, ISL12024_RTC_SECTION_LEN); -+ -+#ifdef DBG -+ int i; -+ for(i=0; idev, "%s: reading RTC section failed\n", -+ __func__); -+ return sr; -+ } -+ -+ tm->tm_sec = BCD2BIN(regs[0]); -+ tm->tm_min = BCD2BIN(regs[1]); -+ -+ { /* HR field has a more complex interpretation */ -+ const u8 _hr = regs[2]; -+ if (_hr & ISL12024_REG_HR_MIL) /* 24h format */ -+ tm->tm_hour = BCD2BIN(_hr & 0x3f); -+ else { // 12h format -+ tm->tm_hour = BCD2BIN(_hr & 0x1f); -+ if (_hr & 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_get_status(struct i2c_client *client, unsigned char *sr) -+{ -+ static unsigned char sr_addr[2] = { 0, ISL12024_REG_SR }; -+ -+ struct i2c_msg msgs[] = { -+ { client->addr, 0, 2, sr_addr }, /* setup read ptr */ -+ { client->addr, I2C_M_RD, 1, sr }, /* read status */ -+ }; -+ -+ /* read status register */ -+ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { -+ dev_err(&client->dev, "%s: read error\n", __func__); -+ return -EIO; -+ } -+ -+ return 0; -+} -+ -+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]; -+ unsigned char rdata[10] = { 0, reg_base }; -+ -+ static const unsigned char wel[3] = { 0, ISL12024_REG_SR, -+ ISL12024_SR_WEL }; -+ -+ static const unsigned char rwel[3] = { 0, ISL12024_REG_SR, -+ ISL12024_SR_WEL | ISL12024_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_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_CCR_BASE) -+ for (i = 0; i <= 4; i++) -+ buf[i] |= 0x80; -+ -+ /* this sequence is required to unlock the chip */ -+ if ((xfer = i2c_master_send(client, wel, 3)) != 3) { -+ dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); -+ return -EIO; -+ } -+ -+ if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { -+ dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); -+ return -EIO; -+ } -+ -+ -+ /* write register's data */ -+ if (datetoo) -+ nbytes = 8; -+ else -+ nbytes = 3; -+ for (i = 0; i < nbytes; i++) -+ rdata[2+i] = buf[i]; -+ -+ xfer = i2c_master_send(client, rdata, nbytes+2); -+ if (xfer != nbytes+2) { -+ dev_err(&client->dev, -+ "%s: result=%d addr=%02x, data=%02x\n", -+ __func__, -+ xfer, rdata[1], rdata[2]); -+ return -EIO; -+ } -+ -+ /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/ -+ if (reg_base < ISL12024_CCR_BASE) { -+ 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: aloe 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 */ -+ if ((xfer = i2c_master_send(client, diswe, 3)) != 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_CCR_BASE, 0); -+ if (err < 0) -+ printk(KERN_INFO "unable to restart the oscillator\n"); -+ -+ return err; -+} -+ -+static int isl12024_rtc_read_time(struct device *dev, struct rtc_time *tm) -+{ -+ return isl12024_read_time(to_i2c_client(dev), tm); -+ -+} -+ -+static int isl12024_rtc_set_time(struct device *dev, struct rtc_time *tm) -+{ -+ return isl12024_set_datetime(to_i2c_client(dev), -+ tm, 1, ISL12024_CCR_BASE, 0); -+} -+ -+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, -+}; -+ -+static int read_proc (char * page, char ** start, off_t off, int count, int * eof, void * data) -+{ -+ int i=0; -+ -+ printk("id: 0x"); -+ for(i=0;iaddr = addr; -+ new_client->adapter = adapter; -+ new_client->driver = &isl12024_driver; -+ new_client->flags = 0; -+ strcpy(new_client->name, DRV_NAME); -+ -+ if (kind < 0) { -+ rc = isl12024_i2c_validate_client(new_client); -+ if (rc < 0) -+ goto failout; -+ } -+ -+ rc = i2c_attach_client(new_client); -+ if (rc < 0) -+ goto failout; -+ -+ rtc = rtc_device_register(isl12024_driver.driver.name, -+ &new_client->dev, -+ &isl12024_rtc_ops, THIS_MODULE); -+ -+ if (IS_ERR(rtc)) { -+ printk("Error during rtc registration\n"); -+ rc = PTR_ERR(rtc); -+ goto failout; -+ } -+ -+ i2c_set_clientdata(new_client, rtc); -+ -+ /* Check for power failures and eventualy enable the osc */ -+ if ((err = isl12024_get_status(new_client, &sr)) == 0) { -+ if (sr & ISL12024_SR_RTCF) { -+ printk(KERN_INFO "power failure detected, " -+ "please set the clock\n"); -+ udelay(50); -+ isl12024_fix_osc(new_client); -+ } -+ } -+ else -+ printk(KERN_INFO "couldn't read status\n"); -+ -+ root_proc = proc_mkdir( "isl12024", 0 ); -+ entry_proc = create_proc_entry("id", S_IFREG | S_IRUGO | S_IWUSR, root_proc); -+ -+ if (entry_proc == NULL) -+ return -1; -+ -+ entry_proc->owner = THIS_MODULE; -+ entry_proc->read_proc = read_proc; -+ -+ /* read unique id from eeprom */ -+ isl12024_i2c_read_regs(new_client, ISL12024_REG_ID, buf_id, sizeof(buf_id)); -+ -+ -+ return 0; -+ -+ failout: -+ kfree(new_client); -+ return rc; -+} -+ -+static int -+isl12024_attach_adapter (struct i2c_adapter *adapter) -+{ -+ return i2c_probe(adapter, &addr_data, isl12024_probe); -+} -+ -+static int -+isl12024_detach_client(struct i2c_client *client) -+{ -+ int rc; -+ struct rtc_device *const rtc = i2c_get_clientdata(client); -+ -+ if (rtc) -+ rtc_device_unregister(rtc); -+ -+ rc = i2c_detach_client(client); -+ if (rc) -+ return rc; -+ -+ kfree(client); -+ -+ return 0; -+} -+ -+/* 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); -Index: linux-2.6.27/drivers/i2c/chips/at24.c -=================================================================== ---- linux-2.6.27.orig/drivers/i2c/chips/at24.c -+++ linux-2.6.27/drivers/i2c/chips/at24.c -@@ -114,6 +114,8 @@ static const struct i2c_device_id at24_i - { "spd", AT24_DEVICE_MAGIC(2048 / 8, - AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, - { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, -+ /* Intersil RTC/Unique-ID isl12024 eeprom handled here */ -+ { "isl12024",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.27/drivers/rtc/isl12024.h -=================================================================== ---- /dev/null -+++ linux-2.6.27/drivers/rtc/isl12024.h -@@ -0,0 +1,100 @@ -+/* -+ * Intersil ISL12024 chip registers definitions -+ * -+ * -+ * Copyright (C) 2008, CenoSYS (www.cenosys.com). -+ * Guillaume Ligneul -+ * Guillaume.ligneul@gmail.com -+ * -+ * This software program is licensed subject to the GNU General Public License -+ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html -+ */ -+ -+#ifndef ISL12024_H_ -+#define ISL12024_H_ -+ -+#define ISL12024_REG_SR 0x3F /* status register */ -+#define ISL12024_REG_Y2K 0x37 -+#define ISL12024_REG_DW 0x36 -+#define ISL12024_REG_YR 0x35 -+#define ISL12024_REG_MO 0x34 -+#define ISL12024_REG_DT 0x33 -+#define ISL12024_REG_HR 0x32 -+#define ISL12024_REG_MN 0x31 -+#define ISL12024_REG_SC 0x30 -+#define ISL12024_REG_DTR 0x13 -+#define ISL12024_REG_ATR 0x12 -+#define ISL12024_REG_INT 0x11 -+#define ISL12024_REG_0 0x10 -+#define ISL12024_REG_Y2K1 0x0F -+#define ISL12024_REG_DWA1 0x0E -+#define ISL12024_REG_YRA1 0x0D -+#define ISL12024_REG_MOA1 0x0C -+#define ISL12024_REG_DTA1 0x0B -+#define ISL12024_REG_HRA1 0x0A -+#define ISL12024_REG_MNA1 0x09 -+#define ISL12024_REG_SCA1 0x08 -+#define ISL12024_REG_Y2K0 0x07 -+#define ISL12024_REG_DWA0 0x06 -+#define ISL12024_REG_YRA0 0x05 -+#define ISL12024_REG_MOA0 0x04 -+#define ISL12024_REG_DTA0 0x03 -+#define ISL12024_REG_HRA0 0x02 -+#define ISL12024_REG_MNA0 0x01 -+#define ISL12024_REG_SCA0 0x00 -+ -+#define ISL12024_CCR_BASE 0x30 /* Base address of CCR */ -+#define ISL12024_ALM0_BASE 0x00 /* Base address of ALARM0 */ -+ -+#define ISL12024_SR_RTCF 0x01 /* Clock failure */ -+#define ISL12024_SR_WEL 0x02 /* Write Enable Latch */ -+#define ISL12024_SR_RWEL 0x04 /* Register Write Enable */ -+#define ISL12024_SR_AL0 0x20 /* Alarm 0 match */ -+ -+#define ISL12024_DTR_DTR0 0x01 -+#define ISL12024_DTR_DTR1 0x02 -+#define ISL12024_DTR_DTR2 0x04 -+ -+#define ISL12024_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ -+ -+#define ISL12024_INT_AL0E 0x20 /* Alarm 0 enable */ -+ -+/* I2C ADDRESS */ -+#define ISL12024_I2C_ADDR 0xDE -+#define ISL12024_I2C_EEPROM_ADDR 0x57 -+ -+/* device id section */ -+#define ISL12024_REG_ID 0x20 -+ -+/* Register map */ -+/* rtc section */ -+#define ISL12024_REG_HR_MIL (1<<7) /* 24h/12h mode */ -+#define ISL12024_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ -+//#define ISL12024_REG_DT 0x33 /* Date */ -+//#define ISL12024_REG_MO 0x34 /* Month */ -+//#define ISL12024_REG_YR 0x35 /* Year */ -+//#define ISL12024_REG_DW 0x36 -+//#define ISL12024_REG_Y2K 0x37 -+#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 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 -+ -+#endif /*ISL12024_H_*/ diff --git a/recipes/linux/linux-2.6.27/boc01/005-090226-isl12024.patch b/recipes/linux/linux-2.6.27/boc01/005-090226-isl12024.patch new file mode 100644 index 0000000000..0c29cdc3de --- /dev/null +++ b/recipes/linux/linux-2.6.27/boc01/005-090226-isl12024.patch @@ -0,0 +1,693 @@ +Index: linux-2.6.27/drivers/i2c/chips/at24.c +=================================================================== +--- linux-2.6.27.orig/drivers/i2c/chips/at24.c ++++ linux-2.6.27/drivers/i2c/chips/at24.c +@@ -114,6 +114,8 @@ static const struct i2c_device_id at24_i + { "spd", AT24_DEVICE_MAGIC(2048 / 8, + AT24_FLAG_READONLY | AT24_FLAG_IRUGO) }, + { "24c04", AT24_DEVICE_MAGIC(4096 / 8, 0) }, ++ /* Intersil RTC/Unique-ID isl12024 eeprom handled here */ ++ { "isl12024",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.27/drivers/rtc/Kconfig +=================================================================== +--- linux-2.6.27.orig/drivers/rtc/Kconfig ++++ linux-2.6.27/drivers/rtc/Kconfig +@@ -124,6 +124,12 @@ comment "I2C RTC drivers" + + if I2C + ++config RTC_DRV_ISL12024 ++ tristate "Intersil 12024 RTC/ UniqueID" ++ help ++ If you say yes .... ++ This driver can also be built as a module. ++ + config RTC_DRV_DS1307 + tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00" + help +Index: linux-2.6.27/drivers/rtc/Makefile +=================================================================== +--- linux-2.6.27.orig/drivers/rtc/Makefile ++++ linux-2.6.27/drivers/rtc/Makefile +@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds17 + 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_M48T59) += rtc-m48t59.o +Index: linux-2.6.27/drivers/rtc/isl12024.h +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/rtc/isl12024.h +@@ -0,0 +1,100 @@ ++/* ++ * Intersil ISL12024 chip registers definitions ++ * ++ * ++ * Copyright (C) 2008, CenoSYS (www.cenosys.com). ++ * Guillaume Ligneul ++ * Guillaume.ligneul@gmail.com ++ * ++ * This software program is licensed subject to the GNU General Public License ++ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html ++ */ ++ ++#ifndef ISL12024_H_ ++#define ISL12024_H_ ++ ++#define ISL12024_REG_SR 0x3F /* status register */ ++#define ISL12024_REG_Y2K 0x37 ++#define ISL12024_REG_DW 0x36 ++#define ISL12024_REG_YR 0x35 ++#define ISL12024_REG_MO 0x34 ++#define ISL12024_REG_DT 0x33 ++#define ISL12024_REG_HR 0x32 ++#define ISL12024_REG_MN 0x31 ++#define ISL12024_REG_SC 0x30 ++#define ISL12024_REG_DTR 0x13 ++#define ISL12024_REG_ATR 0x12 ++#define ISL12024_REG_INT 0x11 ++#define ISL12024_REG_0 0x10 ++#define ISL12024_REG_Y2K1 0x0F ++#define ISL12024_REG_DWA1 0x0E ++#define ISL12024_REG_YRA1 0x0D ++#define ISL12024_REG_MOA1 0x0C ++#define ISL12024_REG_DTA1 0x0B ++#define ISL12024_REG_HRA1 0x0A ++#define ISL12024_REG_MNA1 0x09 ++#define ISL12024_REG_SCA1 0x08 ++#define ISL12024_REG_Y2K0 0x07 ++#define ISL12024_REG_DWA0 0x06 ++#define ISL12024_REG_YRA0 0x05 ++#define ISL12024_REG_MOA0 0x04 ++#define ISL12024_REG_DTA0 0x03 ++#define ISL12024_REG_HRA0 0x02 ++#define ISL12024_REG_MNA0 0x01 ++#define ISL12024_REG_SCA0 0x00 ++ ++#define ISL12024_CCR_BASE 0x30 /* Base address of CCR */ ++#define ISL12024_ALM0_BASE 0x00 /* Base address of ALARM0 */ ++ ++#define ISL12024_SR_RTCF 0x01 /* Clock failure */ ++#define ISL12024_SR_WEL 0x02 /* Write Enable Latch */ ++#define ISL12024_SR_RWEL 0x04 /* Register Write Enable */ ++#define ISL12024_SR_AL0 0x20 /* Alarm 0 match */ ++ ++#define ISL12024_DTR_DTR0 0x01 ++#define ISL12024_DTR_DTR1 0x02 ++#define ISL12024_DTR_DTR2 0x04 ++ ++#define ISL12024_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */ ++ ++#define ISL12024_INT_AL0E 0x20 /* Alarm 0 enable */ ++ ++/* I2C ADDRESS */ ++#define ISL12024_I2C_ADDR 0xDE ++#define ISL12024_I2C_EEPROM_ADDR 0x57 ++ ++/* device id section */ ++#define ISL12024_REG_ID 0x20 ++ ++/* Register map */ ++/* rtc section */ ++#define ISL12024_REG_HR_MIL (1<<7) /* 24h/12h mode */ ++#define ISL12024_REG_HR_PM (1<<5) /* PM/AM bit in 12h mode */ ++//#define ISL12024_REG_DT 0x33 /* Date */ ++//#define ISL12024_REG_MO 0x34 /* Month */ ++//#define ISL12024_REG_YR 0x35 /* Year */ ++//#define ISL12024_REG_DW 0x36 ++//#define ISL12024_REG_Y2K 0x37 ++#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 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 ++ ++#endif /*ISL12024_H_*/ +Index: linux-2.6.27/drivers/rtc/rtc-isl12024.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/rtc/rtc-isl12024.c +@@ -0,0 +1,541 @@ ++/* ++ * Intersil ISL12024 class driver ++ * ++ * ++ * Copyright (C) 2007, CenoSYS (www.cenosys.com). ++ * ++ * Guillaume Ligneul ++ * Sylvain Giroudon ++ * ++ * This software program is licensed subject to the GNU General Public License ++ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "isl12024.h" ++ ++ ++#define DBG 1 ++#undef DBG ++ ++#define DRV_NAME "isl12024" ++#define DRV_VERSION "0.2" ++ ++/* i2c configuration */ ++static const unsigned short normal_i2c[] = { ++ ISL12024_I2C_ADDR >>1, I2C_CLIENT_END ++}; ++I2C_CLIENT_INSMOD; ++ ++static int isl12024_get_status(struct i2c_client *client, unsigned char *sr); ++static int isl12024_fix_osc(struct i2c_client *client); ++ ++static int isl12024_attach_adapter(struct i2c_adapter *adapter); ++static int isl12024_detach_client(struct i2c_client *client); ++ ++ ++/* Bufer to store unique identifier in */ ++static u8 buf_id[ISL12024_RTC_SECTION_LEN] = { 0 }; ++ ++ ++// To debug (may be added in include/linux/i2c-id.h) ++#define I2C_DRIVERID_ISL12024 97 ++ ++ ++static struct i2c_driver isl12024_driver = { ++ .driver = { ++ .name = DRV_NAME, ++ }, ++ .id = I2C_DRIVERID_ISL12024, ++ .attach_adapter = &isl12024_attach_adapter, ++ .detach_client = &isl12024_detach_client, ++}; ++ ++ ++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\n"); ++ return -EIO; ++ } ++ return ret; ++} ++ ++EXPORT_SYMBOL(isl12024_i2c_read_regs); ++ ++ ++int ++isl12024_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], ++ unsigned len) ++{ ++ int ret; ++ u8 i2c_buf[10]; ++ ++ struct i2c_msg msgs[1] = { ++ { ++ .addr = client->addr, ++ .flags = 0, ++ .len = len+2, ++ .buf = i2c_buf, ++ }, ++ }; ++ ++ i2c_buf[0] = 0; ++ i2c_buf[1] = reg; ++ ++ ++ memcpy(&i2c_buf[2], &buf[0], len ); ++ ++ ret = i2c_transfer(client->adapter, msgs, 1); ++ if ( ret < 0 ) ++ printk(KERN_ERR DRV_NAME ": i2c_transfer failed (%d)\n", ret); ++ ++ return ret; ++} ++ ++EXPORT_SYMBOL(isl12024_i2c_set_regs); ++ ++ ++static int isl12024_i2c_validate_client(struct i2c_client *client) ++{ ++ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; ++ u8 zero_mask[ISL12024_RTC_SECTION_LEN] = { ++ 0x80, 0x80, 0x40, 0xc0, 0xe0, 0x00, 0xf8, 0xc6 ++ }; ++ ++ int i; ++ int ret; ++ ++ ret = isl12024_i2c_read_regs(client, ISL12024_REG_SC, regs, ISL12024_RTC_SECTION_LEN); ++ ++ if (ret < 0) ++ return ret; ++ ++ for (i = 0; i < ISL12024_RTC_SECTION_LEN; ++i) { ++ if (regs[i] & zero_mask[i]) /* check if bits are cleared */ ++ return -ENODEV; ++ ++ } ++ ++ return 0; ++} ++ ++ ++static int isl12024_read_time(struct i2c_client *client, ++ struct rtc_time *tm) ++{ ++ unsigned char sr; ++ int err; ++ u8 regs[ISL12024_RTC_SECTION_LEN] = { 0, }; ++ ++ //printk(KERN_INFO DRV_NAME "%s\n ",__FUNCTION__ ); ++ ++ if (isl12024_get_status(client, &sr) < 0) { ++ dev_err(&client->dev, "%s: reading SR failed\n", __func__); ++ return -EIO; ++ } ++ ++ err = isl12024_i2c_read_regs(client, ISL12024_REG_SC, regs, ISL12024_RTC_SECTION_LEN); ++ ++#ifdef DBG ++ int i; ++ for(i=0; idev, "%s: reading RTC section failed\n", ++ __func__); ++ return sr; ++ } ++ ++ tm->tm_sec = BCD2BIN(regs[0]); ++ tm->tm_min = BCD2BIN(regs[1]); ++ ++ { /* HR field has a more complex interpretation */ ++ const u8 _hr = regs[2]; ++ if (_hr & ISL12024_REG_HR_MIL) /* 24h format */ ++ tm->tm_hour = BCD2BIN(_hr & 0x3f); ++ else { // 12h format ++ tm->tm_hour = BCD2BIN(_hr & 0x1f); ++ if (_hr & 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_get_status(struct i2c_client *client, unsigned char *sr) ++{ ++ static unsigned char sr_addr[2] = { 0, ISL12024_REG_SR }; ++ ++ struct i2c_msg msgs[] = { ++ { client->addr, 0, 2, sr_addr }, /* setup read ptr */ ++ { client->addr, I2C_M_RD, 1, sr }, /* read status */ ++ }; ++ ++ /* read status register */ ++ if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) { ++ dev_err(&client->dev, "%s: read error\n", __func__); ++ return -EIO; ++ } ++ ++ return 0; ++} ++ ++ ++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]; ++ unsigned char rdata[10] = { 0, reg_base }; ++ ++ static const unsigned char wel[3] = { 0, ISL12024_REG_SR, ++ ISL12024_SR_WEL }; ++ ++ static const unsigned char rwel[3] = { 0, ISL12024_REG_SR, ++ ISL12024_SR_WEL | ISL12024_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_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_CCR_BASE) ++ for (i = 0; i <= 4; i++) ++ buf[i] |= 0x80; ++ ++ /* this sequence is required to unlock the chip */ ++ if ((xfer = i2c_master_send(client, wel, 3)) != 3) { ++ dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer); ++ return -EIO; ++ } ++ ++ if ((xfer = i2c_master_send(client, rwel, 3)) != 3) { ++ dev_err(&client->dev, "%s: rwel - %d\n", __func__, xfer); ++ return -EIO; ++ } ++ ++ ++ /* write register's data */ ++ if (datetoo) ++ nbytes = 8; ++ else ++ nbytes = 3; ++ for (i = 0; i < nbytes; i++) ++ rdata[2+i] = buf[i]; ++ ++ xfer = i2c_master_send(client, rdata, nbytes+2); ++ if (xfer != nbytes+2) { ++ dev_err(&client->dev, ++ "%s: result=%d addr=%02x, data=%02x\n", ++ __func__, ++ xfer, rdata[1], rdata[2]); ++ return -EIO; ++ } ++ ++ /* If we wrote to the nonvolatile region, wait 10msec for write cycle*/ ++ if (reg_base < ISL12024_CCR_BASE) { ++ 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: aloe 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 */ ++ if ((xfer = i2c_master_send(client, diswe, 3)) != 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_CCR_BASE, 0); ++ if ( err < 0 ) ++ printk(KERN_ERR DRV_NAME ": 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); ++ ++} ++ ++ ++static int isl12024_rtc_set_time(struct device *dev, struct rtc_time *tm) ++{ ++ return isl12024_set_datetime(to_i2c_client(dev), ++ tm, 1, ISL12024_CCR_BASE, 0); ++} ++ ++ ++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, ++}; ++ ++static int ++read_proc(char * page, char ** start, off_t off, int count, int * eof, void * data) ++{ ++ int len = 0; ++ int i; ++ ++ for (i = 0; i < ISL12024_RTC_SECTION_LEN; i++) ++ len += sprintf(page+len, "%02X", buf_id[i]); ++ len += sprintf(page+len, "\n"); ++ ++ len -= off; ++ if ( len < count ) { ++ *eof = 1; ++ if ( len <= 0 ) ++ return 0; ++ } else { ++ len = count; ++ } ++ ++ *start = page + off; ++ ++ return len; ++} ++ ++ ++static int ++isl12024_probe(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ int rc = 0; ++ int err = 0; ++ unsigned char sr; ++ struct i2c_client *new_client = NULL; ++ struct rtc_device *rtc = NULL; ++ struct proc_dir_entry *proc_root; ++ struct proc_dir_entry *proc_entry; ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { ++ rc = -ENODEV; ++ goto failout; ++ } ++ ++ new_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); ++ if (new_client == NULL) { ++ rc = -ENOMEM; ++ goto failout; ++ } ++ ++ new_client->addr = addr; ++ new_client->adapter = adapter; ++ new_client->driver = &isl12024_driver; ++ new_client->flags = 0; ++ strcpy(new_client->name, DRV_NAME); ++ ++ if (kind < 0) { ++ rc = isl12024_i2c_validate_client(new_client); ++ if (rc < 0) ++ goto failout; ++ } ++ ++ rc = i2c_attach_client(new_client); ++ if (rc < 0) ++ goto failout; ++ ++ rtc = rtc_device_register(isl12024_driver.driver.name, ++ &new_client->dev, ++ &isl12024_rtc_ops, THIS_MODULE); ++ ++ if (IS_ERR(rtc)) { ++ printk(KERN_ERR DRV_NAME ": Error during rtc registration\n"); ++ rc = PTR_ERR(rtc); ++ goto failout; ++ } ++ ++ i2c_set_clientdata(new_client, rtc); ++ ++ /* Check for power failures and eventualy enable the osc */ ++ if ((err = isl12024_get_status(new_client, &sr)) == 0) { ++ if (sr & ISL12024_SR_RTCF) { ++ printk(KERN_INFO DRV_NAME ": Power failure detected, please set the clock\n"); ++ udelay(50); ++ isl12024_fix_osc(new_client); ++ } ++ } ++ else { ++ printk(KERN_ERR DRV_NAME ": Couldn't read status\n"); ++ } ++ ++ proc_root = proc_mkdir(DRV_NAME, 0); ++ proc_entry = create_proc_entry("id", S_IFREG | S_IRUGO, proc_root); ++ if (proc_entry == NULL) ++ return -1; ++ ++ proc_entry->owner = THIS_MODULE; ++ proc_entry->read_proc = read_proc; ++ ++ /* Read unique id from eeprom */ ++ isl12024_i2c_read_regs(new_client, ISL12024_REG_ID, buf_id, sizeof(buf_id)); ++ ++ return 0; ++ ++ failout: ++ kfree(new_client); ++ return rc; ++} ++ ++ ++static int ++isl12024_attach_adapter (struct i2c_adapter *adapter) ++{ ++ return i2c_probe(adapter, &addr_data, isl12024_probe); ++} ++ ++ ++static int ++isl12024_detach_client(struct i2c_client *client) ++{ ++ int rc; ++ struct rtc_device *const rtc = i2c_get_clientdata(client); ++ ++ if (rtc) ++ rtc_device_unregister(rtc); ++ ++ rc = i2c_detach_client(client); ++ if (rc) ++ return rc; ++ ++ kfree(client); ++ ++ return 0; ++} ++ ++ ++/* 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.27/boc01/012-090219-capsense.patch b/recipes/linux/linux-2.6.27/boc01/012-090219-capsense.patch index fed8218427..c70339defa 100644 --- a/recipes/linux/linux-2.6.27/boc01/012-090219-capsense.patch +++ b/recipes/linux/linux-2.6.27/boc01/012-090219-capsense.patch @@ -29,7 +29,7 @@ Index: linux-2.6.27/drivers/input/misc/capsense-btns.c =================================================================== --- /dev/null +++ linux-2.6.27/drivers/input/misc/capsense-btns.c -@@ -0,0 +1,438 @@ +@@ -0,0 +1,456 @@ +/* + * CAPSENSE Interface driver + * @@ -68,7 +68,21 @@ Index: linux-2.6.27/drivers/input/misc/capsense-btns.c + +#define BUTTONS_POLL_INTERVAL 30 /* msec */ + ++#define CAP_INPUT_PORT(port) (0x00+(port)) ++#define CAP_STATUS_PORT(port) (0x02+(port)) +#define CAP_OUTPUT_PORT(port) (0x04+(port)) ++#define CAP_CS_ENABLE(port) (0x06+(port)) ++#define CAP_GPIO_ENABLE(port) (0x08+(port)) ++#define CAP_INVERSION_MASK(port) (0x0A+(port)) ++#define CAP_INT_MASK(port) (0x0C+(port)) ++#define CAP_STATUS_HOLD_MSK(port) (0x0E+(port)) ++#define CAP_DM_PULL_UP(port) (0x10+(4*(port))) ++#define CAP_DM_STRONG(port) (0x11+(4*(port))) ++#define CAP_DM_HIGHZ(port) (0x12+(4*(port))) ++#define CAP_OD_LOW(port) (0x13+(4*(port))) ++#define CAP_PWM_ENABLE(port) (0x18+(port)) ++#define CAP_PWM_MODE_DC 0x1A ++#define CAP_PWM_DELAY 0x1B +#define CAP_OP_SEL(port,bit) (0x1C+(25*(port))+(5*(bit))) +#define CAP_READ_STATUS(port) (0x88+(port)) + @@ -433,6 +447,8 @@ Index: linux-2.6.27/drivers/input/misc/capsense-btns.c +{ + struct capsense_ctx *capsense = i2c_get_clientdata(client); + ++ printk(KERN_INFO DRIVER_NAME ": suspend\n"); ++ + capsense_led_suspend(capsense); + + return 0; @@ -442,6 +458,8 @@ Index: linux-2.6.27/drivers/input/misc/capsense-btns.c +{ + struct capsense_ctx *capsense = i2c_get_clientdata(client); + ++ printk(KERN_INFO DRIVER_NAME ": resume\n"); ++ + capsense_led_resume(capsense); + + return 0; diff --git a/recipes/linux/linux-2.6.27/boc01/013-090209-lcd.patch b/recipes/linux/linux-2.6.27/boc01/013-090209-lcd.patch deleted file mode 100644 index c867e2cf3a..0000000000 --- a/recipes/linux/linux-2.6.27/boc01/013-090209-lcd.patch +++ /dev/null @@ -1,933 +0,0 @@ -Index: linux-2.6.27/drivers/video/Kconfig -=================================================================== ---- linux-2.6.27.orig/drivers/video/Kconfig -+++ linux-2.6.27/drivers/video/Kconfig -@@ -480,6 +480,28 @@ config FB_ARC - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. - -+config FB_NT7506 -+ tristate "Novatek 7506 LCD board support" -+ depends on FB -+ select FB_SYS_FILLRECT -+ select FB_SYS_COPYAREA -+ select FB_SYS_IMAGEBLIT -+ select FB_SYS_FOPS -+ select FB_BACKLIGHT -+ select LCD_CLASS_DEVICE -+ help -+ This is the frame buffer device driver for the Novatek 7506 Monochrome/Grayscale LCD board. -+ The board is based on the NT7506 LCD controller. -+ -+config FB_NT7506_GRAYSCALE -+ bool "Novatek 7506 Grayscale mode" -+ depends on FB_NT7506 -+ default y -+ help -+ This option switches the Monochrome/Grayscale mode for the Novatek 7506 LCD board. -+ Say Y to enable 4-levels Grayscale mode (2 bpp). -+ Say N to enable Monochrome mode (1 bpp). -+ - config FB_ATARI - bool "Atari native chipset support" - depends on (FB = y) && ATARI -Index: linux-2.6.27/drivers/video/Makefile -=================================================================== ---- linux-2.6.27.orig/drivers/video/Makefile -+++ linux-2.6.27/drivers/video/Makefile -@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_def - obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o - obj-$(CONFIG_FB_AM200EPD) += am200epd.o - obj-$(CONFIG_FB_ARC) += arcfb.o -+obj-$(CONFIG_FB_NT7506) += nt7506fb.o - obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o - obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o - obj-$(CONFIG_FB_PM2) += pm2fb.o -Index: linux-2.6.27/drivers/video/nt7506fb.c -=================================================================== ---- /dev/null -+++ linux-2.6.27/drivers/video/nt7506fb.c -@@ -0,0 +1,847 @@ -+/* -+ * linux/drivers/video/nt7506fb.c -- FB driver for NT7506 monochrome LCD board -+ * -+ * Copyright (C) 2008, CenoSYS (www.cenosys.com). -+ * -+ * Alexandre Coffignal -+ * Sylvain Giroudon -+ * Jeremy Laine -+ * -+ * This file is subject to the terms and conditions of the GNU General Public -+ * License. See the file COPYING in the main directory of this archive for -+ * more details. -+ * -+ * Layout is based on arcfb.c by Jaya Kumar -+ * -+ * This driver was written to be used with the Novatek NT7506 LCD board. -+ * -+ * Novatek uses a set of NT7506 chips that control individual 128x128 LCD -+ * matrices. The interface between the board and the host is TTL based GPIO. -+ * -+ * General notes: -+ * - User must set tuhold. It's in microseconds. According to the 108 spec, -+ * the hold time is supposed to be at least 1 microsecond. -+ * -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+ -+#define DRIVER_NAME "nt7506fb" -+ -+//NT7506 Hardware -+#define LCD_RST 0x08 -+#define LCD_RSTN 0x00 -+#define LCD_BCKLIGH 0x04 -+#define LCD_BCKLIGHN 0x00 -+#define LCD_RS 0x02 -+#define LCD_RSN 0x00 -+#define LCD_ERD 0x01 -+#define LCD_ERDN 0x00 -+ -+//Base address -+#define LCD_BASE 0xf0000000 -+#define LCD_SIZE 0x2 -+ -+//NT7506 Instructions -+#define NT_ICON 0xA2 -+#define NT_PAGE_ADDR 0xB0 -+#define NT_COL_MSB 0x10 -+#define NT_COL_LSB 0x00 -+#define NT_DISP 0xAE -+#define NT_START_LINE 0x40 -+#define NT_COM0 0x44 -+#define NT_DUTY 0x48 -+#define DUTY_1_128 0x80 -+#define NT_REV_DISP 0xA6 -+#define NT_POWER 0x28 -+#define VC 0x04 -+#define VR 0x02 -+#define VF 0x01 -+#define NT_DCDC 0x64 -+#define TIME6 0x03 -+#define NT_REG_RES 0x20 -+#define RES_7_2 0x07 -+#define NT_ELEC_VOL 0x81 -+#define NT_BIAS 0x50 -+#define BIAS_1_11 0x06 -+#define NT_ADC_NOR 0xA0 -+#define NT_ADC_REV 0xA1 -+#define NT_SHL_NOR 0xC0 -+#define NT_SHL_REV 0xC8 -+#define NT_SET_PWRSAVE 0xA8 -+#define NT_OSC 0xAB -+#define NT_RLS_PWRSAVE 0xE1 -+#define NT_RESET 0xE2 -+#define NT_DATA_DIR 0xe8 -+#define NT_FRC_PWM 0x90 -+#define PWM15 0x03 -+ -+#define ON 0x01 -+#define OFF 0x00 -+ -+#define NT_GRAY_SCALE 0x88 -+#define GRAY_WHITE_AB 0 -+#define GRAY_WHITE_CD 1 -+#define GRAY_LIGHT_AB 2 -+#define GRAY_LIGHT_CD 3 -+#define GRAY_DARK_AB 4 -+#define GRAY_DARK_CD 5 -+#define GRAY_BLACK_AB 6 -+#define GRAY_BLACK_CD 7 -+ -+// Geometric settings -+#define LCD_WIDTH 128 -+#define LCD_HEIGHT 128 -+#define LCD_NPAGES (LCD_HEIGHT/8) /* LCD pages of 8 vertical pixels */ -+ -+#define DEFAULT_CONTRAST 20 -+#define DEFAULT_FPS 10 -+ -+static struct resource *lcd_mem = NULL; -+static void * _lcd_io = NULL; -+static unsigned long tuhold; -+struct fb_info *info; -+static struct timer_list fb_timer; -+static char _fps = DEFAULT_FPS; -+static char _backlight = 1; -+ -+struct nt7506fb_par { -+ atomic_t ref_count; -+ struct fb_info *info; -+ spinlock_t lock; -+ struct lcd_device *lcd_dev; -+ int power; -+ int contrast; -+}; -+ -+static struct fb_fix_screeninfo nt7506fb_fix __initdata = { -+ .id = DRIVER_NAME, -+ .type = FB_TYPE_PACKED_PIXELS, -+#ifdef CONFIG_FB_NT7506_GRAYSCALE -+ .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, -+ .line_length = LCD_WIDTH / 4, -+#else -+ .visual = FB_VISUAL_MONO01, -+ .line_length = LCD_WIDTH / 8, -+#endif -+ .xpanstep = 1, -+ .ypanstep = 1, -+ .ywrapstep = 0, -+ .accel = FB_ACCEL_NONE, -+}; -+ -+static struct fb_var_screeninfo nt7506fb_var __initdata = { -+ .xres = LCD_WIDTH, -+ .yres = LCD_HEIGHT, -+ .xres_virtual = LCD_WIDTH, -+ .yres_virtual = LCD_HEIGHT, -+ .nonstd = 1, -+#ifdef CONFIG_FB_NT7506_GRAYSCALE -+ .bits_per_pixel = 2, -+ .grayscale = 1, -+ .red = { 0, 2, 0 }, -+ .green = { 0, 2, 0 }, -+ .blue = { 0, 2, 0 }, -+ .transp = { 0, 0, 0 }, -+#else -+ .bits_per_pixel = 1, -+#endif -+}; -+ -+ -+/* -+ * Low-level i/o primitives -+ */ -+ -+static void NT7506_init_lcd(char ael); -+ -+static void NT7506_writeb_ctl(unsigned char value) -+{ -+ unsigned short svalue; -+ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; -+ -+ svalue=value<<8 | LCD_RSN | LCD_RST | LCD_ERDN | bl; -+ iowrite16(svalue, _lcd_io); -+ udelay(tuhold); -+ //The data on DB0/7 are latched at the falling edge of the E_RD signal -+ svalue=value<<8 | LCD_RSN | LCD_RST | LCD_ERD | bl; -+ iowrite16(svalue, _lcd_io); -+ udelay(tuhold); -+} -+ -+static void NT7506_writeb_data(unsigned char value) -+{ -+ unsigned short svalue; -+ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; -+ -+ svalue=value<<8|LCD_RS |LCD_RST | LCD_ERD | bl ; -+ iowrite16(svalue, _lcd_io); -+ udelay(tuhold); -+ //The data on DB0/7 are latched at the falling edge of the E_RD signal -+ svalue=value<<8|LCD_RS |LCD_RST | LCD_ERDN | bl; -+ iowrite16(svalue, _lcd_io); -+ udelay(tuhold); -+} -+ -+static void NT7506_set_start_line(unsigned char y) -+{ -+ NT7506_writeb_ctl(NT_START_LINE); -+ NT7506_writeb_ctl(y); -+} -+ -+static void NT7506_set_yaddr(unsigned char y) -+{ -+ NT7506_writeb_ctl(NT_PAGE_ADDR+y); -+} -+ -+static void NT7506_set_xaddr(unsigned char x) -+{ -+ NT7506_writeb_ctl(NT_COL_MSB | (x >> 0x04)); //Send high nibble -+ NT7506_writeb_ctl(NT_COL_LSB | (x & 0x0F) ); //Send low nibble -+} -+ -+ -+/* -+ * LCD device management -+ */ -+ -+static int -+nt7506fb_lcd_get_contrast(struct lcd_device *lcd_dev) -+{ -+ struct nt7506fb_par *par = lcd_get_data(lcd_dev); -+ return par->contrast; -+} -+ -+static int -+nt7506fb_lcd_set_contrast(struct lcd_device *lcd_dev, int contrast) -+{ -+ struct nt7506fb_par *par = lcd_get_data(lcd_dev); -+ -+ par->contrast = contrast; -+ NT7506_writeb_ctl(NT_ELEC_VOL); NT7506_writeb_ctl(par->contrast); -+ -+ //printk(KERN_INFO DRIVER_NAME": contrast = %d\n", par->contrast); -+ return 0; -+} -+ -+static struct lcd_ops nt7506fb_lcd_ops = { -+ .get_contrast = nt7506fb_lcd_get_contrast, -+ .set_contrast = nt7506fb_lcd_set_contrast, -+}; -+ -+static void -+nt7506fb_lcd_init(struct nt7506fb_par *par) -+{ -+ struct fb_info *info = par->info; -+ struct lcd_device *lcd_dev; -+ -+ lcd_dev = lcd_device_register(DRIVER_NAME, info->dev, par, &nt7506fb_lcd_ops); -+ if (IS_ERR(lcd_dev)) { -+ par->lcd_dev = NULL; -+ printk(KERN_WARNING DRIVER_NAME ": LCD device registration failed\n"); -+ return; -+ } -+ -+ par->lcd_dev = lcd_dev; -+ lcd_dev->props.max_contrast = 255; -+ par->contrast = DEFAULT_CONTRAST; -+ printk(KERN_INFO DRIVER_NAME ": LCD contrast management initialized\n"); -+} -+ -+static void -+nt7506fb_lcd_exit(struct nt7506fb_par *par) -+{ -+ if ( par->lcd_dev ) { -+ lcd_device_unregister(par->lcd_dev); -+ par->lcd_dev = NULL; -+ } -+} -+ -+ -+/* -+ * Backlight device management -+ */ -+static void nt7506fb_start_timer(void); -+ -+static int -+nt7506fb_bl_update_status(struct backlight_device *bd) -+{ -+ struct nt7506fb_par *par = bl_get_data(bd); -+ int power_on = (bd->props.power != FB_BLANK_POWERDOWN); -+ -+ _backlight = bd->props.brightness & power_on; -+ -+ printk(KERN_INFO DRIVER_NAME ": backlight=%d power_on=%d\n", _backlight, power_on); -+ -+ if ( bd->props.power != par->power ) { -+ par->power = bd->props.power; -+ -+ if ( power_on ) { -+ /* Power LCD device on */ -+ NT7506_writeb_ctl(NT_SET_PWRSAVE|OFF); -+ NT7506_writeb_ctl(NT_RLS_PWRSAVE); -+ -+ /* Restart refresh timer */ -+ if ( ! timer_pending(&fb_timer) ) -+ nt7506fb_start_timer(); -+ } -+ else { -+ /* Throttle refresh timer */ -+ del_timer(&fb_timer); -+ -+ /* Put LCD device in power save mode */ -+ NT7506_writeb_ctl(NT_SET_PWRSAVE|ON); -+ NT7506_writeb_ctl(NT_RLS_PWRSAVE); -+ } -+ } -+ -+ //printk(KERN_INFO DRIVER_NAME": backlight = %d\n", _backlight); -+ return 0; -+} -+ -+static int -+nt7506fb_bl_get_brightness(struct backlight_device *bd) -+{ -+ return bd->props.brightness; -+} -+ -+static struct backlight_ops nt7506fb_bl_ops = { -+ .get_brightness = nt7506fb_bl_get_brightness, -+ .update_status = nt7506fb_bl_update_status, -+}; -+ -+ -+static void -+nt7506fb_bl_init(struct nt7506fb_par *par) -+{ -+ struct fb_info *info = par->info; -+ struct backlight_device *bd; -+ -+ bd = backlight_device_register(DRIVER_NAME, info->dev, par, &nt7506fb_bl_ops); -+ if (IS_ERR(bd)) { -+ info->bl_dev = NULL; -+ printk(KERN_WARNING DRIVER_NAME ": Backlight device registration failed\n"); -+ return; -+ } -+ -+ info->bl_dev = bd; -+ bd->props.max_brightness = 1; -+ bd->props.power = FB_BLANK_UNBLANK; -+ bd->props.brightness = 1; -+ par->power = bd->props.power; -+ -+ nt7506fb_bl_update_status(bd); -+ -+ printk(KERN_INFO DRIVER_NAME ": Backlight control initialized\n"); -+} -+ -+static void -+nt7506fb_bl_exit(struct fb_info *info) -+{ -+ if ( info->bl_dev ) { -+ backlight_device_unregister(info->bl_dev); -+ info->bl_dev = NULL; -+ } -+} -+ -+ -+/* -+ * Main frame buffer operations -+ */ -+ -+static int nt7506fb_open(struct fb_info *info, int user) -+{ -+ struct nt7506fb_par *par = info->par; -+ atomic_inc(&par->ref_count); -+ return 0; -+} -+ -+static int nt7506fb_release(struct fb_info *info, int user) -+{ -+ struct nt7506fb_par *par = info->par; -+ int count = atomic_read(&par->ref_count); -+ if (!count) -+ return -EINVAL; -+ atomic_dec(&par->ref_count); -+ return 0; -+} -+ -+static int nt7506fb_pan_display(struct fb_var_screeninfo *var, -+ struct fb_info *info) -+{ -+ if ( (var->vmode & FB_VMODE_YWRAP) && -+ (var->yoffset < LCD_HEIGHT) && -+ (info->var.yres <= LCD_HEIGHT) ) { -+ NT7506_set_start_line(var->yoffset); -+ info->var.yoffset = var->yoffset; -+ return 0; -+ } -+ -+ return -EINVAL; -+} -+ -+static void nt7506fb_lcd_update(struct nt7506fb_par *par) -+{ -+ unsigned char *src = (unsigned char __force *) par->info->screen_base; -+ int line_length = par->info->fix.line_length; -+ int page, x, bit; -+ unsigned char plane1, plane2; -+ unsigned char *ptr; -+ unsigned char xshift; -+ -+ if ( info->var.bits_per_pixel == 1 ) { -+ -+ for (page = 0; page < LCD_NPAGES; page++) { -+ NT7506_set_yaddr(page); -+ NT7506_set_xaddr(0); -+ for (x = 0; x < LCD_WIDTH; x++) { -+ xshift = 7 - (x % 8); -+ plane1 = plane2 = 0; -+ ptr = src + (page * 8 * line_length + x / 8); -+ for (bit = 0; bit < 8; ptr += line_length, bit++) { -+ plane1 |= (((*ptr) >> xshift) & 1) << bit; -+ } -+ NT7506_writeb_data(plane1); -+ NT7506_writeb_data(plane2); -+ } -+ NT7506_writeb_data((unsigned char)0); -+ } -+ -+ } else { -+ -+ for (page = 0; page < LCD_NPAGES; page++) { -+ NT7506_set_yaddr(page); -+ NT7506_set_xaddr(0); -+ for (x = 0; x < LCD_WIDTH; x++) { -+ xshift = (3 - (x % 4)) << 1; -+ plane1 = plane2 = 0; -+ ptr = src + (page * 8 * line_length + x / 4); -+ for (bit = 0; bit < 8; ptr += line_length, bit++) { -+ plane1 |= (((*ptr) >> (xshift + 1)) & 1) << bit; -+ plane2 |= (((*ptr) >> xshift) & 1) << bit; -+ } -+ NT7506_writeb_data(plane1); -+ NT7506_writeb_data(plane2); -+ } -+ NT7506_writeb_data((unsigned char)0); -+ } -+ -+ } -+} -+ -+static void nt7506fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ sys_fillrect(info, rect); -+} -+ -+ -+ -+static void nt7506fb_copyarea(struct fb_info *info, -+ const struct fb_copyarea *area) -+{ -+ sys_copyarea(info, area); -+} -+ -+ -+static void nt7506fb_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ sys_imageblit(info, image); -+} -+ -+ -+/* -+ * this is the access path from userspace. they can seek and write to -+ * the fb. it's inefficient for them to do anything less than 128*8 -+ * writes since we update the lcd in each write() anyway. -+ */ -+static ssize_t nt7506fb_write(struct fb_info *info, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ unsigned long p = *ppos; -+ unsigned int fbmemlength; -+ int err = 0; -+ -+ fbmemlength = (info->var.xres * info->var.yres)/8; -+ -+ if ( p > fbmemlength ) { -+ return -EFBIG; -+ } -+ -+ if ( (count + p) > fbmemlength ) { -+ count = fbmemlength - p; -+ err = -ENOSPC; -+ } -+ -+ if ( count ) { -+ char *base_addr = (char __force *) info->screen_base; -+ if ( copy_from_user(base_addr + p, buf, count) ) -+ err = -EFAULT; -+ } -+ -+ if ( !err ) -+ *ppos += count; -+ -+ return err ? err : count; -+} -+ -+ -+static int nt7506fb_mmap(struct fb_info *info, struct vm_area_struct *vma) -+{ -+ unsigned long off; -+ unsigned long start; -+ u32 len; -+ -+ if (vma->vm_end - vma->vm_start == 0) -+ return 0; -+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) -+ return -EINVAL; -+ off = vma->vm_pgoff << PAGE_SHIFT; -+ start = info->fix.smem_start; -+ len = info->fix.smem_len; -+ if (off >= len) -+ { -+ return -EINVAL; -+ -+ } -+ if ((vma->vm_end - vma->vm_start + off) > len) -+ { -+ return -EINVAL; -+ } -+ off += start; -+ vma->vm_pgoff = off >> PAGE_SHIFT; -+ if (remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)info->fix.smem_start) >> PAGE_SHIFT, -+ info->fix.smem_len, vma->vm_page_prot)) -+ -+ { -+ return -EAGAIN; -+ } -+ return 0; -+ -+} -+ -+ -+static int nt7506fb_ioctl(struct fb_info *info, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned char frame_rate; -+ -+ switch ( cmd ) { -+ case FBIO_FRAMERATE: -+ if (get_user(frame_rate, (unsigned char *)arg)) -+ return -EFAULT; -+ printk(KERN_INFO "fb%d: framerate=%d Hz\n", info->node, frame_rate); -+ _fps = frame_rate; -+ return 0; -+ -+ default: -+ return -EINVAL; -+ } -+} -+ -+ -+static struct fb_ops nt7506fb_ops = { -+ .owner = THIS_MODULE, -+ .fb_open = nt7506fb_open, -+ .fb_read = fb_sys_read, -+ .fb_write = nt7506fb_write, -+ .fb_release = nt7506fb_release, -+ .fb_pan_display = nt7506fb_pan_display, -+ .fb_fillrect = nt7506fb_fillrect, -+ .fb_copyarea = nt7506fb_copyarea, -+ .fb_imageblit = nt7506fb_imageblit, -+ .fb_ioctl = nt7506fb_ioctl, -+ .fb_mmap = nt7506fb_mmap, -+}; -+ -+ -+static void -+nt7506fb_start_timer(void) -+{ -+ fb_timer.expires = jiffies + (HZ/_fps); -+ add_timer(&fb_timer); -+} -+ -+static void -+nt7506fb_refresh(unsigned long data) -+{ -+ nt7506fb_lcd_update(info->par); -+ nt7506fb_start_timer(); -+} -+ -+static int __init -+nt7506fb_probe(struct platform_device *dev) -+{ -+ int retval = -ENOMEM; -+ struct nt7506fb_par *par; -+ static unsigned char *videomemory; -+ static int videomemorysize; -+ int i; -+ -+ NT7506_init_lcd(DEFAULT_CONTRAST); -+ -+ videomemorysize = LCD_WIDTH * LCD_HEIGHT / 4; -+ -+ if (!(videomemory = kmalloc(videomemorysize,GFP_ATOMIC))) -+ goto failout; -+ memset(videomemory, 0, videomemorysize); -+ -+ info = framebuffer_alloc(sizeof(struct nt7506fb_par), &dev->dev); -+ -+ if (!info) -+ goto out_alloc; -+ info->screen_base = (char __iomem *)videomemory; -+ info->fbops = &nt7506fb_ops; -+ -+ info->var = nt7506fb_var; -+ info->fix = nt7506fb_fix; -+ info->fix.smem_start = (unsigned long)videomemory; -+ info->fix.smem_len = videomemorysize; -+ -+ par = info->par; -+ par->info = info; -+ -+ info->flags = FBINFO_FLAG_DEFAULT; -+ spin_lock_init(&par->lock); -+ platform_set_drvdata(dev, info); -+ -+#ifdef CONFIG_FB_NT7506_GRAYSCALE -+ /* Allocate cmap */ -+ retval = fb_alloc_cmap(&info->cmap, 4, 0); -+ if (retval < 0) { -+ printk(KERN_ERR "fb%d: Failed to allocate colormap\n", info->node); -+ goto out_register; -+ } -+ -+ /* Set cmap */ -+ for (i = 0; i < 4; i++) -+ info->cmap.red[i] = (((4*i)+1)*(0xFFFF))/16; -+ memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*4); -+ memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*4); -+#endif -+ -+ /* Register framebuffer */ -+ retval = register_framebuffer(info); -+ if (retval < 0) -+ goto out_register; -+ -+ setup_timer(&fb_timer, nt7506fb_refresh, (unsigned long) par); -+ -+ printk(KERN_INFO -+ "fb%d: nt7506 frame buffer device, using %dK of video memory\n", -+ info->node, videomemorysize >> 10); -+ -+ /* Initialize backlight and contrast control (do not abort driver if it fails) */ -+ nt7506fb_bl_init(par); -+ nt7506fb_lcd_init(par); -+ -+ nt7506fb_start_timer(); -+ -+ return 0; -+ -+out_register: -+ framebuffer_release(info); -+out_alloc: -+ vfree(videomemory); -+failout: -+ return retval; -+} -+ -+static int nt7506fb_remove(struct platform_device *dev) -+{ -+ struct fb_info *info = platform_get_drvdata(dev); -+ -+ del_timer(&fb_timer); -+ -+ if (info) { -+ nt7506fb_lcd_exit(info->par); -+ nt7506fb_bl_exit(info); -+ unregister_framebuffer(info); -+ vfree((void __force *)info->screen_base); -+ framebuffer_release(info); -+ } -+ return 0; -+} -+ -+#ifdef CONFIG_PM -+static int nt7506fb_suspend(struct platform_device *dev, pm_message_t state) -+{ -+ struct fb_info *info = platform_get_drvdata(dev); -+ -+ printk(KERN_INFO DRIVER_NAME ": Switching to Power Save mode\n"); -+ -+ info->bl_dev->props.power = FB_BLANK_POWERDOWN; -+ nt7506fb_bl_update_status(info->bl_dev); -+ -+ return 0; -+} -+ -+static int nt7506fb_resume(struct platform_device *dev) -+{ -+ struct fb_info *info = platform_get_drvdata(dev); -+ -+ info->bl_dev->props.power = FB_BLANK_UNBLANK; -+ nt7506fb_bl_update_status(info->bl_dev); -+ -+ return 0; -+} -+#else -+#define nt7506fb_suspend NULL -+#define nt7506fb_resume NULL -+#endif -+ -+ -+static struct platform_driver nt7506fb_driver = { -+ .probe = nt7506fb_probe, -+ .remove = nt7506fb_remove, -+ .suspend = nt7506fb_suspend, -+ .resume = nt7506fb_resume, -+ .driver = { -+ .name = DRIVER_NAME, -+ }, -+}; -+ -+static struct platform_device *nt7506fb_device; -+ -+static int __init nt7506fb_init(void) -+{ -+ int ret; -+ -+ -+ if (!(lcd_mem = request_mem_region(LCD_BASE, LCD_SIZE, "mpc8313-lcd"))) -+ return -ENOMEM; -+ -+ if (!(_lcd_io = ioremap(LCD_BASE, LCD_SIZE))) -+ { -+ release_mem_region(LCD_BASE, LCD_SIZE); -+ lcd_mem = NULL; -+ return -ENOMEM; -+ } -+ ret = platform_driver_register(&nt7506fb_driver); -+ -+ if (!ret) { -+ nt7506fb_device = platform_device_alloc(DRIVER_NAME, 0); -+ if (nt7506fb_device) -+ { -+ ret = platform_device_add(nt7506fb_device); -+ } -+ else -+ { -+ ret = -ENOMEM; -+ } -+ if (ret) -+ { -+ platform_device_put(nt7506fb_device); -+ platform_driver_unregister(&nt7506fb_driver); -+ } -+ -+ } -+ -+ -+ return ret; -+ -+} -+ -+ -+static void NT7506_init_lcd(char ael) -+{ -+ /* this resets the lcd*/ -+ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; -+ -+ iowrite16(LCD_RSTN | LCD_ERD | bl, _lcd_io); -+ udelay(100); -+ iowrite16(LCD_RST| LCD_ERD | bl, _lcd_io); -+ udelay(200); -+ /* Soft reset*/ -+ NT7506_writeb_ctl(NT_RESET); -+ /* Disable ICON display*/ -+ NT7506_writeb_ctl(NT_ICON|OFF); -+ /* Sets the duty ratio 1/128*/ -+ NT7506_writeb_ctl(NT_DUTY); NT7506_writeb_ctl(DUTY_1_128); -+ /* Sets reverse direction between RAM column address and segment driver*/ -+ NT7506_writeb_ctl(NT_ADC_REV); -+ NT7506_writeb_ctl(NT_SHL_NOR); -+ /* Enales the built in Oscillator circuit.*/ -+ NT7506_writeb_ctl(NT_OSC); -+ /* Set Initial row to 0*/ -+ NT7506_writeb_ctl(NT_COM0); NT7506_writeb_ctl(0); -+ /* Sets DC-DC*/ -+ NT7506_writeb_ctl(NT_DCDC|TIME6); -+ /* Selects resistance ratio of the internal resistor*/ -+ NT7506_writeb_ctl(NT_REG_RES|RES_7_2); -+ /* set Reference Voltage mode*/ -+ NT7506_writeb_ctl(NT_ELEC_VOL); NT7506_writeb_ctl(ael); -+ /* Selects LCD bias ratio*/ -+ NT7506_writeb_ctl(NT_BIAS|BIAS_1_11); -+ -+ NT7506_writeb_ctl(NT_DATA_DIR); NT7506_writeb_ctl(0); -+ NT7506_writeb_ctl(NT_FRC_PWM|PWM15); -+ -+#ifdef CONFIG_FB_NT7506_GRAYSCALE -+ /* Feed grayscale palette */ -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_WHITE_AB); -+ NT7506_writeb_ctl(0x00); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_WHITE_CD); -+ NT7506_writeb_ctl(0x00); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_LIGHT_AB); -+ NT7506_writeb_ctl(0x55); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_LIGHT_CD); -+ NT7506_writeb_ctl(0x55); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_DARK_AB); -+ NT7506_writeb_ctl(0xAA); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_DARK_CD); -+ NT7506_writeb_ctl(0xAA); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_BLACK_AB); -+ NT7506_writeb_ctl(0xFF); -+ NT7506_writeb_ctl(NT_GRAY_SCALE | GRAY_BLACK_CD); -+ NT7506_writeb_ctl(0xFF); -+#endif -+ -+ /* Select power circuit functions */ -+ NT7506_writeb_ctl(NT_POWER|VC); -+ udelay(5000); -+ NT7506_writeb_ctl(NT_POWER|VC|VR); -+ udelay(5000); -+ NT7506_writeb_ctl(NT_POWER|VC|VR|VF); -+ udelay(5000); -+ /* Reverses the display status on LCD panel */ -+ NT7506_writeb_ctl(NT_REV_DISP|OFF); -+ /* Forces the whole LCD points to be turned on regardless of the contents of the display data RAM*/ -+ NT7506_writeb_ctl(NT_DISP|ON); -+ /* Set Initial Start Line Address */ -+ NT7506_writeb_ctl(NT_START_LINE); NT7506_writeb_ctl(0x00); -+} -+ -+static void __exit nt7506fb_exit(void) -+{ -+ if (lcd_mem) -+ release_mem_region(LCD_BASE, LCD_SIZE); -+ lcd_mem = NULL; -+ platform_device_unregister(nt7506fb_device); -+ platform_driver_unregister(&nt7506fb_driver); -+} -+ -+module_param(tuhold, ulong, 0); -+MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to NT7506 board"); -+ -+module_init(nt7506fb_init); -+module_exit(nt7506fb_exit); -+ -+MODULE_DESCRIPTION("fbdev driver for Novatek NT7506 monochrome LCD board"); -+MODULE_AUTHOR("Alexandre Coffignal"); -+MODULE_LICENSE("GPL"); -+ -Index: linux-2.6.27/include/linux/nt7506fb.h -=================================================================== ---- /dev/null -+++ linux-2.6.27/include/linux/nt7506fb.h -@@ -0,0 +1,31 @@ -+ -+/* -+ * (C) Copyright 2008 -+ * Alexandre Coffignal, CénoSYS, alexandre.coffignal@cenosys.com -+ * -+ * See file CREDITS for list of people who contributed to this -+ * project. -+ * -+ * 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. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, -+ * MA 02111-1307 USA -+ * -+ */ -+ -+#ifndef __LINUX_NT7506FB_H__ -+#define __LINUX_NT7506FB_H__ -+ -+#define FBIO_FRAMERATE _IOR('f', 1, char) -+ -+#endif diff --git a/recipes/linux/linux-2.6.27/boc01/013-090306-lcd.patch b/recipes/linux/linux-2.6.27/boc01/013-090306-lcd.patch new file mode 100644 index 0000000000..cc53fe45f7 --- /dev/null +++ b/recipes/linux/linux-2.6.27/boc01/013-090306-lcd.patch @@ -0,0 +1,1090 @@ +Index: linux-2.6.27/drivers/video/Kconfig +=================================================================== +--- linux-2.6.27.orig/drivers/video/Kconfig ++++ linux-2.6.27/drivers/video/Kconfig +@@ -480,6 +480,28 @@ config FB_ARC + this driver, say Y or M; otherwise say N. You must specify the + GPIO IO address to be used for setting control and data. + ++config FB_NT7506 ++ tristate "Novatek 7506 LCD board support" ++ depends on FB ++ select FB_SYS_FILLRECT ++ select FB_SYS_COPYAREA ++ select FB_SYS_IMAGEBLIT ++ select FB_SYS_FOPS ++ select FB_BACKLIGHT ++ select LCD_CLASS_DEVICE ++ help ++ This is the frame buffer device driver for the Novatek 7506 Monochrome/Grayscale LCD board. ++ The board is based on the NT7506 LCD controller. ++ ++config FB_NT7506_GRAYSCALE ++ bool "Novatek 7506 Grayscale mode" ++ depends on FB_NT7506 ++ default y ++ help ++ This option switches the Monochrome/Grayscale mode for the Novatek 7506 LCD board. ++ Say Y to enable 4-levels Grayscale mode (2 bpp). ++ Say N to enable Monochrome mode (1 bpp). ++ + config FB_ATARI + bool "Atari native chipset support" + depends on (FB = y) && ATARI +Index: linux-2.6.27/drivers/video/Makefile +=================================================================== +--- linux-2.6.27.orig/drivers/video/Makefile ++++ linux-2.6.27/drivers/video/Makefile +@@ -31,6 +31,7 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_def + obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o + obj-$(CONFIG_FB_AM200EPD) += am200epd.o + obj-$(CONFIG_FB_ARC) += arcfb.o ++obj-$(CONFIG_FB_NT7506) += nt7506fb.o + obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o + obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o + obj-$(CONFIG_FB_PM2) += pm2fb.o +Index: linux-2.6.27/drivers/video/nt7506fb.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/video/nt7506fb.c +@@ -0,0 +1,880 @@ ++/* ++ * linux/drivers/video/nt7506fb.c -- FB driver for NT7506 monochrome LCD board ++ * ++ * Copyright (C) 2008, CenoSYS (www.cenosys.com). ++ * ++ * Alexandre Coffignal ++ * Sylvain Giroudon ++ * Jeremy Laine ++ * ++ * This file is subject to the terms and conditions of the GNU General Public ++ * License. See the file COPYING in the main directory of this archive for ++ * more details. ++ * ++ * Layout is based on arcfb.c by Jaya Kumar ++ * ++ * This driver was written to be used with the Novatek NT7506 LCD board. ++ * ++ * Novatek uses a set of NT7506 chips that control individual 128x128 LCD ++ * matrices. The interface between the board and the host is TTL based GPIO. ++ * ++ * General notes: ++ * - User must set tuhold. It's in microseconds. According to the 108 spec, ++ * the hold time is supposed to be at least 1 microsecond. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#define DRIVER_NAME "nt7506fb" ++ ++//NT7506 Hardware ++#define LCD_RST 0x08 ++#define LCD_RSTN 0x00 ++#define LCD_BCKLIGH 0x04 ++#define LCD_BCKLIGHN 0x00 ++#define LCD_RS 0x02 ++#define LCD_RSN 0x00 ++#define LCD_ERD 0x01 ++#define LCD_ERDN 0x00 ++ ++//Base address ++#define LCD_BASE 0xf0000000 ++#define LCD_SIZE 0x2 ++ ++//NT7506 Instructions ++#define NT_ICON 0xA2 ++#define NT_PAGE_ADDR 0xB0 ++#define NT_COL_MSB 0x10 ++#define NT_COL_LSB 0x00 ++#define NT_DISP 0xAE ++#define NT_START_LINE 0x40 ++#define NT_COM0 0x44 ++#define NT_DUTY 0x48 ++#define DUTY_1_128 0x80 ++#define NT_REV_DISP 0xA6 ++#define NT_POWER 0x28 ++#define VC 0x04 ++#define VR 0x02 ++#define VF 0x01 ++#define NT_DCDC 0x64 ++#define TIME6 0x03 ++#define NT_REG_RES 0x20 ++#define RES_7_2 0x07 ++#define NT_ELEC_VOL 0x81 ++#define NT_BIAS 0x50 ++#define BIAS_1_11 0x06 ++#define NT_ADC_NOR 0xA0 ++#define NT_ADC_REV 0xA1 ++#define NT_SHL_NOR 0xC0 ++#define NT_SHL_REV 0xC8 ++#define NT_SET_PWRSAVE 0xA8 ++#define NT_OSC 0xAB ++#define NT_RLS_PWRSAVE 0xE1 ++#define NT_RESET 0xE2 ++#define NT_DATA_DIR 0xe8 ++#define NT_FRC_PWM 0x90 ++#define PWM15 0x03 ++ ++#define ON 0x01 ++#define OFF 0x00 ++ ++#define NT_GRAY_SCALE 0x88 ++#define GRAY_WHITE_AB 0 ++#define GRAY_WHITE_CD 1 ++#define GRAY_LIGHT_AB 2 ++#define GRAY_LIGHT_CD 3 ++#define GRAY_DARK_AB 4 ++#define GRAY_DARK_CD 5 ++#define GRAY_BLACK_AB 6 ++#define GRAY_BLACK_CD 7 ++ ++#define GRAY_INDEX_WHITE GRAY_WHITE_AB ++#define GRAY_INDEX_LIGHT GRAY_LIGHT_AB ++#define GRAY_INDEX_DARK GRAY_DARK_AB ++#define GRAY_INDEX_BLACK GRAY_BLACK_AB ++ ++#define GRAY_LEVEL_WHITE 0 ++#define GRAY_LEVEL_LIGHT 5 ++#define GRAY_LEVEL_DARK 10 ++#define GRAY_LEVEL_BLACK 15 ++#define GRAY_LEVEL_MAX 15 ++ ++#define GRAY_VALUE(level) (((level)<<4)+(level)) ++ ++// Geometric settings ++#define LCD_WIDTH 128 ++#define LCD_HEIGHT 128 ++#define LCD_NPAGES (LCD_HEIGHT/8) /* LCD pages of 8 vertical pixels */ ++ ++#define DEFAULT_CONTRAST 20 ++#define DEFAULT_FPS 10 ++ ++static struct resource *lcd_mem = NULL; ++static void * _lcd_io = NULL; ++static unsigned long tuhold; ++struct fb_info *info; ++static struct timer_list fb_timer; ++static char _fps = DEFAULT_FPS; ++static char _backlight = 1; ++ ++struct nt7506fb_par { ++ atomic_t ref_count; ++ struct fb_info *info; ++ spinlock_t lock; ++ struct lcd_device *lcd_dev; ++ int power; ++ int contrast; ++}; ++ ++static struct fb_fix_screeninfo nt7506fb_fix __initdata = { ++ .id = DRIVER_NAME, ++ .type = FB_TYPE_PACKED_PIXELS, ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ .visual = FB_VISUAL_STATIC_PSEUDOCOLOR, ++ .line_length = LCD_WIDTH / 4, ++#else ++ .visual = FB_VISUAL_MONO01, ++ .line_length = LCD_WIDTH / 8, ++#endif ++ .xpanstep = 1, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static struct fb_var_screeninfo nt7506fb_var __initdata = { ++ .xres = LCD_WIDTH, ++ .yres = LCD_HEIGHT, ++ .xres_virtual = LCD_WIDTH, ++ .yres_virtual = LCD_HEIGHT, ++ .nonstd = 1, ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ .bits_per_pixel = 2, ++ .grayscale = 1, ++ .red = { 0, 2, 0 }, ++ .green = { 0, 2, 0 }, ++ .blue = { 0, 2, 0 }, ++ .transp = { 0, 0, 0 }, ++#else ++ .bits_per_pixel = 1, ++#endif ++}; ++ ++ ++/* ++ * Low-level i/o primitives ++ */ ++ ++static void NT7506_init_lcd(char ael); ++ ++static void NT7506_writeb_ctl(unsigned char value) ++{ ++ unsigned short svalue; ++ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; ++ ++ svalue=value<<8 | LCD_RSN | LCD_RST | LCD_ERDN | bl; ++ iowrite16(svalue, _lcd_io); ++ udelay(tuhold); ++ //The data on DB0/7 are latched at the falling edge of the E_RD signal ++ svalue=value<<8 | LCD_RSN | LCD_RST | LCD_ERD | bl; ++ iowrite16(svalue, _lcd_io); ++ udelay(tuhold); ++} ++ ++static void NT7506_writeb_data(unsigned char value) ++{ ++ unsigned short svalue; ++ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; ++ ++ svalue=value<<8|LCD_RS |LCD_RST | LCD_ERD | bl ; ++ iowrite16(svalue, _lcd_io); ++ udelay(tuhold); ++ //The data on DB0/7 are latched at the falling edge of the E_RD signal ++ svalue=value<<8|LCD_RS |LCD_RST | LCD_ERDN | bl; ++ iowrite16(svalue, _lcd_io); ++ udelay(tuhold); ++} ++ ++static void NT7506_set_start_line(unsigned char y) ++{ ++ NT7506_writeb_ctl(NT_START_LINE); ++ NT7506_writeb_ctl(y); ++} ++ ++static void NT7506_set_yaddr(unsigned char y) ++{ ++ NT7506_writeb_ctl(NT_PAGE_ADDR+y); ++} ++ ++static void NT7506_set_xaddr(unsigned char x) ++{ ++ NT7506_writeb_ctl(NT_COL_MSB | (x >> 0x04)); //Send high nibble ++ NT7506_writeb_ctl(NT_COL_LSB | (x & 0x0F) ); //Send low nibble ++} ++ ++ ++/* ++ * LCD device management ++ */ ++ ++static int ++nt7506fb_lcd_get_contrast(struct lcd_device *lcd_dev) ++{ ++ struct nt7506fb_par *par = lcd_get_data(lcd_dev); ++ return par->contrast; ++} ++ ++static int ++nt7506fb_lcd_set_contrast(struct lcd_device *lcd_dev, int contrast) ++{ ++ struct nt7506fb_par *par = lcd_get_data(lcd_dev); ++ ++ par->contrast = contrast; ++ NT7506_writeb_ctl(NT_ELEC_VOL); NT7506_writeb_ctl(par->contrast); ++ ++ //printk(KERN_INFO DRIVER_NAME": contrast = %d\n", par->contrast); ++ return 0; ++} ++ ++static struct lcd_ops nt7506fb_lcd_ops = { ++ .get_contrast = nt7506fb_lcd_get_contrast, ++ .set_contrast = nt7506fb_lcd_set_contrast, ++}; ++ ++static void ++nt7506fb_lcd_init(struct nt7506fb_par *par) ++{ ++ struct fb_info *info = par->info; ++ struct lcd_device *lcd_dev; ++ ++ lcd_dev = lcd_device_register(DRIVER_NAME, info->dev, par, &nt7506fb_lcd_ops); ++ if (IS_ERR(lcd_dev)) { ++ par->lcd_dev = NULL; ++ printk(KERN_WARNING DRIVER_NAME ": LCD device registration failed\n"); ++ return; ++ } ++ ++ par->lcd_dev = lcd_dev; ++ lcd_dev->props.max_contrast = 255; ++ par->contrast = DEFAULT_CONTRAST; ++ printk(KERN_INFO DRIVER_NAME ": LCD contrast management initialized\n"); ++} ++ ++static void ++nt7506fb_lcd_exit(struct nt7506fb_par *par) ++{ ++ if ( par->lcd_dev ) { ++ lcd_device_unregister(par->lcd_dev); ++ par->lcd_dev = NULL; ++ } ++} ++ ++ ++/* ++ * Backlight device management ++ */ ++static void nt7506fb_start_timer(void); ++ ++static int ++nt7506fb_bl_update_status(struct backlight_device *bd) ++{ ++ struct nt7506fb_par *par = bl_get_data(bd); ++ int power_on = (bd->props.power != FB_BLANK_POWERDOWN); ++ ++ _backlight = bd->props.brightness & power_on; ++ ++ printk(KERN_INFO DRIVER_NAME ": backlight=%d power_on=%d\n", _backlight, power_on); ++ ++ if ( bd->props.power != par->power ) { ++ par->power = bd->props.power; ++ ++ if ( power_on ) { ++ /* Power LCD device on */ ++ NT7506_writeb_ctl(NT_SET_PWRSAVE|OFF); ++ NT7506_writeb_ctl(NT_RLS_PWRSAVE); ++ ++ /* Restart refresh timer */ ++ if ( ! timer_pending(&fb_timer) ) ++ nt7506fb_start_timer(); ++ } ++ else { ++ /* Throttle refresh timer */ ++ del_timer(&fb_timer); ++ ++ /* Put LCD device in power save mode */ ++ NT7506_writeb_ctl(NT_SET_PWRSAVE|ON); ++ NT7506_writeb_ctl(NT_RLS_PWRSAVE); ++ } ++ } ++ ++ //printk(KERN_INFO DRIVER_NAME": backlight = %d\n", _backlight); ++ return 0; ++} ++ ++static int ++nt7506fb_bl_get_brightness(struct backlight_device *bd) ++{ ++ return bd->props.brightness; ++} ++ ++static struct backlight_ops nt7506fb_bl_ops = { ++ .get_brightness = nt7506fb_bl_get_brightness, ++ .update_status = nt7506fb_bl_update_status, ++}; ++ ++ ++static void ++nt7506fb_bl_init(struct nt7506fb_par *par) ++{ ++ struct fb_info *info = par->info; ++ struct backlight_device *bd; ++ ++ bd = backlight_device_register(DRIVER_NAME, info->dev, par, &nt7506fb_bl_ops); ++ if (IS_ERR(bd)) { ++ info->bl_dev = NULL; ++ printk(KERN_WARNING DRIVER_NAME ": Backlight device registration failed\n"); ++ return; ++ } ++ ++ info->bl_dev = bd; ++ bd->props.max_brightness = 1; ++ bd->props.power = FB_BLANK_UNBLANK; ++ bd->props.brightness = 1; ++ par->power = bd->props.power; ++ ++ nt7506fb_bl_update_status(bd); ++ ++ printk(KERN_INFO DRIVER_NAME ": Backlight control initialized\n"); ++} ++ ++static void ++nt7506fb_bl_exit(struct fb_info *info) ++{ ++ if ( info->bl_dev ) { ++ backlight_device_unregister(info->bl_dev); ++ info->bl_dev = NULL; ++ } ++} ++ ++ ++/* ++ * Main frame buffer operations ++ */ ++ ++static int nt7506fb_open(struct fb_info *info, int user) ++{ ++ struct nt7506fb_par *par = info->par; ++ atomic_inc(&par->ref_count); ++ return 0; ++} ++ ++static int nt7506fb_release(struct fb_info *info, int user) ++{ ++ struct nt7506fb_par *par = info->par; ++ int count = atomic_read(&par->ref_count); ++ if (!count) ++ return -EINVAL; ++ atomic_dec(&par->ref_count); ++ return 0; ++} ++ ++static int nt7506fb_pan_display(struct fb_var_screeninfo *var, ++ struct fb_info *info) ++{ ++ if ( (var->vmode & FB_VMODE_YWRAP) && ++ (var->yoffset < LCD_HEIGHT) && ++ (info->var.yres <= LCD_HEIGHT) ) { ++ NT7506_set_start_line(var->yoffset); ++ info->var.yoffset = var->yoffset; ++ return 0; ++ } ++ ++ return -EINVAL; ++} ++ ++static void nt7506fb_lcd_update(struct nt7506fb_par *par) ++{ ++ unsigned char *src = (unsigned char __force *) par->info->screen_base; ++ int line_length = par->info->fix.line_length; ++ int page, x, bit; ++ unsigned char plane1, plane2; ++ unsigned char *ptr; ++ unsigned char xshift; ++ ++ if ( info->var.bits_per_pixel == 1 ) { ++ ++ for (page = 0; page < LCD_NPAGES; page++) { ++ NT7506_set_yaddr(page); ++ NT7506_set_xaddr(0); ++ for (x = 0; x < LCD_WIDTH; x++) { ++ xshift = 7 - (x % 8); ++ plane1 = plane2 = 0; ++ ptr = src + (page * 8 * line_length + x / 8); ++ for (bit = 0; bit < 8; ptr += line_length, bit++) { ++ plane1 |= (((*ptr) >> xshift) & 1) << bit; ++ } ++ NT7506_writeb_data(plane1); ++ NT7506_writeb_data(plane2); ++ } ++ } ++ ++ } else { ++ ++ for (page = 0; page < LCD_NPAGES; page++) { ++ NT7506_set_yaddr(page); ++ NT7506_set_xaddr(0); ++ for (x = 0; x < LCD_WIDTH; x++) { ++ xshift = (3 - (x % 4)) << 1; ++ plane1 = plane2 = 0; ++ ptr = src + (page * 8 * line_length + x / 4); ++ for (bit = 0; bit < 8; ptr += line_length, bit++) { ++ plane1 |= (((*ptr) >> (xshift + 1)) & 1) << bit; ++ plane2 |= (((*ptr) >> xshift) & 1) << bit; ++ } ++ NT7506_writeb_data(plane1); ++ NT7506_writeb_data(plane2); ++ } ++ } ++ ++ } ++} ++ ++static void nt7506fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) ++{ ++ sys_fillrect(info, rect); ++} ++ ++ ++ ++static void nt7506fb_copyarea(struct fb_info *info, ++ const struct fb_copyarea *area) ++{ ++ sys_copyarea(info, area); ++} ++ ++ ++static void nt7506fb_imageblit(struct fb_info *info, const struct fb_image *image) ++{ ++ sys_imageblit(info, image); ++} ++ ++ ++/* ++ * this is the access path from userspace. they can seek and write to ++ * the fb. it's inefficient for them to do anything less than 128*8 ++ * writes since we update the lcd in each write() anyway. ++ */ ++static ssize_t nt7506fb_write(struct fb_info *info, const char __user *buf, ++ size_t count, loff_t *ppos) ++{ ++ unsigned long p = *ppos; ++ unsigned int fbmemlength; ++ int err = 0; ++ ++ fbmemlength = (info->var.xres * info->var.yres) / (8 / info->var.bits_per_pixel); ++ ++ if ( p > fbmemlength ) { ++ return -EFBIG; ++ } ++ ++ if ( (count + p) > fbmemlength ) { ++ count = fbmemlength - p; ++ err = -ENOSPC; ++ } ++ ++ if ( count ) { ++ char *base_addr = (char __force *) info->screen_base; ++ if ( copy_from_user(base_addr + p, buf, count) ) ++ err = -EFAULT; ++ } ++ ++ if ( !err ) ++ *ppos += count; ++ ++ return err ? err : count; ++} ++ ++ ++static int nt7506fb_mmap(struct fb_info *info, struct vm_area_struct *vma) ++{ ++ unsigned long off; ++ unsigned long start; ++ u32 len; ++ ++ if (vma->vm_end - vma->vm_start == 0) ++ return 0; ++ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) ++ return -EINVAL; ++ off = vma->vm_pgoff << PAGE_SHIFT; ++ start = info->fix.smem_start; ++ len = info->fix.smem_len; ++ if (off >= len) ++ { ++ return -EINVAL; ++ ++ } ++ if ((vma->vm_end - vma->vm_start + off) > len) ++ { ++ return -EINVAL; ++ } ++ off += start; ++ vma->vm_pgoff = off >> PAGE_SHIFT; ++ if (remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)info->fix.smem_start) >> PAGE_SHIFT, ++ info->fix.smem_len, vma->vm_page_prot)) ++ ++ { ++ return -EAGAIN; ++ } ++ return 0; ++ ++} ++ ++ ++static int nt7506fb_ioctl(struct fb_info *info, ++ unsigned int cmd, unsigned long arg) ++{ ++ unsigned char frame_rate; ++ ++ switch ( cmd ) { ++ case FBIO_FRAMERATE: ++ if (get_user(frame_rate, (unsigned char *)arg)) ++ return -EFAULT; ++ printk(KERN_INFO "fb%d: framerate=%d Hz\n", info->node, frame_rate); ++ _fps = frame_rate; ++ return 0; ++ ++ default: ++ return -EINVAL; ++ } ++} ++ ++ ++static struct fb_ops nt7506fb_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = nt7506fb_open, ++ .fb_read = fb_sys_read, ++ .fb_write = nt7506fb_write, ++ .fb_release = nt7506fb_release, ++ .fb_pan_display = nt7506fb_pan_display, ++ .fb_fillrect = nt7506fb_fillrect, ++ .fb_copyarea = nt7506fb_copyarea, ++ .fb_imageblit = nt7506fb_imageblit, ++ .fb_ioctl = nt7506fb_ioctl, ++ .fb_mmap = nt7506fb_mmap, ++}; ++ ++ ++static void ++nt7506fb_start_timer(void) ++{ ++ fb_timer.expires = jiffies + (HZ/_fps); ++ add_timer(&fb_timer); ++} ++ ++static void ++nt7506fb_refresh(unsigned long data) ++{ ++ nt7506fb_lcd_update(info->par); ++ nt7506fb_start_timer(); ++} ++ ++/* ++ * Grayscale levels adjustment ++ */ ++ ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ ++static void nt7506fb_set_gray_level(unsigned char index, unsigned char level) ++{ ++ NT7506_writeb_ctl(NT_GRAY_SCALE | index); ++ NT7506_writeb_ctl(GRAY_VALUE(level)); ++ NT7506_writeb_ctl(NT_GRAY_SCALE | (index+1)); ++ NT7506_writeb_ctl(GRAY_VALUE(level)); ++} ++ ++#ifdef CONFIG_PROC_FS ++#include "nt7506fb-procfs.c" ++#endif ++ ++#endif ++ ++ ++/* ++ * Device driver intialisation ++ */ ++ ++static int __init ++nt7506fb_probe(struct platform_device *dev) ++{ ++ int retval = -ENOMEM; ++ struct nt7506fb_par *par; ++ static unsigned char *videomemory; ++ static int videomemorysize; ++ int i; ++ ++ NT7506_init_lcd(DEFAULT_CONTRAST); ++ ++ videomemorysize = LCD_WIDTH * LCD_HEIGHT / 4; ++ ++ if (!(videomemory = kmalloc(videomemorysize,GFP_ATOMIC))) ++ goto failout; ++ memset(videomemory, 0, videomemorysize); ++ ++ info = framebuffer_alloc(sizeof(struct nt7506fb_par), &dev->dev); ++ ++ if (!info) ++ goto out_alloc; ++ info->screen_base = (char __iomem *)videomemory; ++ info->fbops = &nt7506fb_ops; ++ ++ info->var = nt7506fb_var; ++ info->fix = nt7506fb_fix; ++ info->fix.smem_start = (unsigned long)videomemory; ++ info->fix.smem_len = videomemorysize; ++ ++ par = info->par; ++ par->info = info; ++ ++ info->flags = FBINFO_FLAG_DEFAULT; ++ spin_lock_init(&par->lock); ++ platform_set_drvdata(dev, info); ++ ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ /* Allocate cmap */ ++ retval = fb_alloc_cmap(&info->cmap, 4, 0); ++ if (retval < 0) { ++ printk(KERN_ERR "fb%d: Failed to allocate colormap\n", info->node); ++ goto out_register; ++ } ++ ++ /* Set cmap */ ++ for (i = 0; i < 4; i++) ++ info->cmap.red[i] = (((4*i)+1)*(0xFFFF))/16; ++ memcpy(info->cmap.green, info->cmap.red, sizeof(u16)*4); ++ memcpy(info->cmap.blue, info->cmap.red, sizeof(u16)*4); ++#endif ++ ++ /* Register framebuffer */ ++ retval = register_framebuffer(info); ++ if (retval < 0) ++ goto out_register; ++ ++ setup_timer(&fb_timer, nt7506fb_refresh, (unsigned long) par); ++ ++ printk(KERN_INFO ++ "fb%d: nt7506 frame buffer device, using %dK of video memory\n", ++ info->node, videomemorysize >> 10); ++ ++ /* Create procfs entries for grayscale levels adjustment */ ++#ifdef CONFIG_PROC_FS ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ nt7506fb_proc_init(par); ++#endif ++#endif ++ ++ /* Initialize backlight and contrast control (do not abort driver if it fails) */ ++ nt7506fb_bl_init(par); ++ nt7506fb_lcd_init(par); ++ ++ nt7506fb_start_timer(); ++ ++ return 0; ++ ++out_register: ++ framebuffer_release(info); ++out_alloc: ++ vfree(videomemory); ++failout: ++ return retval; ++} ++ ++static int nt7506fb_remove(struct platform_device *dev) ++{ ++ struct fb_info *info = platform_get_drvdata(dev); ++ ++ del_timer(&fb_timer); ++ ++ if (info) { ++ nt7506fb_lcd_exit(info->par); ++ nt7506fb_bl_exit(info); ++ unregister_framebuffer(info); ++ vfree((void __force *)info->screen_base); ++ framebuffer_release(info); ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_PM ++static int nt7506fb_suspend(struct platform_device *dev, pm_message_t state) ++{ ++ struct fb_info *info = platform_get_drvdata(dev); ++ ++ printk(KERN_INFO DRIVER_NAME ": suspend\n"); ++ ++ info->bl_dev->props.power = FB_BLANK_POWERDOWN; ++ nt7506fb_bl_update_status(info->bl_dev); ++ ++ return 0; ++} ++ ++static int nt7506fb_resume(struct platform_device *dev) ++{ ++ struct fb_info *info = platform_get_drvdata(dev); ++ ++ printk(KERN_INFO DRIVER_NAME ": resume\n"); ++ ++ info->bl_dev->props.power = FB_BLANK_UNBLANK; ++ nt7506fb_bl_update_status(info->bl_dev); ++ ++ return 0; ++} ++#else ++#define nt7506fb_suspend NULL ++#define nt7506fb_resume NULL ++#endif ++ ++ ++static struct platform_driver nt7506fb_driver = { ++ .probe = nt7506fb_probe, ++ .remove = nt7506fb_remove, ++ .suspend = nt7506fb_suspend, ++ .resume = nt7506fb_resume, ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++static struct platform_device *nt7506fb_device; ++ ++static int __init nt7506fb_init(void) ++{ ++ int ret; ++ ++ ++ if (!(lcd_mem = request_mem_region(LCD_BASE, LCD_SIZE, "mpc8313-lcd"))) ++ return -ENOMEM; ++ ++ if (!(_lcd_io = ioremap(LCD_BASE, LCD_SIZE))) ++ { ++ release_mem_region(LCD_BASE, LCD_SIZE); ++ lcd_mem = NULL; ++ return -ENOMEM; ++ } ++ ret = platform_driver_register(&nt7506fb_driver); ++ ++ if (!ret) { ++ nt7506fb_device = platform_device_alloc(DRIVER_NAME, 0); ++ if (nt7506fb_device) ++ { ++ ret = platform_device_add(nt7506fb_device); ++ } ++ else ++ { ++ ret = -ENOMEM; ++ } ++ if (ret) ++ { ++ platform_device_put(nt7506fb_device); ++ platform_driver_unregister(&nt7506fb_driver); ++ } ++ ++ } ++ ++ ++ return ret; ++ ++} ++ ++ ++static void NT7506_init_lcd(char ael) ++{ ++ /* this resets the lcd*/ ++ char bl = _backlight ? LCD_BCKLIGH : LCD_BCKLIGHN; ++ ++ iowrite16(LCD_RSTN | LCD_ERD | bl, _lcd_io); ++ udelay(100); ++ iowrite16(LCD_RST| LCD_ERD | bl, _lcd_io); ++ udelay(200); ++ /* Soft reset*/ ++ NT7506_writeb_ctl(NT_RESET); ++ /* Disable ICON display*/ ++ NT7506_writeb_ctl(NT_ICON|OFF); ++ /* Sets the duty ratio 1/128*/ ++ NT7506_writeb_ctl(NT_DUTY); NT7506_writeb_ctl(DUTY_1_128); ++ /* Sets reverse direction between RAM column address and segment driver*/ ++ NT7506_writeb_ctl(NT_ADC_REV); ++ NT7506_writeb_ctl(NT_SHL_NOR); ++ /* Enales the built in Oscillator circuit.*/ ++ NT7506_writeb_ctl(NT_OSC); ++ /* Set Initial row to 0*/ ++ NT7506_writeb_ctl(NT_COM0); NT7506_writeb_ctl(0); ++ /* Sets DC-DC*/ ++ NT7506_writeb_ctl(NT_DCDC|TIME6); ++ /* Selects resistance ratio of the internal resistor*/ ++ NT7506_writeb_ctl(NT_REG_RES|RES_7_2); ++ /* set Reference Voltage mode*/ ++ NT7506_writeb_ctl(NT_ELEC_VOL); NT7506_writeb_ctl(ael); ++ /* Selects LCD bias ratio*/ ++ NT7506_writeb_ctl(NT_BIAS|BIAS_1_11); ++ ++ NT7506_writeb_ctl(NT_DATA_DIR); NT7506_writeb_ctl(0); ++ NT7506_writeb_ctl(NT_FRC_PWM|PWM15); ++ ++#ifdef CONFIG_FB_NT7506_GRAYSCALE ++ /* Feed grayscale palette */ ++ nt7506fb_set_gray_level(GRAY_INDEX_WHITE, GRAY_LEVEL_WHITE); ++ nt7506fb_set_gray_level(GRAY_INDEX_LIGHT, GRAY_LEVEL_LIGHT); ++ nt7506fb_set_gray_level(GRAY_INDEX_DARK, GRAY_LEVEL_DARK); ++ nt7506fb_set_gray_level(GRAY_INDEX_BLACK, GRAY_LEVEL_BLACK); ++#endif ++ ++ /* Select power circuit functions */ ++ NT7506_writeb_ctl(NT_POWER|VC); ++ udelay(5000); ++ NT7506_writeb_ctl(NT_POWER|VC|VR); ++ udelay(5000); ++ NT7506_writeb_ctl(NT_POWER|VC|VR|VF); ++ udelay(5000); ++ /* Reverses the display status on LCD panel */ ++ NT7506_writeb_ctl(NT_REV_DISP|OFF); ++ /* Forces the whole LCD points to be turned on regardless of the contents of the display data RAM*/ ++ NT7506_writeb_ctl(NT_DISP|ON); ++ /* Set Initial Start Line Address */ ++ NT7506_writeb_ctl(NT_START_LINE); NT7506_writeb_ctl(0x00); ++} ++ ++static void __exit nt7506fb_exit(void) ++{ ++ if (lcd_mem) ++ release_mem_region(LCD_BASE, LCD_SIZE); ++ lcd_mem = NULL; ++ platform_device_unregister(nt7506fb_device); ++ platform_driver_unregister(&nt7506fb_driver); ++} ++ ++module_param(tuhold, ulong, 0); ++MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to NT7506 board"); ++ ++module_init(nt7506fb_init); ++module_exit(nt7506fb_exit); ++ ++MODULE_DESCRIPTION("fbdev driver for Novatek NT7506 monochrome LCD board"); ++MODULE_AUTHOR("Alexandre Coffignal"); ++MODULE_LICENSE("GPL"); ++ +Index: linux-2.6.27/include/linux/nt7506fb.h +=================================================================== +--- /dev/null ++++ linux-2.6.27/include/linux/nt7506fb.h +@@ -0,0 +1,31 @@ ++ ++/* ++ * (C) Copyright 2008 ++ * Alexandre Coffignal, CénoSYS, alexandre.coffignal@cenosys.com ++ * ++ * See file CREDITS for list of people who contributed to this ++ * project. ++ * ++ * 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. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, ++ * MA 02111-1307 USA ++ * ++ */ ++ ++#ifndef __LINUX_NT7506FB_H__ ++#define __LINUX_NT7506FB_H__ ++ ++#define FBIO_FRAMERATE _IOR('f', 1, char) ++ ++#endif +Index: linux-2.6.27/drivers/video/nt7506fb-procfs.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/video/nt7506fb-procfs.c +@@ -0,0 +1,119 @@ ++/* ++ * FB driver for NT7506 monochrome/grayscale LCD board ++ * Device setup using procfs ++ * ++ * Copyright (C) 2009, Goobie (www.goobie.fr). ++ * ++ * Sylvain Giroudon ++ * ++ * This software program is licensed subject to the GNU General Public License ++ * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html ++ */ ++ ++#include ++#include ++ ++struct nt7506fb_proc_entry { ++ char *name; ++ unsigned char index; ++ unsigned char level; ++ struct nt7506fb_par *par; ++}; ++ ++static struct nt7506fb_proc_entry nt7506fb_proc_entries[] = { ++ { "white", GRAY_INDEX_WHITE, GRAY_LEVEL_WHITE }, ++ { "light", GRAY_INDEX_LIGHT, GRAY_LEVEL_LIGHT }, ++ { "dark", GRAY_INDEX_DARK, GRAY_LEVEL_DARK }, ++ { "black", GRAY_INDEX_BLACK, GRAY_LEVEL_BLACK }, ++}; ++ ++static int nt7506fb_proc_read(char *page, char **start, off_t off, int count, ++ int *eof, void *data) ++{ ++ struct nt7506fb_proc_entry *entry = data; ++ int len; ++ ++ len = sprintf(page, "%d\n", entry->level); ++ ++ len -= off; ++ if ( len < count ) { ++ *eof = 1; ++ if ( len <= 0 ) ++ return 0; ++ } else { ++ len = count; ++ } ++ ++ *start = page + off; ++ ++ return len; ++} ++ ++ ++static int nt7506fb_proc_write(struct file *file, const char *buf, ++ unsigned long count, void *data) ++{ ++ struct nt7506fb_proc_entry *entry = data; ++ char lbuf[count+1]; ++ ++ /* Only root can do this */ ++ if ( !capable(CAP_SYS_ADMIN) ) ++ return -EACCES; ++ ++ memset(lbuf, 0, sizeof(lbuf)); ++ ++ if (copy_from_user(lbuf, buf, count)) ++ return -EFAULT; ++ ++ if ( sscanf(lbuf, "%hhi", &entry->level) == 1 ) { ++ if ( entry->level > GRAY_LEVEL_MAX ) ++ entry->level = GRAY_LEVEL_MAX; ++ ++ /* Set grayscale palette entry */ ++ nt7506fb_set_gray_level(entry->index, entry->level); ++ } ++ else { ++ printk(KERN_INFO DRIVER_NAME ": [%s] Syntax error in expression\n", entry->name); ++ return -EINVAL; ++ } ++ ++ return count; ++} ++ ++ ++static int nt7506fb_proc_init(struct nt7506fb_par *par) ++{ ++ struct proc_dir_entry *root; ++ struct proc_dir_entry *ent; ++ int i; ++ ++ /* Create nt7506fb proc directory */ ++ printk(KERN_INFO DRIVER_NAME ": Creating setup entries in /proc/" DRIVER_NAME "/\n"); ++ ++ root = proc_mkdir(DRIVER_NAME, NULL); ++ if ( root == NULL ) { ++ printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "\n"); ++ return -1; ++ } ++ ++ root->owner = THIS_MODULE; ++ ++ /* Create gray level entries */ ++ for (i = 0; i < ARRAY_SIZE(nt7506fb_proc_entries); i++) { ++ struct nt7506fb_proc_entry *entry = &nt7506fb_proc_entries[i]; ++ ++ entry->par = par; ++ ++ ent = create_proc_entry(entry->name, S_IFREG|S_IWUSR, root); ++ if ( ent == NULL ) { ++ printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/%s\n", entry->name); ++ return -1; ++ } ++ ++ ent->owner = THIS_MODULE; ++ ent->data = entry; ++ ent->write_proc = nt7506fb_proc_write; ++ ent->read_proc = nt7506fb_proc_read; ++ } ++ return 0; ++} diff --git a/recipes/linux/linux-2.6.27/boc01/014-090209-pm-wakeup.patch b/recipes/linux/linux-2.6.27/boc01/014-090209-pm-wakeup.patch deleted file mode 100644 index 3acbf40c32..0000000000 --- a/recipes/linux/linux-2.6.27/boc01/014-090209-pm-wakeup.patch +++ /dev/null @@ -1,195 +0,0 @@ -Index: linux-2.6.27/arch/powerpc/platforms/83xx/Kconfig -=================================================================== ---- linux-2.6.27.orig/arch/powerpc/platforms/83xx/Kconfig 2008-10-10 00:13:53.000000000 +0200 -+++ linux-2.6.27/arch/powerpc/platforms/83xx/Kconfig 2009-01-23 10:54:03.000000000 +0100 -@@ -104,6 +104,13 @@ - - endif - -+ -+config WAKEUP_IT -+ tristate "83xx interrupt for PM wakeup" -+ help -+ This enables a driver to be used as a wakeup source . -+ -+ - # used for usb - config PPC_MPC831x - bool -Index: linux-2.6.27/arch/powerpc/platforms/83xx/Makefile -=================================================================== ---- linux-2.6.27.orig/arch/powerpc/platforms/83xx/Makefile 2008-10-10 00:13:53.000000000 +0200 -+++ linux-2.6.27/arch/powerpc/platforms/83xx/Makefile 2009-01-23 10:54:03.000000000 +0100 -@@ -14,3 +14,4 @@ - obj-$(CONFIG_SBC834x) += sbc834x.o - obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o - obj-$(CONFIG_ASP834x) += asp834x.o -+obj-$(CONFIG_WAKEUP_IT) += wakeup-it.o -Index: linux-2.6.27/arch/powerpc/platforms/83xx/wakeup-it.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ linux-2.6.27/arch/powerpc/platforms/83xx/wakeup-it.c 2009-01-23 10:49:09.000000000 +0100 -@@ -0,0 +1,163 @@ -+/* -+ * This support a driver to be used as a wakeup source on the MPC8313. -+ * -+ * Copyright (c) 2008 Cenosys -+ * -+ * Alexandre Coffignal -+ * Sylvain Giroudon -+ * -+ * 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 -+#include -+#include -+ -+#include -+ -+#define DRIVER_NAME "wakeup-it" -+ -+char suspend = 0; -+ -+static char *wakeup_irq_ids[] = { -+ "capsense", -+ "rfid", -+}; -+ -+struct wakeup_priv { -+ int nirq; -+ int irq[ARRAY_SIZE(wakeup_irq_ids)]; -+ spinlock_t lock; -+}; -+ -+struct wakeup_irq_desc { -+ char *name; -+ int index; -+}; -+ -+static irqreturn_t wakeup(int irq, void *dev_id) -+{ -+ //printk(KERN_INFO "===== WAKEUP INTERRUPT %d !!\n", irq); -+ -+// if ( suspend ) -+// kernel_restart(NULL); -+ return IRQ_HANDLED ; -+} -+ -+ -+static void wakeup_free(struct wakeup_priv *priv) -+{ -+ int i; -+ -+ for (i = 0; i < priv->nirq; i++) { -+ free_irq(priv->irq[i], priv); -+ } -+ -+ kfree(priv); -+} -+ -+ -+static int __devinit wakeup_probe(struct of_device *dev, const struct of_device_id *match) -+{ -+ struct device_node *np = dev->node; -+ struct resource res; -+ int ret = 0; -+ struct wakeup_priv *priv; -+ int i; -+ -+ priv = kmalloc(sizeof(struct wakeup_priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->nirq = 0; -+ spin_lock_init(&priv->lock); -+ dev_set_drvdata(&dev->dev, priv); -+ -+ ret = of_address_to_resource(np, 0, &res); -+ if (ret) -+ goto out; -+ -+ for (i = 0; i < ARRAY_SIZE(wakeup_irq_ids); i++) { -+ char *id = wakeup_irq_ids[i]; -+ char it_name[32]; -+ int it_num; -+ -+ it_num = irq_of_parse_and_map(np, i); -+ if ( it_num == NO_IRQ ) { -+ dev_err(&dev->dev, DRIVER_NAME ": interrupt #%d (%s) does not exist in device tree.\n", i, id); -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ set_irq_type(it_num, IRQ_TYPE_EDGE_FALLING); -+ -+ snprintf(it_name, sizeof(it_name), DRIVER_NAME ":%s", id); -+ -+ ret = request_irq(it_num, wakeup, 0, it_name, priv); -+ if ( ret ) { -+ printk(KERN_WARNING DRIVER_NAME ": cannot request interrupt %d (%s)\n", it_num, id); -+ goto out; -+ } -+ -+ printk(KERN_INFO DRIVER_NAME ": accepting wakeup event from %s (%d)\n", id, it_num); -+ -+ priv->irq[priv->nirq++] = it_num; -+ } -+ -+ return 0; -+ -+out: -+ wakeup_free(priv); -+ return ret; -+} -+ -+static int __devexit wakeup_remove(struct of_device *dev) -+{ -+ struct wakeup_priv *priv = dev_get_drvdata(&dev->dev); -+ wakeup_free(priv); -+ return 0; -+} -+ -+static struct of_device_id wakeup_match[] = { -+ { -+ .compatible = "fsl,wakeup-it", -+ }, -+ {}, -+}; -+ -+static int wakeup_suspend(struct of_device * dev, pm_message_t state) -+{ -+ int ret = 0; -+ printk(KERN_INFO DRIVER_NAME ": suspend\n"); -+ suspend=1; -+ return ret; -+} -+ -+ -+static struct of_platform_driver wakeup_driver = { -+ .name = DRIVER_NAME, -+ .match_table = wakeup_match, -+ .probe = wakeup_probe, -+ .suspend = wakeup_suspend, -+ .remove = __devexit_p(wakeup_remove) -+ -+}; -+ -+static int __init wakeup_init(void) -+{ -+ return of_register_platform_driver(&wakeup_driver); -+} -+ -+static void __exit wakeup_exit(void) -+{ -+ of_unregister_platform_driver(&wakeup_driver); -+} -+ -+module_init(wakeup_init); -+module_exit(wakeup_exit); diff --git a/recipes/linux/linux-2.6.27/boc01/defconfig b/recipes/linux/linux-2.6.27/boc01/defconfig index bb667bcd10..24b147baf8 100644 --- a/recipes/linux/linux-2.6.27/boc01/defconfig +++ b/recipes/linux/linux-2.6.27/boc01/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.27 -# Thu Feb 26 12:59:36 2009 +# Wed Mar 4 18:33:27 2009 # # CONFIG_PPC64 is not set @@ -40,6 +40,7 @@ CONFIG_ARCH_HAS_ILOG2_U32=y CONFIG_GENERIC_HWEIGHT=y CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_GPIO=y # CONFIG_ARCH_NO_VIRT_TO_BUS is not set CONFIG_PPC=y CONFIG_EARLY_PRINTK=y @@ -181,7 +182,6 @@ CONFIG_MPC831x_RDB=y # CONFIG_MPC837x_RDB is not set # CONFIG_SBC834x is not set # CONFIG_ASP834x is not set -CONFIG_WAKEUP_IT=y CONFIG_PPC_MPC831x=y # CONFIG_PPC_86xx is not set # CONFIG_EMBEDDED6xx is not set @@ -263,6 +263,7 @@ CONFIG_GENERIC_ISA_DMA=y CONFIG_PPC_INDIRECT_PCI=y CONFIG_FSL_SOC=y CONFIG_FSL_PCI=y +CONFIG_FSL_LBC=y CONFIG_PPC_PCI_CHOICE=y CONFIG_PCI=y CONFIG_PCI_DOMAINS=y @@ -732,6 +733,7 @@ CONFIG_MTD_NAND_IDS=y # CONFIG_MTD_NAND_PLATFORM is not set # CONFIG_MTD_ALAUDA is not set CONFIG_MTD_NAND_FSL_ELBC=y +CONFIG_MTD_NAND_FSL_UPM=y # CONFIG_MTD_ONENAND is not set # @@ -739,6 +741,7 @@ CONFIG_MTD_NAND_FSL_ELBC=y # # CONFIG_MTD_UBI is not set CONFIG_OF_DEVICE=y +CONFIG_OF_GPIO=y CONFIG_OF_I2C=y CONFIG_OF_SPI=y # CONFIG_PARPORT is not set @@ -1087,6 +1090,7 @@ CONFIG_I2C_HELPER_AUTO=y # # I2C system bus drivers (mostly embedded / system-on-chip) # +# CONFIG_I2C_GPIO is not set CONFIG_I2C_MPC=y # CONFIG_I2C_OCORES is not set # CONFIG_I2C_SIMTEC is not set @@ -1119,6 +1123,7 @@ CONFIG_AT24=y # CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -1141,7 +1146,26 @@ CONFIG_SPI_MPC83xx=y CONFIG_SPI_SPIDEV=y # CONFIG_SPI_TLE62X0 is not set CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y -# CONFIG_GPIOLIB is not set +CONFIG_GPIOLIB=y +# CONFIG_GPIO_SYSFS is not set + +# +# I2C GPIO expanders: +# +# CONFIG_GPIO_MAX732X is not set +# CONFIG_GPIO_PCA953X is not set +# CONFIG_GPIO_PCF857X is not set + +# +# PCI GPIO expanders: +# +# CONFIG_GPIO_BT8XX is not set + +# +# SPI GPIO expanders: +# +# CONFIG_GPIO_MAX7301 is not set +# CONFIG_GPIO_MCP23S08 is not set # CONFIG_W1 is not set CONFIG_POWER_SUPPLY=y CONFIG_POWER_SUPPLY_DEBUG=y @@ -1502,6 +1526,7 @@ CONFIG_LEDS_CLASS=y # LED drivers # # CONFIG_LEDS_PCA9532 is not set +# CONFIG_LEDS_GPIO is not set # CONFIG_LEDS_PCA955X is not set # diff --git a/recipes/linux/linux_2.6.27.bb b/recipes/linux/linux_2.6.27.bb index 0b219ec705..5d2d485b12 100644 --- a/recipes/linux/linux_2.6.27.bb +++ b/recipes/linux/linux_2.6.27.bb @@ -1,6 +1,6 @@ require linux.inc -PR = "r6" +PR = "r7" # Mark archs/machines that this kernel supports DEFAULT_PREFERENCE = "-1" @@ -15,14 +15,13 @@ SRC_URI_append_boc01 = "\ file://boc01.dts \ file://001-090114-sqn11x0-usb-hack.patch;patch=1 \ file://004-081205-usb.patch;patch=1 \ - file://005-090217-isl12024.patch;patch=1 \ + file://005-090226-isl12024.patch;patch=1 \ file://007-081217-lm73.patch;patch=1 \ file://008-081208-spi.patch;patch=1 \ file://010-090112-mii.patch;patch=1 \ file://011-090115-gpio.patch;patch=1 \ file://012-090219-capsense.patch;patch=1 \ - file://013-090209-lcd.patch;patch=1 \ - file://014-090209-pm-wakeup.patch;patch=1 \ + file://013-090306-lcd.patch;patch=1 \ " SRC_URI_append_progear = "file://progear-bl.patch;patch=1\ -- cgit 1.2.3-korg