]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge commit 'v2.6.39-rc4' into next
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Sat, 23 Apr 2011 06:35:25 +0000 (23:35 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Sat, 23 Apr 2011 06:35:25 +0000 (23:35 -0700)
drivers/input/keyboard/gpio_keys.c
drivers/input/touchscreen/Kconfig
drivers/input/touchscreen/Makefile
drivers/input/touchscreen/atmel_mxt_ts.c
drivers/input/touchscreen/max11801_ts.c [new file with mode: 0644]
include/linux/gpio_keys.h

index eb3006361ee4440179b46377e272f97e6c7010b3..6e6145b9a4c10b2d84bfd3cce75b1ea12a100b43 100644 (file)
@@ -324,7 +324,12 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata)
        unsigned int type = button->type ?: EV_KEY;
        int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) ^ button->active_low;
 
-       input_event(input, type, button->code, !!state);
+       if (type == EV_ABS) {
+               if (state)
+                       input_event(input, type, button->code, button->value);
+       } else {
+               input_event(input, type, button->code, !!state);
+       }
        input_sync(input);
 }
 
@@ -363,7 +368,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
                                         struct gpio_button_data *bdata,
                                         struct gpio_keys_button *button)
 {
-       char *desc = button->desc ? button->desc : "gpio_keys";
+       const char *desc = button->desc ? button->desc : "gpio_keys";
        struct device *dev = &pdev->dev;
        unsigned long irqflags;
        int irq, error;
@@ -468,7 +473,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ddata);
        input_set_drvdata(input, ddata);
 
-       input->name = pdev->name;
+       input->name = pdata->name ? : pdev->name;
        input->phys = "gpio-keys/input0";
        input->dev.parent = &pdev->dev;
        input->open = gpio_keys_open;
index 434fd800cd24e7eb54adf896b8ec20e7f17e4dc5..cabd9e54863f9643664eb1e71c5cd5217d3fe528 100644 (file)
@@ -248,6 +248,18 @@ config TOUCHSCREEN_LPC32XX
          To compile this driver as a module, choose M here: the
          module will be called lpc32xx_ts.
 
+config TOUCHSCREEN_MAX11801
+       tristate "MAX11801 based touchscreens"
+       depends on I2C
+       help
+         Say Y here if you have a MAX11801 based touchscreen
+         controller.
+
+         If unsure, say N.
+
+         To compile this driver as a module, choose M here: the
+         module will be called max11801_ts.
+
 config TOUCHSCREEN_MCS5000
        tristate "MELFAS MCS-5000 touchscreen"
        depends on I2C
index ca94098d4c92b8116815c17a9ac742e77aa622e3..282d6f76ae26d10576332903ea633b8b03a17d05 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_TOUCHSCREEN_FUJITSU)     += fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)       += inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INTEL_MID)    += intel-mid-touch.o
 obj-$(CONFIG_TOUCHSCREEN_LPC32XX)      += lpc32xx_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MAX11801)     += max11801_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MC13783)      += mc13783_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MCS5000)      += mcs5000_ts.o
 obj-$(CONFIG_TOUCHSCREEN_MIGOR)                += migor_ts.o
index 4012436633b18ef0d087b95ca4f6792c6c8e290b..1e61387c73cafa01f40825a710427414a4a7e2aa 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/firmware.h>
 #include <linux/i2c.h>
 #include <linux/i2c/atmel_mxt_ts.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
 
 #define MXT_PRESS              (1 << 6)
 #define MXT_DETECT             (1 << 7)
 
+/* Touch orient bits */
+#define MXT_XY_SWITCH          (1 << 0)
+#define MXT_X_INVERT           (1 << 1)
+#define MXT_Y_INVERT           (1 << 2)
+
 /* Touchscreen absolute values */
-#define MXT_MAX_XC             0x3ff
-#define MXT_MAX_YC             0x3ff
 #define MXT_MAX_AREA           0xff
 
 #define MXT_MAX_FINGER         10
