]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/input/touchscreen/edt-ft5x06.c
Merge remote-tracking branch 'omap/for-next'
[karo-tx-linux.git] / drivers / input / touchscreen / edt-ft5x06.c
index 48de1e8b3c93578cf4c1faf88c220c008a75569c..0b0f8c17f3f7e0f4df1e69144d693b46741f4025 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/module.h>
 #include <linux/ratelimit.h>
+#include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/input.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/input/mt.h>
 #include <linux/input/touchscreen.h>
-#include <linux/input/edt-ft5x06.h>
-
-#define MAX_SUPPORT_POINTS             5
+#include <linux/of_device.h>
 
 #define WORK_REGISTER_THRESHOLD                0x00
 #define WORK_REGISTER_REPORT_RATE      0x08
@@ -91,9 +89,8 @@ struct edt_ft5x06_ts_data {
        u16 num_x;
        u16 num_y;
 
-       int reset_pin;
-       int irq_pin;
-       int wake_pin;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *wake_gpio;
 
 #if defined(CONFIG_DEBUG_FS)
        struct dentry *debug_dir;
@@ -107,6 +104,7 @@ struct edt_ft5x06_ts_data {
        int gain;
        int offset;
        int report_rate;
+       int max_support_points;
 
        char name[EDT_NAME_LEN];
 
@@ -114,6 +112,10 @@ struct edt_ft5x06_ts_data {
        enum edt_ver version;
 };
 
+struct edt_i2c_chip_data {
+       int  max_support_points;
+};
+
 static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
                                   u16 wr_len, u8 *wr_buf,
                                   u16 rd_len, u8 *rd_buf)
@@ -170,9 +172,9 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
        struct edt_ft5x06_ts_data *tsdata = dev_id;
        struct device *dev = &tsdata->client->dev;
        u8 cmd;
-       u8 rdbuf[29];
+       u8 rdbuf[63];
        int i, type, x, y, id;
-       int offset, tplen, datalen;
+       int offset, tplen, datalen, crclen;
        int error;
 
        switch (tsdata->version) {
@@ -180,14 +182,14 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
                cmd = 0xf9; /* tell the controller to send touch data */
                offset = 5; /* where the actual touch data starts */
                tplen = 4;  /* data comes in so called frames */
-               datalen = 26; /* how much bytes to listen for */
+               crclen = 1; /* length of the crc data */
                break;
 
        case M09:
-               cmd = 0x02;
-               offset = 1;
+               cmd = 0x0;
+               offset = 3;
                tplen = 6;
-               datalen = 29;
+               crclen = 0;
                break;
 
        default:
@@ -195,6 +197,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
        }
 
        memset(rdbuf, 0, sizeof(rdbuf));
+       datalen = tplen * tsdata->max_support_points + offset + crclen;
 
        error = edt_ft5x06_ts_readwrite(tsdata->client,
                                        sizeof(cmd), &cmd,
@@ -219,7 +222,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
                        goto out;
        }
 
-       for (i = 0; i < MAX_SUPPORT_POINTS; i++) {
+       for (i = 0; i < tsdata->max_support_points; i++) {
                u8 *buf = &rdbuf[i * tplen + offset];
                bool down;
 
@@ -752,45 +755,6 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
 
 #endif /* CONFIG_DEBUGFS */
 
-static int edt_ft5x06_ts_reset(struct i2c_client *client,
-                       struct edt_ft5x06_ts_data *tsdata)
-{
-       int error;
-
-       if (gpio_is_valid(tsdata->wake_pin)) {
-               error = devm_gpio_request_one(&client->dev,
-                                       tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
-                                       "edt-ft5x06 wake");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d as wake pin, error %d\n",
-                               tsdata->wake_pin, error);
-                       return error;
-               }
-
-               msleep(5);
-               gpio_set_value(tsdata->wake_pin, 1);
-       }
-       if (gpio_is_valid(tsdata->reset_pin)) {
-               /* this pulls reset down, enabling the low active reset */
-               error = devm_gpio_request_one(&client->dev,
-                                       tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
-                                       "edt-ft5x06 reset");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d as reset pin, error %d\n",
-                               tsdata->reset_pin, error);
-                       return error;
-               }
-
-               msleep(5);
-               gpio_set_value(tsdata->reset_pin, 1);
-               msleep(300);
-       }
-
-       return 0;
-}
-
 static int edt_ft5x06_ts_identify(struct i2c_client *client,
                                        struct edt_ft5x06_ts_data *tsdata,
                                        char *fw_version)
