From 47e3f7bc0ec31948832e410f2a4cc201c81e04a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jeremy=20Lain=C3=A9?= <jeremy.laine@m4x.org>
Date: Mon, 19 Oct 2009 16:19:05 +0200
Subject: linux-2.6.29: update boc01 capsense driver to new i2c style

---
 .../linux-2.6.29/boc01/012-090219-capsense.patch   | 883 ---------------------
 .../linux-2.6.29/boc01/012-091019-capsense.patch   | 867 ++++++++++++++++++++
 recipes/linux/linux-2.6.29/boc01/boc01.dts         |   4 +
 recipes/linux/linux-2.6.29/boc01/boc01.dts.v1      |   4 +
 4 files changed, 875 insertions(+), 883 deletions(-)
 delete mode 100644 recipes/linux/linux-2.6.29/boc01/012-090219-capsense.patch
 create mode 100644 recipes/linux/linux-2.6.29/boc01/012-091019-capsense.patch

(limited to 'recipes/linux/linux-2.6.29/boc01')

diff --git a/recipes/linux/linux-2.6.29/boc01/012-090219-capsense.patch b/recipes/linux/linux-2.6.29/boc01/012-090219-capsense.patch
deleted file mode 100644
index ce4af93e3a..0000000000
--- a/recipes/linux/linux-2.6.29/boc01/012-090219-capsense.patch
+++ /dev/null
@@ -1,883 +0,0 @@
-Index: linux-2.6.29/drivers/input/misc/Kconfig
-===================================================================
---- linux-2.6.29.orig/drivers/input/misc/Kconfig	2009-03-24 00:12:14.000000000 +0100
-+++ linux-2.6.29/drivers/input/misc/Kconfig	2009-04-01 17:38:02.000000000 +0200
-@@ -227,4 +227,13 @@
- 	 Say Y to include support for delivering  PMU events via  input
- 	 layer on NXP PCF50633.
- 
-+config INPUT_CAPSENSE_BTNS
-+	tristate "CAPSENSE CY8C201xx buttons interface"
-+	select INPUT_POLLDEV
-+	select LEDS_CLASS
-+	help
-+	  To compile this driver as a module, choose M here:
-+	  the module will be called capsense-btns.
-+	  To change poll interval, invoque poll parameter in msecs.
-+
- endif
-Index: linux-2.6.29/drivers/input/misc/Makefile
-===================================================================
---- linux-2.6.29.orig/drivers/input/misc/Makefile	2009-03-24 00:12:14.000000000 +0100
-+++ linux-2.6.29/drivers/input/misc/Makefile	2009-04-01 17:38:23.000000000 +0200
-@@ -22,3 +22,4 @@
- obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
- obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
- obj-$(CONFIG_INPUT_PCF50633_PMU)	+= pcf50633-input.o
-+obj-$(CONFIG_INPUT_CAPSENSE_BTNS)	+= capsense-btns.o
-Index: linux-2.6.29/drivers/input/misc/capsense-btns.c
-===================================================================
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.29/drivers/input/misc/capsense-btns.c	2009-04-01 17:38:02.000000000 +0200
-@@ -0,0 +1,456 @@
-+/*
-+ * CAPSENSE Interface driver
-+ *
-+ *
-+ * Copyright (C) 2008, CenoSYS (www.cenosys.com).
-+ *
-+ * Guillaume Ligneul <guillaume.ligneul@gmail.com>
-+ * Jeremy Lainé <jeremy.laine@bolloretelecom.eu>
-+ * Sylvain Giroudon <sylvain.giroudon@goobie.fr>
-+ *
-+ * 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 <linux/init.h>
-+#include <linux/input-polldev.h>
-+#include <linux/ioport.h>
-+#include <linux/module.h>
-+#include <linux/i2c.h>
-+#include <linux/leds.h>
-+
-+
-+static int capsense_attach_adapter(struct i2c_adapter *adapter);
-+static int capsense_detach_client(struct i2c_client *client);
-+#ifdef CONFIG_PM
-+static int capsense_suspend(struct i2c_client *client, pm_message_t mesg);
-+static int capsense_resume(struct i2c_client *client);
-+#endif
-+
-+#define DRIVER_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_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))
-+
-+#define CAP_CS(command,port,bit)     ((command)+(5*(port))+(bit))
-+#define CAP_CS_FINGER_TH(port,bit)   CAP_CS(0x61,port,bit)
-+#define CAP_CS_IDAC(port,bit)        CAP_CS(0x6B,port,bit)
-+
-+#define CAP_DEVICE_ID           0x7A
-+#define CAP_DEVICE_STATUS       0x7B
-+#define CAP_I2C_ADDR_DM         0x7C
-+
-+#define CAP_COMMAND_REG         0xA0
-+#define CAP_COMMAND_STORE_NVM        0x01
-+#define CAP_COMMAND_RESTORE_FACTORY  0x02
-+#define CAP_COMMAND_RECONFIGURE      0x06
-+#define CAP_COMMAND_NORMAL_MODE      0x07
-+#define CAP_COMMAND_SETUP_MODE       0x08
-+
-+#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	= DRIVER_NAME,
-+	},
-+	.id		= I2C_DRIVERID_CAPSENSE,
-+	.attach_adapter = &capsense_attach_adapter,
-+	.detach_client	= &capsense_detach_client,
-+#ifdef CONFIG_PM
-+	.suspend        = &capsense_suspend,
-+	.resume         = &capsense_resume,
-+#endif
-+};
-+
-+struct capsense_led {
-+	struct led_classdev cdev;
-+	struct capsense_ctx *capsense;
-+	int port;
-+	int bit;
-+};
-+
-+struct capsense_ctx {
-+	struct input_polled_dev *ipdev;
-+	struct i2c_client client;
-+	unsigned char key_state;
-+	struct capsense_led leds[CAP_NLEDS];
-+	unsigned char led_state[2];
-+	struct mutex mutex;
-+};
-+
-+static unsigned short input_keymap[] = {
-+	// GP0
-+	KEY_F1,
-+	KEY_ENTER,
-+	KEY_DOWN,
-+	KEY_BACKSPACE,
-+	// GP1
-+	KEY_UP,
-+};
-+
-+struct capsense_keymap {
-+	char *name;
-+	int port, bit;
-+};
-+
-+static struct capsense_keymap phys_keymap[] = {
-+	{ "info", 0, 4 },
-+	{ "ok",   0, 2 },
-+	{ "down", 0, 3 },
-+	{ "back", 0, 0 },
-+	{ "up",   1, 4 },
-+};
-+
-+
-+struct capsense_ledmap {
-+	char *name;
-+	int port, bit;
-+};
-+
-+static struct capsense_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 },
-+};
-+
-+
-+/*
-+ * Buttons events handling
-+ */
-+
-+static void handle_buttons(struct input_polled_dev *dev)
-+{
-+	struct capsense_ctx *capsense = dev->private;
-+	u8 port_value;
-+	u8 new_state = 0;
-+	int port;
-+	u8 changed;
-+	int i;
-+
-+	mutex_lock(&capsense->mutex);
-+
-+	// read status
-+	port = -1;
-+	port_value = 0;
-+	for (i = 0; i < ARRAY_SIZE(phys_keymap); i++) {
-+		if ( phys_keymap[i].port != port ) {
-+			port = phys_keymap[i].port;
-+			port_value = i2c_smbus_read_byte_data(&capsense->client, CAP_READ_STATUS(port));
-+		}
-+
-+		if ( port_value & (1 << phys_keymap[i].bit) )
-+			new_state |= (1 << i);
-+	}
-+
-+	mutex_unlock(&capsense->mutex);
-+
-+	// update keyboard state
-+	changed = capsense->key_state ^ new_state;
-+	for (i = 0; i < ARRAY_SIZE(input_keymap); i++)
-+		if (changed & (1 << i))
-+			input_report_key(dev->input, input_keymap[i], (new_state & (1 << i)));
-+	capsense->key_state = new_state;
-+	input_sync(dev->input);
-+}
-+
-+
-+/*
-+ * LEDs management
-+ */
-+
-+static void
-+capsense_led_set(struct led_classdev *led_cdev,
-+		 enum led_brightness value)
-+{
-+	struct capsense_led *led = (struct capsense_led *) led_cdev;
-+	struct capsense_ctx *capsense = led->capsense;
-+	int port = led->port;
-+	unsigned char mask = (1 << led->bit);
-+
-+	if ( value )
-+		capsense->led_state[port] |= mask;
-+	else
-+		capsense->led_state[port] &= ~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 void
-+capsense_led_enable(struct capsense_led *led, int state)
-+{
-+	struct capsense_ctx *capsense = led->capsense;
-+
-+	mutex_lock(&capsense->mutex);
-+	i2c_smbus_write_byte_data(&capsense->client, CAP_OP_SEL(led->port, led->bit), state ? 0x00 : 0x80);
-+	mutex_unlock(&capsense->mutex);
-+}
-+
-+static int
-+capsense_led_init(struct capsense_ctx *capsense)
-+{
-+	int i;
-+	int ret;
-+
-+	for (i = 0; i < CAP_NLEDS; i++) {
-+		struct capsense_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->bit = ledmap[i].bit;
-+
-+		ret = led_classdev_register(&capsense->ipdev->input->dev, &led->cdev);
-+		if ( ret < 0 )
-+			return -1;
-+
-+		capsense_led_enable(led, 1);
-+	}
-+
-+	/* Switch all leds off */
-+	mutex_lock(&capsense->mutex);
-+
-+	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);
-+
-+	mutex_unlock(&capsense->mutex);
-+
-+	return 0;
-+}
-+
-+
-+static void
-+capsense_led_exit(struct capsense_ctx *capsense)
-+{
-+	int i;
-+
-+	for (i = 0; i < CAP_NLEDS; i++) {
-+		led_classdev_unregister(&capsense->leds[i].cdev);
-+	}
-+}
-+
-+
-+static inline void
-+capsense_led_suspend(struct capsense_ctx *capsense)
-+{
-+	int i;
-+
-+	for (i = 0; i < CAP_NLEDS; i++) {
-+		struct capsense_led *led = &(capsense->leds[i]);
-+
-+		led_classdev_suspend(&led->cdev);
-+		capsense_led_enable(led, 0);
-+	}
-+}
-+
-+
-+static inline void
-+capsense_led_resume(struct capsense_ctx *capsense)
-+{
-+	int i;
-+
-+	for (i = 0; i < CAP_NLEDS; i++) {
-+		struct capsense_led *led = &(capsense->leds[i]);
-+
-+		capsense_led_enable(led, 1);
-+		led_classdev_resume(&led->cdev);
-+	}
-+}
-+
-+
-+/*
-+ * Device configuration through procfs entries
-+ */
-+
-+#ifdef CONFIG_PROC_FS
-+#include "capsense-procfs.c"
-+#endif
-+
-+
-+/*
-+ * Device initialisation
-+ */
-+
-+static int
-+capsense_probe(struct i2c_adapter *adapter, int addr, int kind)
-+{
-+	struct capsense_ctx *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, DRIVER_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 = input_keymap;
-+	input->keycodemax = ARRAY_SIZE(input_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(input_keymap); i++)
-+		set_bit(input_keymap[i], ipdev->input->keybit);
-+
-+	rc = input_register_polled_device(ipdev);
-+	if(rc)
-+		goto out_polled;
-+
-+	if ( capsense_led_init(capsense) )
-+		goto out_registered;
-+
-+#ifdef CONFIG_PROC_FS
-+	/* Create /proc entries for hardware device configuration */
-+	capsense_proc_init(capsense);
-+#endif
-+
-+	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 capsense_ctx *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;
-+}
-+
-+
-+/*
-+ * Power management
-+ */
-+
-+#ifdef CONFIG_PM
-+static int capsense_suspend(struct i2c_client *client, pm_message_t mesg)
-+{
-+	struct capsense_ctx *capsense = i2c_get_clientdata(client);
-+
-+	printk(KERN_INFO DRIVER_NAME ": suspend\n");
-+
-+	capsense_led_suspend(capsense);
-+
-+	return 0;
-+}
-+
-+static int capsense_resume(struct i2c_client *client)
-+{
-+	struct capsense_ctx *capsense = i2c_get_clientdata(client);
-+
-+	printk(KERN_INFO DRIVER_NAME ": resume\n");
-+
-+	capsense_led_resume(capsense);
-+
-+	return 0;
-+}
-+#endif
-+
-+
-+/*
-+ * Driver initialisation
-+ */
-+
-+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 <guillaume.ligneul@cenosys.com>");
-+MODULE_DESCRIPTION("Capsense CY8C201xx Input driver");
-+MODULE_LICENSE("GPL");
-+module_init(capsense_buttons_init);
-+module_exit(capsense_buttons_exit);
-Index: linux-2.6.29/drivers/input/misc/capsense-procfs.c
-===================================================================
---- /dev/null	1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.29/drivers/input/misc/capsense-procfs.c	2009-04-01 17:38:02.000000000 +0200
-@@ -0,0 +1,390 @@
-+/*
-+ * CAPSENSE Interface driver
-+ * Device setup using procfs
-+ *
-+ * Copyright (C) 2008, Goobie (www.goobie.fr).
-+ *
-+ * Sylvain Giroudon <sylvain.giroudon@goobie.fr>
-+ *
-+ * 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 <linux/proc_fs.h>
-+#include <linux/uaccess.h>
-+
-+
-+struct capsense_proc_data {
-+	struct capsense_ctx *capsense;
-+	struct capsense_keymap *phys;
-+	char *name;
-+	unsigned char command;
-+	unsigned char hex;
-+};
-+
-+struct capsense_proc_entry {
-+	char *name;
-+	unsigned char command;
-+	struct capsense_proc_data data[ARRAY_SIZE(phys_keymap)];
-+};
-+
-+static struct capsense_proc_entry capsense_proc_key_entries[] = {
-+	{ "CS_FINGER_TH", CAP_CS_FINGER_TH(0,0) },
-+	{ "CS_IDAC",      CAP_CS_IDAC(0,0)      },
-+};
-+
-+static struct capsense_proc_entry capsense_proc_device_entries[] = {
-+	{ "DEVICE_ID",     CAP_DEVICE_ID        },
-+	{ "DEVICE_STATUS", CAP_DEVICE_STATUS    },
-+};
-+
-+struct capsense_proc_command {
-+	char *name;
-+	unsigned char command;
-+	struct capsense_ctx *capsense;
-+};
-+
-+static struct capsense_proc_command capsense_proc_commands[] = {
-+	{ "store",       CAP_COMMAND_STORE_NVM       },
-+	//{ "factory",     CAP_COMMAND_RESTORE_FACTORY },
-+	//{ "reconfigure", CAP_COMMAND_RECONFIGURE     },
-+};
-+
-+
-+static int capsense_proc_read(char *page, char **start, off_t off, int count,
-+			      int *eof, void *_data)
-+{
-+	struct capsense_proc_data *data = _data;
-+	struct capsense_ctx *capsense = data->capsense;
-+	u8 value;
-+	int len;
-+
-+	mutex_lock(&capsense->mutex);
-+	value = i2c_smbus_read_byte_data(&capsense->client, data->command);
-+	mutex_unlock(&capsense->mutex);
-+
-+	if ( data->hex )
-+		len = sprintf(page, "%02X\n", value);
-+	else
-+		len = sprintf(page, "%u\n", value);
-+
-+	len -= off;
-+	if ( len < count ) {
-+		*eof = 1;
-+		if ( len <= 0 )
-+			return 0;
-+	} else {
-+		len = count;
-+	}
-+
-+	*start = page + off;
-+
-+	return len;
-+}
-+
-+
-+static int capsense_proc_write(struct file *file, const char *buf,
-+			       unsigned long count, void *_data)
-+{
-+	struct capsense_proc_data *data = _data;
-+	struct capsense_ctx *capsense = data->capsense;
-+	char lbuf[count+1];
-+	u8 value;
-+
-+	/* 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", &value) == 1 ) {
-+		mutex_lock(&capsense->mutex);
-+		i2c_smbus_write_byte_data(&capsense->client, CAP_COMMAND_REG, CAP_COMMAND_SETUP_MODE);
-+		i2c_smbus_write_byte_data(&capsense->client, data->command, value);
-+		i2c_smbus_write_byte_data(&capsense->client, CAP_COMMAND_REG, CAP_COMMAND_NORMAL_MODE);
-+		mutex_unlock(&capsense->mutex);
-+	}
-+	else {
-+		printk(KERN_INFO DRIVER_NAME ": [%s/%s] Syntax error in expression\n", data->phys->name, data->name);
-+		return -EINVAL;
-+	}
-+
-+	return count;
-+}
-+
-+
-+static inline char *str_skip_blanks(char *s)
-+{
-+	while ( (*s != '\0') && (*s <= ' ') )
-+		s++;
-+	return s;
-+}
-+
-+
-+static inline char *str_skip_chars(char *s)
-+{
-+	while ( *s > ' ' )
-+		s++;
-+	return s;
-+}
-+
-+
-+static int capsense_proc_write_iic(struct file *file, const char *buf,
-+				   unsigned long count, void *data)
-+{
-+	struct capsense_ctx *capsense = data;
-+	char lbuf[count+1];
-+	int lnum;
-+	char *s;
-+
-+	/* Only root can do this */
-+	if ( !capable(CAP_SYS_ADMIN) )
-+		return -EACCES;
-+
-+	printk(KERN_INFO DRIVER_NAME ": Reading configuration script from /proc/" DRIVER_NAME "/iic (%lu bytes)\n", count);
-+
-+	memset(lbuf, 0, sizeof(lbuf));
-+
-+	if (copy_from_user(lbuf, buf, count))
-+		return -EFAULT;
-+
-+	s = lbuf;
-+	lnum = 0;
-+
-+	while ( *s != '\0' ) {
-+		char *line;
-+		char operation;
-+		unsigned char data[255];
-+		int size;
-+		struct i2c_msg msg;
-+		int ret;
-+
-+		lnum++;
-+
-+		/* Spot the end of the line */
-+		line = s;
-+		while ( (*s != '\0') && (*s != '\n') )
-+			s++;
-+		if ( *s != '\0' )
-+			*(s++) = '\0';
-+
-+		//printk(KERN_INFO DRIVER_NAME ": iic:%d: '%s'\n", lnum, line);
-+
-+		/* Strip leading blank characters */
-+		line = str_skip_blanks(line);
-+
-+		/* Empty or commented line: skip! */
-+		if ( (*line == '\0') || (*line == '#') )
-+			continue;
-+
-+		/* Only accept write operations 'w' */
-+		operation = *(line++);
-+		if ( operation != 'w' ) {
-+			printk(KERN_ERR DRIVER_NAME ": iic:%d: Unknown operation '%c ...' -- skipped\n", lnum, operation);
-+			continue;
-+		}
-+
-+		/* Extract data values */
-+		size = 0;
-+		while ( (*line != '\0') && (size < sizeof(data)) ) {
-+			line = str_skip_blanks(line);
-+			if ( *line != '\0' )
-+				sscanf(line, "%hhx", &data[size++]);
-+			line = str_skip_chars(line);
-+		}
-+
-+		{
-+			int i;
-+
-+			printk(KERN_DEBUG DRIVER_NAME ": iic:%d: %c", lnum, operation);
-+			for (i = 0; i < size; i++)
-+				printk(" %02X", data[i]);
-+			printk("\n");
-+		}
-+
-+		/* Do nothing if there are less than 2 data bytes (address, command) */
-+		if ( size < 3 ) {
-+			printk(KERN_ERR DRIVER_NAME ": iic:%d: Too few data for operation '%c ...' -- skipped\n", lnum, operation);
-+			continue;
-+		}
-+
-+		/* First data byte is the i2c device address:
-+		   Warn if it does not match the standard i2c address */
-+		if ( data[0] != CAPSENSE_I2C_ADDR ) {
-+			printk(KERN_WARNING DRIVER_NAME ": iic:%d: WARNING - Specified i2c address (%02X) differs from standard i2c address (%02X)\n", lnum, data[0], CAPSENSE_I2C_ADDR);
-+		}
-+
-+		/* Second data byte is the capsense register:
-+		   Warn if changing the device I2C address */
-+		if ( data[1] == CAP_I2C_ADDR_DM ) {
-+			printk(KERN_WARNING DRIVER_NAME ": iic:%d: WARNING - Changing i2c address to %02X (I2C_ADDR_DM=%02X)\n", lnum, data[2] & 0x7F, data[2]);
-+		}
-+
-+		/* Send command to i2c device */
-+		mutex_lock(&capsense->mutex);
-+
-+		msg.addr = data[0];
-+		msg.flags = capsense->client.flags;
-+		msg.len = size - 1;
-+		msg.buf = data + 1;
-+		//printk(KERN_INFO DRIVER_NAME ": iic:%d: i2c transfer: addr=0x%02X flags=0x%04X len=%d\n", lnum, msg.addr, msg.flags, msg.len);
-+
-+		ret = i2c_transfer(capsense->client.adapter, &msg, 1);
-+		if ( ret < 0 )
-+			printk(KERN_ERR DRIVER_NAME ": iic:%d: i2c transfer failed (%d), command rejected\n", lnum, ret);
-+
-+		mutex_unlock(&capsense->mutex);
-+	}
-+
-+	return count;
-+}
-+
-+
-+static int capsense_proc_write_command(struct file *file, const char *buf,
-+				       unsigned long count, void *data)
-+{
-+	struct capsense_proc_command *command = data;
-+	struct capsense_ctx *capsense = command->capsense;
-+
-+	/* Only root can do this */
-+	if ( !capable(CAP_SYS_ADMIN) )
-+		return -EACCES;
-+
-+	printk(KERN_INFO DRIVER_NAME ": %s (%02X)\n", command->name, command->command);
-+
-+	mutex_lock(&capsense->mutex);
-+	i2c_smbus_write_byte_data(&capsense->client, CAP_COMMAND_REG, CAP_COMMAND_SETUP_MODE);
-+	i2c_smbus_write_byte_data(&capsense->client, CAP_COMMAND_REG, command->command);
-+	i2c_smbus_write_byte_data(&capsense->client, CAP_COMMAND_REG, CAP_COMMAND_NORMAL_MODE);
-+	mutex_unlock(&capsense->mutex);
-+
-+	return count;
-+}
-+
-+
-+static int capsense_proc_init(struct capsense_ctx *capsense)
-+{
-+	struct proc_dir_entry *root;
-+	struct proc_dir_entry *dir;
-+	struct proc_dir_entry *ent;
-+	int i;
-+
-+	/* Create capsense 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 iic config file dump entry */
-+	ent = create_proc_entry("iic", S_IFREG|S_IWUSR, root);
-+	if ( ent == NULL ) {
-+		printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/iic\n");
-+		return -1;
-+	}
-+
-+	ent->owner = THIS_MODULE;
-+	ent->data = capsense;
-+	ent->write_proc = capsense_proc_write_iic;
-+
-+	/* Create commands directory */
-+	dir = proc_mkdir("commands", root);
-+	if ( dir == NULL ) {
-+		printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/commands\n");
-+		return -1;
-+	}
-+
-+	dir->owner = THIS_MODULE;
-+
-+	/* Create command entries */
-+	for (i = 0; i < ARRAY_SIZE(capsense_proc_commands); i++) {
-+		struct capsense_proc_command *command = &capsense_proc_commands[i];
-+
-+		command->capsense = capsense;
-+
-+		ent = create_proc_entry(command->name, S_IFREG|S_IWUSR, dir);
-+		if ( ent == NULL ) {
-+			printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/commands/%s\n", command->name);
-+			return -1;
-+		}
-+
-+		ent->owner = THIS_MODULE;
-+		ent->data = command;
-+		ent->write_proc = capsense_proc_write_command;
-+	}
-+
-+	/* Create device status read entries */
-+	for (i = 0; i < ARRAY_SIZE(capsense_proc_device_entries); i++) {
-+		struct capsense_proc_entry *entry = &(capsense_proc_device_entries[i]);
-+		struct capsense_proc_data *data = &(entry->data[i]);
-+
-+		data->capsense = capsense;
-+		data->phys = NULL;
-+		data->name = entry->name;
-+		data->command = entry->command;
-+		data->hex = 1;
-+
-+		ent = create_proc_entry(entry->name, S_IFREG|S_IRUSR, root);
-+		if ( ent == NULL ) {
-+			printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/%s\n", entry->name);
-+			continue;
-+		}
-+
-+		ent->owner = THIS_MODULE;
-+		ent->data = data;
-+		ent->read_proc = capsense_proc_read;
-+	}
-+
-+	/* Create keys management directory */
-+	dir = proc_mkdir("keys", root);
-+	if ( dir == NULL ) {
-+		printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/keys\n");
-+		return -1;
-+	}
-+
-+	dir->owner = THIS_MODULE;
-+
-+	/* Create keys sensitivity adjustment entries */
-+	for (i = 0; i < ARRAY_SIZE(phys_keymap); i++) {
-+		struct capsense_keymap *phys = &phys_keymap[i];
-+		struct proc_dir_entry *subdir;
-+		int ientry;
-+
-+		subdir = proc_mkdir(phys->name, dir);
-+		if ( subdir == NULL ) {
-+			printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/keys/%s\n", phys->name);
-+			continue;
-+		}
-+
-+		for (ientry = 0; ientry < ARRAY_SIZE(capsense_proc_key_entries); ientry++) {
-+			struct capsense_proc_entry *entry = &(capsense_proc_key_entries[ientry]);
-+			struct capsense_proc_data *data = &(entry->data[i]);
-+
-+			data->capsense = capsense;
-+			data->phys = phys;
-+			data->name = entry->name;
-+			data->command = CAP_CS(entry->command, phys->port, phys->bit);
-+			data->hex = 0;
-+
-+			ent = create_proc_entry(entry->name, S_IFREG|S_IRUSR|S_IWUSR, subdir);
-+			if ( ent == NULL ) {
-+				printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/keys/%s/%s\n", phys->name, entry->name);
-+				continue;
-+			}
-+
-+			ent->owner = THIS_MODULE;
-+			ent->data = data;
-+			ent->read_proc = capsense_proc_read;
-+			ent->write_proc = capsense_proc_write;
-+		}
-+	}
-+
-+	return 0;
-+}
diff --git a/recipes/linux/linux-2.6.29/boc01/012-091019-capsense.patch b/recipes/linux/linux-2.6.29/boc01/012-091019-capsense.patch
new file mode 100644
index 0000000000..d3e07c24b3
--- /dev/null
+++ b/recipes/linux/linux-2.6.29/boc01/012-091019-capsense.patch
@@ -0,0 +1,867 @@
+Index: linux-2.6.29/drivers/input/misc/Kconfig
+===================================================================
+--- linux-2.6.29.orig/drivers/input/misc/Kconfig	2009-10-19 16:16:01.000000000 +0200
++++ linux-2.6.29/drivers/input/misc/Kconfig	2009-10-19 16:16:03.000000000 +0200
+@@ -227,4 +227,13 @@
+ 	 Say Y to include support for delivering  PMU events via  input
+ 	 layer on NXP PCF50633.
+ 
++config INPUT_CAPSENSE_BTNS
++	tristate "CAPSENSE CY8C201xx buttons interface"
++	select INPUT_POLLDEV
++	select LEDS_CLASS
++	help
++	  To compile this driver as a module, choose M here:
++	  the module will be called capsense-btns.
++	  To change poll interval, invoque poll parameter in msecs.
++
+ endif
+Index: linux-2.6.29/drivers/input/misc/Makefile
+===================================================================
+--- linux-2.6.29.orig/drivers/input/misc/Makefile	2009-10-19 16:16:01.000000000 +0200
++++ linux-2.6.29/drivers/input/misc/Makefile	2009-10-19 16:16:03.000000000 +0200
+@@ -22,3 +22,4 @@
+ obj-$(CONFIG_INPUT_APANEL)		+= apanel.o
+ obj-$(CONFIG_INPUT_SGI_BTNS)		+= sgi_btns.o
+ obj-$(CONFIG_INPUT_PCF50633_PMU)	+= pcf50633-input.o
++obj-$(CONFIG_INPUT_CAPSENSE_BTNS)	+= capsense-btns.o
+Index: linux-2.6.29/drivers/input/misc/capsense-btns.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.29/drivers/input/misc/capsense-btns.c	2009-10-19 16:16:12.000000000 +0200
+@@ -0,0 +1,440 @@
++/*
++ * CAPSENSE Interface driver
++ *
++ *
++ * Copyright (C) 2008, CenoSYS (www.cenosys.com).
++ * Copyright (C) 2009, Bollore telecom (www.bolloretelecom.eu).
++ *
++ * Guillaume Ligneul <guillaume.ligneul@gmail.com>
++ * Adrien Demarez <jeremy.laine@bolloretelecom.eu>
++ * Jeremy Lainé <jeremy.laine@bolloretelecom.eu>
++ * Sylvain Giroudon <sylvain.giroudon@goobie.fr>
++ *
++ * 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 <linux/init.h>
++#include <linux/input-polldev.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/leds.h>
++
++#define DRIVER_NAME "capsense"
++
++#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))
++
++#define CAP_CS(command,port,bit)     ((command)+(5*(port))+(bit))
++#define CAP_CS_FINGER_TH(port,bit)   CAP_CS(0x61,port,bit)
++#define CAP_CS_IDAC(port,bit)        CAP_CS(0x6B,port,bit)
++
++#define CAP_DEVICE_ID           0x7A
++#define CAP_DEVICE_STATUS       0x7B
++#define CAP_I2C_ADDR_DM         0x7C
++
++#define CAP_COMMAND_REG         0xA0
++#define CAP_COMMAND_STORE_NVM        0x01
++#define CAP_COMMAND_RESTORE_FACTORY  0x02
++#define CAP_COMMAND_RECONFIGURE      0x06
++#define CAP_COMMAND_NORMAL_MODE      0x07
++#define CAP_COMMAND_SETUP_MODE       0x08
++
++#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)");
++
++struct capsense_led {
++	struct led_classdev cdev;
++	struct capsense_ctx *capsense;
++	int port;
++	int bit;
++};
++
++struct capsense_ctx {
++	struct input_polled_dev *ipdev;
++	struct i2c_client *client;
++	unsigned char key_state;
++	struct capsense_led leds[CAP_NLEDS];
++	unsigned char led_state[2];
++	struct mutex mutex;
++};
++
++static unsigned short input_keymap[] = {
++	// GP0
++	KEY_F1,
++	KEY_ENTER,
++	KEY_DOWN,
++	KEY_BACKSPACE,
++	// GP1
++	KEY_UP,
++};
++
++struct capsense_keymap {
++	char *name;
++	int port, bit;
++};
++
++static struct capsense_keymap phys_keymap[] = {
++	{ "info", 0, 4 },
++	{ "ok",   0, 2 },
++	{ "down", 0, 3 },
++	{ "back", 0, 0 },
++	{ "up",   1, 4 },
++};
++
++
++struct capsense_ledmap {
++	char *name;
++	int port, bit;
++};
++
++static struct capsense_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 },
++};
++
++
++/*
++ * Buttons events handling
++ */
++
++static void handle_buttons(struct input_polled_dev *dev)
++{
++	struct capsense_ctx *capsense = dev->private;
++	u8 port_value;
++	u8 new_state = 0;
++	int port;
++	u8 changed;
++	int i;
++
++	mutex_lock(&capsense->mutex);
++
++	// read status
++	port = -1;
++	port_value = 0;
++	for (i = 0; i < ARRAY_SIZE(phys_keymap); i++) {
++		if ( phys_keymap[i].port != port ) {
++			port = phys_keymap[i].port;
++			port_value = i2c_smbus_read_byte_data(capsense->client, CAP_READ_STATUS(port));
++		}
++
++		if ( port_value & (1 << phys_keymap[i].bit) )
++			new_state |= (1 << i);
++	}
++
++	mutex_unlock(&capsense->mutex);
++
++	// update keyboard state
++	changed = capsense->key_state ^ new_state;
++	for (i = 0; i < ARRAY_SIZE(input_keymap); i++)
++		if (changed & (1 << i))
++			input_report_key(dev->input, input_keymap[i], (new_state & (1 << i)));
++	capsense->key_state = new_state;
++	input_sync(dev->input);
++}
++
++
++/*
++ * LEDs management
++ */
++
++static void
++capsense_led_set(struct led_classdev *led_cdev,
++		 enum led_brightness value)
++{
++	struct capsense_led *led = (struct capsense_led *) led_cdev;
++	struct capsense_ctx *capsense = led->capsense;
++	int port = led->port;
++	unsigned char mask = (1 << led->bit);
++
++	if ( value )
++		capsense->led_state[port] |= mask;
++	else
++		capsense->led_state[port] &= ~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 void
++capsense_led_enable(struct capsense_led *led, int state)
++{
++	struct capsense_ctx *capsense = led->capsense;
++
++	mutex_lock(&capsense->mutex);
++	i2c_smbus_write_byte_data(capsense->client, CAP_OP_SEL(led->port, led->bit), state ? 0x00 : 0x80);
++	mutex_unlock(&capsense->mutex);
++}
++
++static int
++capsense_led_init(struct capsense_ctx *capsense)
++{
++	int i;
++	int ret;
++
++	for (i = 0; i < CAP_NLEDS; i++) {
++		struct capsense_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->bit = ledmap[i].bit;
++
++		ret = led_classdev_register(&capsense->ipdev->input->dev, &led->cdev);
++		if ( ret < 0 )
++			return -1;
++
++		capsense_led_enable(led, 1);
++	}
++
++	/* Switch all leds off */
++	mutex_lock(&capsense->mutex);
++
++	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);
++
++	mutex_unlock(&capsense->mutex);
++
++	return 0;
++}
++
++static void
++capsense_led_exit(struct capsense_ctx *capsense)
++{
++	int i;
++
++	for (i = 0; i < CAP_NLEDS; i++) {
++		led_classdev_unregister(&capsense->leds[i].cdev);
++	}
++}
++
++static inline void
++capsense_led_suspend(struct capsense_ctx *capsense)
++{
++	int i;
++
++	for (i = 0; i < CAP_NLEDS; i++) {
++		struct capsense_led *led = &(capsense->leds[i]);
++
++		led_classdev_suspend(&led->cdev);
++		capsense_led_enable(led, 0);
++	}
++}
++
++static inline void
++capsense_led_resume(struct capsense_ctx *capsense)
++{
++	int i;
++
++	for (i = 0; i < CAP_NLEDS; i++) {
++		struct capsense_led *led = &(capsense->leds[i]);
++
++		capsense_led_enable(led, 1);
++		led_classdev_resume(&led->cdev);
++	}
++}
++
++
++/*
++ * Device configuration through procfs entries
++ */
++
++#ifdef CONFIG_PROC_FS
++#include "capsense-procfs.c"
++#endif
++
++
++/*
++ * Device initialisation
++ */
++
++static int
++capsense_detect(struct i2c_client *client, int kind, struct i2c_board_info *info)
++{
++	struct i2c_adapter *adapter = client->adapter;
++
++	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
++		return -ENODEV;
++
++	// FIXME: how do we identify the device?
++
++	return 0;
++}
++
++static int
++capsense_probe(struct i2c_client *client, const struct i2c_device_id *id)
++{
++	struct capsense_ctx *capsense;
++	struct input_polled_dev *ipdev;
++	struct input_dev *input;
++	int rc=0, i=0;
++
++	capsense = kzalloc(sizeof(*capsense), GFP_KERNEL);
++	if (!capsense)
++		return -ENOMEM;
++
++	mutex_init(&capsense->mutex);
++
++	ipdev = input_allocate_polled_device();
++	if (!ipdev) {
++		rc = -ENOMEM;
++		goto out_allocated;
++	}
++
++	capsense->key_state = 0;
++	capsense->ipdev = ipdev;
++	capsense->client = client;
++	i2c_set_clientdata(client, capsense);
++
++	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 = &client->dev;
++	input->keycode = input_keymap;
++	input->keycodemax = ARRAY_SIZE(input_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(input_keymap); i++)
++		set_bit(input_keymap[i], ipdev->input->keybit);
++
++	rc = input_register_polled_device(ipdev);
++	if (rc)
++		goto out_polled;
++
++	rc = capsense_led_init(capsense);
++	if (rc)
++		goto out_registered;
++
++#ifdef CONFIG_PROC_FS
++	/* Create /proc entries for hardware device configuration */
++	capsense_proc_init(capsense);
++#endif
++
++	return 0;
++
++out_registered:
++	input_unregister_polled_device(ipdev);
++out_polled:
++	input_free_polled_device(ipdev);
++out_allocated:
++	kfree(capsense);
++	return rc;
++}
++
++static int
++capsense_remove(struct i2c_client *client)
++{
++	struct capsense_ctx *capsense = i2c_get_clientdata(client);
++
++	capsense_led_exit(capsense);
++	input_unregister_polled_device(capsense->ipdev);
++	input_free_polled_device(capsense->ipdev);
++	kfree(capsense);
++	return 0;
++}
++
++/*
++ * Power management
++ */
++
++#ifdef CONFIG_PM
++static int capsense_suspend(struct i2c_client *client, pm_message_t mesg)
++{
++	struct capsense_ctx *capsense = i2c_get_clientdata(client);
++
++	dev_info(&client->dev, "suspend\n");
++
++	capsense_led_suspend(capsense);
++
++	return 0;
++}
++
++static int capsense_resume(struct i2c_client *client)
++{
++	struct capsense_ctx *capsense = i2c_get_clientdata(client);
++
++	dev_info(&client->dev, "resume\n");
++
++	capsense_led_resume(capsense);
++
++	return 0;
++}
++#endif
++
++
++/*
++ * Driver initialisation
++ */
++
++struct i2c_device_id capsense_idtable[] = {
++       { "capsense", 0 },
++       { }
++};
++MODULE_DEVICE_TABLE(i2c, capsense_idtable);
++
++static struct i2c_driver capsense_driver = {
++	.driver		= {
++		.name	= DRIVER_NAME,
++	},
++	.detect		= capsense_detect,
++	.probe		= capsense_probe,
++	.remove		= capsense_remove,
++	.id_table	= capsense_idtable,
++#ifdef CONFIG_PM
++	.suspend        = capsense_suspend,
++	.resume         = capsense_resume,
++#endif
++};
++
++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 <guillaume.ligneul@cenosys.com>");
++MODULE_DESCRIPTION("Capsense CY8C201xx Input driver");
++MODULE_LICENSE("GPL");
++module_init(capsense_buttons_init);
++module_exit(capsense_buttons_exit);
+Index: linux-2.6.29/drivers/input/misc/capsense-procfs.c
+===================================================================
+--- /dev/null	1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.29/drivers/input/misc/capsense-procfs.c	2009-10-19 16:16:03.000000000 +0200
+@@ -0,0 +1,390 @@
++/*
++ * CAPSENSE Interface driver
++ * Device setup using procfs
++ *
++ * Copyright (C) 2008, Goobie (www.goobie.fr).
++ *
++ * Sylvain Giroudon <sylvain.giroudon@goobie.fr>
++ *
++ * 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 <linux/proc_fs.h>
++#include <linux/uaccess.h>
++
++
++struct capsense_proc_data {
++	struct capsense_ctx *capsense;
++	struct capsense_keymap *phys;
++	char *name;
++	unsigned char command;
++	unsigned char hex;
++};
++
++struct capsense_proc_entry {
++	char *name;
++	unsigned char command;
++	struct capsense_proc_data data[ARRAY_SIZE(phys_keymap)];
++};
++
++static struct capsense_proc_entry capsense_proc_key_entries[] = {
++	{ "CS_FINGER_TH", CAP_CS_FINGER_TH(0,0) },
++	{ "CS_IDAC",      CAP_CS_IDAC(0,0)      },
++};
++
++static struct capsense_proc_entry capsense_proc_device_entries[] = {
++	{ "DEVICE_ID",     CAP_DEVICE_ID        },
++	{ "DEVICE_STATUS", CAP_DEVICE_STATUS    },
++};
++
++struct capsense_proc_command {
++	char *name;
++	unsigned char command;
++	struct capsense_ctx *capsense;
++};
++
++static struct capsense_proc_command capsense_proc_commands[] = {
++	{ "store",       CAP_COMMAND_STORE_NVM       },
++	//{ "factory",     CAP_COMMAND_RESTORE_FACTORY },
++	//{ "reconfigure", CAP_COMMAND_RECONFIGURE     },
++};
++
++
++static int capsense_proc_read(char *page, char **start, off_t off, int count,
++			      int *eof, void *_data)
++{
++	struct capsense_proc_data *data = _data;
++	struct capsense_ctx *capsense = data->capsense;
++	u8 value;
++	int len;
++
++	mutex_lock(&capsense->mutex);
++	value = i2c_smbus_read_byte_data(capsense->client, data->command);
++	mutex_unlock(&capsense->mutex);
++
++	if ( data->hex )
++		len = sprintf(page, "%02X\n", value);
++	else
++		len = sprintf(page, "%u\n", value);
++
++	len -= off;
++	if ( len < count ) {
++		*eof = 1;
++		if ( len <= 0 )
++			return 0;
++	} else {
++		len = count;
++	}
++
++	*start = page + off;
++
++	return len;
++}
++
++
++static int capsense_proc_write(struct file *file, const char *buf,
++			       unsigned long count, void *_data)
++{
++	struct capsense_proc_data *data = _data;
++	struct capsense_ctx *capsense = data->capsense;
++	char lbuf[count+1];
++	u8 value;
++
++	/* 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", &value) == 1 ) {
++		mutex_lock(&capsense->mutex);
++		i2c_smbus_write_byte_data(capsense->client, CAP_COMMAND_REG, CAP_COMMAND_SETUP_MODE);
++		i2c_smbus_write_byte_data(capsense->client, data->command, value);
++		i2c_smbus_write_byte_data(capsense->client, CAP_COMMAND_REG, CAP_COMMAND_NORMAL_MODE);
++		mutex_unlock(&capsense->mutex);
++	}
++	else {
++		printk(KERN_INFO DRIVER_NAME ": [%s/%s] Syntax error in expression\n", data->phys->name, data->name);
++		return -EINVAL;
++	}
++
++	return count;
++}
++
++
++static inline char *str_skip_blanks(char *s)
++{
++	while ( (*s != '\0') && (*s <= ' ') )
++		s++;
++	return s;
++}
++
++
++static inline char *str_skip_chars(char *s)
++{
++	while ( *s > ' ' )
++		s++;
++	return s;
++}
++
++
++static int capsense_proc_write_iic(struct file *file, const char *buf,
++				   unsigned long count, void *data)
++{
++	struct capsense_ctx *capsense = data;
++	char lbuf[count+1];
++	int lnum;
++	char *s;
++
++	/* Only root can do this */
++	if ( !capable(CAP_SYS_ADMIN) )
++		return -EACCES;
++
++	printk(KERN_INFO DRIVER_NAME ": Reading configuration script from /proc/" DRIVER_NAME "/iic (%lu bytes)\n", count);
++
++	memset(lbuf, 0, sizeof(lbuf));
++
++	if (copy_from_user(lbuf, buf, count))
++		return -EFAULT;
++
++	s = lbuf;
++	lnum = 0;
++
++	while ( *s != '\0' ) {
++		char *line;
++		char operation;
++		unsigned char data[255];
++		int size;
++		struct i2c_msg msg;
++		int ret;
++
++		lnum++;
++
++		/* Spot the end of the line */
++		line = s;
++		while ( (*s != '\0') && (*s != '\n') )
++			s++;
++		if ( *s != '\0' )
++			*(s++) = '\0';
++
++		//printk(KERN_INFO DRIVER_NAME ": iic:%d: '%s'\n", lnum, line);
++
++		/* Strip leading blank characters */
++		line = str_skip_blanks(line);
++
++		/* Empty or commented line: skip! */
++		if ( (*line == '\0') || (*line == '#') )
++			continue;
++
++		/* Only accept write operations 'w' */
++		operation = *(line++);
++		if ( operation != 'w' ) {
++			printk(KERN_ERR DRIVER_NAME ": iic:%d: Unknown operation '%c ...' -- skipped\n", lnum, operation);
++			continue;
++		}
++
++		/* Extract data values */
++		size = 0;
++		while ( (*line != '\0') && (size < sizeof(data)) ) {
++			line = str_skip_blanks(line);
++			if ( *line != '\0' )
++				sscanf(line, "%hhx", &data[size++]);
++			line = str_skip_chars(line);
++		}
++
++		{
++			int i;
++
++			printk(KERN_DEBUG DRIVER_NAME ": iic:%d: %c", lnum, operation);
++			for (i = 0; i < size; i++)
++				printk(" %02X", data[i]);
++			printk("\n");
++		}
++
++		/* Do nothing if there are less than 2 data bytes (address, command) */
++		if ( size < 3 ) {
++			printk(KERN_ERR DRIVER_NAME ": iic:%d: Too few data for operation '%c ...' -- skipped\n", lnum, operation);
++			continue;
++		}
++
++		/* First data byte is the i2c device address:
++		   Warn if it does not match the current i2c address */
++		if ( data[0] != capsense->client->addr ) {
++			printk(KERN_WARNING DRIVER_NAME ": iic:%d: WARNING - Specified i2c address (%02X) differs from current i2c address (%02X)\n", lnum, data[0], capsense->client->addr);
++		}
++
++		/* Second data byte is the capsense register:
++		   Warn if changing the device I2C address */
++		if ( data[1] == CAP_I2C_ADDR_DM ) {
++			printk(KERN_WARNING DRIVER_NAME ": iic:%d: WARNING - Changing i2c address to %02X (I2C_ADDR_DM=%02X)\n", lnum, data[2] & 0x7F, data[2]);
++		}
++
++		/* Send command to i2c device */
++		mutex_lock(&capsense->mutex);
++
++		msg.addr = data[0];
++		msg.flags = capsense->client->flags;
++		msg.len = size - 1;
++		msg.buf = data + 1;
++		//printk(KERN_INFO DRIVER_NAME ": iic:%d: i2c transfer: addr=0x%02X flags=0x%04X len=%d\n", lnum, msg.addr, msg.flags, msg.len);
++
++		ret = i2c_transfer(capsense->client->adapter, &msg, 1);
++		if ( ret < 0 )
++			printk(KERN_ERR DRIVER_NAME ": iic:%d: i2c transfer failed (%d), command rejected\n", lnum, ret);
++
++		mutex_unlock(&capsense->mutex);
++	}
++
++	return count;
++}
++
++
++static int capsense_proc_write_command(struct file *file, const char *buf,
++				       unsigned long count, void *data)
++{
++	struct capsense_proc_command *command = data;
++	struct capsense_ctx *capsense = command->capsense;
++
++	/* Only root can do this */
++	if ( !capable(CAP_SYS_ADMIN) )
++		return -EACCES;
++
++	printk(KERN_INFO DRIVER_NAME ": %s (%02X)\n", command->name, command->command);
++
++	mutex_lock(&capsense->mutex);
++	i2c_smbus_write_byte_data(capsense->client, CAP_COMMAND_REG, CAP_COMMAND_SETUP_MODE);
++	i2c_smbus_write_byte_data(capsense->client, CAP_COMMAND_REG, command->command);
++	i2c_smbus_write_byte_data(capsense->client, CAP_COMMAND_REG, CAP_COMMAND_NORMAL_MODE);
++	mutex_unlock(&capsense->mutex);
++
++	return count;
++}
++
++
++static int capsense_proc_init(struct capsense_ctx *capsense)
++{
++	struct proc_dir_entry *root;
++	struct proc_dir_entry *dir;
++	struct proc_dir_entry *ent;
++	int i;
++
++	/* Create capsense 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 iic config file dump entry */
++	ent = create_proc_entry("iic", S_IFREG|S_IWUSR, root);
++	if ( ent == NULL ) {
++		printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/iic\n");
++		return -1;
++	}
++
++	ent->owner = THIS_MODULE;
++	ent->data = capsense;
++	ent->write_proc = capsense_proc_write_iic;
++
++	/* Create commands directory */
++	dir = proc_mkdir("commands", root);
++	if ( dir == NULL ) {
++		printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/commands\n");
++		return -1;
++	}
++
++	dir->owner = THIS_MODULE;
++
++	/* Create command entries */
++	for (i = 0; i < ARRAY_SIZE(capsense_proc_commands); i++) {
++		struct capsense_proc_command *command = &capsense_proc_commands[i];
++
++		command->capsense = capsense;
++
++		ent = create_proc_entry(command->name, S_IFREG|S_IWUSR, dir);
++		if ( ent == NULL ) {
++			printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/commands/%s\n", command->name);
++			return -1;
++		}
++
++		ent->owner = THIS_MODULE;
++		ent->data = command;
++		ent->write_proc = capsense_proc_write_command;
++	}
++
++	/* Create device status read entries */
++	for (i = 0; i < ARRAY_SIZE(capsense_proc_device_entries); i++) {
++		struct capsense_proc_entry *entry = &(capsense_proc_device_entries[i]);
++		struct capsense_proc_data *data = &(entry->data[i]);
++
++		data->capsense = capsense;
++		data->phys = NULL;
++		data->name = entry->name;
++		data->command = entry->command;
++		data->hex = 1;
++
++		ent = create_proc_entry(entry->name, S_IFREG|S_IRUSR, root);
++		if ( ent == NULL ) {
++			printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/%s\n", entry->name);
++			continue;
++		}
++
++		ent->owner = THIS_MODULE;
++		ent->data = data;
++		ent->read_proc = capsense_proc_read;
++	}
++
++	/* Create keys management directory */
++	dir = proc_mkdir("keys", root);
++	if ( dir == NULL ) {
++		printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/keys\n");
++		return -1;
++	}
++
++	dir->owner = THIS_MODULE;
++
++	/* Create keys sensitivity adjustment entries */
++	for (i = 0; i < ARRAY_SIZE(phys_keymap); i++) {
++		struct capsense_keymap *phys = &phys_keymap[i];
++		struct proc_dir_entry *subdir;
++		int ientry;
++
++		subdir = proc_mkdir(phys->name, dir);
++		if ( subdir == NULL ) {
++			printk(KERN_WARNING DRIVER_NAME ": Cannot create directory /proc/" DRIVER_NAME "/keys/%s\n", phys->name);
++			continue;
++		}
++
++		for (ientry = 0; ientry < ARRAY_SIZE(capsense_proc_key_entries); ientry++) {
++			struct capsense_proc_entry *entry = &(capsense_proc_key_entries[ientry]);
++			struct capsense_proc_data *data = &(entry->data[i]);
++
++			data->capsense = capsense;
++			data->phys = phys;
++			data->name = entry->name;
++			data->command = CAP_CS(entry->command, phys->port, phys->bit);
++			data->hex = 0;
++
++			ent = create_proc_entry(entry->name, S_IFREG|S_IRUSR|S_IWUSR, subdir);
++			if ( ent == NULL ) {
++				printk(KERN_WARNING DRIVER_NAME ": Cannot create entry /proc/" DRIVER_NAME "/keys/%s/%s\n", phys->name, entry->name);
++				continue;
++			}
++
++			ent->owner = THIS_MODULE;
++			ent->data = data;
++			ent->read_proc = capsense_proc_read;
++			ent->write_proc = capsense_proc_write;
++		}
++	}
++
++	return 0;
++}
diff --git a/recipes/linux/linux-2.6.29/boc01/boc01.dts b/recipes/linux/linux-2.6.29/boc01/boc01.dts
index 1abe296842..d18fd7fd71 100644
--- a/recipes/linux/linux-2.6.29/boc01/boc01.dts
+++ b/recipes/linux/linux-2.6.29/boc01/boc01.dts
@@ -164,6 +164,10 @@
 			interrupts = <15 0x8>;
 			interrupt-parent = <&ipic>;
 			dfsrr;
+			capsense@25 {
+				compatible = "cypress,capsense";
+				reg = <0x25>;
+			};
 		};
 
 		spi@7000 {
diff --git a/recipes/linux/linux-2.6.29/boc01/boc01.dts.v1 b/recipes/linux/linux-2.6.29/boc01/boc01.dts.v1
index b71373a9ab..b2e2456438 100644
--- a/recipes/linux/linux-2.6.29/boc01/boc01.dts.v1
+++ b/recipes/linux/linux-2.6.29/boc01/boc01.dts.v1
@@ -164,6 +164,10 @@
 			interrupts = <15 0x8>;
 			interrupt-parent = <&ipic>;
 			dfsrr;
+			capsense@25 {
+				compatible = "cypress,capsense";
+				reg = <0x25>;
+			};
 		};
 
 		spi@7000 {
-- 
cgit v1.2.3