@@ -246,6 +249,8 @@ struct mxt_data {
        struct mxt_info info;
        struct mxt_finger finger[MXT_MAX_FINGER];
        unsigned int irq;
+       unsigned int max_x;
+       unsigned int max_y;
 };
 
 static bool mxt_object_readable(unsigned int type)
@@ -499,19 +504,21 @@ static void mxt_input_report(struct mxt_data *data, int single_id)
                if (!finger[id].status)
                        continue;
 
-               input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
-                               finger[id].status != MXT_RELEASE ?
-                               finger[id].area : 0);
-               input_report_abs(input_dev, ABS_MT_POSITION_X,
-                               finger[id].x);
-               input_report_abs(input_dev, ABS_MT_POSITION_Y,
-                               finger[id].y);
-               input_mt_sync(input_dev);
+               input_mt_slot(input_dev, id);
+               input_mt_report_slot_state(input_dev, MT_TOOL_FINGER,
+                               finger[id].status != MXT_RELEASE);
 
-               if (finger[id].status == MXT_RELEASE)
-                       finger[id].status = 0;
-               else
+               if (finger[id].status != MXT_RELEASE) {
                        finger_num++;
+                       input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR,
+                                       finger[id].area);
+                       input_report_abs(input_dev, ABS_MT_POSITION_X,
+                                       finger[id].x);
+                       input_report_abs(input_dev, ABS_MT_POSITION_Y,
+                                       finger[id].y);
+               } else {
+                       finger[id].status = 0;
+               }
        }
 
        input_report_key(input_dev, BTN_TOUCH, finger_num > 0);
@@ -549,8 +556,13 @@ static void mxt_input_touchevent(struct mxt_data *data,
        if (!(status & (MXT_PRESS | MXT_MOVE)))
                return;
 
-       x = (message->message[1] << 2) | ((message->message[3] & ~0x3f) >> 6);
-       y = (message->message[2] << 2) | ((message->message[3] & ~0xf3) >> 2);
+       x = (message->message[1] << 4) | ((message->message[3] >> 4) & 0xf);
+       y = (message->message[2] << 4) | ((message->message[3] & 0xf));
+       if (data->max_x < 1024)
+               x = x >> 2;
+       if (data->max_y < 1024)
+               y = y >> 2;
+
        area = message->message[4];
 
        dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
@@ -804,10 +816,6 @@ static int mxt_initialize(struct mxt_data *data)
        if (error)
                return error;
 
-       error = mxt_make_highchg(data);
-       if (error)
-               return error;
-
        mxt_handle_pdata(data);
 
        /* Backup to memory */
@@ -845,6 +853,20 @@ static int mxt_initialize(struct mxt_data *data)
        return 0;
 }
 
+static void mxt_calc_resolution(struct mxt_data *data)
+{
+       unsigned int max_x = data->pdata->x_size - 1;
+       unsigned int max_y = data->pdata->y_size - 1;
+
+       if (data->pdata->orient & MXT_XY_SWITCH) {
+               data->max_x = max_y;
+               data->max_y = max_x;
+       } else {
+               data->max_x = max_x;
+               data->max_y = max_y;
+       }
+}
+
 static ssize_t mxt_object_show(struct device *dev,
                                    struct device_attribute *attr, char *buf)
 {
@@ -981,6 +1003,10 @@ static ssize_t mxt_update_fw_store(struct device *dev,
 
        enable_irq(data->irq);
 
+       error = mxt_make_highchg(data);
+       if (error)
+               return error;
+
        return count;
 }
 
@@ -1052,31 +1078,33 @@ static int __devinit mxt_probe(struct i2c_client *client,
        input_dev->open = mxt_input_open;
        input_dev->close = mxt_input_close;
 
+       data->client = client;
+       data->input_dev = input_dev;
+       data->pdata = pdata;
+       data->irq = client->irq;
+
+       mxt_calc_resolution(data);
+
        __set_bit(EV_ABS, input_dev->evbit);
        __set_bit(EV_KEY, input_dev->evbit);
        __set_bit(BTN_TOUCH, input_dev->keybit);
 
        /* For single touch */
        input_set_abs_params(input_dev, ABS_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        /* For multi touch */
+       input_mt_init_slots(input_dev, MXT_MAX_FINGER);
        input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
                             0, MXT_MAX_AREA, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_X,
-                            0, MXT_MAX_XC, 0, 0);
+                            0, data->max_x, 0, 0);
        input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
-                            0, MXT_MAX_YC, 0, 0);
+                            0, data->max_y, 0, 0);
 
        input_set_drvdata(input_dev, data);
