From patchwork Thu Dec 10 16:11:12 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Damien Riegel X-Patchwork-Id: 7819711 Return-Path: X-Original-To: patchwork-linux-input@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7855EBEEE1 for ; Thu, 10 Dec 2015 16:11:48 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 620EE20576 for ; Thu, 10 Dec 2015 16:11:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CCC04205CA for ; Thu, 10 Dec 2015 16:11:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751662AbbLJQL2 (ORCPT ); Thu, 10 Dec 2015 11:11:28 -0500 Received: from mail.savoirfairelinux.com ([208.88.110.44]:58421 "EHLO mail.savoirfairelinux.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751937AbbLJQL0 (ORCPT ); Thu, 10 Dec 2015 11:11:26 -0500 Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id AFF89620918; Thu, 10 Dec 2015 11:11:24 -0500 (EST) Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id uPNgSVPu-eBF; Thu, 10 Dec 2015 11:11:19 -0500 (EST) Received: from localhost (localhost [127.0.0.1]) by mail.savoirfairelinux.com (Postfix) with ESMTP id 6F80A620BCC; Thu, 10 Dec 2015 11:11:19 -0500 (EST) X-Virus-Scanned: amavisd-new at mail.savoirfairelinux.com Received: from mail.savoirfairelinux.com ([127.0.0.1]) by localhost (mail.savoirfairelinux.com [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 1TEFtGesEkBe; Thu, 10 Dec 2015 11:11:19 -0500 (EST) Received: from pc-driegel.mtl.sfl (pc-driegel.mtl.sfl [192.168.49.138]) by mail.savoirfairelinux.com (Postfix) with ESMTPSA id 3FA96620918; Thu, 10 Dec 2015 11:11:19 -0500 (EST) From: Damien Riegel To: linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, devicetree@vger.kernel.org Cc: Rob Herring , Pawel Moll , Mark Rutland , Ian Campbell , Kumar Gala , Dmitry Torokhov , kernel@savoirfairelinux.com, Damien Riegel Subject: [PATCH 2/2] Input: add touchscreen support for TS-4800 Date: Thu, 10 Dec 2015 11:11:12 -0500 Message-Id: <1449763872-572-2-git-send-email-damien.riegel@savoirfairelinux.com> X-Mailer: git-send-email 2.5.0 In-Reply-To: <1449763872-572-1-git-send-email-damien.riegel@savoirfairelinux.com> References: <1449763872-572-1-git-send-email-damien.riegel@savoirfairelinux.com> Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 --- drivers/input/touchscreen/Kconfig | 15 +++ drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/ts4800-ts.c | 238 ++++++++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 drivers/input/touchscreen/ts4800-ts.c diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index deb14c1..2d3b2f2 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -914,6 +914,21 @@ config TOUCHSCREEN_TOUCHIT213 To compile this driver as a module, choose M here: the module will be called touchit213. +config TOUCHSCREEN_TS4800 + tristate "TS-4800 touchscreen" + depends on HAS_IOMEM && OF + select MFD_SYSCON + help + Say Y here if you have a touchscreen on a TS-4800 board. + + On TS-4800, the touchscreen is not handled directly by Linux but by + a companion FPGA. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called ts4800_ts. + config TOUCHSCREEN_TSC_SERIO tristate "TSC-10/25/40 serial touchscreen support" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 1b79cc0..5d81ba8c 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o +obj-$(CONFIG_TOUCHSCREEN_TS4800) += ts4800-ts.o obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c new file mode 100644 index 0000000..1e81b17 --- /dev/null +++ b/drivers/input/touchscreen/ts4800-ts.c @@ -0,0 +1,238 @@ +/* + * Touchscreen driver for the TS-4800 board + * + * Copyright (c) 2015 - Savoir-faire Linux + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* polling interval in ms*/ +#define POLL_INTERVAL 3 + +/* sensor values are 12-bit wide */ +#define MAX_12BIT ((1 << 12) - 1) + +#define PENDOWN_MASK 0x1 + +#define X_OFFSET 0x0 +#define Y_OFFSET 0x2 + +struct ts4800_ts { + struct input_polled_dev *poll_dev; + struct device *dev; + char phys[32]; + + void __iomem *base; + struct regmap *regmap; + unsigned int reg; + unsigned int bit; + + bool pendown; + int debounce; +}; + +static void ts4800_ts_open(struct input_polled_dev *dev) +{ + struct ts4800_ts *ts = dev->private; + int ret; + + ret = regmap_update_bits(ts->regmap, ts->reg, + 1 << ts->bit, 1 << ts->bit); + if (ret) + dev_warn(ts->dev, "Failed to enable touchscreen\n"); +} + +static void ts4800_ts_close(struct input_polled_dev *dev) +{ + struct ts4800_ts *ts = dev->private; + int ret; + + ret = regmap_update_bits(ts->regmap, ts->reg, + 1 << ts->bit, 0); + if (ret) + dev_warn(ts->dev, "Failed to disable touchscreen\n"); + +} + +static void ts4800_ts_poll(struct input_polled_dev *dev) +{ + struct input_dev *input_dev = dev->input; + struct ts4800_ts *ts = dev->private; + u16 last_x = readw(ts->base + X_OFFSET); + u16 last_y = readw(ts->base + Y_OFFSET); + bool pendown = last_x & PENDOWN_MASK; + + if (!pendown && ts->pendown) { + ts->pendown = false; + ts->debounce = 1; + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + } + + if (pendown) { + if (ts->debounce) { + ts->debounce = 0; + return; + } + + if (!ts->pendown) { + input_report_key(input_dev, BTN_TOUCH, 1); + ts->pendown = true; + } + + last_x = ((~last_x) >> 4) & MAX_12BIT; + last_y = ((~last_y) >> 4) & MAX_12BIT; + + input_report_abs(input_dev, ABS_X, last_x); + input_report_abs(input_dev, ABS_Y, last_y); + input_sync(input_dev); + } +} + +static void ts4800_input_setup(struct input_dev *input_dev) +{ + 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, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, 0, 0); +} + +static int ts4800_parse_dt(struct platform_device *pdev, + struct ts4800_ts *ts) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *syscon_np; + struct resource *res; + u32 reg, bit; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ts->base = devm_ioremap_resource(dev, res); + if (IS_ERR(ts->base)) + return PTR_ERR(ts->base); + + syscon_np = of_parse_phandle(np, "syscon", 0); + if (!syscon_np) { + dev_err(dev, "no syscon property\n"); + return -ENODEV; + } + + ret = of_property_read_u32_index(np, "syscon", 1, ®); + if (ret < 0) { + dev_err(dev, "no offset in syscon\n"); + return ret; + } + + ret = of_property_read_u32_index(np, "syscon", 2, &bit); + if (ret < 0) { + dev_err(dev, "no bit in syscon\n"); + return ret; + } + + ts->reg = reg; + ts->bit = bit; + ts->regmap = syscon_node_to_regmap(syscon_np); + + if (IS_ERR(ts->regmap)) { + dev_err(dev, "cannot get parent's regmap\n"); + return PTR_ERR(ts->regmap); + } + + return 0; +} + +static int ts4800_ts_probe(struct platform_device *pdev) +{ + struct input_polled_dev *poll_dev; + struct input_dev *input_dev; + struct ts4800_ts *ts; + int ret; + + ts = devm_kzalloc(&pdev->dev, sizeof(struct ts4800_ts), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + ret = ts4800_parse_dt(pdev, ts); + if (ret) + return ret; + + poll_dev = devm_input_allocate_polled_device(&pdev->dev); + if (!poll_dev) + return -ENOMEM; + + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&pdev->dev)); + ts->poll_dev = poll_dev; + ts->dev = &pdev->dev; + ts->pendown = false; + ts->debounce = 1; + + poll_dev->private = ts; + poll_dev->poll_interval = POLL_INTERVAL; + poll_dev->open = ts4800_ts_open; + poll_dev->close = ts4800_ts_close; + poll_dev->poll = ts4800_ts_poll; + + ts4800_input_setup(poll_dev->input); + + input_dev = poll_dev->input; + input_dev->name = "TS-4800 Touchscreen"; + input_dev->phys = ts->phys; + input_dev->dev.parent = pdev->dev.parent; + + ret = input_register_polled_device(poll_dev); + if (ret) { + dev_err(&pdev->dev, + "Unabled to register polled input device (%d)\n", + ret); + return ret; + } + + platform_set_drvdata(pdev, ts); + + return 0; +} + +static int ts4800_ts_remove(struct platform_device *pdev) +{ + struct ts4800_ts *ts = platform_get_drvdata(pdev); + struct input_polled_dev *poll_dev = ts->poll_dev; + + input_unregister_polled_device(poll_dev); + + return 0; +} + +static const struct of_device_id ts4800_ts_of_match[] = { + { .compatible = "technologic,ts4800-ts", }, + { }, +}; +MODULE_DEVICE_TABLE(of, ts4800_ts_of_match); + +static struct platform_driver ts4800_ts_driver = { + .driver = { + .name = "ts4800-ts", + .of_match_table = ts4800_ts_of_match, + }, + .probe = ts4800_ts_probe, + .remove = ts4800_ts_remove, +}; +module_platform_driver(ts4800_ts_driver); + +MODULE_AUTHOR("Damien Riegel "); +MODULE_DESCRIPTION("TS-4800 Touchscreen Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ts4800_ts");