summaryrefslogtreecommitdiffstats
path: root/drivers/input/touchscreen/edt-ft5x06.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-11-06 11:57:41 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2015-11-06 11:57:41 -0800
commit3e069adabc9487b5e28065a17e6a228da3412dfd (patch)
tree93b4db74b3d293bc30e69a7ffb4a2ea1c4069682 /drivers/input/touchscreen/edt-ft5x06.c
parent02f0d3f758ab456c50199b723a53f2443fa4f684 (diff)
parente60e063c14b13d0f66ffc708b8aa5d1a8208606e (diff)
downloadop-kernel-dev-3e069adabc9487b5e28065a17e6a228da3412dfd.zip
op-kernel-dev-3e069adabc9487b5e28065a17e6a228da3412dfd.tar.gz
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: "Items of note: - evdev users can now limit or mask the kind of events they will receive. This will allow applications such as power manager or network manager to only be woken when user presses special keys such as KEY_POWER or KEY_WIFI and not be bothered with ordinary key presses coming from keyboard - support for FocalTech FT6236 touchscreen controller - support for ROHM BU21023/24 touchscreen controller - edt-ft5x06 touchscreen driver got a face lift and can now be used with FT5506 - support for Google Fiber TV Box remote controls - improvements in xpad driver (with more to come) - several parport-based drivers have been switched to the new device model - other miscellaneous driver improvements" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (70 commits) HID: hid-gfrm: avoid warning for input_configured API change HID: hid-input: allow input_configured callback return errors Input: evdev - fix bug in checking duplicate clock change request Input: add userio module Input: evdev - add event-mask API Input: snvs_pwrkey - remove duplicated semicolon HID: hid-gfrm: Google Fiber TV Box remote controls Input: e3x0-button - update Kconfig description Input: tegra-kbc - drop use of IRQF_NO_SUSPEND flag Input: tegra-kbc - enable support for the standard "wakeup-source" property Input: xen - check return value of xenbus_printf Input: hp_sdc_rtc - fix y2038 problem in proc_show Input: nomadik-ske-keypad - fix a trivial typo Input: xpad - fix clash of presence handling with LED setting Input: edt-ft5x06 - work around FT5506 firmware bug Input: edt-ft5x06 - add support for FT5506 Input: edt-ft5x06 - add support for different max support points Input: edt-ft5x06 - use max support points to determine how much to read Input: rotary-encoder - add support for quarter-period mode Input: rotary-encoder - use of_property_read_bool ...
Diffstat (limited to 'drivers/input/touchscreen/edt-ft5x06.c')
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c246
1 files changed, 94 insertions, 152 deletions
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 48de1e8..0b0f8c1 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -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>
@@ -34,13 +35,10 @@
#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);
OpenPOWER on IntegriCloud