@@ -850,44 +814,24 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
        return 0;
 }
 
-#define EDT_ATTR_CHECKSET(name, reg) \
-do {                                                           \
-       if (pdata->name >= edt_ft5x06_attr_##name.limit_low &&          \
-           pdata->name <= edt_ft5x06_attr_##name.limit_high)           \
-               edt_ft5x06_register_write(tsdata, reg, pdata->name);    \
-} while (0)
-
-#define EDT_GET_PROP(name, reg) {                              \
-       u32 val;                                                \
-       if (of_property_read_u32(np, #name, &val) == 0)         \
-               edt_ft5x06_register_write(tsdata, reg, val);    \
-}
-
-static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
-                                       struct edt_ft5x06_ts_data *tsdata)
+static void edt_ft5x06_ts_get_defaults(struct device *dev,
+                                      struct edt_ft5x06_ts_data *tsdata)
 {
        struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
+       u32 val;
+       int error;
 
-       EDT_GET_PROP(threshold, reg_addr->reg_threshold);
-       EDT_GET_PROP(gain, reg_addr->reg_gain);
-       EDT_GET_PROP(offset, reg_addr->reg_offset);
-}
+       error = device_property_read_u32(dev, "threshold", &val);
+       if (!error)
+               reg_addr->reg_threshold = val;
 
-static void
-edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
-                          const struct edt_ft5x06_platform_data *pdata)
-{
-       struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
-
-       if (!pdata->use_parameters)
-               return;
+       error = device_property_read_u32(dev, "gain", &val);
+       if (!error)
+               reg_addr->reg_gain = val;
 
-       /* pick up defaults from the platform data */
-       EDT_ATTR_CHECKSET(threshold, reg_addr->reg_threshold);
-       EDT_ATTR_CHECKSET(gain, reg_addr->reg_gain);
-       EDT_ATTR_CHECKSET(offset, reg_addr->reg_offset);
-       if (reg_addr->reg_report_rate != NO_REGISTER)
-               EDT_ATTR_CHECKSET(report_rate, reg_addr->reg_report_rate);
+       error = device_property_read_u32(dev, "offset", &val);
+       if (!error)
+               reg_addr->reg_offset = val;
 }
 
 static void
@@ -931,37 +875,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
        }
 }
 
-#ifdef CONFIG_OF
-static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
-                               struct edt_ft5x06_ts_data *tsdata)
-{
-       struct device_node *np = dev->of_node;
-
-       /*
-        * irq_pin is not needed for DT setup.
-        * irq is associated via 'interrupts' property in DT
-        */
-       tsdata->irq_pin = -EINVAL;
-       tsdata->reset_pin = of_get_named_gpio(np, "reset-gpios", 0);
-       tsdata->wake_pin = of_get_named_gpio(np, "wake-gpios", 0);
-
-       return 0;
-}
-#else
-static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
-                                       struct edt_ft5x06_ts_data *tsdata)
-{
-       return -ENODEV;
-}
-#endif
-
 static int edt_ft5x06_ts_probe(struct i2c_client *client,
                                         const struct i2c_device_id *id)
 {
-       const struct edt_ft5x06_platform_data *pdata =
-                                               dev_get_platdata(&client->dev);
+       const struct edt_i2c_chip_data *chip_data;
        struct edt_ft5x06_ts_data *tsdata;
        struct input_dev *input;
+       unsigned long irq_flags;
        int error;
        char fw_version[EDT_NAME_LEN];
 
@@ -973,32 +893,43 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
-       if (!pdata) {
-               error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
-               if (error) {
-                       dev_err(&client->dev,
-                               "DT probe failed and no platform data present\n");
-                       return error;
-               }
-       } else {
-               tsdata->reset_pin = pdata->reset_pin;
-               tsdata->irq_pin = pdata->irq_pin;
-               tsdata->wake_pin = -EINVAL;
+       chip_data = of_device_get_match_data(&client->dev);
+       if (!chip_data)
+               chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
+       if (!chip_data || !chip_data->max_support_points) {
+               dev_err(&client->dev, "invalid or missing chip data\n");
+               return -EINVAL;
        }
 
-       error = edt_ft5x06_ts_reset(client, tsdata);
-       if (error)
+       tsdata->max_support_points = chip_data->max_support_points;
+
+       tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev,
+                                                    "reset", GPIOD_OUT_HIGH);
+       if (IS_ERR(tsdata->reset_gpio)) {
+               error = PTR_ERR(tsdata->reset_gpio);
+               dev_err(&client->dev,
+                       "Failed to request GPIO reset pin, error %d\n", error);
+               return error;
+       }
+
+       tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev,
+                                                   "wake", GPIOD_OUT_LOW);
+       if (IS_ERR(tsdata->wake_gpio)) {
+               error = PTR_ERR(tsdata->wake_gpio);
+               dev_err(&client->dev,
+                       "Failed to request GPIO wake pin, error %d\n", error);
                return error;
+       }
 
