* [PATCH v4 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support
@ 2014-05-05 9:04 Roger Quadros
[not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>
` (2 more replies)
0 siblings, 3 replies; 12+ messages in thread
From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw)
To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w
Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0,
dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0,
nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros
Hi Dmitry,
This series does the following
- use devres managed resource allocations
- convert to Type-B multi touch protocol
- support upto 5 fingers with hardware supplied tracking IDs
- device tree support
Please queue this for -next (3.16). Thanks.
cheers,
-roger
Changelog:
v4:
- imporved pixcir_stop() as per Dmitry's suggestion.
- removed unnecessary input_unregister_device() from .remove().
v3:
- Rebased to 3.15-rc3
- Fixed suspend while touchscreen in use
- Fixed module removal while touchscreen in use
v2:
- Addressed review comments and re-arranged patch order
v1:
- http://article.gmane.org/gmane.linux.kernel/1616417
---
Roger Quadros (7):
Input: pixcir_i2c_ts: Use devres managed resource allocations
Input: pixcir_i2c_ts: Initialize interrupt mode and power mode
Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol
Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided
tracking IDs
Input: pixcir_i2c_ts: Implement wakeup from suspend
Input: pixcir_i2c_ts: Add device tree support
.../bindings/input/touchscreen/pixcir_i2c_ts.txt | 26 +
.../devicetree/bindings/vendor-prefixes.txt | 1 +
drivers/input/touchscreen/pixcir_i2c_ts.c | 524 ++++++++++++++++++---
include/linux/input/pixcir_ts.h | 56 ++-
4 files changed, 546 insertions(+), 61 deletions(-)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
--
1.8.3.2
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 12+ messages in thread[parent not found: <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>]
* [PATCH v4 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> @ 2014-05-05 9:04 ` Roger Quadros 2014-05-05 9:04 ` [PATCH v4 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val() Roger Quadros ` (3 subsequent siblings) 4 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros Use devm_() and friends for allocating memory, input device and IRQ. Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 38 ++++++++++++------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 02392d2..8a083bd 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -130,6 +130,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); + struct device *dev = &client->dev; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; @@ -139,12 +140,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return -EINVAL; } - tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL); - input = input_allocate_device(); - if (!tsdata || !input) { - dev_err(&client->dev, "Failed to allocate driver data!\n"); - error = -ENOMEM; - goto err_free_mem; + tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); + if (!tsdata) + return -ENOMEM; + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(&client->dev, "Failed to allocate input device\n"); + return -ENOMEM; } tsdata->client = client; @@ -165,29 +168,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); - error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr, - IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - client->name, tsdata); + error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + client->name, tsdata); if (error) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); - goto err_free_mem; + dev_err(dev, "failed to request irq %d\n", client->irq); + return error; } error = input_register_device(input); if (error) - goto err_free_irq; + return error; i2c_set_clientdata(client, tsdata); device_init_wakeup(&client->dev, 1); return 0; - -err_free_irq: - free_irq(client->irq, tsdata); -err_free_mem: - input_free_device(input); - kfree(tsdata); - return error; } static int pixcir_i2c_ts_remove(struct i2c_client *client) @@ -198,10 +194,6 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) tsdata->exiting = true; mb(); - free_irq(client->irq, tsdata); - - input_unregister_device(tsdata->input); - kfree(tsdata); return 0; } -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val() [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> 2014-05-05 9:04 ` [PATCH v4 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations Roger Quadros @ 2014-05-05 9:04 ` Roger Quadros 2014-05-05 9:04 ` [PATCH v4 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs Roger Quadros ` (2 subsequent siblings) 4 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros Get rid of the attb_read_val() platform hook. Instead, read the ATTB gpio directly from the driver. Fail if valid ATTB gpio is not provided by patform data. Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 16 +++++++++++++++- include/linux/input/pixcir_ts.h | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 53d01d4..d0f6989 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,6 +24,7 @@ #include <linux/i2c.h> #include <linux/input.h> #include <linux/input/pixcir_ts.h> +#include <linux/gpio.h> struct pixcir_i2c_ts_data { struct i2c_client *client; @@ -87,11 +88,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; + const struct pixcir_ts_platform_data *pdata = tsdata->chip; while (!tsdata->exiting) { pixcir_ts_poscheck(tsdata); - if (tsdata->chip->attb_read_val()) + if (gpio_get_value(pdata->gpio_attb)) break; msleep(20); @@ -296,6 +298,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, if (!pdata) { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; + } else { + if (!gpio_is_valid(pdata->gpio_attb)) { + dev_err(dev, "Invalid gpio_attb in pdata\n"); + return -EINVAL; + } } tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); @@ -328,6 +335,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); + error = devm_gpio_request_one(dev, pdata->gpio_attb, + GPIOF_DIR_IN, "pixcir_i2c_attb"); + if (error) { + dev_err(dev, "Failed to request ATTB gpio\n"); + return error; + } + error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7942804..160cf35 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -44,9 +44,9 @@ enum pixcir_int_mode { #define PIXCIR_INT_POL_HIGH (1UL << 2) struct pixcir_ts_platform_data { - int (*attb_read_val)(void); int x_max; int y_max; + int gpio_attb; /* GPIO connected to ATTB line */ }; #endif -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> 2014-05-05 9:04 ` [PATCH v4 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations Roger Quadros 2014-05-05 9:04 ` [PATCH v4 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val() Roger Quadros @ 2014-05-05 9:04 ` Roger Quadros 2014-05-05 9:04 ` [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend Roger Quadros 2014-05-05 9:04 ` [PATCH v4 7/7] Input: pixcir_i2c_ts: Add device tree support Roger Quadros 4 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros Some variants of the Pixcir touch controller support upto 5 simultaneous fingers and hardware tracking IDs. Prepare the driver for that. Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 74 ++++++++++++++++++++++++------- include/linux/input/pixcir_ts.h | 12 +++++ 2 files changed, 69 insertions(+), 17 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 3123699..927aed1 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -27,18 +27,20 @@ #include <linux/input/pixcir_ts.h> #include <linux/gpio.h> -#define PIXCIR_MAX_SLOTS 2 +#define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; - const struct pixcir_ts_platform_data *chip; + const struct pixcir_ts_platform_data *pdata; bool exiting; + int max_fingers; /* Max fingers supported in this instance */ }; struct pixcir_touch { int x; int y; + int id; }; struct pixcir_report_data { @@ -49,13 +51,21 @@ struct pixcir_report_data { static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, struct pixcir_report_data *report) { - u8 rdbuf[10], wrbuf[1] = { 0 }; + u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5]; + u8 wrbuf[1] = { 0 }; u8 *bufptr; u8 touch; int ret, i; + int readsize; + const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip; memset(report, 0, sizeof(struct pixcir_report_data)); + i = chip->has_hw_ids ? 1 : 0; + readsize = 2 + tsdata->max_fingers * (4 + i); + if (readsize > sizeof(rdbuf)) + readsize = sizeof(rdbuf); + ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); if (ret != sizeof(wrbuf)) { dev_err(&tsdata->client->dev, @@ -64,7 +74,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, return; } - ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf)); + ret = i2c_master_recv(tsdata->client, rdbuf, readsize); if (ret != sizeof(rdbuf)) { dev_err(&tsdata->client->dev, "%s: i2c_master_recv failed(), ret=%d\n", @@ -73,8 +83,8 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, } touch = rdbuf[0] & 0x7; - if (touch > PIXCIR_MAX_SLOTS) - touch = PIXCIR_MAX_SLOTS; + if (touch > tsdata->max_fingers) + touch = tsdata->max_fingers; report->num_touches = touch; bufptr = &rdbuf[2]; @@ -83,7 +93,12 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, report->touches[i].x = (bufptr[1] << 8) | bufptr[0]; report->touches[i].y = (bufptr[3] << 8) | bufptr[2]; - bufptr = &bufptr[4]; + if (chip->has_hw_ids) { + report->touches[i].id = bufptr[4]; + bufptr = &bufptr[5]; + } else { + bufptr = &bufptr[4]; + } } } @@ -95,22 +110,35 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, struct pixcir_touch *touch; int n, i, slot; struct device *dev = &ts->client->dev; + const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip; n = report->num_touches; if (n > PIXCIR_MAX_SLOTS) n = PIXCIR_MAX_SLOTS; - for (i = 0; i < n; i++) { - touch = &report->touches[i]; - pos[i].x = touch->x; - pos[i].y = touch->y; - } + if (!chip->has_hw_ids) { + for (i = 0; i < n; i++) { + touch = &report->touches[i]; + pos[i].x = touch->x; + pos[i].y = touch->y; + } - input_mt_assign_slots(ts->input, slots, pos, n); + input_mt_assign_slots(ts->input, slots, pos, n); + } for (i = 0; i < n; i++) { touch = &report->touches[i]; - slot = slots[i]; + + if (chip->has_hw_ids) { + slot = input_mt_get_slot_by_key(ts->input, touch->id); + if (slot < 0) { + dev_dbg(dev, "no free slot for id 0x%x\n", + touch->id); + continue; + } + } else { + slot = slots[i]; + } input_mt_slot(ts->input, slot); input_mt_report_slot_state(ts->input, @@ -130,7 +158,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; - const struct pixcir_ts_platform_data *pdata = tsdata->chip; + const struct pixcir_ts_platform_data *pdata = tsdata->pdata; struct pixcir_report_data report; while (!tsdata->exiting) { @@ -359,6 +387,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, dev_err(dev, "Invalid gpio_attb in pdata\n"); return -EINVAL; } + + if (pdata->chip.max_fingers <= 0) { + dev_err(dev, "Invalid max_fingers in pdata\n"); + return -EINVAL; + } } tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); @@ -373,7 +406,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, tsdata->client = client; tsdata->input = input; - tsdata->chip = pdata; + tsdata->pdata = pdata; input->name = client->name; input->id.bustype = BUS_I2C; @@ -389,7 +422,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); - error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS, + tsdata->max_fingers = tsdata->pdata->chip.max_fingers; + if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) { + tsdata->max_fingers = PIXCIR_MAX_SLOTS; + dev_info(dev, "Limiting maximum fingers to %d\n", + tsdata->max_fingers); + } + + error = input_mt_init_slots(input, tsdata->max_fingers, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); if (error) { dev_err(dev, "Error initializing Multi-Touch slots\n"); diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 160cf35..7bae83b 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -43,10 +43,22 @@ enum pixcir_int_mode { #define PIXCIR_INT_ENABLE (1UL << 3) #define PIXCIR_INT_POL_HIGH (1UL << 2) +/** + * struct pixcir_irc_chip_data - chip related data + * @max_fingers: Max number of fingers reported simultaneously by h/w + * @has_hw_ids: Hardware supports finger tracking IDs + * + */ +struct pixcir_i2c_chip_data { + u8 max_fingers; + bool has_hw_ids; +}; + struct pixcir_ts_platform_data { int x_max; int y_max; int gpio_attb; /* GPIO connected to ATTB line */ + struct pixcir_i2c_chip_data chip; }; #endif -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> ` (2 preceding siblings ...) 2014-05-05 9:04 ` [PATCH v4 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs Roger Quadros @ 2014-05-05 9:04 ` Roger Quadros 2014-05-06 5:21 ` Dmitry Torokhov 2014-05-05 9:04 ` [PATCH v4 7/7] Input: pixcir_i2c_ts: Add device tree support Roger Quadros 4 siblings, 1 reply; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros Improve the suspend and resume handlers to allow the device to wakeup the system from suspend. Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 53 ++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 927aed1..5f6a27e 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -348,21 +348,66 @@ static void pixcir_input_close(struct input_dev *dev) static int pixcir_i2c_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); + struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); + struct input_dev *input = ts->input; + int ret = 0; + + mutex_lock(&input->mutex); + + if (input->users) { + ret = pixcir_stop(ts); + if (ret) + goto unlock; + } + + /* + * If wakeup is enabled we need to enable interrupt generation + * but don't need to process any reports i.e. ts->exiting must be true. + */ + if (device_may_wakeup(&client->dev)) { + /* enable wakeup interrupt generation */ + ret = pixcir_int_enable(ts, 1); + if (ret) { + dev_err(dev, "Failed to enable interrupt generation\n"); + goto unlock; + } - if (device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); + } - return 0; +unlock: + mutex_unlock(&input->mutex); + + return ret; } static int pixcir_i2c_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); + struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); + struct input_dev *input = ts->input; + int ret = 0; - if (device_may_wakeup(&client->dev)) + mutex_lock(&input->mutex); + + if (device_may_wakeup(&client->dev)) { disable_irq_wake(client->irq); - return 0; + /* disable wakeup interrupt generation */ + ret = pixcir_int_enable(ts, 0); + if (ret) { + dev_err(dev, "Failed to disable interrupt generation\n"); + goto unlock; + } + } + + if (input->users) + ret = pixcir_start(ts); + +unlock: + mutex_unlock(&input->mutex); + + return ret; } #endif -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend 2014-05-05 9:04 ` [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend Roger Quadros @ 2014-05-06 5:21 ` Dmitry Torokhov [not found] ` <20140506052148.GB2608-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org> 0 siblings, 1 reply; 12+ messages in thread From: Dmitry Torokhov @ 2014-05-06 5:21 UTC (permalink / raw) To: Roger Quadros Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel, devicetree On Mon, May 05, 2014 at 12:04:37PM +0300, Roger Quadros wrote: > Improve the suspend and resume handlers to allow the device > to wakeup the system from suspend. > > Signed-off-by: Roger Quadros <rogerq@ti.com> > Acked-by: Mugunthan V N <mugunthanvnm@ti.com> > --- > drivers/input/touchscreen/pixcir_i2c_ts.c | 53 ++++++++++++++++++++++++++++--- > 1 file changed, 49 insertions(+), 4 deletions(-) > > diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c > index 927aed1..5f6a27e 100644 > --- a/drivers/input/touchscreen/pixcir_i2c_ts.c > +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c > @@ -348,21 +348,66 @@ static void pixcir_input_close(struct input_dev *dev) > static int pixcir_i2c_ts_suspend(struct device *dev) > { > struct i2c_client *client = to_i2c_client(dev); > + struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); > + struct input_dev *input = ts->input; > + int ret = 0; > + > + mutex_lock(&input->mutex); > + > + if (input->users) { > + ret = pixcir_stop(ts); > + if (ret) > + goto unlock; > + } > + > + /* > + * If wakeup is enabled we need to enable interrupt generation > + * but don't need to process any reports i.e. ts->exiting must be true. > + */ > + if (device_may_wakeup(&client->dev)) { > + /* enable wakeup interrupt generation */ > + ret = pixcir_int_enable(ts, 1); > + if (ret) { > + dev_err(dev, "Failed to enable interrupt generation\n"); > + goto unlock; > + } I am not sure why we need to disable event processing here. Why not do if (device_may_wakeup(&client->dev)) { enable_irq_wake(client->irq); ret = pixcir_int_enable(ts, true); ... } else if (input->users) { ret = pixcir_stop(ts); } like many of the drivers do? Thanks. -- Dmitry ^ permalink raw reply [flat|nested] 12+ messages in thread
[parent not found: <20140506052148.GB2608-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>]
* Re: [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend [not found] ` <20140506052148.GB2608-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org> @ 2014-05-06 8:33 ` Roger Quadros 0 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-06 8:33 UTC (permalink / raw) To: Dmitry Torokhov Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA On 05/06/2014 08:21 AM, Dmitry Torokhov wrote: > On Mon, May 05, 2014 at 12:04:37PM +0300, Roger Quadros wrote: >> Improve the suspend and resume handlers to allow the device >> to wakeup the system from suspend. >> >> Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> >> Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> >> --- >> drivers/input/touchscreen/pixcir_i2c_ts.c | 53 ++++++++++++++++++++++++++++--- >> 1 file changed, 49 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c >> index 927aed1..5f6a27e 100644 >> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c >> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c >> @@ -348,21 +348,66 @@ static void pixcir_input_close(struct input_dev *dev) >> static int pixcir_i2c_ts_suspend(struct device *dev) >> { >> struct i2c_client *client = to_i2c_client(dev); >> + struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); >> + struct input_dev *input = ts->input; >> + int ret = 0; >> + >> + mutex_lock(&input->mutex); >> + >> + if (input->users) { >> + ret = pixcir_stop(ts); >> + if (ret) >> + goto unlock; >> + } >> + >> + /* >> + * If wakeup is enabled we need to enable interrupt generation >> + * but don't need to process any reports i.e. ts->exiting must be true. >> + */ >> + if (device_may_wakeup(&client->dev)) { >> + /* enable wakeup interrupt generation */ >> + ret = pixcir_int_enable(ts, 1); >> + if (ret) { >> + dev_err(dev, "Failed to enable interrupt generation\n"); >> + goto unlock; >> + } > > I am not sure why we need to disable event processing here. Why not do > > if (device_may_wakeup(&client->dev)) { > enable_irq_wake(client->irq); > ret = pixcir_int_enable(ts, true); > ... > } else if (input->users) { > ret = pixcir_stop(ts); > } > > like many of the drivers do? Seems to work without disabling event processing. I'll send a v5 with this and patch 2 fixed as per your suggestion. Thanks. cheers, -roger -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 7/7] Input: pixcir_i2c_ts: Add device tree support [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> ` (3 preceding siblings ...) 2014-05-05 9:04 ` [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend Roger Quadros @ 2014-05-05 9:04 ` Roger Quadros 4 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA, Roger Quadros Provide device tree support and binding information. Also provide support for a new chip "pixcir_tangoc". Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> --- .../bindings/input/touchscreen/pixcir_i2c_ts.txt | 26 ++++++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/input/touchscreen/pixcir_i2c_ts.c | 78 ++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt new file mode 100644 index 0000000..0ab9505 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt @@ -0,0 +1,26 @@ +* Pixcir I2C touchscreen controllers + +Required properties: +- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc" +- reg: I2C address of the chip +- interrupts: interrupt to which the chip is connected +- attb-gpio: GPIO connected to the ATTB line of the chip +- x-size: horizontal resolution of touchscreen +- y-size: vertical resolution of touchscreen + +Example: + + i2c@00000000 { + /* ... */ + + pixcir_ts@5c { + compatible = "pixcir,pixcir_ts"; + reg = <0x5c>; + interrupts = <2 0>; + attb-gpio = <&gpf 2 0 2>; + x-size = <800>; + y-size = <600>; + }; + + /* ... */ + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index abc3080..2270ebe 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -94,6 +94,7 @@ panasonic Panasonic Corporation phytec PHYTEC Messtechnik GmbH picochip Picochip Ltd plathome Plat'Home Co., Ltd. +pixcir PIXCIR MICROELECTRONICS Co., Ltd powervr PowerVR (deprecated, use img) qca Qualcomm Atheros, Inc. qcom Qualcomm Technologies, Inc diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 5f6a27e..bd547ea 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -26,6 +26,9 @@ #include <linux/input/mt.h> #include <linux/input/pixcir_ts.h> #include <linux/gpio.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ @@ -414,16 +417,70 @@ unlock: static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); +#ifdef CONFIG_OF +static const struct of_device_id pixcir_of_match[]; + +static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +{ + struct pixcir_ts_platform_data *pdata; + struct device_node *np = dev->of_node; + + const struct of_device_id *match; + + match = of_match_device(of_match_ptr(pixcir_of_match), dev); + if (!match) + return ERR_PTR(-EINVAL); + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; + + pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0); + /* gpio_attb validity is checked in probe */ + + if (of_property_read_u32(np, "x-size", &pdata->x_max)) { + dev_err(dev, "Failed to get x-size property\n"); + return ERR_PTR(-EINVAL); + } + pdata->x_max -= 1; + + if (of_property_read_u32(np, "y-size", &pdata->y_max)) { + dev_err(dev, "Failed to get y-size property\n"); + return ERR_PTR(-EINVAL); + } + pdata->y_max -= 1; + + dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__, + pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb); + + return pdata; +} +#else +static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + static int pixcir_i2c_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; + struct device_node *np = dev->of_node; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; + if (np && !pdata) { + pdata = pixcir_parse_dt(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + if (!pdata) { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; @@ -534,15 +591,36 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) static const struct i2c_device_id pixcir_i2c_ts_id[] = { { "pixcir_ts", 0 }, + { "pixcir_tangoc", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); +#ifdef CONFIG_OF +static const struct pixcir_i2c_chip_data pixcir_ts_data = { + .max_fingers = 2, + /* no hw id support */ +}; + +static const struct pixcir_i2c_chip_data pixcir_tangoc_data = { + .max_fingers = 5, + .has_hw_ids = true, +}; + +static const struct of_device_id pixcir_of_match[] = { + { .compatible = "pixcir,pixcir_ts", .data = &pixcir_ts_data }, + { .compatible = "pixcir,pixcir_tangoc", .data = &pixcir_tangoc_data }, + { } +}; +MODULE_DEVICE_TABLE(of, pixcir_of_match); +#endif + static struct i2c_driver pixcir_i2c_ts_driver = { .driver = { .owner = THIS_MODULE, .name = "pixcir_ts", .pm = &pixcir_dev_pm_ops, + .of_match_table = of_match_ptr(pixcir_of_match), }, .probe = pixcir_i2c_ts_probe, .remove = pixcir_i2c_ts_remove, -- 1.8.3.2 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode 2014-05-05 9:04 [PATCH v4 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support Roger Quadros [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> @ 2014-05-05 9:04 ` Roger Quadros [not found] ` <1399280678-23925-3-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> 2014-05-05 9:04 ` [PATCH v4 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol Roger Quadros 2 siblings, 1 reply; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel, devicetree, Roger Quadros Introduce helper functions to configure power and interrupt registers. Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode on detecting finger touch. Configure interrupt mode and polarity on start up. Power down on device closure or module removal. Signed-off-by: Roger Quadros <rogerq@ti.com> Acked-by: Mugunthan V N <mugunthanvnm@ti.com> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 176 +++++++++++++++++++++++++++++- include/linux/input/pixcir_ts.h | 42 +++++++ 2 files changed, 216 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 8a083bd..53d01d4 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_power_mode mode) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_POWER_MODE_MASK; + ret |= mode; + + /* Always AUTO_IDLE */ + ret |= PIXCIR_POWER_ALLOW_IDLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Set the interrupt mode for the device i.e. ATTB line behaviour + * + * @polarity : 1 for active high, 0 for active low. + */ +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_int_mode mode, + bool polarity) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_INT_MODE_MASK; + ret |= mode; + + if (polarity) + ret |= PIXCIR_INT_POL_HIGH; + else + ret &= ~PIXCIR_INT_POL_HIGH; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Enable/disable interrupt generation + */ +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + if (enable) + ret |= PIXCIR_INT_ENABLE; + else + ret &= ~PIXCIR_INT_ENABLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +static int pixcir_start(struct pixcir_i2c_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + int ret; + + /* LEVEL_TOUCH interrupt with active low polarity */ + ret = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); + if (ret) { + dev_err(dev, "Failed to set interrupt mode\n"); + return ret; + } + + ts->exiting = false; + mb(); /* Update status before IRQ can fire */ + + /* enable interrupt generation */ + ret = pixcir_int_enable(ts, 1); + if (ret) { + dev_err(dev, "Failed to enable interrupt generation\n"); + return ret; + } + + return 0; +} + +static int pixcir_stop(struct pixcir_i2c_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + int ret; + + /* disable interrupt generation */ + ret = pixcir_int_enable(ts, 0); + if (ret) { + dev_err(dev, "Failed to disable interrupt generation\n"); + return ret; + } + + /* exit ISR if running, no more report parsing */ + ts->exiting = true; + mb(); /* update status before we synchronize irq */ + + /* wait till running ISR complete */ + synchronize_irq(ts->client->irq); + + return 0; +} + +static int pixcir_input_open(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + return pixcir_start(ts); +} + +static void pixcir_input_close(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + pixcir_stop(ts); +} + + #ifdef CONFIG_PM_SLEEP static int pixcir_i2c_ts_suspend(struct device *dev) { @@ -157,6 +315,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->name = client->name; input->id.bustype = BUS_I2C; input->dev.parent = &client->dev; + input->open = pixcir_input_open; + input->close = pixcir_input_close; __set_bit(EV_KEY, input->evbit); __set_bit(EV_ABS, input->evbit); @@ -176,6 +336,18 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + /* Always be in IDLE mode to save power, device supports auto wake */ + error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); + if (error) { + dev_err(dev, "Failed to set IDLE mode\n"); + return error; + } + + /* Stop device till opened */ + error = pixcir_stop(tsdata); + if (error) + return error; + error = input_register_device(input); if (error) return error; @@ -192,8 +364,8 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) device_init_wakeup(&client->dev, 0); - tsdata->exiting = true; - mb(); + if (!tsdata->exiting) + pixcir_stop(tsdata); return 0; } diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7163d91..7942804 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -1,6 +1,48 @@ #ifndef _PIXCIR_I2C_TS_H #define _PIXCIR_I2C_TS_H +/* + * Register map + */ +#define PIXCIR_REG_POWER_MODE 51 +#define PIXCIR_REG_INT_MODE 52 + +/* + * Power modes: + * active: max scan speed + * idle: lower scan speed with automatic transition to active on touch + * halt: datasheet says sleep but this is more like halt as the chip + * clocks are cut and it can only be brought out of this mode + * using the RESET pin. + */ +enum pixcir_power_mode { + PIXCIR_POWER_ACTIVE, + PIXCIR_POWER_IDLE, + PIXCIR_POWER_HALT, +}; + +#define PIXCIR_POWER_MODE_MASK 0x03 +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) + +/* + * Interrupt modes: + * periodical: interrupt is asserted periodicaly + * diff coordinates: interrupt is asserted when coordinates change + * level on touch: interrupt level asserted during touch + * pulse on touch: interrupt pulse asserted druing touch + * + */ +enum pixcir_int_mode { + PIXCIR_INT_PERIODICAL, + PIXCIR_INT_DIFF_COORD, + PIXCIR_INT_LEVEL_TOUCH, + PIXCIR_INT_PULSE_TOUCH, +}; + +#define PIXCIR_INT_MODE_MASK 0x03 +#define PIXCIR_INT_ENABLE (1UL << 3) +#define PIXCIR_INT_POL_HIGH (1UL << 2) + struct pixcir_ts_platform_data { int (*attb_read_val)(void); int x_max; -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 12+ messages in thread
[parent not found: <1399280678-23925-3-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>]
* Re: [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode [not found] ` <1399280678-23925-3-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> @ 2014-05-06 5:19 ` Dmitry Torokhov 2014-05-06 8:31 ` Roger Quadros 0 siblings, 1 reply; 12+ messages in thread From: Dmitry Torokhov @ 2014-05-06 5:19 UTC (permalink / raw) To: Roger Quadros Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, balbi-l0cyMroinI0, dmurphy-l0cyMroinI0, mugunthanvnm-l0cyMroinI0, nsekhar-l0cyMroinI0, linux-input-u79uwXL29TY76Z2rM5mHXA, linux-kernel-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA Hi Roger, On Mon, May 05, 2014 at 12:04:33PM +0300, Roger Quadros wrote: > @@ -192,8 +364,8 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) > > device_init_wakeup(&client->dev, 0); > > - tsdata->exiting = true; > - mb(); > + if (!tsdata->exiting) > + pixcir_stop(tsdata); > I think if we change tsdata->exiting to tsdata->running we won't have to do it here. Does the version of the patch below work for you? -- Dmitry Input: pixcir_i2c_ts - initialize interrupt mode and power mode From: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> Introduce helper functions to configure power and interrupt registers. Default to IDLE mode on probe as device supports auto wakeup to ACVIE mode on detecting finger touch. Configure interrupt mode and polarity on start up. Power down on device closure or module removal. Signed-off-by: Roger Quadros <rogerq-l0cyMroinI0@public.gmane.org> Acked-by: Mugunthan V N <mugunthanvnm-l0cyMroinI0@public.gmane.org> Signed-off-by: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 182 ++++++++++++++++++++++++++++- include/linux/input/pixcir_ts.h | 42 +++++++ 2 files changed, 216 insertions(+), 8 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 724b839..7d39268 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -29,7 +29,7 @@ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; const struct pixcir_ts_platform_data *chip; - bool exiting; + bool running; }; static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) @@ -88,7 +88,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; - while (!tsdata->exiting) { + while (tsdata->running) { pixcir_ts_poscheck(tsdata); if (tsdata->chip->attb_read_val()) @@ -100,6 +100,164 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_power_mode mode) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_POWER_MODE_MASK; + ret |= mode; + + /* Always AUTO_IDLE */ + ret |= PIXCIR_POWER_ALLOW_IDLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_POWER_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Set the interrupt mode for the device i.e. ATTB line behaviour + * + * @polarity : 1 for active high, 0 for active low. + */ +static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, + enum pixcir_int_mode mode, bool polarity) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + ret &= ~PIXCIR_INT_MODE_MASK; + ret |= mode; + + if (polarity) + ret |= PIXCIR_INT_POL_HIGH; + else + ret &= ~PIXCIR_INT_POL_HIGH; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +/* + * Enable/disable interrupt generation + */ +static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) +{ + struct device *dev = &ts->client->dev; + int ret; + + ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE); + if (ret < 0) { + dev_err(dev, "%s: can't read reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + if (enable) + ret |= PIXCIR_INT_ENABLE; + else + ret &= ~PIXCIR_INT_ENABLE; + + ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret); + if (ret < 0) { + dev_err(dev, "%s: can't write reg 0x%x : %d\n", + __func__, PIXCIR_REG_INT_MODE, ret); + return ret; + } + + return 0; +} + +static int pixcir_start(struct pixcir_i2c_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + int error; + + /* LEVEL_TOUCH interrupt with active low polarity */ + error = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0); + if (error) { + dev_err(dev, "Failed to set interrupt mode: %d\n", error); + return error; + } + + ts->running = true; + mb(); /* Update status before IRQ can fire */ + + /* enable interrupt generation */ + error = pixcir_int_enable(ts, true); + if (error) { + dev_err(dev, "Failed to enable interrupt generation: %d\n", + error); + return error; + } + + return 0; +} + +static int pixcir_stop(struct pixcir_i2c_ts_data *ts) +{ + int error; + + /* Disable interrupt generation */ + error = pixcir_int_enable(ts, false); + if (error) { + dev_err(&ts->client->dev, + "Failed to disable interrupt generation: %d\n", + error); + return error; + } + + /* Exit ISR if running, no more report parsing */ + ts->running = false; + mb(); /* update status before we synchronize irq */ + + /* Wait till running ISR is complete */ + synchronize_irq(ts->client->irq); + + return 0; +} + +static int pixcir_input_open(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + return pixcir_start(ts); +} + +static void pixcir_input_close(struct input_dev *dev) +{ + struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); + + pixcir_stop(ts); +} + #ifdef CONFIG_PM_SLEEP static int pixcir_i2c_ts_suspend(struct device *dev) { @@ -156,6 +314,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->name = client->name; input->id.bustype = BUS_I2C; + input->open = pixcir_input_open; + input->close = pixcir_input_close; __set_bit(EV_KEY, input->evbit); __set_bit(EV_ABS, input->evbit); @@ -175,11 +335,22 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + /* Always be in IDLE mode to save power, device supports auto wake */ + error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); + if (error) { + dev_err(dev, "Failed to set IDLE mode\n"); + return error; + } + + /* Stop device till opened */ + error = pixcir_stop(tsdata); + if (error) + return error; + error = input_register_device(input); if (error) return error; - i2c_set_clientdata(client, tsdata); device_init_wakeup(&client->dev, 1); return 0; @@ -187,13 +358,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, static int pixcir_i2c_ts_remove(struct i2c_client *client) { - struct pixcir_i2c_ts_data *tsdata = i2c_get_clientdata(client); - device_init_wakeup(&client->dev, 0); - tsdata->exiting = true; - mb(); - return 0; } diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h index 7163d91..7942804 100644 --- a/include/linux/input/pixcir_ts.h +++ b/include/linux/input/pixcir_ts.h @@ -1,6 +1,48 @@ #ifndef _PIXCIR_I2C_TS_H #define _PIXCIR_I2C_TS_H +/* + * Register map + */ +#define PIXCIR_REG_POWER_MODE 51 +#define PIXCIR_REG_INT_MODE 52 + +/* + * Power modes: + * active: max scan speed + * idle: lower scan speed with automatic transition to active on touch + * halt: datasheet says sleep but this is more like halt as the chip + * clocks are cut and it can only be brought out of this mode + * using the RESET pin. + */ +enum pixcir_power_mode { + PIXCIR_POWER_ACTIVE, + PIXCIR_POWER_IDLE, + PIXCIR_POWER_HALT, +}; + +#define PIXCIR_POWER_MODE_MASK 0x03 +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) + +/* + * Interrupt modes: + * periodical: interrupt is asserted periodicaly + * diff coordinates: interrupt is asserted when coordinates change + * level on touch: interrupt level asserted during touch + * pulse on touch: interrupt pulse asserted druing touch + * + */ +enum pixcir_int_mode { + PIXCIR_INT_PERIODICAL, + PIXCIR_INT_DIFF_COORD, + PIXCIR_INT_LEVEL_TOUCH, + PIXCIR_INT_PULSE_TOUCH, +}; + +#define PIXCIR_INT_MODE_MASK 0x03 +#define PIXCIR_INT_ENABLE (1UL << 3) +#define PIXCIR_INT_POL_HIGH (1UL << 2) + struct pixcir_ts_platform_data { int (*attb_read_val)(void); int x_max; -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode 2014-05-06 5:19 ` Dmitry Torokhov @ 2014-05-06 8:31 ` Roger Quadros 0 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-06 8:31 UTC (permalink / raw) To: Dmitry Torokhov Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel, devicetree Dmitry, On 05/06/2014 08:19 AM, Dmitry Torokhov wrote: > Hi Roger, > > On Mon, May 05, 2014 at 12:04:33PM +0300, Roger Quadros wrote: >> @@ -192,8 +364,8 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client) >> >> device_init_wakeup(&client->dev, 0); >> >> - tsdata->exiting = true; >> - mb(); >> + if (!tsdata->exiting) >> + pixcir_stop(tsdata); >> > > I think if we change tsdata->exiting to tsdata->running we won't have to > do it here. Does the version of the patch below work for you? > The call to pixcir_stop() was not required in the original version as well. It seems that the root of the problem for remove() and suspend() that I was trying to solve was in the pixcir_stop() function. i.e. the order of mb() and synchronize_irq(); But I like your version more since "running" reflects the behaviour more accurately than "exiting". cheers, -roger ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v4 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol 2014-05-05 9:04 [PATCH v4 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support Roger Quadros [not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org> 2014-05-05 9:04 ` [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode Roger Quadros @ 2014-05-05 9:04 ` Roger Quadros 2 siblings, 0 replies; 12+ messages in thread From: Roger Quadros @ 2014-05-05 9:04 UTC (permalink / raw) To: dmitry.torokhov Cc: rydberg, balbi, dmurphy, mugunthanvnm, nsekhar, linux-input, linux-kernel, devicetree, Roger Quadros Switch to using the Type-B Multi-Touch protocol. Signed-off-by: Roger Quadros <rogerq@ti.com> --- drivers/input/touchscreen/pixcir_i2c_ts.c | 125 ++++++++++++++++++++++-------- 1 file changed, 94 insertions(+), 31 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index d0f6989..3123699 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -23,9 +23,12 @@ #include <linux/slab.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/input/mt.h> #include <linux/input/pixcir_ts.h> #include <linux/gpio.h> +#define PIXCIR_MAX_SLOTS 2 + struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; @@ -33,12 +36,25 @@ struct pixcir_i2c_ts_data { bool exiting; }; -static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) +struct pixcir_touch { + int x; + int y; +}; + +struct pixcir_report_data { + int num_touches; + struct pixcir_touch touches[PIXCIR_MAX_SLOTS]; +}; + +static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, + struct pixcir_report_data *report) { - struct pixcir_i2c_ts_data *tsdata = data; u8 rdbuf[10], wrbuf[1] = { 0 }; + u8 *bufptr; u8 touch; - int ret; + int ret, i; + + memset(report, 0, sizeof(struct pixcir_report_data)); ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf)); if (ret != sizeof(wrbuf)) { @@ -56,45 +72,85 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data) return; } - touch = rdbuf[0]; - if (touch) { - u16 posx1 = (rdbuf[3] << 8) | rdbuf[2]; - u16 posy1 = (rdbuf[5] << 8) | rdbuf[4]; - u16 posx2 = (rdbuf[7] << 8) | rdbuf[6]; - u16 posy2 = (rdbuf[9] << 8) | rdbuf[8]; - - input_report_key(tsdata->input, BTN_TOUCH, 1); - input_report_abs(tsdata->input, ABS_X, posx1); - input_report_abs(tsdata->input, ABS_Y, posy1); - - input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1); - input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1); - input_mt_sync(tsdata->input); - - if (touch == 2) { - input_report_abs(tsdata->input, - ABS_MT_POSITION_X, posx2); - input_report_abs(tsdata->input, - ABS_MT_POSITION_Y, posy2); - input_mt_sync(tsdata->input); - } - } else { - input_report_key(tsdata->input, BTN_TOUCH, 0); + touch = rdbuf[0] & 0x7; + if (touch > PIXCIR_MAX_SLOTS) + touch = PIXCIR_MAX_SLOTS; + + report->num_touches = touch; + bufptr = &rdbuf[2]; + + for (i = 0; i < touch; i++) { + report->touches[i].x = (bufptr[1] << 8) | bufptr[0]; + report->touches[i].y = (bufptr[3] << 8) | bufptr[2]; + + bufptr = &bufptr[4]; } +} + +static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, + struct pixcir_report_data *report) +{ + struct input_mt_pos pos[PIXCIR_MAX_SLOTS]; + int slots[PIXCIR_MAX_SLOTS]; + struct pixcir_touch *touch; + int n, i, slot; + struct device *dev = &ts->client->dev; - input_sync(tsdata->input); + n = report->num_touches; + if (n > PIXCIR_MAX_SLOTS) + n = PIXCIR_MAX_SLOTS; + + for (i = 0; i < n; i++) { + touch = &report->touches[i]; + pos[i].x = touch->x; + pos[i].y = touch->y; + } + + input_mt_assign_slots(ts->input, slots, pos, n); + + for (i = 0; i < n; i++) { + touch = &report->touches[i]; + slot = slots[i]; + + input_mt_slot(ts->input, slot); + input_mt_report_slot_state(ts->input, + MT_TOOL_FINGER, true); + + input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, touch->x); + input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, touch->y); + + dev_dbg(dev, "%d: slot %d, x %d, y %d\n", + i, slot, touch->x, touch->y); + } + + input_mt_sync_frame(ts->input); + input_sync(ts->input); } static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; const struct pixcir_ts_platform_data *pdata = tsdata->chip; + struct pixcir_report_data report; while (!tsdata->exiting) { - pixcir_ts_poscheck(tsdata); - - if (gpio_get_value(pdata->gpio_attb)) + /* parse packet */ + pixcir_ts_parse(tsdata, &report); + + /* report it */ + pixcir_ts_report(tsdata, &report); + + if (gpio_get_value(pdata->gpio_attb)) { + if (report.num_touches) { + /* + * Last report with no finger up? + * Do it now then. + */ + input_mt_sync_frame(tsdata->input); + input_sync(tsdata->input); + } break; + } msleep(20); } @@ -333,6 +389,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); + error = input_mt_init_slots(input, PIXCIR_MAX_SLOTS, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) { + dev_err(dev, "Error initializing Multi-Touch slots\n"); + return error; + } + input_set_drvdata(input, tsdata); error = devm_gpio_request_one(dev, pdata->gpio_attb, -- 1.8.3.2 ^ permalink raw reply related [flat|nested] 12+ messages in thread
end of thread, other threads:[~2014-05-06 8:33 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-05-05 9:04 [PATCH v4 0/7] Input: pixcir_i2c_ts: Add Type-B Multi-touch and DT support Roger Quadros
[not found] ` <1399280678-23925-1-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>
2014-05-05 9:04 ` [PATCH v4 1/7] Input: pixcir_i2c_ts: Use devres managed resource allocations Roger Quadros
2014-05-05 9:04 ` [PATCH v4 3/7] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val() Roger Quadros
2014-05-05 9:04 ` [PATCH v4 5/7] Input: pixcir_i2c_ts: support upto 5 fingers and hardware provided tracking IDs Roger Quadros
2014-05-05 9:04 ` [PATCH v4 6/7] Input: pixcir_i2c_ts: Implement wakeup from suspend Roger Quadros
2014-05-06 5:21 ` Dmitry Torokhov
[not found] ` <20140506052148.GB2608-WlK9ik9hQGAhIp7JRqBPierSzoNAToWh@public.gmane.org>
2014-05-06 8:33 ` Roger Quadros
2014-05-05 9:04 ` [PATCH v4 7/7] Input: pixcir_i2c_ts: Add device tree support Roger Quadros
2014-05-05 9:04 ` [PATCH v4 2/7] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode Roger Quadros
[not found] ` <1399280678-23925-3-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>
2014-05-06 5:19 ` Dmitry Torokhov
2014-05-06 8:31 ` Roger Quadros
2014-05-05 9:04 ` [PATCH v4 4/7] Input: pixcir_i2c_ts: Use Type-B Multi-Touch protocol Roger Quadros
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).