diff -urN linux-2.6.26.orig/drivers/input/misc/cy3218-btns.c linux-2.6.26/drivers/input/misc/cy3218-btns.c --- linux-2.6.26.orig/drivers/input/misc/cy3218-btns.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.26/drivers/input/misc/cy3218-btns.c 2008-12-22 12:54:47.000000000 +0100 @@ -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); diff -urN linux-2.6.26.orig/drivers/input/misc/Kconfig linux-2.6.26/drivers/input/misc/Kconfig --- linux-2.6.26.orig/drivers/input/misc/Kconfig 2008-07-13 23:51:29.000000000 +0200 +++ linux-2.6.26/drivers/input/misc/Kconfig 2008-12-22 07:47:08.000000000 +0100 @@ -197,4 +197,12 @@ 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 diff -urN linux-2.6.26.orig/drivers/input/misc/Makefile linux-2.6.26/drivers/input/misc/Makefile --- linux-2.6.26.orig/drivers/input/misc/Makefile 2008-07-13 23:51:29.000000000 +0200 +++ linux-2.6.26/drivers/input/misc/Makefile 2008-12-22 07:47:19.000000000 +0100 @@ -19,3 +19,4 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_APANEL) += apanel.o +obj-$(CONFIG_INPUT_CAPSENSE_BTNS) +=cy3218-btns.o