Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add touchscreen support for TS-4800

On this board, the touchscreen, an ads7843, is not handled directly by
Linux but by a companion FPGA. This FPGA is memory-mapped and the IP
design is very similar to the mk712.

This commit adds the support for this IP.

Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Damien Riegel and committed by
Dmitry Torokhov
40e3be39 6b0f8f9c

+244
+11
Documentation/devicetree/bindings/input/touchscreen/ts4800-ts.txt
··· 1 + * TS-4800 Touchscreen bindings 2 + 3 + Required properties: 4 + - compatible: must be "technologic,ts4800-ts" 5 + - reg: physical base address of the controller and length of memory mapped 6 + region. 7 + - syscon: phandle / integers array that points to the syscon node which 8 + describes the FPGA's syscon registers. 9 + - phandle to FPGA's syscon 10 + - offset to the touchscreen register 11 + - offset to the touchscreen enable bit
+16
drivers/input/touchscreen/Kconfig
··· 937 937 To compile this driver as a module, choose M here: the 938 938 module will be called touchit213. 939 939 940 + config TOUCHSCREEN_TS4800 941 + tristate "TS-4800 touchscreen" 942 + depends on HAS_IOMEM && OF 943 + select MFD_SYSCON 944 + select INPUT_POLLDEV 945 + help 946 + Say Y here if you have a touchscreen on a TS-4800 board. 947 + 948 + On TS-4800, the touchscreen is not handled directly by Linux but by 949 + a companion FPGA. 950 + 951 + If unsure, say N. 952 + 953 + To compile this driver as a module, choose M here: the 954 + module will be called ts4800_ts. 955 + 940 956 config TOUCHSCREEN_TSC_SERIO 941 957 tristate "TSC-10/25/40 serial touchscreen support" 942 958 select SERIO
+1
drivers/input/touchscreen/Makefile
··· 69 69 obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o 70 70 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o 71 71 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o 72 + obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o 72 73 obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o 73 74 obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o 74 75 obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
+216
drivers/input/touchscreen/ts4800-ts.c
··· 1 + /* 2 + * Touchscreen driver for the TS-4800 board 3 + * 4 + * Copyright (c) 2015 - Savoir-faire Linux 5 + * 6 + * This file is licensed under the terms of the GNU General Public 7 + * License version 2. This program is licensed "as is" without any 8 + * warranty of any kind, whether express or implied. 9 + */ 10 + 11 + #include <linux/bitops.h> 12 + #include <linux/input.h> 13 + #include <linux/input-polldev.h> 14 + #include <linux/io.h> 15 + #include <linux/kernel.h> 16 + #include <linux/mfd/syscon.h> 17 + #include <linux/module.h> 18 + #include <linux/of.h> 19 + #include <linux/platform_device.h> 20 + #include <linux/regmap.h> 21 + 22 + /* polling interval in ms */ 23 + #define POLL_INTERVAL 3 24 + 25 + #define DEBOUNCE_COUNT 1 26 + 27 + /* sensor values are 12-bit wide */ 28 + #define MAX_12BIT ((1 << 12) - 1) 29 + 30 + #define PENDOWN_MASK 0x1 31 + 32 + #define X_OFFSET 0x0 33 + #define Y_OFFSET 0x2 34 + 35 + struct ts4800_ts { 36 + struct input_polled_dev *poll_dev; 37 + struct device *dev; 38 + char phys[32]; 39 + 40 + void __iomem *base; 41 + struct regmap *regmap; 42 + unsigned int reg; 43 + unsigned int bit; 44 + 45 + bool pendown; 46 + int debounce; 47 + }; 48 + 49 + static void ts4800_ts_open(struct input_polled_dev *dev) 50 + { 51 + struct ts4800_ts *ts = dev->private; 52 + int ret; 53 + 54 + ts->pendown = false; 55 + ts->debounce = DEBOUNCE_COUNT; 56 + 57 + ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, ts->bit); 58 + if (ret) 59 + dev_warn(ts->dev, "Failed to enable touchscreen\n"); 60 + } 61 + 62 + static void ts4800_ts_close(struct input_polled_dev *dev) 63 + { 64 + struct ts4800_ts *ts = dev->private; 65 + int ret; 66 + 67 + ret = regmap_update_bits(ts->regmap, ts->reg, ts->bit, 0); 68 + if (ret) 69 + dev_warn(ts->dev, "Failed to disable touchscreen\n"); 70 + 71 + } 72 + 73 + static void ts4800_ts_poll(struct input_polled_dev *dev) 74 + { 75 + struct input_dev *input_dev = dev->input; 76 + struct ts4800_ts *ts = dev->private; 77 + u16 last_x = readw(ts->base + X_OFFSET); 78 + u16 last_y = readw(ts->base + Y_OFFSET); 79 + bool pendown = last_x & PENDOWN_MASK; 80 + 81 + if (pendown) { 82 + if (ts->debounce) { 83 + ts->debounce--; 84 + return; 85 + } 86 + 87 + if (!ts->pendown) { 88 + input_report_key(input_dev, BTN_TOUCH, 1); 89 + ts->pendown = true; 90 + } 91 + 92 + last_x = ((~last_x) >> 4) & MAX_12BIT; 93 + last_y = ((~last_y) >> 4) & MAX_12BIT; 94 + 95 + input_report_abs(input_dev, ABS_X, last_x); 96 + input_report_abs(input_dev, ABS_Y, last_y); 97 + input_sync(input_dev); 98 + } else if (ts->pendown) { 99 + ts->pendown = false; 100 + ts->debounce = DEBOUNCE_COUNT; 101 + input_report_key(input_dev, BTN_TOUCH, 0); 102 + input_sync(input_dev); 103 + } 104 + } 105 + 106 + static int ts4800_parse_dt(struct platform_device *pdev, 107 + struct ts4800_ts *ts) 108 + { 109 + struct device *dev = &pdev->dev; 110 + struct device_node *np = dev->of_node; 111 + struct device_node *syscon_np; 112 + u32 reg, bit; 113 + int error; 114 + 115 + syscon_np = of_parse_phandle(np, "syscon", 0); 116 + if (!syscon_np) { 117 + dev_err(dev, "no syscon property\n"); 118 + return -ENODEV; 119 + } 120 + 121 + error = of_property_read_u32_index(np, "syscon", 1, &reg); 122 + if (error < 0) { 123 + dev_err(dev, "no offset in syscon\n"); 124 + return error; 125 + } 126 + 127 + ts->reg = reg; 128 + 129 + error = of_property_read_u32_index(np, "syscon", 2, &bit); 130 + if (error < 0) { 131 + dev_err(dev, "no bit in syscon\n"); 132 + return error; 133 + } 134 + 135 + ts->bit = BIT(bit); 136 + 137 + ts->regmap = syscon_node_to_regmap(syscon_np); 138 + if (IS_ERR(ts->regmap)) { 139 + dev_err(dev, "cannot get parent's regmap\n"); 140 + return PTR_ERR(ts->regmap); 141 + } 142 + 143 + return 0; 144 + } 145 + 146 + static int ts4800_ts_probe(struct platform_device *pdev) 147 + { 148 + struct input_polled_dev *poll_dev; 149 + struct ts4800_ts *ts; 150 + struct resource *res; 151 + int error; 152 + 153 + ts = devm_kzalloc(&pdev->dev, sizeof(*ts), GFP_KERNEL); 154 + if (!ts) 155 + return -ENOMEM; 156 + 157 + error = ts4800_parse_dt(pdev, ts); 158 + if (error) 159 + return error; 160 + 161 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 162 + ts->base = devm_ioremap_resource(&pdev->dev, res); 163 + if (IS_ERR(ts->base)) 164 + return PTR_ERR(ts->base); 165 + 166 + poll_dev = devm_input_allocate_polled_device(&pdev->dev); 167 + if (!poll_dev) 168 + return -ENOMEM; 169 + 170 + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev)); 171 + ts->poll_dev = poll_dev; 172 + ts->dev = &pdev->dev; 173 + 174 + poll_dev->private = ts; 175 + poll_dev->poll_interval = POLL_INTERVAL; 176 + poll_dev->open = ts4800_ts_open; 177 + poll_dev->close = ts4800_ts_close; 178 + poll_dev->poll = ts4800_ts_poll; 179 + 180 + poll_dev->input->name = "TS-4800 Touchscreen"; 181 + poll_dev->input->phys = ts->phys; 182 + 183 + input_set_capability(poll_dev->input, EV_KEY, BTN_TOUCH); 184 + input_set_abs_params(poll_dev->input, ABS_X, 0, MAX_12BIT, 0, 0); 185 + input_set_abs_params(poll_dev->input, ABS_Y, 0, MAX_12BIT, 0, 0); 186 + 187 + error = input_register_polled_device(poll_dev); 188 + if (error) { 189 + dev_err(&pdev->dev, 190 + "Unabled to register polled input device (%d)\n", 191 + error); 192 + return error; 193 + } 194 + 195 + return 0; 196 + } 197 + 198 + static const struct of_device_id ts4800_ts_of_match[] = { 199 + { .compatible = "technologic,ts4800-ts", }, 200 + { }, 201 + }; 202 + MODULE_DEVICE_TABLE(of, ts4800_ts_of_match); 203 + 204 + static struct platform_driver ts4800_ts_driver = { 205 + .driver = { 206 + .name = "ts4800-ts", 207 + .of_match_table = ts4800_ts_of_match, 208 + }, 209 + .probe = ts4800_ts_probe, 210 + }; 211 + module_platform_driver(ts4800_ts_driver); 212 + 213 + MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>"); 214 + MODULE_DESCRIPTION("TS-4800 Touchscreen Driver"); 215 + MODULE_LICENSE("GPL v2"); 216 + MODULE_ALIAS("platform:ts4800_ts");