-       if (gpio_is_valid(tsdata->irq_pin)) {
-               error = devm_gpio_request_one(&client->dev, tsdata->irq_pin,
-                                       GPIOF_IN, "edt-ft5x06 irq");
-               if (error) {
-                       dev_err(&client->dev,
-                               "Failed to request GPIO %d, error %d\n",
-                               tsdata->irq_pin, error);
-                       return error;
-               }
+       if (tsdata->wake_gpio) {
+               usleep_range(5000, 6000);
+               gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
+       }
+
+       if (tsdata->reset_gpio) {
+               usleep_range(5000, 6000);
+               gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
+               msleep(300);
        }
 
        input = devm_input_allocate_device(&client->dev);
@@ -1019,12 +950,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        }
 
        edt_ft5x06_ts_set_regs(tsdata);
-
-       if (!pdata)
-               edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
-       else
-               edt_ft5x06_ts_get_defaults(tsdata, pdata);
-
+       edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
        edt_ft5x06_ts_get_parameters(tsdata);
 
        dev_dbg(&client->dev,
@@ -1040,10 +966,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        input_set_abs_params(input, ABS_MT_POSITION_Y,
                             0, tsdata->num_y * 64 - 1, 0, 0);
 
-       if (!pdata)
-               touchscreen_parse_properties(input, true);
+       touchscreen_parse_properties(input, true);
 
-       error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT);
+       error = input_mt_init_slots(input, tsdata->max_support_points,
+                               INPUT_MT_DIRECT);
        if (error) {
                dev_err(&client->dev, "Unable to init MT slots.\n");
                return error;
@@ -1052,9 +978,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
        input_set_drvdata(input, tsdata);
        i2c_set_clientdata(client, tsdata);
 
-       error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
-                                       edt_ft5x06_ts_isr,
-                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+       irq_flags = irq_get_trigger_type(client->irq);
+       if (irq_flags == IRQF_TRIGGER_NONE)
+               irq_flags = IRQF_TRIGGER_FALLING;
+       irq_flags |= IRQF_ONESHOT;
+
+       error = devm_request_threaded_irq(&client->dev, client->irq,
+                                       NULL, edt_ft5x06_ts_isr, irq_flags,
                                        client->name, tsdata);
        if (error) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
@@ -1074,7 +1004,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 
        dev_dbg(&client->dev,
                "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
-               client->irq, tsdata->wake_pin, tsdata->reset_pin);
+               client->irq,
+               tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1,
+               tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
 
        return 0;
 
@@ -1116,17 +1048,27 @@ static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
                         edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
 
+static const struct edt_i2c_chip_data edt_ft5x06_data = {
+       .max_support_points = 5,
+};
+
+static const struct edt_i2c_chip_data edt_ft5506_data = {
+       .max_support_points = 10,
+};
+
 static const struct i2c_device_id edt_ft5x06_ts_id[] = {
-       { "edt-ft5x06", 0, },
+       { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data },
+       { .name = "edt-ft5506", .driver_data = (long)&edt_ft5506_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(i2c, edt_ft5x06_ts_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id edt_ft5x06_of_match[] = {
-       { .compatible = "edt,edt-ft5206", },
-       { .compatible = "edt,edt-ft5306", },
-       { .compatible = "edt,edt-ft5406", },
+       { .compatible = "edt,edt-ft5206", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5306", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
+       { .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match);