From patchwork Tue Nov 9 02:15:04 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: jooaun X-Patchwork-Id: 309972 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oA92G8VE031966 for ; Tue, 9 Nov 2010 02:16:09 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752563Ab0KICP4 (ORCPT ); Mon, 8 Nov 2010 21:15:56 -0500 Received: from mail-gx0-f174.google.com ([209.85.161.174]:40001 "EHLO mail-gx0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752370Ab0KICPq (ORCPT ); Mon, 8 Nov 2010 21:15:46 -0500 Received: by gxk23 with SMTP id 23so3933812gxk.19 for ; Mon, 08 Nov 2010 18:15:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=+ukxaD7RGcHj1/fDYtLtSMrMBst36Orp6UcgbulEJMg=; b=KRqb3Qu8LVG5uwZtdF/XaojB51b+qMmvfR9lSXH4tl7cGm4+jC2UwJxL/Cd7hED6an Tp6TyBxHSqx/jVzv8caPfojsKkfp60P1B1aP7DXjWYl464OGx1gzMuCd1e/1x/YhMTCj OsnJsS9k/U7wL6FiczyI6DxxXVSO60+48XC24= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=Z7oZYYw5I7y9KbokkPDE0tszZz4l1tQx3K3HKs1pRvf/foKs9SbMQaElZU3U4sLdiT f6w0HoMw0SESa4LQAFDddoxtwyVn1ZuQtl5vWbqTHowQXFmEkINqbriC56LjXlcKZ6EM Fn9+ERlGbTE/NQNLXBdxKK/lSNoc//StsGf/8= Received: by 10.90.22.29 with SMTP id 29mr6263668agv.14.1289268945038; Mon, 08 Nov 2010 18:15:45 -0800 (PST) Received: from localhost.localdomain (203-206-227-95.perm.iinet.net.au [203.206.227.95]) by mx.google.com with ESMTPS id j27sm449455yha.30.2010.11.08.18.15.42 (version=TLSv1/SSLv3 cipher=RC4-MD5); Mon, 08 Nov 2010 18:15:44 -0800 (PST) From: jooaun To: dmitry.torokhov@gmail.com Cc: linux-input@vger.kernel.org, raphaelpereira@gmail.com, jooaun Subject: [PATCH 1/8] qt2160: add slider support Date: Tue, 9 Nov 2010 13:15:04 +1100 Message-Id: <1289268911-32322-1-git-send-email-jasaw81@gmail.com> X-Mailer: git-send-email 1.7.0.4 Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 09 Nov 2010 02:16:09 +0000 (UTC) diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c old mode 100644 new mode 100755 index fac6951..7ec256c --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -27,6 +27,9 @@ #include #include #include +#include + +#include #define QT2160_VALID_CHIPID 0x11 @@ -39,14 +42,32 @@ #define QT2160_CMD_GPIOS 6 #define QT2160_CMD_SUBVER 7 #define QT2160_CMD_CALIBRATE 10 +#define QT2160_CMD_RESET 11 +#define QT2160_CMD_SLIDE_CTRL 20 +#define QT2160_CMD_SLIDE_OPT 21 +#define QT2160_CMD_KEY0_AKS 22 #define QT2160_CYCLE_INTERVAL (2*HZ) -static unsigned char qt2160_key2code[] = { - KEY_0, KEY_1, KEY_2, KEY_3, - KEY_4, KEY_5, KEY_6, KEY_7, - KEY_8, KEY_9, KEY_A, KEY_B, - KEY_C, KEY_D, KEY_E, KEY_F, +#define QT2160_SLIDE_RESOLUTION (8) +#define QT2160_SLIDE_HYSTERESIS (10) +#define QT2160_SLIDE_MAX_VALUE (0xFF) + +static struct qt2160_info default_hw_info = { + .slider_length = 0, + .slider_axis = 0, + .keycodes = { + KEY_0, KEY_1, KEY_2, KEY_3, + KEY_4, KEY_5, KEY_6, KEY_7, + KEY_8, KEY_9, KEY_A, KEY_B, + KEY_C, KEY_D, KEY_E, KEY_F, + }, + .key_aks = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + }, }; struct qt2160_data { @@ -54,8 +75,10 @@ struct qt2160_data { struct input_dev *input; struct delayed_work dwork; spinlock_t lock; /* Protects canceling/rescheduling of dwork */ - unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)]; + struct qt2160_info *hw_info; u16 key_matrix; + u8 slide_val; + unsigned char num_keys; }; static int qt2160_read_block(struct i2c_client *client, @@ -113,8 +136,10 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) { struct i2c_client *client = qt2160->client; struct input_dev *input = qt2160->input; + struct qt2160_info *hw_info = qt2160->hw_info; u8 regs[6]; u16 old_matrix, new_matrix; + u8 old_slide; int ret, i, mask; dev_dbg(&client->dev, "requesting keys...\n"); @@ -130,17 +155,30 @@ static int qt2160_get_key_matrix(struct qt2160_data *qt2160) return ret; } - old_matrix = qt2160->key_matrix; - qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1]; - - mask = 0x01; - for (i = 0; i < 16; ++i, mask <<= 1) { - int keyval = new_matrix & mask; + if (hw_info->slider_length) { + old_slide = qt2160->slide_val; + if (old_slide != regs[3]) { + qt2160->slide_val = regs[3]; + input_report_abs(input, hw_info->slider_axis, regs[3]); + } + } - if ((old_matrix & mask) != keyval) { - input_report_key(input, qt2160->keycodes[i], keyval); - dev_dbg(&client->dev, "key %d %s\n", - i, keyval ? "pressed" : "released"); + if (qt2160->num_keys) { + old_matrix = qt2160->key_matrix; + qt2160->key_matrix = new_matrix = (regs[2] << 8) | regs[1]; + + mask = 0x01 << hw_info->slider_length; + for (i = hw_info->slider_length; i < QT2160_MAXKEYS; + ++i, mask <<= 1) { + int keyval = new_matrix & mask; + + if (((old_matrix & mask) != keyval) && + (hw_info->keycodes[i])) { + input_report_key(input, hw_info->keycodes[i], + keyval); + dev_dbg(&client->dev, "key %d %s\n", + i, keyval ? "pressed" : "released"); + } } } @@ -226,6 +264,52 @@ static int __devinit qt2160_write(struct i2c_client *client, u8 reg, u8 data) return error; } +static int __devinit qt2160_configure_device(struct i2c_client *client, + struct qt2160_data *qt2160) +{ + struct qt2160_info *pdata = qt2160->hw_info; + int i; + int error = 0; + + /* perform software reset and wait for at least 32ms */ + i2c_smbus_write_byte_data(client, QT2160_CMD_RESET, 0xFF); + msleep(200); + + /* perform dummy write to reset I2C state */ + i2c_smbus_write_byte(client, QT2160_CMD_CHIPID); + + /* setup slider control and slider options */ + if (pdata->slider_length) { + error |= i2c_smbus_write_byte_data( + client, + QT2160_CMD_SLIDE_CTRL, + (QT2160_SLIDE_HYSTERESIS << 4) | + (pdata->slider_length & 0x0F)); + error |= i2c_smbus_write_byte_data(client, QT2160_CMD_SLIDE_OPT, + 8 - QT2160_SLIDE_RESOLUTION); + } else { + error = i2c_smbus_write_byte_data(client, + QT2160_CMD_SLIDE_CTRL, 0); + } + if (error) { + dev_err(&client->dev, "could not write slider config\n"); + goto config_fault; + } + + for (i = 0; i < QT2160_MAXKEYS; i++) { + /* set AKS */ + error |= i2c_smbus_write_byte_data(client, + QT2160_CMD_KEY0_AKS + i, + pdata->key_aks[i]); + } + if (error) { + dev_err(&client->dev, "could not write key config\n"); + goto config_fault; + } + +config_fault: + return error; +} static bool __devinit qt2160_identify(struct i2c_client *client) { @@ -263,6 +347,8 @@ static int __devinit qt2160_probe(struct i2c_client *client, { struct qt2160_data *qt2160; struct input_dev *input; + struct qt2160_info *pdata; + struct qt2160_info *hw_info; int i; int error; @@ -275,6 +361,8 @@ static int __devinit qt2160_probe(struct i2c_client *client, return -ENODEV; } + pdata = client->dev.platform_data; + if (!qt2160_identify(client)) return -ENODEV; @@ -287,6 +375,33 @@ static int __devinit qt2160_probe(struct i2c_client *client, goto err_free_mem; } + if (pdata) + qt2160->hw_info = pdata; + else + qt2160->hw_info = &default_hw_info; + hw_info = qt2160->hw_info; + + qt2160->num_keys = 0; + for (i = hw_info->slider_length; i < QT2160_MAXKEYS; ++i) { + if (hw_info->keycodes[i]) + qt2160->num_keys++; + } + if ((!qt2160->num_keys) && + (hw_info->slider_length < QT2160_MIN_SLIDER_LENGTH)) { + dev_err(&client->dev, "No valid input device specified\n"); + error = -EINVAL; + goto err_free_mem; + } + if (hw_info->slider_length != 0) { + if ((hw_info->slider_length > QT2160_MAX_SLIDER_LENGTH) || + (hw_info->slider_length < QT2160_MIN_SLIDER_LENGTH)) { + dev_err(&client->dev, "%d keys slider not supported\n", + hw_info->slider_length); + error = -EINVAL; + goto err_free_mem; + } + } + qt2160->client = client; qt2160->input = input; INIT_DELAYED_WORK(&qt2160->dwork, qt2160_worker); @@ -295,17 +410,32 @@ static int __devinit qt2160_probe(struct i2c_client *client, input->name = "AT42QT2160 Touch Sense Keyboard"; input->id.bustype = BUS_I2C; - input->keycode = qt2160->keycodes; - input->keycodesize = sizeof(qt2160->keycodes[0]); - input->keycodemax = ARRAY_SIZE(qt2160_key2code); + if (qt2160->num_keys) { + input->keycode = hw_info->keycodes; + input->keycodesize = sizeof(hw_info->keycodes[0]); + input->keycodemax = QT2160_MAXKEYS - hw_info->slider_length; + + __set_bit(EV_KEY, input->evbit); + __clear_bit(EV_REP, input->evbit); + for (i = hw_info->slider_length; i < QT2160_MAXKEYS; i++) { + if (hw_info->keycodes[i]) + __set_bit(hw_info->keycodes[i], input->keybit); + } + __clear_bit(KEY_RESERVED, input->keybit); + } + if (hw_info->slider_length) { + __set_bit(EV_ABS, input->evbit); + __set_bit(hw_info->slider_axis, input->absbit); + input_set_abs_params(input, hw_info->slider_axis, 0, + QT2160_SLIDE_MAX_VALUE, 0, 0); + } - __set_bit(EV_KEY, input->evbit); - __clear_bit(EV_REP, input->evbit); - for (i = 0; i < ARRAY_SIZE(qt2160_key2code); i++) { - qt2160->keycodes[i] = qt2160_key2code[i]; - __set_bit(qt2160_key2code[i], input->keybit); + /* Configure device */ + error = qt2160_configure_device(client, qt2160); + if (error) { + dev_err(&client->dev, "failed to configure device\n"); + goto err_free_mem; } - __clear_bit(KEY_RESERVED, input->keybit); /* Calibrate device */ error = qt2160_write(client, QT2160_CMD_CALIBRATE, 1); diff --git a/include/linux/input/qt2160.h b/include/linux/input/qt2160.h new file mode 100755 index 0000000..9d1252e --- /dev/null +++ b/include/linux/input/qt2160.h @@ -0,0 +1,26 @@ +#ifndef __QT2160_H__ +#define __QT2160_H__ + +#define QT2160_MAXKEYS 16 +#define QT2160_MAX_SLIDER_LENGTH 8 +#define QT2160_MIN_SLIDER_LENGTH 2 + +/** + * struct qt2160_info - defines the chip configuration + * @slider_length: number of keys to use as slider, max 8 keys, min 2 keys + * @slider_axis: absolute axis type, value 0 is ABS_X + * @keycodes: key codes for keys that are part of the slider are ignored; slider + * keys always start from key index 0 and end at key index (slider_length - 1); + * set to value 0 if key is not used; + * @key_aks: adjacent key suppression; keys that form a slider must be in the + * same aks group; keys in the same aks group will only report 1 active key at + * any time; value 0 disables aks group; valid aks groups are 1, 2, 3 + */ +struct qt2160_info { + unsigned char slider_length; + unsigned int slider_axis; + unsigned short keycodes[QT2160_MAXKEYS]; + unsigned char key_aks[QT2160_MAXKEYS]; +}; + +#endif /* __QT2160_H__ */