commit b98abe52fa8e ("Input: add common DT binding for touchscreens") introduced common DT bindings for touchscreens [1] and a helper function to parse the DT. This has been integrated and interpretation of the inversion (flipping) properties for the x and y axis has been added to accommodate any orientation of the touch in relation to the LCD. By scaling the min/max ADC values to the screen size it is now possible to pre-calibrate the touch so that is (almost) exactly matches the LCD it is glued onto. This allows to well enough operate the touch before a user space calibration can improve the precision. calculate_pressure has been renamed to calculate_resistance because that is what it is doing. [1]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt Signed-off-by: H. Nikolaus Schaller <hns@xxxxxxxxxxxxx> --- .../bindings/input/touchscreen/tsc2007.txt | 20 +-- drivers/input/touchscreen/tsc2007.c | 135 +++++++++++++++++---- include/linux/i2c/tsc2007.h | 8 ++ 3 files changed, 135 insertions(+), 28 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt index ec365e1..6e9fd55 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt @@ -6,6 +6,7 @@ Required properties: - ti,x-plate-ohms: X-plate resistance in ohms. Optional properties: +- generic touch screen properties: see touchscreen binding [2]. - gpios: the interrupt gpio the chip is connected to (trough the penirq pin). The penirq pin goes to low when the panel is touched. (see GPIO binding[1] for more details). @@ -13,17 +14,20 @@ Optional properties: (see interrupt binding[0]). - interrupts: (gpio) interrupt to which the chip is connected (see interrupt binding[0]). -- ti,max-rt: maximum pressure. -- ti,fuzzx: specifies the absolute input fuzz x value. - If set, it will permit noise in the data up to +- the value given to the fuzz - parameter, that is used to filter noise from the event stream. -- ti,fuzzy: specifies the absolute input fuzz y value. -- ti,fuzzz: specifies the absolute input fuzz z value. +- ti,max-rt: maximum pressure resistance above which samples are ignored + (default: 4095). +- ti,report-resistance: report resistance (no pressure = max_rt) instead + of pressure (no pressure = 0). +- ti,min-x: minimum value reported by X axis ADC (default 0). +- ti,max-x: maximum value reported by X axis ADC (default 4095). +- ti,min-y: minimum value reported by Y axis ADC (default 0). +- ti,max-y: maximum value reported by Y axis ADC (default 4095). - ti,poll-period: how much time to wait (in milliseconds) before reading again the - values from the tsc2007. + values from the tsc2007 (default 1). [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt [1]: Documentation/devicetree/bindings/gpio/gpio.txt +[2]: Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt Example: &i2c1 { @@ -35,6 +39,8 @@ Example: interrupts = <0x0 0x8>; gpios = <&gpio4 0 0>; ti,x-plate-ohms = <180>; + touchscreen-size-x = <640>; + touchscreen-size-y = <480>; }; /* ... */ diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 5d0cd51..e0c7173 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -29,6 +29,7 @@ #include <linux/of_device.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/input/touchscreen.h> #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -74,6 +75,14 @@ struct tsc2007 { u16 model; u16 x_plate_ohms; + bool swap_xy; + bool invert_x; + bool invert_y; + bool report_resistance; + u16 min_x; + u16 min_y; + u16 max_x; + u16 max_y; u16 max_rt; unsigned long poll_period; /* in jiffies */ int fuzzx; @@ -128,7 +137,8 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc) tsc2007_xfer(tsc, PWRDOWN); } -static u32 tsc2007_calculate_pressure(struct tsc2007 *tsc, struct ts_event *tc) +static u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, + struct ts_event *tc) { u32 rt = 0; @@ -177,12 +187,13 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) struct ts_event tc; u32 rt; + dev_dbg(&ts->client->dev, "soft irq %d\n", irq); while (!ts->stopped && tsc2007_is_pen_down(ts)) { /* pen is down, continue with the measurement */ tsc2007_read_values(ts, &tc); - rt = tsc2007_calculate_pressure(ts, &tc); + rt = tsc2007_calculate_resistance(ts, &tc); if (!rt && !ts->get_pendown_state) { /* @@ -198,6 +209,48 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) "DOWN point(%4d,%4d), pressure (%4u)\n", tc.x, tc.y, rt); + /* clamp to expected ADC range */ + if (tc.x < ts->min_x) + tc.x = ts->min_x; + if (tc.x > ts->max_x) + tc.x = ts->max_x; + if (tc.y < ts->min_y) + tc.y = ts->min_y; + if (tc.y > ts->max_y) + tc.y = ts->max_y; + + dev_dbg(&ts->client->dev, + "Clamped point(%4d,%4d), pressure (%4u)\n", + tc.x, tc.y, rt); + + /* flip */ + if (ts->invert_x) + tc.x = (ts->max_x - tc.x) + ts->min_x; + if (ts->invert_y) + tc.y = (ts->max_y - tc.y) + ts->min_y; + if (!ts->report_resistance) + rt = ts->max_rt - rt; + + dev_dbg(&ts->client->dev, + "Flipped point(%4d,%4d), pressure (%4u)\n", + tc.x, tc.y, rt); + + /* scale to desired output range */ + tc.x = (input->absinfo[ABS_X].maximum * + (tc.x - ts->min_x)) / (ts->max_x - ts->min_x); + tc.y = (input->absinfo[ABS_Y].maximum * + (tc.y - ts->min_y)) / (ts->max_y - ts->min_y); + rt = (input->absinfo[ABS_PRESSURE].maximum * rt) + / ts->max_rt; + + /* swap x and y */ + if (ts->swap_xy) + swap(tc.x, tc.y); + + /* report event */ + dev_dbg(&ts->client->dev, + "shaped point(%4d,%4d), pressure (%4u)\n", + tc.x, tc.y, rt); input_report_key(input, BTN_TOUCH, 1); input_report_abs(input, ABS_X, tc.x); input_report_abs(input, ABS_Y, tc.y); @@ -207,8 +260,8 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) } else { /* - * Sample found inconsistent by debouncing or pressure is - * beyond the maximum. Don't report it to user space, + * Sample found inconsistent by debouncing or resistance + * is beyond the maximum. Don't report it to user space, * repeat at least once more the measurement. */ dev_dbg(&ts->client->dev, "ignored pressure %d\n", rt); @@ -233,6 +286,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle) { struct tsc2007 *ts = handle; + dev_dbg(&ts->client->dev, "hard irq %d\n", irq); if (tsc2007_is_pen_down(ts)) return IRQ_WAKE_THREAD; @@ -303,14 +357,25 @@ static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) else ts->max_rt = MAX_12BIT; - if (!of_property_read_u32(np, "ti,fuzzx", &val32)) - ts->fuzzx = val32; + ts->swap_xy = of_property_read_bool(np, "touchscreen-swapped-x-y"); + ts->invert_x = of_property_read_bool(np, "touchscreen-inverted-x"); + ts->invert_y = of_property_read_bool(np, "touchscreen-inverted-y"); + ts->report_resistance = + of_property_read_bool(np, "ti,report-resistance"); - if (!of_property_read_u32(np, "ti,fuzzy", &val32)) - ts->fuzzy = val32; + if (!of_property_read_u32(np, "ti,min-x", &val32)) + ts->min_x = val32; + if (!of_property_read_u32(np, "ti,max-x", &val32)) + ts->max_x = val32; + else + ts->max_x = MAX_12BIT; - if (!of_property_read_u32(np, "ti,fuzzz", &val32)) - ts->fuzzz = val32; + if (!of_property_read_u32(np, "ti,min-y", &val32)) + ts->min_y = val32; + if (!of_property_read_u32(np, "ti,max-y", &val32)) + ts->max_y = val32; + else + ts->max_y = MAX_12BIT; if (!of_property_read_u64(np, "ti,poll-period", &val64)) ts->poll_period = msecs_to_jiffies(val64); @@ -324,6 +389,16 @@ static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) return -EINVAL; } + dev_dbg(&client->dev, + "min/max_x (%4d,%4d)\n", + ts->min_x, ts->max_x); + dev_dbg(&client->dev, + "min/max_y (%4d,%4d)\n", + ts->min_y, ts->max_y); + dev_dbg(&client->dev, + "max_rt (%4d)\n", + ts->max_rt); + ts->gpio = of_get_gpio(np, 0); if (gpio_is_valid(ts->gpio)) ts->get_pendown_state = tsc2007_get_pendown_state_gpio; @@ -332,6 +407,10 @@ static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) "GPIO not specified in DT (of_get_gpio returned %d)\n", ts->gpio); + dev_dbg(&client->dev, + "ts-gpio: %d\n", + ts->gpio); + return 0; } #else @@ -349,6 +428,14 @@ static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->max_rt = pdata->max_rt ? : MAX_12BIT; + ts->swap_xy = pdata->swap_xy; + ts->invert_x = pdata->invert_x; + ts->invert_y = pdata->invert_y; + ts->report_resistance = pdata->report_resistance; + ts->min_x = pdata->min_x ? : 0; + ts->min_y = pdata->min_y ? : 0; + ts->max_x = pdata->max_x ? : MAX_12BIT; + ts->max_y = pdata->max_y ? : MAX_12BIT; ts->poll_period = msecs_to_jiffies(pdata->poll_period ? : 1); ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; @@ -388,13 +475,6 @@ static int tsc2007_probe(struct i2c_client *client, if (!ts) return -ENOMEM; - if (pdata) - err = tsc2007_probe_pdev(client, ts, pdata, id); - else - err = tsc2007_probe_dt(client, ts); - if (err) - return err; - input_dev = devm_input_allocate_device(&client->dev); if (!input_dev) return -ENOMEM; @@ -421,10 +501,21 @@ static int tsc2007_probe(struct i2c_client *client, input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); - input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, - ts->fuzzz, 0); + if (pdata) + err = tsc2007_probe_pdev(client, ts, pdata, id); + else + err = tsc2007_probe_dt(client, ts); + if (err) + return err; + + input_set_abs_params(input_dev, ABS_X, 0, ts->max_x-ts->min_x, + ts->fuzzx, 0); + input_set_abs_params(input_dev, ABS_Y, 0, ts->max_y-ts->min_y, + ts->fuzzy, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, ts->max_rt, + ts->fuzzz, 0); + + touchscreen_parse_properties(input_dev, false); if (pdata) { if (pdata->exit_platform_hw) { @@ -443,6 +534,8 @@ static int tsc2007_probe(struct i2c_client *client, pdata->init_platform_hw(); } + dev_dbg(&client->dev, "request irq %d\n", + ts->irq); err = devm_request_threaded_irq(&client->dev, ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, IRQF_ONESHOT, diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h index 4f35b6a..632db20 100644 --- a/include/linux/i2c/tsc2007.h +++ b/include/linux/i2c/tsc2007.h @@ -6,6 +6,14 @@ struct tsc2007_platform_data { u16 model; /* 2007. */ u16 x_plate_ohms; /* must be non-zero value */ + bool swap_xy; /* swap x and y axis */ + bool invert_x; + bool invert_y; + bool report_resistance; + u16 min_x; /* min and max values reported by ADC */ + u16 min_y; + u16 max_x; + u16 max_y; u16 max_rt; /* max. resistance above which samples are ignored */ unsigned long poll_period; /* time (in ms) between samples */ int fuzzx; /* fuzz factor for X, Y and pressure axes */ -- 2.5.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html