From c228a100d3a685b811f90a0d4fa317d6f9c5d44f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= Date: Tue, 6 Jan 2009 11:11:49 +0100 Subject: linux-2.6.27: update keyboard and LCD patches for boc01 --- .../boc01/012-081222-cy3218-btns.patch | 227 ------ .../boc01/012-081223-cy3218-btns.patch | 334 +++++++++ .../linux/linux-2.6.27/boc01/013-081216-lcd.patch | 735 ------------------- .../linux/linux-2.6.27/boc01/013-081224-lcd.patch | 808 +++++++++++++++++++++ packages/linux/linux-2.6.27/boc01/defconfig | 13 +- packages/linux/linux_2.6.27.bb | 6 +- 6 files changed, 1156 insertions(+), 967 deletions(-) delete mode 100644 packages/linux/linux-2.6.27/boc01/012-081222-cy3218-btns.patch create mode 100644 packages/linux/linux-2.6.27/boc01/012-081223-cy3218-btns.patch delete mode 100644 packages/linux/linux-2.6.27/boc01/013-081216-lcd.patch create mode 100644 packages/linux/linux-2.6.27/boc01/013-081224-lcd.patch (limited to 'packages') diff --git a/packages/linux/linux-2.6.27/boc01/012-081222-cy3218-btns.patch b/packages/linux/linux-2.6.27/boc01/012-081222-cy3218-btns.patch deleted file mode 100644 index fe5bfc21ab..0000000000 --- a/packages/linux/linux-2.6.27/boc01/012-081222-cy3218-btns.patch +++ /dev/null @@ -1,227 +0,0 @@ -Index: linux-2.6.27/drivers/input/misc/cy3218-btns.c -=================================================================== ---- /dev/null -+++ linux-2.6.27/drivers/input/misc/cy3218-btns.c -@@ -0,0 +1,195 @@ -+/* -+ * CAPSENSE Interface driver -+ * -+ * -+ * Copyright (C) 2007, CenoSYS (www.cenosys.com). -+ * -+ * Guillaume Ligneul -+ * Jeremy Lainé -+ * -+ * 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 -+ -+static int capsense_attach_adapter(struct i2c_adapter *adapter); -+static int capsense_detach_client(struct i2c_client *client); -+ -+#define CAPSENSE_NAME "Capsense" -+/* i2c configuration */ -+#define CAPSENSE_I2C_ADDR 0x25 -+// To debug (may be add in include/linux/i2c-id.h) -+#define I2C_DRIVERID_CAPSENSE 98 -+#define BUTTONS_POLL_INTERVAL 30 /* msec */ -+#define CAP_STATE_GP0 0x88 -+#define CAP_STATE_GP1 0x89 -+#define MASK0 0x10 -+#define MASK1 0x4 -+#define MASK2 0x8 -+#define MASK3 0x1 -+ -+ -+static int poll_interval = BUTTONS_POLL_INTERVAL; -+module_param_named(poll, poll_interval, uint, 0); -+MODULE_PARM_DESC(poll, "poll interval in msec (30=default)"); -+ -+static const unsigned short normal_i2c[] = { -+ CAPSENSE_I2C_ADDR , I2C_CLIENT_END -+}; -+I2C_CLIENT_INSMOD; -+ -+static struct i2c_driver capsense_driver = { -+ .driver = { -+ .name = CAPSENSE_NAME, -+ }, -+ .id = I2C_DRIVERID_CAPSENSE, -+ .attach_adapter = &capsense_attach_adapter, -+ .detach_client = &capsense_detach_client, -+}; -+ -+struct cy3218 { -+ struct input_polled_dev *ipdev; -+ struct i2c_client client; -+ unsigned char key_state; -+}; -+ -+unsigned short keymap[] = { -+ // GP0 -+ KEY_F1, -+ KEY_ENTER, -+ KEY_DOWN, -+ KEY_BACKSPACE, -+ // GP1 -+ KEY_UP, -+}; -+ -+static void handle_buttons(struct input_polled_dev *dev) -+{ -+ struct cy3218 *capsense = dev->private; -+ u8 port_value; -+ u8 new_state = 0; -+ u8 changed; -+ int i; -+ -+ // read status -+ port_value = i2c_smbus_read_byte_data(&capsense->client, CAP_STATE_GP0); -+ if (port_value & MASK0) new_state |= 0x01; -+ if (port_value & MASK1) new_state |= 0x02; -+ if (port_value & MASK2) new_state |= 0x04; -+ if (port_value & MASK3) new_state |= 0x08; -+ -+ port_value = i2c_smbus_read_byte_data(&capsense->client, CAP_STATE_GP1); -+ if (port_value & MASK0) new_state |= 0x10; -+ -+ // update keyboard state -+ changed = capsense->key_state ^ new_state; -+ for (i = 0; i < ARRAY_SIZE(keymap); i++) -+ if (changed & (1 << i)) -+ input_report_key(dev->input, keymap[i], (new_state & (1 << i))); -+ capsense->key_state = new_state; -+ input_sync(dev->input); -+} -+ -+static int -+capsense_probe(struct i2c_adapter *adapter, int addr, int kind) -+{ -+ struct cy3218 *capsense; -+ struct input_polled_dev *ipdev; -+ struct input_dev *input; -+ int rc = 0, err = -ENOMEM, i=0; -+ -+ capsense = kzalloc(sizeof(*capsense), GFP_KERNEL); -+ if (!capsense) -+ goto failout; -+ -+ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { -+ goto failout; -+ } -+ -+ ipdev = input_allocate_polled_device(); -+ if (!ipdev) -+ goto failout; -+ -+ capsense->key_state = 0; -+ capsense->ipdev = ipdev; -+ capsense->client.adapter = adapter; -+ capsense->client.addr = addr; -+ capsense->client.driver = &capsense_driver; -+ strlcpy(capsense->client.name, CAPSENSE_NAME, I2C_NAME_SIZE); -+ i2c_set_clientdata(&capsense->client, capsense); -+ -+ rc = i2c_attach_client(&capsense->client); -+ if (rc) -+ goto out_attach; -+ -+ ipdev->poll = handle_buttons; -+ ipdev->private = capsense; -+ ipdev->poll_interval = poll_interval; -+ -+ input = ipdev->input; -+ input->name = "Capsense buttons"; -+ input->phys = "capsense/input0"; -+ input->id.bustype = BUS_I2C; -+ input->dev.parent = &capsense->client.dev; -+ -+ input->keycode = keymap; -+ input->keycodemax = ARRAY_SIZE(keymap); -+ input->keycodesize = sizeof(unsigned short); -+ -+ input_set_capability(input, EV_MSC, MSC_SCAN); -+ set_bit(EV_KEY, ipdev->input->evbit); -+ -+ for (i = 0; i < ARRAY_SIZE(keymap); i++) -+ set_bit(keymap[i], ipdev->input->keybit); -+ -+ rc = input_register_polled_device(ipdev); -+ if(rc) -+ goto out_polled; -+ -+ return 0; -+ -+out_polled: -+ i2c_detach_client(&capsense->client); -+out_attach: -+ input_free_polled_device(ipdev); -+failout: -+ return err; -+} -+ -+static int -+capsense_attach_adapter (struct i2c_adapter *adapter) -+{ -+ return i2c_probe(adapter, &addr_data, capsense_probe); -+} -+ -+static int -+capsense_detach_client(struct i2c_client *client) -+{ -+ struct cy3218 *capsense = i2c_get_clientdata(client); -+ -+ input_unregister_polled_device(capsense->ipdev); -+ i2c_detach_client(&capsense->client); -+ input_free_polled_device(capsense->ipdev); -+ return 0; -+} -+ -+static int __init capsense_buttons_init(void) -+{ -+ return i2c_add_driver(&capsense_driver); -+} -+ -+static void __exit capsense_buttons_exit(void) -+{ -+ i2c_del_driver(&capsense_driver); -+} -+ -+MODULE_AUTHOR("Guillaume Ligneul "); -+MODULE_DESCRIPTION("Capsense CY3218 Input driver"); -+MODULE_LICENSE("GPL"); -+module_init(capsense_buttons_init); -+module_exit(capsense_buttons_exit); -Index: linux-2.6.27/drivers/input/misc/Kconfig -=================================================================== ---- linux-2.6.27.orig/drivers/input/misc/Kconfig -+++ linux-2.6.27/drivers/input/misc/Kconfig -@@ -207,4 +207,12 @@ config HP_SDC_RTC - Say Y here if you want to support the built-in real time clock - of the HP SDC controller. - -+config INPUT_CAPSENSE_BTNS -+ tristate "CAPSENSE CY3218 button interface" -+ select INPUT_POLLDEV -+ help -+ To compile this driver as a module, choose M here: the -+ module will be called cy3218-btns. -+ To change poll interval, invoque poll parameter in msecs. -+ - endif -Index: linux-2.6.27/drivers/input/misc/Makefile -=================================================================== ---- linux-2.6.27.orig/drivers/input/misc/Makefile -+++ linux-2.6.27/drivers/input/misc/Makefile -@@ -20,3 +20,5 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc. - obj-$(CONFIG_INPUT_UINPUT) += uinput.o - obj-$(CONFIG_INPUT_APANEL) += apanel.o - obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o -+obj-$(CONFIG_INPUT_CAPSENSE_BTNS) += cy3218-btns.o -+ diff --git a/packages/linux/linux-2.6.27/boc01/012-081223-cy3218-btns.patch b/packages/linux/linux-2.6.27/boc01/012-081223-cy3218-btns.patch new file mode 100644 index 0000000000..4ad9feb762 --- /dev/null +++ b/packages/linux/linux-2.6.27/boc01/012-081223-cy3218-btns.patch @@ -0,0 +1,334 @@ +Index: linux-2.6.27/drivers/input/misc/cy3218-btns.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/input/misc/cy3218-btns.c +@@ -0,0 +1,301 @@ ++/* ++ * CAPSENSE Interface driver ++ * ++ * ++ * Copyright (C) 2008, CenoSYS (www.cenosys.com). ++ * ++ * Guillaume Ligneul ++ * Jeremy Lainé ++ * 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 ++ ++static int capsense_attach_adapter(struct i2c_adapter *adapter); ++static int capsense_detach_client(struct i2c_client *client); ++ ++#define CAPSENSE_NAME "Capsense" ++ ++/* i2c configuration */ ++#define CAPSENSE_I2C_ADDR 0x25 ++// To debug (may be add in include/linux/i2c-id.h) ++#define I2C_DRIVERID_CAPSENSE 98 ++ ++#define BUTTONS_POLL_INTERVAL 30 /* msec */ ++ ++#define CAP_OUTPUT_PORT(port) (0x04+(port)) ++#define CAP_OP_SEL(port,bit) (0x1C+(25*(port))+(5*(bit))) ++#define CAP_READ_STATUS(port) (0x88+(port)) ++ ++#define MASK0 0x10 ++#define MASK1 0x4 ++#define MASK2 0x8 ++#define MASK3 0x1 ++ ++#define CAP_NLEDS 5 ++ ++static int poll_interval = BUTTONS_POLL_INTERVAL; ++module_param_named(poll, poll_interval, uint, 0); ++MODULE_PARM_DESC(poll, "poll interval in msec (30=default)"); ++ ++static const unsigned short normal_i2c[] = { ++ CAPSENSE_I2C_ADDR , I2C_CLIENT_END ++}; ++I2C_CLIENT_INSMOD; ++ ++static struct i2c_driver capsense_driver = { ++ .driver = { ++ .name = CAPSENSE_NAME, ++ }, ++ .id = I2C_DRIVERID_CAPSENSE, ++ .attach_adapter = &capsense_attach_adapter, ++ .detach_client = &capsense_detach_client, ++}; ++ ++struct cy3218_led { ++ struct led_classdev cdev; ++ struct cy3218 *capsense; ++ int port; ++ unsigned char mask; ++}; ++ ++struct cy3218 { ++ struct input_polled_dev *ipdev; ++ struct i2c_client client; ++ unsigned char key_state; ++ struct cy3218_led leds[CAP_NLEDS]; ++ unsigned char led_state[2]; ++ struct mutex mutex; ++}; ++ ++static unsigned short keymap[] = { ++ // GP0 ++ KEY_F1, ++ KEY_ENTER, ++ KEY_DOWN, ++ KEY_BACKSPACE, ++ // GP1 ++ KEY_UP, ++}; ++ ++struct cy3218_ledmap { ++ char *name; ++ int port, bit; ++}; ++ ++static struct cy3218_ledmap ledmap[CAP_NLEDS] = { ++ { "capsense:blue:back", 0, 1 }, ++ { "capsense:blue:info", 1, 0 }, ++ { "capsense:blue:down", 1, 1 }, ++ { "capsense:blue:ok", 1, 2 }, ++ { "capsense:blue:up", 1, 3 }, ++}; ++ ++static void handle_buttons(struct input_polled_dev *dev) ++{ ++ struct cy3218 *capsense = dev->private; ++ u8 port_value; ++ u8 new_state = 0; ++ u8 changed; ++ int i; ++ ++ mutex_lock(&capsense->mutex); ++ ++ // read status ++ port_value = i2c_smbus_read_byte_data(&capsense->client, CAP_READ_STATUS(0)); ++ if (port_value & MASK0) new_state |= 0x01; ++ if (port_value & MASK1) new_state |= 0x02; ++ if (port_value & MASK2) new_state |= 0x04; ++ if (port_value & MASK3) new_state |= 0x08; ++ ++ port_value = i2c_smbus_read_byte_data(&capsense->client, CAP_READ_STATUS(1)); ++ if (port_value & MASK0) new_state |= 0x10; ++ ++ mutex_unlock(&capsense->mutex); ++ ++ // update keyboard state ++ changed = capsense->key_state ^ new_state; ++ for (i = 0; i < ARRAY_SIZE(keymap); i++) ++ if (changed & (1 << i)) ++ input_report_key(dev->input, keymap[i], (new_state & (1 << i))); ++ capsense->key_state = new_state; ++ input_sync(dev->input); ++} ++ ++ ++static void ++capsense_led_set(struct led_classdev *led_cdev, ++ enum led_brightness value) ++{ ++ struct cy3218_led *led = (struct cy3218_led *) led_cdev; ++ struct cy3218 *capsense = led->capsense; ++ int port = led->port; ++ ++ if ( value ) ++ capsense->led_state[port] |= led->mask; ++ else ++ capsense->led_state[port] &= ~led->mask; ++ ++ mutex_lock(&capsense->mutex); ++ i2c_smbus_write_byte_data(&capsense->client, CAP_OUTPUT_PORT(port), capsense->led_state[port]); ++ mutex_unlock(&capsense->mutex); ++} ++ ++static int ++capsense_led_init(struct cy3218 *capsense) ++{ ++ int i; ++ int ret; ++ ++ for (i = 0; i < CAP_NLEDS; i++) { ++ struct cy3218_led *led = &(capsense->leds[i]); ++ ++ led->cdev.name = ledmap[i].name; ++ led->cdev.brightness_set = capsense_led_set; ++ led->capsense = capsense; ++ led->port = ledmap[i].port; ++ led->mask = (1 << ledmap[i].bit); ++ ++ ret = led_classdev_register(&capsense->ipdev->input->dev, &led->cdev); ++ if ( ret < 0 ) ++ return -1; ++ ++ i2c_smbus_write_byte_data(&capsense->client, CAP_OP_SEL(led->port, ledmap[i].bit), 0x00); ++ } ++ ++ /* Switch all leds off */ ++ capsense->led_state[0] = 0x00; ++ i2c_smbus_write_byte_data(&capsense->client, CAP_OUTPUT_PORT(0), 0x00); ++ ++ capsense->led_state[1] = 0x00; ++ i2c_smbus_write_byte_data(&capsense->client, CAP_OUTPUT_PORT(1), 0x00); ++ ++ return 0; ++} ++ ++ ++static void ++capsense_led_exit(struct cy3218 *capsense) ++{ ++ int i; ++ ++ for (i = 0; i < CAP_NLEDS; i++) { ++ led_classdev_unregister(&capsense->leds[i].cdev); ++ } ++} ++ ++ ++static int ++capsense_probe(struct i2c_adapter *adapter, int addr, int kind) ++{ ++ struct cy3218 *capsense; ++ struct input_polled_dev *ipdev; ++ struct input_dev *input; ++ int rc = 0, err = -ENOMEM, i=0; ++ ++ capsense = kzalloc(sizeof(*capsense), GFP_KERNEL); ++ if (!capsense) ++ goto failout; ++ ++ mutex_init(&capsense->mutex); ++ ++ if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { ++ goto failout; ++ } ++ ++ ipdev = input_allocate_polled_device(); ++ if (!ipdev) ++ goto failout; ++ ++ capsense->key_state = 0; ++ capsense->ipdev = ipdev; ++ capsense->client.adapter = adapter; ++ capsense->client.addr = addr; ++ capsense->client.driver = &capsense_driver; ++ strlcpy(capsense->client.name, CAPSENSE_NAME, I2C_NAME_SIZE); ++ i2c_set_clientdata(&capsense->client, capsense); ++ ++ rc = i2c_attach_client(&capsense->client); ++ if (rc) ++ goto out_attach; ++ ++ ipdev->poll = handle_buttons; ++ ipdev->private = capsense; ++ ipdev->poll_interval = poll_interval; ++ ++ input = ipdev->input; ++ input->name = "Capsense buttons"; ++ input->phys = "capsense/input0"; ++ input->id.bustype = BUS_I2C; ++ input->dev.parent = &capsense->client.dev; ++ ++ input->keycode = keymap; ++ input->keycodemax = ARRAY_SIZE(keymap); ++ input->keycodesize = sizeof(unsigned short); ++ ++ input_set_capability(input, EV_MSC, MSC_SCAN); ++ set_bit(EV_KEY, ipdev->input->evbit); ++ ++ for (i = 0; i < ARRAY_SIZE(keymap); i++) ++ set_bit(keymap[i], ipdev->input->keybit); ++ ++ rc = input_register_polled_device(ipdev); ++ if(rc) ++ goto out_polled; ++ ++ if ( capsense_led_init(capsense) ) ++ goto out_registered; ++ ++ return 0; ++ ++out_registered: ++ input_unregister_polled_device(ipdev); ++out_polled: ++ i2c_detach_client(&capsense->client); ++out_attach: ++ input_free_polled_device(ipdev); ++failout: ++ return err; ++} ++ ++static int ++capsense_attach_adapter (struct i2c_adapter *adapter) ++{ ++ return i2c_probe(adapter, &addr_data, capsense_probe); ++} ++ ++static int ++capsense_detach_client(struct i2c_client *client) ++{ ++ struct cy3218 *capsense = i2c_get_clientdata(client); ++ ++ capsense_led_exit(capsense); ++ input_unregister_polled_device(capsense->ipdev); ++ i2c_detach_client(&capsense->client); ++ input_free_polled_device(capsense->ipdev); ++ return 0; ++} ++ ++static int __init capsense_buttons_init(void) ++{ ++ return i2c_add_driver(&capsense_driver); ++} ++ ++static void __exit capsense_buttons_exit(void) ++{ ++ i2c_del_driver(&capsense_driver); ++} ++ ++MODULE_AUTHOR("Guillaume Ligneul "); ++MODULE_DESCRIPTION("Capsense CY3218 Input driver"); ++MODULE_LICENSE("GPL"); ++module_init(capsense_buttons_init); ++module_exit(capsense_buttons_exit); +Index: linux-2.6.27/drivers/input/misc/Kconfig +=================================================================== +--- linux-2.6.27.orig/drivers/input/misc/Kconfig ++++ linux-2.6.27/drivers/input/misc/Kconfig +@@ -207,4 +207,13 @@ config HP_SDC_RTC + Say Y here if you want to support the built-in real time clock + of the HP SDC controller. + ++config INPUT_CAPSENSE_BTNS ++ tristate "CAPSENSE CY3218 button interface" ++ select INPUT_POLLDEV ++ select LEDS_CLASS ++ help ++ To compile this driver as a module, choose M here: the ++ module will be called cy3218-btns. ++ To change poll interval, invoque poll parameter in msecs. ++ + endif +Index: linux-2.6.27/drivers/input/misc/Makefile +=================================================================== +--- linux-2.6.27.orig/drivers/input/misc/Makefile ++++ linux-2.6.27/drivers/input/misc/Makefile +@@ -20,3 +20,5 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc. + obj-$(CONFIG_INPUT_UINPUT) += uinput.o + obj-$(CONFIG_INPUT_APANEL) += apanel.o + obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o ++obj-$(CONFIG_INPUT_CAPSENSE_BTNS) += cy3218-btns.o ++ diff --git a/packages/linux/linux-2.6.27/boc01/013-081216-lcd.patch b/packages/linux/linux-2.6.27/boc01/013-081216-lcd.patch deleted file mode 100644 index 271fd5f147..0000000000 --- a/packages/linux/linux-2.6.27/boc01/013-081216-lcd.patch +++ /dev/null @@ -1,735 +0,0 @@ -Index: linux-2.6.26-NEW/drivers/video/Kconfig -=================================================================== ---- linux-2.6.26-NEW.orig/drivers/video/Kconfig -+++ linux-2.6.26-NEW/drivers/video/Kconfig -@@ -480,6 +480,17 @@ 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_NOVA -+ tristate "Nova 7506 Monochrome LCD board support" -+ depends on FB -+ select FB_SYS_FILLRECT -+ select FB_SYS_COPYAREA -+ select FB_SYS_IMAGEBLIT -+ select FB_SYS_FOPS -+ help -+ This enables support for the Nova 7506 Monochrome LCD board. The board -+ is based on the NT7506 lcd controller. -+ - config FB_ATARI - bool "Atari native chipset support" - depends on (FB = y) && ATARI -Index: linux-2.6.26-NEW/drivers/video/Makefile -=================================================================== ---- linux-2.6.26-NEW.orig/drivers/video/Makefile -+++ linux-2.6.26-NEW/drivers/video/Makefile -@@ -13,8 +13,8 @@ fb-objs := $(f - - obj-$(CONFIG_VT) += console/ - obj-$(CONFIG_LOGO) += logo/ --obj-y += backlight/ display/ -- -+obj-y += backlight/ display/ -+obj-$(CONFIG_FB_NOVA) += N7506fb.o - obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o - obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o - obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o -Index: linux-2.6.26-NEW/drivers/video/N7506fb.c -=================================================================== ---- /dev/null -+++ linux-2.6.26-NEW/drivers/video/N7506fb.c -@@ -0,0 +1,655 @@ -+/* -+ * linux/drivers/video/N7506fb.c -- FB driver for Nova NT7506 monochrome LCD board -+ * -+ * Copyright (C) 2008, Alexandre Coffignal -+ * -+ * 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 Nova 7506 LCD board. -+ * -+ * -+ * -+ * -+ * Nova 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 -+ -+#define floor8(a) (a&(~0x07)) -+#define floorXres(a,xres) (a&(~(xres - 1))) -+#define iceil8(a) (((int)((a+7)/8))*8) -+#define ceil128(a) (a|0x7F) -+#define ceilXres(a,xres) (a|(xres - 1)) -+ -+//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_OSC 0xAB -+#define NT_RESET 0xE2 -+#define NT_DATA_DIR 0xe8 -+#define NT_FRC_PWM 0x90 -+#define PWM15 0x03 -+ -+#define ON 0x01 -+#define OFF 0x00 -+ -+// Geometric settings -+#define LCD_WIDTH 128 -+#define LCD_HEIGHT 128 -+#define LCD_NPAGES (LCD_HEIGHT/8) /* LCD pages of 8 vertical pixels */ -+ -+#define LINE_LENGTH (LCD_WIDTH/8) /* FB line size, 8 pixels per byte */ -+ -+#define CONTRASTE 0xF -+#define FRAME_PER_SECOND 5 -+ -+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 _refresh; -+static char _fps = FRAME_PER_SECOND; -+static char _backlight=1; -+ -+struct novafb_par { -+ atomic_t ref_count; -+ unsigned char cslut[9]; -+ struct fb_info *info; -+ unsigned int irq; -+ spinlock_t lock; -+}; -+ -+static struct fb_fix_screeninfo novafb_fix __initdata = { -+ .id = "novafb", -+ .type = FB_TYPE_PACKED_PIXELS, -+ .visual = FB_VISUAL_MONO01, -+ .xpanstep = 1, -+ .ypanstep = 1, -+ .ywrapstep = 0, -+ .line_length = LINE_LENGTH, -+ .accel = FB_ACCEL_NONE, -+}; -+ -+static struct fb_var_screeninfo novafb_var __initdata = { -+ .xres = LCD_WIDTH, -+ .yres = LCD_HEIGHT, -+ .xres_virtual = LCD_WIDTH, -+ .yres_virtual = LCD_HEIGHT, -+ .bits_per_pixel = 1, -+ .nonstd = 1, -+}; -+ -+ -+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 -+} -+ -+/* main novafb functions */ -+ -+static int novafb_open(struct fb_info *info, int user) -+{ -+ struct novafb_par *par = info->par; -+ atomic_inc(&par->ref_count); -+ return 0; -+} -+ -+static int novafb_release(struct fb_info *info, int user) -+{ -+ struct novafb_par *par = info->par; -+ int count = atomic_read(&par->ref_count); -+ if (!count) -+ return -EINVAL; -+ atomic_dec(&par->ref_count); -+ return 0; -+} -+ -+static int novafb_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 novafb_lcd_update(struct novafb_par *par, unsigned int dx, -+ unsigned int dy, unsigned int w, unsigned int h) -+{ -+ int bit,x,y,xfb,yfb,i; -+ char mask=0; -+ char dest[LCD_WIDTH * LCD_NPAGES]; -+ char * src; -+ char value; -+ src = (unsigned char __force *) par->info->screen_base; -+ for(i=0;ipar; -+ -+ int xfb,yfb,i=0; -+ char * src = (unsigned char __force *) par->info->screen_base; -+ -+ for(yfb=image->dy;yfb<(image->height+image->dy);yfb++) -+ { -+ for(xfb=(image->dx)/8;xfb<(image->dx+image->width)/8;xfb++) -+ { -+ src[yfb*16+xfb]=image->data[i++]; -+ } -+ } -+ -+} -+ -+/* -+ * 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 novafb_write(struct fb_info *info, const char __user *buf, -+ size_t count, loff_t *ppos) -+{ -+ unsigned long p; -+ int err=-EINVAL; -+ unsigned int fbmemlength ; -+ struct novafb_par *par; -+ unsigned int xres; -+ p = *ppos; -+ par = info->par; -+ xres = info->var.xres; -+ fbmemlength = (xres * info->var.yres)/8; -+ -+ if (p > fbmemlength) -+ { -+ return -ENOSPC; -+ } -+ err = 0; -+ if ((count + p) > fbmemlength) { -+ count = fbmemlength - p; -+ err = -ENOSPC; -+ } -+ -+ if (count) { -+ char *base_addr; -+ base_addr = (char __force *)info->screen_base; -+ count -= copy_from_user(base_addr + p, buf, count); -+ *ppos += count; -+ err = -EFAULT; -+ } -+ if (count) -+ { -+ return count; -+ } -+ return err; -+} -+ -+static int novafb_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 novafb_ioctl(struct fb_info *info, -+ unsigned int cmd, unsigned long arg) -+{ -+ unsigned char contrast; -+ unsigned char frame_rate; -+ unsigned char backlight; -+ 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; -+ } -+ case FBIO_CONTRAST: -+ { -+ _refresh=0; -+ if (get_user(contrast, (unsigned char *)arg)) -+ return -EFAULT; -+ printk(KERN_INFO "fb%d: contrast=%d\n", info->node, contrast); -+ NT7506_writeb_ctl(NT_ELEC_VOL); NT7506_writeb_ctl(contrast); -+ _refresh=1; -+ return 0; -+ } -+ case FBIO_BACKLIGHT: -+ { -+ _refresh=0; -+ if (get_user(backlight, (unsigned char *)arg)) -+ return -EFAULT; -+ if(backlight) -+ { -+ printk(KERN_INFO "fb%d: Backlight ON\n", info->node); -+ _backlight=1; -+ } -+ else -+ { -+ printk(KERN_INFO "fb%d: Backlight OFF\n", info->node); -+ _backlight=0; -+ } -+ _refresh=1; -+ return 0; -+ -+ } -+ -+ -+ default: -+ return -EINVAL; -+ } -+ -+} -+ -+static struct fb_ops novafb_ops = { -+ .owner = THIS_MODULE, -+ .fb_open = novafb_open, -+ .fb_read = fb_sys_read, -+ .fb_write = novafb_write, -+ .fb_release = novafb_release, -+ .fb_pan_display = novafb_pan_display, -+ .fb_fillrect = novafb_fillrect, -+ .fb_copyarea = novafb_copyarea, -+ .fb_imageblit = novafb_imageblit, -+ .fb_ioctl = novafb_ioctl, -+ .fb_mmap =novafb_mmap, -+}; -+ -+ -+static void -+novafb_refresh(unsigned long ignore_me) -+{ -+ struct novafb_par *par = info->par; -+ if ( _refresh ) { -+ novafb_lcd_update(par, 0, 0, LCD_WIDTH, LCD_HEIGHT); -+ } -+ -+ fb_timer.expires = jiffies + (HZ/_fps); -+ add_timer(&fb_timer); -+} -+ -+static int -+__init novafb_probe(struct platform_device *dev) -+{ -+ -+ int retval = -ENOMEM; -+ char * src; -+ int i; -+ -+ struct novafb_par *par; -+ static unsigned char *videomemory; -+ static int videomemorysize; -+ -+ NT7506_init_lcd(CONTRASTE); -+ -+ videomemorysize = (LCD_WIDTH * LINE_LENGTH) * 2; -+ -+ if (!(videomemory = kmalloc(videomemorysize,GFP_ATOMIC))) -+ return retval; -+ memset(videomemory, 0, videomemorysize); -+ -+ info = framebuffer_alloc(sizeof(struct novafb_par), &dev->dev); -+ -+ if (!info) -+ goto err; -+ info->screen_base = (char __iomem *)videomemory; -+ info->fbops = &novafb_ops; -+ -+ info->var = novafb_var; -+ info->fix = novafb_fix; -+ info->fix.smem_start=(unsigned long)videomemory; -+ info->fix.smem_len = videomemorysize; -+ -+ par = info->par; -+ par->info = info; -+ par->cslut[0] = 0x00; -+ par->cslut[1] = 0x06; -+ src = (unsigned char __force *) par->info->screen_base; -+ for(i=0;iflags = FBINFO_FLAG_DEFAULT; -+ spin_lock_init(&par->lock); -+ platform_set_drvdata(dev, info); -+ retval = register_framebuffer(info); -+ if (retval < 0) -+ goto err1; -+ -+ init_timer(&fb_timer); -+ fb_timer.function = novafb_refresh; -+ fb_timer.expires = jiffies + (HZ / _fps); -+ add_timer(&fb_timer); -+ -+ printk(KERN_INFO -+ "fb%d: nova frame buffer device, using %dK of video memory\n", -+ info->node, videomemorysize >> 10); -+ return 0; -+err1: -+ framebuffer_release(info); -+err: -+ vfree(videomemory); -+ return retval; -+} -+ -+static int novafb_remove(struct platform_device *dev) -+{ -+ struct fb_info *info = platform_get_drvdata(dev); -+ -+ if (info) { -+ unregister_framebuffer(info); -+ vfree((void __force *)info->screen_base); -+ framebuffer_release(info); -+ } -+ return 0; -+} -+ -+static struct platform_driver novafb_driver = { -+ .probe = novafb_probe, -+ .remove = novafb_remove, -+ .driver = { -+ .name = "novafb", -+ }, -+}; -+ -+static struct platform_device *novafb_device; -+ -+static int __init novafb_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(&novafb_driver); -+ -+ if (!ret) { -+ novafb_device = platform_device_alloc("novafb", 0); -+ if (novafb_device) -+ { -+ ret = platform_device_add(novafb_device); -+ } -+ else -+ { -+ ret = -ENOMEM; -+ } -+ if (ret) -+ { -+ platform_device_put(novafb_device); -+ platform_driver_unregister(&novafb_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); -+ /* 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); -+ _refresh=1; -+} -+ -+static void __exit novafb_exit(void) -+{ -+ if (lcd_mem) -+ release_mem_region(LCD_BASE, LCD_SIZE); -+ lcd_mem = NULL; -+ platform_device_unregister(novafb_device); -+ platform_driver_unregister(&novafb_driver); -+} -+ -+module_param(tuhold, ulong, 0); -+MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Nova board"); -+ -+module_init(novafb_init); -+module_exit(novafb_exit); -+ -+MODULE_DESCRIPTION("fbdev driver for nova NT7506 monochrome LCD board"); -+MODULE_AUTHOR("Alexandre Coffignal"); -+MODULE_LICENSE("GPL"); -+ -Index: linux-2.6.26-NEW/include/linux/NT7506.h -=================================================================== ---- /dev/null -+++ linux-2.6.26-NEW/include/linux/NT7506.h -@@ -0,0 +1,33 @@ -+ -+/* -+ * (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_NOVAFB_H__ -+#define __LINUX_NOVAFB_H__ -+ -+#define FBIO_FRAMERATE _IOR('f', 1, char) -+#define FBIO_CONTRAST _IOR('f', 2, char) -+#define FBIO_BACKLIGHT _IOR('f', 3, char) -+ -+#endif diff --git a/packages/linux/linux-2.6.27/boc01/013-081224-lcd.patch b/packages/linux/linux-2.6.27/boc01/013-081224-lcd.patch new file mode 100644 index 0000000000..e592615b0c --- /dev/null +++ b/packages/linux/linux-2.6.27/boc01/013-081224-lcd.patch @@ -0,0 +1,808 @@ +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,19 @@ 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_NOVA ++ tristate "Nova 7506 Monochrome 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 enables support for the Nova 7506 Monochrome LCD board. The board ++ is based on the NT7506 lcd controller. ++ + 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 +@@ -13,8 +13,8 @@ fb-objs := $(f + + obj-$(CONFIG_VT) += console/ + obj-$(CONFIG_LOGO) += logo/ +-obj-y += backlight/ display/ +- ++obj-y += backlight/ display/ ++obj-$(CONFIG_FB_NOVA) += N7506fb.o + obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o + obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o + obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o +Index: linux-2.6.27/drivers/video/N7506fb.c +=================================================================== +--- /dev/null ++++ linux-2.6.27/drivers/video/N7506fb.c +@@ -0,0 +1,728 @@ ++/* ++ * linux/drivers/video/N7506fb.c -- FB driver for Nova NT7506 monochrome LCD board ++ * ++ * Copyright (C) 2008, CenoSYS (www.cenosys.com). ++ * ++ * Alexandre Coffignal ++ * Sylvain Giroudon ++ * ++ * 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 Nova 7506 LCD board. ++ * ++ * ++ * ++ * ++ * Nova 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 ++ ++#include ++ ++#define DRIVER_NAME "novafb" ++ ++#define floor8(a) (a&(~0x07)) ++#define floorXres(a,xres) (a&(~(xres - 1))) ++#define iceil8(a) (((int)((a+7)/8))*8) ++#define ceil128(a) (a|0x7F) ++#define ceilXres(a,xres) (a|(xres - 1)) ++ ++//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_OSC 0xAB ++#define NT_RESET 0xE2 ++#define NT_DATA_DIR 0xe8 ++#define NT_FRC_PWM 0x90 ++#define PWM15 0x03 ++ ++#define ON 0x01 ++#define OFF 0x00 ++ ++// Geometric settings ++#define LCD_WIDTH 128 ++#define LCD_HEIGHT 128 ++#define LCD_NPAGES (LCD_HEIGHT/8) /* LCD pages of 8 vertical pixels */ ++ ++#define LINE_LENGTH (LCD_WIDTH/8) /* FB line size, 8 pixels per byte */ ++ ++#define DEFAULT_CONTRAST 20 ++#define DEFAULT_FPS 5 ++ ++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 _refresh = 0; ++static char _fps = DEFAULT_FPS; ++static char _backlight = 1; ++ ++struct novafb_par { ++ atomic_t ref_count; ++ struct fb_info *info; ++ spinlock_t lock; ++ struct lcd_device *lcd_dev; ++ int contrast; ++}; ++ ++static struct fb_fix_screeninfo novafb_fix __initdata = { ++ .id = DRIVER_NAME, ++ .type = FB_TYPE_PACKED_PIXELS, ++ .visual = FB_VISUAL_MONO01, ++ .xpanstep = 1, ++ .ypanstep = 1, ++ .ywrapstep = 0, ++ .line_length = LINE_LENGTH, ++ .accel = FB_ACCEL_NONE, ++}; ++ ++static struct fb_var_screeninfo novafb_var __initdata = { ++ .xres = LCD_WIDTH, ++ .yres = LCD_HEIGHT, ++ .xres_virtual = LCD_WIDTH, ++ .yres_virtual = LCD_HEIGHT, ++ .bits_per_pixel = 1, ++ .nonstd = 1, ++}; ++ ++ ++/* ++ * 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 ++novafb_lcd_get_contrast(struct lcd_device *lcd_dev) ++{ ++ struct novafb_par *par = lcd_get_data(lcd_dev); ++ return par->contrast; ++} ++ ++static int ++novafb_lcd_set_contrast(struct lcd_device *lcd_dev, int contrast) ++{ ++ struct novafb_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 novafb_lcd_ops = { ++ .get_contrast = novafb_lcd_get_contrast, ++ .set_contrast = novafb_lcd_set_contrast, ++}; ++ ++static void ++novafb_lcd_init(struct novafb_par *par) ++{ ++ struct fb_info *info = par->info; ++ struct lcd_device *lcd_dev; ++ ++ lcd_dev = lcd_device_register(DRIVER_NAME, info->dev, par, &novafb_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 ++novafb_lcd_exit(struct novafb_par *par) ++{ ++ if ( par->lcd_dev ) { ++ lcd_device_unregister(par->lcd_dev); ++ par->lcd_dev = NULL; ++ } ++} ++ ++ ++/* ++ * Backlight device management ++ */ ++ ++static int ++novafb_bl_update_status(struct backlight_device *bd) ++{ ++ _refresh = 0; ++ ++ if (bd->props.power != FB_BLANK_UNBLANK || ++ bd->props.fb_blank != FB_BLANK_UNBLANK) ++ _backlight = 0; ++ else ++ _backlight = bd->props.brightness; ++ ++ _refresh = 1; ++ ++ //printk(KERN_INFO DRIVER_NAME": backlight = %d\n", _backlight); ++ return 0; ++} ++ ++static int ++novafb_bl_get_brightness(struct backlight_device *bd) ++{ ++ return bd->props.brightness; ++} ++ ++static struct backlight_ops novafb_bl_ops = { ++ .get_brightness = novafb_bl_get_brightness, ++ .update_status = novafb_bl_update_status, ++}; ++ ++ ++static void ++novafb_bl_init(struct novafb_par *par) ++{ ++ struct fb_info *info = par->info; ++ struct backlight_device *bd; ++ ++ bd = backlight_device_register(DRIVER_NAME, info->dev, par, &novafb_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; ++ novafb_bl_update_status(bd); ++ ++ printk(KERN_INFO DRIVER_NAME ": Backlight control initialized\n"); ++} ++ ++static void ++novafb_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 novafb_open(struct fb_info *info, int user) ++{ ++ struct novafb_par *par = info->par; ++ atomic_inc(&par->ref_count); ++ return 0; ++} ++ ++static int novafb_release(struct fb_info *info, int user) ++{ ++ struct novafb_par *par = info->par; ++ int count = atomic_read(&par->ref_count); ++ if (!count) ++ return -EINVAL; ++ atomic_dec(&par->ref_count); ++ return 0; ++} ++ ++static int novafb_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 novafb_lcd_update(struct novafb_par *par) ++{ ++ unsigned char *src = (unsigned char __force *) par->info->screen_base; ++ unsigned char dest[LCD_WIDTH * LCD_NPAGES]; ++ int x, y; ++ ++ for (x = 0; x < LCD_WIDTH; x++) { ++ int xfb = x / 8; ++ ++ for(y = 0; y < LCD_NPAGES; y++) { ++ int i = (y * LCD_WIDTH) + x; ++ int yfb = y * 8; ++ int bit; ++ ++ dest[i] = 0; ++ ++ for (bit = 0; bit < 8; yfb++, bit++) { ++ int ifb = (yfb * LINE_LENGTH) + xfb; ++ unsigned char mask = (1 << (7-(x%8))); ++ unsigned char value = (src[ifb] & mask) ? 1:0; ++ ++ dest[i] += (value<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 novafb_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 novafb_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 novafb_ops = { ++ .owner = THIS_MODULE, ++ .fb_open = novafb_open, ++ .fb_read = fb_sys_read, ++ .fb_write = novafb_write, ++ .fb_release = novafb_release, ++ .fb_pan_display = novafb_pan_display, ++ .fb_fillrect = novafb_fillrect, ++ .fb_copyarea = novafb_copyarea, ++ .fb_imageblit = novafb_imageblit, ++ .fb_ioctl = novafb_ioctl, ++ .fb_mmap = novafb_mmap, ++}; ++ ++ ++static void ++novafb_refresh(unsigned long ignore_me) ++{ ++ struct novafb_par *par = info->par; ++ if ( _refresh ) { ++ novafb_lcd_update(par); ++ } ++ ++ fb_timer.expires = jiffies + (HZ/_fps); ++ add_timer(&fb_timer); ++} ++ ++static int __init ++novafb_probe(struct platform_device *dev) ++{ ++ int retval = -ENOMEM; ++ struct novafb_par *par; ++ static unsigned char *videomemory; ++ static int videomemorysize; ++ ++ NT7506_init_lcd(DEFAULT_CONTRAST); ++ ++ videomemorysize = (LINE_LENGTH * LCD_HEIGHT) * 2; ++ ++ if (!(videomemory = kmalloc(videomemorysize,GFP_ATOMIC))) ++ goto failout; ++ memset(videomemory, 0, videomemorysize); ++ ++ info = framebuffer_alloc(sizeof(struct novafb_par), &dev->dev); ++ ++ if (!info) ++ goto out_alloc; ++ info->screen_base = (char __iomem *)videomemory; ++ info->fbops = &novafb_ops; ++ ++ info->var = novafb_var; ++ info->fix = novafb_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); ++ retval = register_framebuffer(info); ++ if (retval < 0) ++ goto out_register; ++ ++ init_timer(&fb_timer); ++ fb_timer.function = novafb_refresh; ++ fb_timer.expires = jiffies + (HZ / _fps); ++ add_timer(&fb_timer); ++ ++ printk(KERN_INFO ++ "fb%d: nova 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) */ ++ novafb_bl_init(par); ++ novafb_lcd_init(par); ++ ++ return 0; ++ ++out_register: ++ framebuffer_release(info); ++out_alloc: ++ vfree(videomemory); ++failout: ++ return retval; ++} ++ ++static int novafb_remove(struct platform_device *dev) ++{ ++ struct fb_info *info = platform_get_drvdata(dev); ++ ++ if (info) { ++ novafb_lcd_exit(info->par); ++ novafb_bl_exit(info); ++ unregister_framebuffer(info); ++ vfree((void __force *)info->screen_base); ++ framebuffer_release(info); ++ } ++ return 0; ++} ++ ++static struct platform_driver novafb_driver = { ++ .probe = novafb_probe, ++ .remove = novafb_remove, ++ .driver = { ++ .name = DRIVER_NAME, ++ }, ++}; ++ ++static struct platform_device *novafb_device; ++ ++static int __init novafb_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(&novafb_driver); ++ ++ if (!ret) { ++ novafb_device = platform_device_alloc(DRIVER_NAME, 0); ++ if (novafb_device) ++ { ++ ret = platform_device_add(novafb_device); ++ } ++ else ++ { ++ ret = -ENOMEM; ++ } ++ if (ret) ++ { ++ platform_device_put(novafb_device); ++ platform_driver_unregister(&novafb_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); ++ /* 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); ++ _refresh=1; ++} ++ ++static void __exit novafb_exit(void) ++{ ++ if (lcd_mem) ++ release_mem_region(LCD_BASE, LCD_SIZE); ++ lcd_mem = NULL; ++ platform_device_unregister(novafb_device); ++ platform_driver_unregister(&novafb_driver); ++} ++ ++module_param(tuhold, ulong, 0); ++MODULE_PARM_DESC(tuhold, "Time to hold between strobing data to Nova board"); ++ ++module_init(novafb_init); ++module_exit(novafb_exit); ++ ++MODULE_DESCRIPTION("fbdev driver for nova NT7506 monochrome LCD board"); ++MODULE_AUTHOR("Alexandre Coffignal"); ++MODULE_LICENSE("GPL"); ++ +Index: linux-2.6.27/include/linux/NT7506.h +=================================================================== +--- /dev/null ++++ linux-2.6.27/include/linux/NT7506.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_NOVAFB_H__ ++#define __LINUX_NOVAFB_H__ ++ ++#define FBIO_FRAMERATE _IOR('f', 1, char) ++ ++#endif diff --git a/packages/linux/linux-2.6.27/boc01/defconfig b/packages/linux/linux-2.6.27/boc01/defconfig index bdca6aa1de..60bf9b9000 100644 --- a/packages/linux/linux-2.6.27/boc01/defconfig +++ b/packages/linux/linux-2.6.27/boc01/defconfig @@ -1302,7 +1302,7 @@ CONFIG_FB_SYS_IMAGEBLIT=y CONFIG_FB_SYS_FOPS=y # CONFIG_FB_SVGALIB is not set # CONFIG_FB_MACMODES is not set -# CONFIG_FB_BACKLIGHT is not set +CONFIG_FB_BACKLIGHT=y # CONFIG_FB_MODE_HELPERS is not set # CONFIG_FB_TILEBLITTING is not set @@ -1340,7 +1340,14 @@ CONFIG_FB_NOVA=y # CONFIG_FB_FSL_DIU is not set # CONFIG_FB_IBM_GXT4500 is not set # CONFIG_FB_VIRTUAL is not set -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +# CONFIG_LCD_LTV350QV is not set +# CONFIG_LCD_ILI9320 is not set +# CONFIG_LCD_VGG2432A4 is not set +# CONFIG_LCD_PLATFORM is not set +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_CORGI is not set # # Display device support @@ -1438,7 +1445,7 @@ CONFIG_USB_OHCI_HCD_PCI=y CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y CONFIG_USB_OHCI_LITTLE_ENDIAN=y -CONFIG_USB_UHCI_HCD=y +# CONFIG_USB_UHCI_HCD is not set # CONFIG_USB_SL811_HCD is not set # CONFIG_USB_R8A66597_HCD is not set diff --git a/packages/linux/linux_2.6.27.bb b/packages/linux/linux_2.6.27.bb index e490afe511..cf064d3523 100644 --- a/packages/linux/linux_2.6.27.bb +++ b/packages/linux/linux_2.6.27.bb @@ -1,5 +1,7 @@ require linux.inc +PR = "r1" + # Mark archs/machines that this kernel supports DEFAULT_PREFERENCE = "-1" DEFAULT_PREFERENCE_boc01 = "1" @@ -18,8 +20,8 @@ SRC_URI_append_boc01 = "\ file://008-081208-spi.patch;patch=1 \ file://010-081208-mii.patch;patch=1 \ file://011-081218-gpio.patch;patch=1 \ - file://012-081222-cy3218-btns.patch;patch=1 \ - file://013-081216-lcd.patch;patch=1 \ + file://012-081223-cy3218-btns.patch;patch=1 \ + file://013-081224-lcd.patch;patch=1 \ " SRC_URI_append_progear = "file://progear-bl.patch;patch=1\ -- cgit v1.2.3