-
-       data->client = client;
-       data->input_dev = input_dev;
-       data->pdata = pdata;
-       data->irq = client->irq;
-
        i2c_set_clientdata(client, data);
 
        error = mxt_initialize(data);
@@ -1090,6 +1118,10 @@ static int __devinit mxt_probe(struct i2c_client *client,
                goto err_free_object;
        }
 
+       error = mxt_make_highchg(data);
+       if (error)
+               goto err_free_irq;
+
        error = input_register_device(input_dev);
        if (error)
                goto err_free_irq;
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
new file mode 100644 (file)
index 0000000..4f2713d
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Driver for MAXI MAX11801 - A Resistive touch screen controller with
+ * i2c interface
+ *
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ * Author: Zhang Jiejing <jiejing.zhang@freescale.com>
+ *
+ * Based on mcs5000_ts.c
+ *
+ * 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.
+ */
+
+/*
+ * This driver aims to support the series of MAXI touch chips max11801
+ * through max11803. The main difference between these 4 chips can be
+ * found in the table below:
+ * -----------------------------------------------------
+ * | CHIP     |  AUTO MODE SUPPORT(FIFO) | INTERFACE    |
+ * |----------------------------------------------------|
+ * | max11800 |  YES                     |   SPI        |
+ * | max11801 |  YES                     |   I2C        |
+ * | max11802 |  NO                      |   SPI        |
+ * | max11803 |  NO                      |   I2C        |
+ * ------------------------------------------------------
+ *
+ * Currently, this driver only supports max11801.
+ *
+ * Data Sheet:
+ * http://www.maxim-ic.com/datasheet/index.mvp/id/5943
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+
+/* Register Address define */
+#define GENERNAL_STATUS_REG            0x00
+#define GENERNAL_CONF_REG              0x01
+#define MESURE_RES_CONF_REG            0x02
+#define MESURE_AVER_CONF_REG           0x03
+#define ADC_SAMPLE_TIME_CONF_REG       0x04
+#define PANEL_SETUPTIME_CONF_REG       0x05
+#define DELAY_CONVERSION_CONF_REG      0x06
+#define TOUCH_DETECT_PULLUP_CONF_REG   0x07
+#define AUTO_MODE_TIME_CONF_REG                0x08 /* only for max11800/max11801 */
+#define APERTURE_CONF_REG              0x09 /* only for max11800/max11801 */
+#define AUX_MESURE_CONF_REG            0x0a
+#define OP_MODE_CONF_REG               0x0b
+
+/* FIFO is found only in max11800 and max11801 */
+#define FIFO_RD_CMD                    (0x50 << 1)
+#define MAX11801_FIFO_INT              (1 << 2)
+#define MAX11801_FIFO_OVERFLOW         (1 << 3)
+
+#define XY_BUFSIZE                     4
+#define XY_BUF_OFFSET                  4
+
+#define MAX11801_MAX_X                 0xfff
+#define MAX11801_MAX_Y                 0xfff
+
+#define MEASURE_TAG_OFFSET             2
+#define MEASURE_TAG_MASK               (3 << MEASURE_TAG_OFFSET)
+#define EVENT_TAG_OFFSET               0
+#define EVENT_TAG_MASK                 (3 << EVENT_TAG_OFFSET)
+#define MEASURE_X_TAG                  (0 << MEASURE_TAG_OFFSET)
+#define MEASURE_Y_TAG                  (1 << MEASURE_TAG_OFFSET)
+
+/* These are the state of touch event state machine */
+enum {
+       EVENT_INIT,
+       EVENT_MIDDLE,
+       EVENT_RELEASE,
+       EVENT_FIFO_END
+};
+
+struct max11801_data {
+       struct i2c_client               *client;
+       struct input_dev                *input_dev;
+};
+
+static u8 read_register(struct i2c_client *client, int addr)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_read_byte_data(client, addr << 1);
+}
+
+static int max11801_write_reg(struct i2c_client *client, int addr, int data)
+{
+       /* XXX: The chip ignores LSB of register address */
+       return i2c_smbus_write_byte_data(client, addr << 1, data);
+}
+
+static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
+{
+       struct max11801_data *data = dev_id;
+       struct i2c_client *client = data->client;
+       int status, i, ret;
+       u8 buf[XY_BUFSIZE];
+       int x = -1;
+       int y = -1;
+
+       status = read_register(data->client, GENERNAL_STATUS_REG);
+
+       if (status & (MAX11801_FIFO_INT | MAX11801_FIFO_OVERFLOW)) {
+               status = read_register(data->client, GENERNAL_STATUS_REG);
+
+               ret = i2c_smbus_read_i2c_block_data(client, FIFO_RD_CMD,
+                                                   XY_BUFSIZE, buf);
+
+               /*
+                * We should get 4 bytes buffer that contains X,Y
+                * and event tag
+                */
+               if (ret < XY_BUFSIZE)
+                       goto out;
+
+               for (i = 0; i < XY_BUFSIZE; i += XY_BUFSIZE / 2) {
+                       if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_X_TAG)
+                               x = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+                       else if ((buf[i + 1] & MEASURE_TAG_MASK) == MEASURE_Y_TAG)
+                               y = (buf[i] << XY_BUF_OFFSET) +
+                                   (buf[i + 1] >> XY_BUF_OFFSET);
+               }
+
+               if ((buf[1] & EVENT_TAG_MASK) != (buf[3] & EVENT_TAG_MASK))
+                       goto out;
+
+               switch (buf[1] & EVENT_TAG_MASK) {
+               case EVENT_INIT:
+                       /* fall through */
+               case EVENT_MIDDLE:
+                       input_report_abs(data->input_dev, ABS_X, x);
+                       input_report_abs(data->input_dev, ABS_Y, y);
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 1);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_RELEASE:
+                       input_event(data->input_dev, EV_KEY, BTN_TOUCH, 0);
+                       input_sync(data->input_dev);
+                       break;
+
+               case EVENT_FIFO_END:
+                       break;
+               }
+       }
+out:
+       return IRQ_HANDLED;
+}
+
+static void __devinit max11801_ts_phy_init(struct max11801_data *data)
+{
+       struct i2c_client *client = data->client;
+
+       /* Average X,Y, take 16 samples, average eight media sample */
+       max11801_write_reg(client, MESURE_AVER_CONF_REG, 0xff);
+       /* X,Y panel setup time set to 20us */
+       max11801_write_reg(client, PANEL_SETUPTIME_CONF_REG, 0x11);
+       /* Rough pullup time (2uS), Fine pullup time (10us)  */
+       max11801_write_reg(client, TOUCH_DETECT_PULLUP_CONF_REG, 0x10);
+       /* Auto mode init period = 5ms , scan period = 5ms*/
+       max11801_write_reg(client, AUTO_MODE_TIME_CONF_REG, 0xaa);
+       /* Aperture X,Y set to +- 4LSB */
+       max11801_write_reg(client, APERTURE_CONF_REG, 0x33);
+       /* Enable Power, enable Automode, enable Aperture, enable Average X,Y */
+       max11801_write_reg(client, OP_MODE_CONF_REG, 0x36);
+}
+
+static int __devinit max11801_ts_probe(struct i2c_client *client,
+                                      const struct i2c_device_id *id)
+{
+       struct max11801_data *data;
+       struct input_dev *input_dev;
+       int error;
+
+       data = kzalloc(sizeof(struct max11801_data), GFP_KERNEL);
+       input_dev = input_allocate_device();
+       if (!data || !input_dev) {
+               dev_err(&client->dev, "Failed to allocate memory\n");
+               error = -ENOMEM;
+               goto err_free_mem;
+       }
+
+       data->client = client;
+       data->input_dev = input_dev;
+
+       input_dev->name = "max11801_ts";
+       input_dev->id.bustype = BUS_I2C;
+       input_dev->dev.parent = &client->dev;
+
+       __set_bit(EV_ABS, input_dev->evbit);
+       __set_bit(EV_KEY, input_dev->evbit);
+       __set_bit(BTN_TOUCH, input_dev->keybit);
+       input_set_abs_params(input_dev, ABS_X, 0, MAX11801_MAX_X, 0, 0);
+       input_set_abs_params(input_dev, ABS_Y, 0, MAX11801_MAX_Y, 0, 0);
+       input_set_drvdata(input_dev, data);
+
+       max11801_ts_phy_init(data);
+
+       error = request_threaded_irq(client->irq, NULL, max11801_ts_interrupt,
+                                    IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+                                    "max11801_ts", data);
+       if (error) {
+               dev_err(&client->dev, "Failed to register interrupt\n");
+               goto err_free_mem;
+       }
+
+       error = input_register_device(data->input_dev);
+       if (error)
+               goto err_free_irq;
+
+       i2c_set_clientdata(client, data);
+       return 0;
+
+err_free_irq:
+       free_irq(client->irq, data);
+err_free_mem:
+       input_free_device(input_dev);
+       kfree(data);
+       return error;
+}
+
+static __devexit int max11801_ts_remove(struct i2c_client *client)
+{
+       struct max11801_data *data = i2c_get_clientdata(client);
+
+       free_irq(client->irq, data);
+       input_unregister_device(data->input_dev);
+       kfree(data);
+
+       return 0;
+}
+
+static const struct i2c_device_id max11801_ts_id[] = {
+       {"max11801", 0},
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
+
+static struct i2c_driver max11801_ts_driver = {
+       .driver = {
+               .name   = "max11801_ts",
+               .owner  = THIS_MODULE,
+       },
+       .id_table       = max11801_ts_id,
+       .probe          = max11801_ts_probe,
+       .remove         = __devexit_p(max11801_ts_remove),
+};
+
+static int __init max11801_ts_init(void)
+{
+       return i2c_add_driver(&max11801_ts_driver);
+}
+
+static void __exit max11801_ts_exit(void)
+{
+       i2c_del_driver(&max11801_ts_driver);
+}
+
+module_init(max11801_ts_init);
+module_exit(max11801_ts_exit);
+
+MODULE_AUTHOR("Zhang Jiejing <jiejing.zhang@freescale.com>");
+MODULE_DESCRIPTION("Touchscreen driver for MAXI MAX11801 controller");
+MODULE_LICENSE("GPL");
index dd1a56fbe9241235f4baa059394d5d36bd050de7..b5ca4b2c08ecad2fad00c33d48b62466737966b0 100644 (file)
@@ -3,14 +3,15 @@
 
 struct gpio_keys_button {
        /* Configuration parameters */
-       int code;               /* input event code (KEY_*, SW_*) */
+       unsigned int code;      /* input event code (KEY_*, SW_*) */
        int gpio;
        int active_low;
-       char *desc;
-       int type;               /* input event type (EV_KEY, EV_SW) */
+       const char *desc;
+       unsigned int type;      /* input event type (EV_KEY, EV_SW, EV_ABS) */
        int wakeup;             /* configure the button as a wake-up source */
        int debounce_interval;  /* debounce ticks interval in msecs */
        bool can_disable;
+       int value;              /* axis value for EV_ABS */
 };
 
 struct gpio_keys_platform_data {
@@ -21,6 +22,7 @@ struct gpio_keys_platform_data {
        unsigned int rep:1;             /* enable input subsystem auto repeat */
        int (*enable)(struct device *dev);
        void (*disable)(struct device *dev);
+       const char *name;               /* input device name */
 };
 
 #endif