get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/813708/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 813708,
    "url": "http://patchwork.ozlabs.org/api/patches/813708/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/devicetree-bindings/patch/1505363804-6827-1-git-send-email-anthony.kim@hideep.com/",
    "project": {
        "id": 37,
        "url": "http://patchwork.ozlabs.org/api/projects/37/?format=api",
        "name": "Devicetree Bindings",
        "link_name": "devicetree-bindings",
        "list_id": "devicetree.vger.kernel.org",
        "list_email": "devicetree@vger.kernel.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": "",
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<1505363804-6827-1-git-send-email-anthony.kim@hideep.com>",
    "list_archive_url": null,
    "date": "2017-09-14T04:36:44",
    "name": "Input: add support for HiDeep touchscreen",
    "commit_ref": null,
    "pull_url": null,
    "state": "not-applicable",
    "archived": true,
    "hash": "9de173e989d95955f592ee268fb64e1280c2550e",
    "submitter": {
        "id": 72202,
        "url": "http://patchwork.ozlabs.org/api/people/72202/?format=api",
        "name": "Anthony Kim",
        "email": "anthony.kim@hideep.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/devicetree-bindings/patch/1505363804-6827-1-git-send-email-anthony.kim@hideep.com/mbox/",
    "series": [
        {
            "id": 3030,
            "url": "http://patchwork.ozlabs.org/api/series/3030/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/devicetree-bindings/list/?series=3030",
            "date": "2017-09-14T04:36:44",
            "name": "Input: add support for HiDeep touchscreen",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/3030/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/813708/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/813708/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<devicetree-owner@vger.kernel.org>",
        "X-Original-To": "incoming-dt@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming-dt@bilbo.ozlabs.org",
        "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=devicetree-owner@vger.kernel.org; receiver=<UNKNOWN>)",
        "Received": [
            "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xt5NL5G4Rz9sCZ\n\tfor <incoming-dt@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 14:37:06 +1000 (AEST)",
            "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1750760AbdINEhC (ORCPT\n\t<rfc822;incoming-dt@patchwork.ozlabs.org>);\n\tThu, 14 Sep 2017 00:37:02 -0400",
            "from mail-pg0-f67.google.com ([74.125.83.67]:35220 \"EHLO\n\tmail-pg0-f67.google.com\" rhost-flags-OK-OK-OK-OK) by vger.kernel.org\n\twith ESMTP id S1750740AbdINEhA (ORCPT\n\t<rfc822; devicetree@vger.kernel.org>); Thu, 14 Sep 2017 00:37:00 -0400",
            "by mail-pg0-f67.google.com with SMTP id j16so1131715pga.2;\n\tWed, 13 Sep 2017 21:37:00 -0700 (PDT)",
            "from anthonylinux-hideep.hideep.com ([59.11.99.65])\n\tby smtp.gmail.com with ESMTPSA id\n\tl30sm16278038pgc.78.2017.09.13.21.36.56\n\t(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);\n\tWed, 13 Sep 2017 21:36:58 -0700 (PDT)"
        ],
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to\n\t:references;\n\tbh=uoN8DlQpdz/sm67Epa4otGYquxhoNRTU5BpYV5gAUxc=;\n\tb=ItbPchl5eTlY7VaZ2uLVpmdK8XWVpfTgpqhV1X9zp0dExzPPYzXqP2F03NG0OYk89P\n\tczCiYMWFym3b5w0rgDQ3KXrLK8ehq6+4a/lNo5sWQPIhLbbWKfksgKHjtO3fnVaIpEWb\n\tiMhhha6QWEviHy+kek/lFBRWlGSmlCGhwD20iR+3u58cp/36u6M50oKn/wiuFd0Nr2Iy\n\t5MNL9ItUrhrZ5k+esK+2puLbQapjIgP9EIUOwdX85r/4Uuv8PpoJdNV0DlWq6Z0dSBkV\n\tIKk4zJR+8C8F2g9p+roIn/m01/BciYwJ/mUp+uBW1r+UzkCeTH5c+dzih9YwG65L0HAx\n\ti/Xg==",
        "X-Gm-Message-State": "AHPjjUhBDR8j+wpW/ssZGn0MH+P5Pj/SAoVW3fQcd+iPMUclJES7wioD\n\tHublK1RuZ5SG4A==",
        "X-Google-Smtp-Source": "ADKCNb6zA6K2fesyLt9QO1aR3x6Qf9vY5d/bcEQDj0XECctinxfod11GSkZhbq1L6/pthSkR+4zVeg==",
        "X-Received": "by 10.99.121.135 with SMTP id\n\tu129mr19775046pgc.250.1505363819527; \n\tWed, 13 Sep 2017 21:36:59 -0700 (PDT)",
        "From": "Anthony Kim <anthony.kim@hideep.com>",
        "To": "dmitry.torokhov@gmail.com, robh+dt@kernel.org, lkp@intel.com",
        "Cc": "kbuild-all@01.org, linux-input@vger.kernel.org,\n\tdevicetree@vger.kernel.org, linux-kernel@vger.kernel.org,\n\tAnthony Kim <anthony.kim@hideep.com>",
        "Subject": "[PATCH] Input: add support for HiDeep touchscreen",
        "Date": "Thu, 14 Sep 2017 13:36:44 +0900",
        "Message-Id": "<1505363804-6827-1-git-send-email-anthony.kim@hideep.com>",
        "X-Mailer": "git-send-email 2.7.4",
        "In-Reply-To": "<1505114862-32489-1-git-send-email-anthony.kim@hideep.com>",
        "References": "<1505114862-32489-1-git-send-email-anthony.kim@hideep.com>",
        "Sender": "devicetree-owner@vger.kernel.org",
        "Precedence": "bulk",
        "List-ID": "<devicetree.vger.kernel.org>",
        "X-Mailing-List": "devicetree@vger.kernel.org"
    },
    "content": "The HiDeep touchscreen device is a capacitive multi-touch controller\nmainly for multi-touch supported devices use. It use I2C interface for\ncommunication to IC and provide axis X, Y, Z locations for ten finger\ntouch through input event interface to userspace.\n\nIt support the Crimson and the Lime two type IC. They are different\nthe number of channel supported and FW size. But the working protocol\nis same.\n\nSigned-off-by: Anthony Kim <anthony.kim@hideep.com>\n---\n .../bindings/input/touchscreen/hideep.txt          |   42 +\n .../devicetree/bindings/vendor-prefixes.txt        |    1 +\n drivers/input/touchscreen/Kconfig                  |   11 +\n drivers/input/touchscreen/Makefile                 |    1 +\n drivers/input/touchscreen/hideep.c                 | 1274 ++++++++++++++++++++\n 5 files changed, 1329 insertions(+)\n create mode 100644 Documentation/devicetree/bindings/input/touchscreen/hideep.txt\n create mode 100644 drivers/input/touchscreen/hideep.c",
    "diff": "diff --git a/Documentation/devicetree/bindings/input/touchscreen/hideep.txt b/Documentation/devicetree/bindings/input/touchscreen/hideep.txt\nnew file mode 100644\nindex 0000000..86b3a97\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/input/touchscreen/hideep.txt\n@@ -0,0 +1,42 @@\n+* HiDeep Finger and Stylus touchscreen controller\n+\n+Required properties:\n+- compatible\t\t: must be \"hideep,hideep-ts\"\n+- reg\t\t\t: I2C slave address, (e.g. 0x6C).\n+- interrupt-parent : Interrupt controller to which the chip is connected.\n+- interrupts : Interrupt to which the chip is connected.\n+\n+Optional properties:\n+- vdd-supply\t: It is the controller supply for controlling\n+\t\t\t\t\t main voltage(3.3V) through the regulator.\n+- vid-supply\t: It is the controller supply for controlling\n+\t\t\t\t\tIO voltage(1.8V) through the regulator.\n+- reset-gpios\t: Define for reset gpio pin.\n+\t\t\t\t\t\tIt is to use for reset IC.\n+- touchscreen-size-x\t: X axis size of touchscreen\n+- touchscreen-size-y\t: Y axis size of touchscreen\n+- linux,keycodes\t: Specifies an array of numeric keycode values to\n+\t\t\tbe used for reporting button presses. The array can\n+\t\t\tcontain up to 3 entries.\n+\n+Example:\n+\n+#include \"dt-bindings/input/input.h\"\n+\n+i2c@00000000 {\n+\n+\t/* ... */\n+\n+\ttouchscreen@6c {\n+\t\tcompatible = \"hideep,hideep-ts\";\n+\t\treg = <0x6c>;\n+\t\tinterrupt-parent = <&gpx1>;\n+\t\tinterrupts = <2 IRQ_TYPE_LEVEL_LOW>;\n+\t\tvdd-supply = <&ldo15_reg>\";\n+\t\tvid-supply = <&ldo18_reg>;\n+\t\treset-gpios = <&gpx1 5 0>;\n+\t\ttouchscreen-size-x = 1079;\n+\t\ttouchscreen-size-y = 1919;\n+\t\tlinux,keycodes = <KEY_HOME>, <KEY_MENU>, <KEY_BACK>;\n+\t};\n+};\ndiff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt\nindex c03d201..aa2a301 100644\n--- a/Documentation/devicetree/bindings/vendor-prefixes.txt\n+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt\n@@ -131,6 +131,7 @@ gw\tGateworks Corporation\n hannstar\tHannStar Display Corporation\n haoyu\tHaoyu Microelectronic Co. Ltd.\n hardkernel\tHardkernel Co., Ltd\n+hideep\tHiDeep Inc.\n himax\tHimax Technologies, Inc.\n hisilicon\tHisilicon Limited.\n hit\tHitachi Ltd.\ndiff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig\nindex 64b30fe..d0c8dafc 100644\n--- a/drivers/input/touchscreen/Kconfig\n+++ b/drivers/input/touchscreen/Kconfig\n@@ -344,6 +344,17 @@ config TOUCHSCREEN_GOODIX\n \t  To compile this driver as a module, choose M here: the\n \t  module will be called goodix.\n \n+config TOUCHSCREEN_HIDEEP\n+\ttristate \"HiDeep Touch IC\"\n+\tdepends on I2C\n+\thelp\n+\t  Say Y here if you have a touchscreen using HiDeep.\n+\n+\t  If unsure, say N.\n+\n+\t  To compile this driver as a moudle, choose M here : the\n+\t  module will be called hideep_ts.\n+\n config TOUCHSCREEN_ILI210X\n \ttristate \"Ilitek ILI210X based touchscreen\"\n \tdepends on I2C\ndiff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile\nindex 6badce8..873b67e 100644\n--- a/drivers/input/touchscreen/Makefile\n+++ b/drivers/input/touchscreen/Makefile\n@@ -39,6 +39,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX)\t+= egalax_ts.o\n obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)\t+= egalax_ts_serial.o\n obj-$(CONFIG_TOUCHSCREEN_FUJITSU)\t+= fujitsu_ts.o\n obj-$(CONFIG_TOUCHSCREEN_GOODIX)\t+= goodix.o\n+obj-$(CONFIG_TOUCHSCREEN_HIDEEP)\t+= hideep.o\n obj-$(CONFIG_TOUCHSCREEN_ILI210X)\t+= ili210x.o\n obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC)\t+= imx6ul_tsc.o\n obj-$(CONFIG_TOUCHSCREEN_INEXIO)\t+= inexio.o\ndiff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c\nnew file mode 100644\nindex 0000000..f1b021b\n--- /dev/null\n+++ b/drivers/input/touchscreen/hideep.c\n@@ -0,0 +1,1274 @@\n+/*\n+ * Copyright (C) 2012-2017 Hideep, Inc.\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License version 2\n+ * as published by the Free Software Foudation.\n+ */\n+\n+#include <linux/module.h>\n+#include <linux/of.h>\n+#include <linux/firmware.h>\n+#include <linux/delay.h>\n+#include <linux/regulator/consumer.h>\n+#include <linux/gpio.h>\n+#include <linux/i2c.h>\n+#include <linux/acpi.h>\n+#include <linux/interrupt.h>\n+#include <linux/sysfs.h>\n+#include <linux/input.h>\n+#include <linux/input/mt.h>\n+#include <linux/input/touchscreen.h>\n+#include <asm/unaligned.h>\n+\n+#define HIDEEP_TS_NAME\t\t\t\t\t\"HiDeep Touchscreen\"\n+#define HIDEEP_I2C_NAME\t\t\t\t\t\"hideep_ts\"\n+\n+#define HIDEEP_MT_MAX\t\t\t\t\t10\n+#define HIDEEP_KEY_MAX\t\t\t\t\t3\n+#define FRAME_HEADER_SIZE\t\t\t\t8\n+\n+/* Touch & key event */\n+#define HIDEEP_EVENT_COUNT_ADDR\t\t\t0x240\n+#define HIDEEP_TOUCH_DATA_ADDR\t\t\t0x242\n+#define HIDEEP_KEY_DATA_ADDR\t\t\t0x2A6\n+#define HIDEEP_RAW_DATA_ADDR\t\t\t0x1000\n+\n+/* command list */\n+#define HIDEEP_RESET_CMD\t\t\t\t0x9800\n+#define HIDEEP_INTCLR_CMD\t\t\t\t0x9802\n+#define HIDEEP_OPMODE_CMD\t\t\t\t0x9804\n+#define HIDEEP_SWTICH_CMD\t\t\t\t0x9805\n+#define HIDEEP_SLEEP_CMD\t\t\t\t0x980D\n+\n+/* multi touch event bit */\n+#define HIDEEP_MT_ALWAYS_REPORT\t\t\t0\n+#define HIDEEP_MT_TOUCHED\t\t\t\t1\n+#define HIDEEP_MT_FIRST_CONTACT\t\t\t2\n+#define HIDEEP_MT_DRAG_MOVE\t\t\t\t3\n+#define HIDEEP_MT_RELEASED\t\t\t\t4\n+#define HIDEEP_MT_PINCH\t\t\t\t\t5\n+#define HIDEEP_MT_PRESSURE\t\t\t\t6\n+\n+/* key event bit */\n+#define HIDEEP_KEY_RELEASED\t\t\t\t0x20\n+#define HIDEEP_KEY_PRESSED\t\t\t\t0x40\n+#define HIDEEP_KEY_FIRST_PRESSED\t\t0x80\n+#define HIDEEP_KEY_PRESSED_MASK\t\t\t0xC0\n+\n+/* For NVM */\n+#define YRAM_BASE\t\t\t\t0x40000000\n+#define PERIPHERAL_BASE\t\t\t0x50000000\n+#define ESI_BASE\t\t\t\t(PERIPHERAL_BASE + 0x00000000)\n+#define FLASH_BASE\t\t\t\t(PERIPHERAL_BASE + 0x01000000)\n+#define SYSCON_BASE\t\t\t\t(PERIPHERAL_BASE + 0x02000000)\n+\n+#define SYSCON_MOD_CON\t\t\t(SYSCON_BASE + 0x0000)\n+#define SYSCON_SPC_CON\t\t\t(SYSCON_BASE + 0x0004)\n+#define SYSCON_CLK_CON\t\t\t(SYSCON_BASE + 0x0008)\n+#define SYSCON_CLK_ENA\t\t\t(SYSCON_BASE + 0x000C)\n+#define SYSCON_RST_CON\t\t\t(SYSCON_BASE + 0x0010)\n+#define SYSCON_WDT_CON\t\t\t(SYSCON_BASE + 0x0014)\n+#define SYSCON_WDT_CNT\t\t\t(SYSCON_BASE + 0x0018)\n+#define SYSCON_PWR_CON\t\t\t(SYSCON_BASE + 0x0020)\n+#define SYSCON_PGM_ID\t\t\t(SYSCON_BASE + 0x00F4)\n+\n+#define FLASH_CON\t\t\t\t(FLASH_BASE + 0x0000)\n+#define FLASH_STA\t\t\t\t(FLASH_BASE + 0x0004)\n+#define FLASH_CFG\t\t\t\t(FLASH_BASE + 0x0008)\n+#define FLASH_TIM\t\t\t\t(FLASH_BASE + 0x000C)\n+#define FLASH_CACHE_CFG\t\t\t(FLASH_BASE + 0x0010)\n+#define FLASH_PIO_SIG\t\t\t(FLASH_BASE + 0x400000)\n+\n+#define ESI_TX_INVALID\t\t\t(ESI_BASE + 0x0008)\n+\n+#define PERASE\t\t\t\t\t0x00040000\n+#define WRONLY\t\t\t\t\t0x00100000\n+\n+#define NVM_MASK_OFS\t\t\t0x0000000C\n+#define NVM_DEFAULT_PAGE\t\t0\n+#define NVM_SFR_WPAGE\t\t\t1\n+#define NVM_SFR_RPAGE\t\t\t2\n+\n+#define PIO_SIG\t\t\t\t\t0x00400000\n+#define _PROT_MODE\t\t\t\t0x03400000\n+\n+#define NVM_PAGE_SIZE\t\t\t128\n+\n+#define HIDEEP_DWZ_INFO\t\t\t0x000002C0\n+\n+enum e_dev_state {\n+\tstate_init = 1,\n+\tstate_normal,\n+\tstate_sleep,\n+\tstate_updating,\n+};\n+\n+struct hideep_event {\n+\t__le16 x;\n+\t__le16 y;\n+\t__le16 z;\n+\tunsigned char w;\n+\tunsigned char flag;\n+\tunsigned char type;\n+\tunsigned char index;\n+} __packed;\n+\n+struct dwz_info {\n+\t__le32\tcode_start;\n+\tunsigned char code_crc[12];\n+\n+\t__le32 c_code_start;\n+\t__le16 c_code_len;\n+\t__le16 gen_ver;\n+\n+\t__le32 vr_start;\n+\t__le16 vr_len;\n+\t__le16 rsv0;\n+\n+\t__le32 ft_start;\n+\t__le16 ft_len;\n+\t__le16 vr_version;\n+\n+\t__le16 boot_ver;\n+\t__le16 core_ver;\n+\t__le16 custom_ver;\n+\t__le16 release_ver;\n+\n+\tunsigned char factory_id;\n+\tunsigned char panel_type;\n+\tunsigned char model_name[6];\n+\t__le16 product_code;\n+\t__le16 extra_option;\n+\n+\t__le16 product_id;\n+\t__le16 vendor_id;\n+} __packed;\n+\n+struct hideep_ts {\n+\tstruct i2c_client *client;\n+\tstruct input_dev *input_dev;\n+\n+\tstruct touchscreen_properties prop;\n+\n+\tstruct gpio_desc *reset_gpio;\n+\n+\tstruct regulator *vcc_vdd;\n+\tstruct regulator *vcc_vid;\n+\n+\tstruct mutex dev_mutex;\n+\tstruct mutex i2c_mutex;\n+\n+\tenum e_dev_state dev_state;\n+\n+\tunsigned int tch_count;\n+\tunsigned int key_count;\n+\tunsigned int lpm_count;\n+\n+\tunsigned char touch_event[HIDEEP_MT_MAX * 10];\n+\tunsigned char key_event[HIDEEP_KEY_MAX * 2];\n+\n+\tint key_num;\n+\tint key_codes[HIDEEP_KEY_MAX];\n+\n+\tstruct dwz_info dwz_info;\n+\n+\tint fw_size;\n+\tint nvm_mask;\n+} __packed;\n+\n+struct pgm_packet {\n+\tunion {\n+\t\tunsigned char b[8];\n+\t\t__be32 w[2];\n+\t} header;\n+\n+\t__be32 payload[NVM_PAGE_SIZE / sizeof(unsigned int)];\n+};\n+\n+static void hideep_reset_ic(struct hideep_ts *ts);\n+\n+static int hideep_pgm_w_mem(struct hideep_ts *ts, unsigned int addr,\n+\tstruct pgm_packet *packet, unsigned int len)\n+{\n+\tint ret;\n+\tint i;\n+\n+\tif ((len % sizeof(u32)) != 0)\n+\t\treturn -EINVAL;\n+\n+\tput_unaligned_be32((0x80 | (len / sizeof(u32) - 1)),\n+\t\t&packet->header.w[0]);\n+\tput_unaligned_be32(addr, &packet->header.w[1]);\n+\n+\tfor (i = 0; i < len / sizeof(u32); i++)\n+\t\tput_unaligned_be32(packet->payload[i], &packet->payload[i]);\n+\n+\tret = i2c_master_send(ts->client, &packet->header.b[3],\n+\t\t(len + 5));\n+\n+\treturn ret;\n+}\n+\n+static int hideep_pgm_r_mem(struct hideep_ts *ts, unsigned int addr,\n+\tstruct pgm_packet *packet, unsigned int len)\n+{\n+\tint ret;\n+\tint i;\n+\tunsigned char buff[len];\t// need to modify\n+\tstruct i2c_msg msg[2];\n+\n+\tif ((len % sizeof(u32)) != 0)\n+\t\treturn -EINVAL;\n+\n+\tput_unaligned_be32((0x00 | (len / sizeof(u32) - 1)),\n+\t\t&packet->header.w[0]);\n+\tput_unaligned_be32(addr, &packet->header.w[1]);\n+\n+\tmsg[0].addr = ts->client->addr;\n+\tmsg[0].flags = 0;\n+\tmsg[0].len = 5;\n+\tmsg[0].buf = &packet->header.b[3];\n+\n+\tmsg[1].addr = ts->client->addr;\n+\tmsg[1].flags = I2C_M_RD;\n+\tmsg[1].len = len;\n+\tmsg[1].buf = buff;\n+\n+\tret = i2c_transfer(ts->client->adapter, msg, 2);\n+\n+\tif (ret < 0)\n+\t\tgoto err;\n+\n+\tfor (i = 0; i < len / sizeof(u32); i++)\n+\t\tpacket->payload[i] = get_unaligned_be32(&buff[i * sizeof(u32)]);\n+\n+err:\n+\treturn ret;\n+}\n+\n+static int hideep_pgm_r_reg(struct hideep_ts *ts, unsigned int addr,\n+\tunsigned int *val)\n+{\n+\tint ret;\n+\tstruct pgm_packet packet;\n+\n+\tput_unaligned_be32(0x00, &packet.header.w[0]);\n+\tput_unaligned_be32(addr, &packet.header.w[1]);\n+\n+\tret = hideep_pgm_r_mem(ts, addr, &packet, sizeof(u32));\n+\n+\tif (ret < 0)\n+\t\tgoto err;\n+\n+\t*val = packet.payload[0];\n+\n+err:\n+\treturn ret;\n+}\n+\n+static int hideep_pgm_w_reg(struct hideep_ts *ts, unsigned int addr,\n+\tunsigned int data)\n+{\n+\tint ret;\n+\tstruct pgm_packet packet;\n+\n+\tput_unaligned_be32(0x80, &packet.header.w[0]);\n+\tput_unaligned_be32(addr, &packet.header.w[1]);\n+\tpacket.payload[0] = data;\n+\n+\tret = hideep_pgm_w_mem(ts, addr, &packet, sizeof(u32));\n+\n+\treturn ret;\n+}\n+\n+#define SW_RESET_IN_PGM(CLK) \\\n+{ \\\n+\thideep_pgm_w_reg(ts, SYSCON_WDT_CNT, CLK); \\\n+\thideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x03); \\\n+\thideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x01); \\\n+}\n+\n+#define SET_FLASH_PIO(CE) \\\n+\thideep_pgm_w_reg(ts, FLASH_CON, 0x01 | (CE << 1))\n+#define SET_PIO_SIG(X, Y) \\\n+\thideep_pgm_w_reg(ts, FLASH_PIO_SIG + X, Y)\n+#define SET_FLASH_HWCONTROL() \\\n+\thideep_pgm_w_reg(ts, FLASH_CON, 0x00)\n+\n+#define NVM_W_SFR(x, y) \\\n+{ \\\n+\tSET_FLASH_PIO(1); \\\n+\tSET_PIO_SIG(x, y); \\\n+\tSET_FLASH_PIO(0); \\\n+}\n+\n+static void hideep_pgm_set(struct hideep_ts *ts)\n+{\n+\thideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x00);\n+\thideep_pgm_w_reg(ts, SYSCON_SPC_CON, 0x00);\n+\thideep_pgm_w_reg(ts, SYSCON_CLK_ENA, 0xFF);\n+\thideep_pgm_w_reg(ts, SYSCON_CLK_CON, 0x01);\n+\thideep_pgm_w_reg(ts, SYSCON_PWR_CON, 0x01);\n+\thideep_pgm_w_reg(ts, FLASH_TIM, 0x03);\n+\thideep_pgm_w_reg(ts, FLASH_CACHE_CFG, 0x00);\n+}\n+\n+static int hideep_pgm_get_pattern(struct hideep_ts *ts)\n+{\n+\tint ret;\n+\tunsigned int status;\n+\tconst unsigned char pattern[] = { 0x39, 0xAF, 0x9D, 0xDF };\n+\n+\tret = i2c_master_send(ts->client, pattern, sizeof(pattern));\n+\n+\tif (ret < 0) {\n+\t\tdev_err(&ts->client->dev, \"%d, %08X\", __LINE__, ret);\n+\t\treturn ret;\n+\t}\n+\n+\tmdelay(1);\n+\n+\t/* flush invalid Tx load register */\n+\tret = hideep_pgm_w_reg(ts, ESI_TX_INVALID, 0x01);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = hideep_pgm_r_reg(ts, SYSCON_PGM_ID, &status);\n+\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tdev_info(&ts->client->dev, \"%s, %08X\", __func__, status);\n+\treturn status;\n+}\n+\n+static int hideep_enter_pgm(struct hideep_ts *ts)\n+{\n+\tint retry_count = 10;\n+\tint val;\n+\tunsigned int pgm_pattern = 0xDF9DAF39;\n+\n+\twhile (retry_count--) {\n+\t\tval = hideep_pgm_get_pattern(ts);\n+\n+\t\tif (pgm_pattern != get_unaligned_be32(&val)) {\n+\t\t\tdev_err(&ts->client->dev, \"enter_pgm : error(%08x):\",\n+\t\t\t\tget_unaligned_be32(&val));\n+\t\t} else {\n+\t\t\tdev_dbg(&ts->client->dev, \"found magic code\");\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\n+\tif (retry_count < 0) {\n+\t\tdev_err(&ts->client->dev, \"couldn't enter pgm mode!!!\");\n+\t\tSW_RESET_IN_PGM(1000);\n+\t\treturn -EBADMSG;\n+\t}\n+\n+\thideep_pgm_set(ts);\n+\tmdelay(1);\n+\n+\treturn 0;\n+}\n+\n+static void hideep_nvm_unlock(struct hideep_ts *ts)\n+{\n+\tunsigned int unmask_code = 0;\n+\n+\thideep_pgm_w_reg(ts, FLASH_CFG, NVM_SFR_RPAGE);\n+\n+\thideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);\n+\n+\thideep_pgm_w_reg(ts, FLASH_CFG, NVM_DEFAULT_PAGE);\n+\n+\t/* make it unprotected code */\n+\tunmask_code &= (~_PROT_MODE);\n+\n+\t/* compare unmask code */\n+\tif (unmask_code != ts->nvm_mask)\n+\t\tdev_dbg(&ts->client->dev, \"read mask code different 0x%x\",\n+\t\t\tunmask_code);\n+\n+\thideep_pgm_w_reg(ts, FLASH_CFG, NVM_SFR_WPAGE);\n+\tSET_FLASH_PIO(0);\n+\n+\tNVM_W_SFR(NVM_MASK_OFS, ts->nvm_mask);\n+\tSET_FLASH_HWCONTROL();\n+\thideep_pgm_w_reg(ts, FLASH_CFG, NVM_DEFAULT_PAGE);\n+}\n+\n+static int hideep_check_status(struct hideep_ts *ts)\n+{\n+\tint ret, status;\n+\tint time_out = 100;\n+\n+\twhile (time_out--) {\n+\t\tmdelay(1);\n+\t\tret = hideep_pgm_r_reg(ts, FLASH_STA, &status);\n+\n+\t\tif (ret < 0)\n+\t\t\tcontinue;\n+\n+\t\tif (status)\n+\t\t\treturn status;\n+\t}\n+\n+\treturn time_out;\n+}\n+\n+static int hideep_program_page(struct hideep_ts *ts,\n+\tunsigned int addr, struct pgm_packet *packet_w)\n+{\n+\tint ret;\n+\n+\n+\tret = hideep_check_status(ts);\n+\n+\tif (ret < 0)\n+\t\treturn -EBUSY;\n+\n+\taddr = addr & ~(NVM_PAGE_SIZE - 1);\n+\n+\tSET_FLASH_PIO(0);\n+\tSET_FLASH_PIO(1);\n+\n+\t/* erase page */\n+\tSET_PIO_SIG((PERASE | addr), 0xFFFFFFFF);\n+\n+\tSET_FLASH_PIO(0);\n+\n+\tret = hideep_check_status(ts);\n+\n+\tif (ret < 0)\n+\t\treturn -EBUSY;\n+\n+\t/* write page */\n+\tSET_FLASH_PIO(1);\n+\n+\tSET_PIO_SIG((WRONLY | addr), get_unaligned_be32(&packet_w->payload[0]));\n+\n+\thideep_pgm_w_mem(ts, (FLASH_PIO_SIG | WRONLY),\n+\t\tpacket_w, NVM_PAGE_SIZE);\n+\n+\tSET_PIO_SIG(124, get_unaligned_be32(&packet_w->payload[31]));\n+\n+\tSET_FLASH_PIO(0);\n+\n+\tmdelay(1);\n+\n+\tret = hideep_check_status(ts);\n+\n+\tif (ret < 0)\n+\t\treturn -EBUSY;\n+\n+\tSET_FLASH_HWCONTROL();\n+\n+\treturn 0;\n+}\n+\n+static void hideep_program_nvm(struct hideep_ts *ts, const unsigned char *ucode,\n+\tint len)\n+{\n+\tstruct pgm_packet packet_w;\n+\tstruct pgm_packet packet_r;\n+\tint i;\n+\tint ret;\n+\tint addr = 0;\n+\tint len_r = len;\n+\tint len_w = NVM_PAGE_SIZE;\n+\tunsigned int pages = DIV_ROUND_UP(len, NVM_PAGE_SIZE);\n+\n+\n+\thideep_nvm_unlock(ts);\n+\n+\tdev_dbg(&ts->client->dev, \"pages : %d\", pages);\n+\n+\tfor (i = 0; i < pages; i++) {\n+\t\tif (len_r < NVM_PAGE_SIZE)\n+\t\t\tlen_w = len_r;\n+\n+\t\t/* compare */\n+\t\thideep_pgm_r_mem(ts, 0x00000000 + addr, &packet_r,\n+\t\t\tNVM_PAGE_SIZE);\n+\t\tret = memcmp(&ucode[addr], packet_r.payload, len_w);\n+\n+\t\tif (ret) {\n+\t\t\t/* write page */\n+\t\t\tmemcpy(packet_w.payload, &ucode[addr], len_w);\n+\t\t\tret = hideep_program_page(ts, addr, &packet_w);\n+\t\t\tif (ret)\n+\t\t\t\tdev_err(&ts->client->dev,\n+\t\t\t\t\t\"%s : error(%08x):\",\n+\t\t\t\t\t__func__, addr);\n+\t\t\tmdelay(1);\n+\t\t}\n+\n+\t\taddr += NVM_PAGE_SIZE;\n+\t\tlen_r -= NVM_PAGE_SIZE;\n+\t\tif (len_r < 0)\n+\t\t\tbreak;\n+\t}\n+}\n+\n+static int hideep_verify_nvm(struct hideep_ts *ts, const unsigned char *ucode,\n+\tint len)\n+{\n+\tstruct pgm_packet packet_r;\n+\tint i, j;\n+\tint ret;\n+\tint addr = 0;\n+\tint len_r = len;\n+\tint len_v = NVM_PAGE_SIZE;\n+\tunsigned int pages = DIV_ROUND_UP(len, NVM_PAGE_SIZE);\n+\n+\tfor (i = 0; i < pages; i++) {\n+\t\tif (len_r < NVM_PAGE_SIZE)\n+\t\t\tlen_v = len_r;\n+\n+\t\thideep_pgm_r_mem(ts, 0x00000000 + addr, &packet_r,\n+\t\t\tNVM_PAGE_SIZE);\n+\n+\t\tret = memcmp(&ucode[addr], packet_r.payload, len_v);\n+\n+\t\tif (ret) {\n+\t\t\tu8 *read = (u8 *)packet_r.payload;\n+\n+\t\t\tfor (j = 0; j < NVM_PAGE_SIZE; j++) {\n+\t\t\t\tif (ucode[addr + j] != read[j])\n+\t\t\t\t\tdev_err(&ts->client->dev,\n+\t\t\t\t\t\t\"verify : error([%d] %02x : %02x)\",\n+\t\t\t\t\t\taddr + j, ucode[addr + j],\n+\t\t\t\t\t\tread[j]);\n+\t\t\t}\n+\t\t\treturn ret;\n+\t\t}\n+\n+\t\taddr += NVM_PAGE_SIZE;\n+\t\tlen_r -= NVM_PAGE_SIZE;\n+\t\tif (len_r < 0)\n+\t\t\tbreak;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int hideep_update_firmware(struct hideep_ts *ts, const char *fn)\n+{\n+\tint ret;\n+\tint retry, retry_cnt = 3;\n+\tconst struct firmware *fw_entry;\n+\n+\tdev_dbg(&ts->client->dev, \"enter\");\n+\tret = request_firmware(&fw_entry, fn, &ts->client->dev);\n+\n+\tif (ret != 0) {\n+\t\tdev_err(&ts->client->dev, \"request_firmware : fail(%d)\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\tif (fw_entry->size > ts->fw_size) {\n+\t\tdev_err(&ts->client->dev,\n+\t\t\t\"file size(%zu) is big more than fw memory size(%d)\",\n+\t\t\tfw_entry->size, ts->fw_size);\n+\t\trelease_firmware(fw_entry);\n+\t\treturn -EFBIG;\n+\t}\n+\n+\t/* chip specific code for flash fuse */\n+\tmutex_lock(&ts->dev_mutex);\n+\n+\tts->dev_state = state_updating;\n+\n+\t/* enter program mode */\n+\tret = hideep_enter_pgm(ts);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* comparing & programming each page, if the memory of specified\n+\t * page is exactly same, no need to update.\n+\t */\n+\tfor (retry = 0; retry < retry_cnt; retry++) {\n+\t\thideep_program_nvm(ts, fw_entry->data, fw_entry->size);\n+\n+\t\tret = hideep_verify_nvm(ts, fw_entry->data, fw_entry->size);\n+\t\tif (!ret)\n+\t\t\tbreak;\n+\t}\n+\n+\tif (retry < retry_cnt)\n+\t\tdev_dbg(&ts->client->dev, \"update success!!!\");\n+\telse\n+\t\tdev_err(&ts->client->dev, \"update failed!!!\");\n+\n+\tSW_RESET_IN_PGM(1000);\n+\n+\tts->dev_state = state_normal;\n+\n+\tmutex_unlock(&ts->dev_mutex);\n+\n+\trelease_firmware(fw_entry);\n+\n+\treturn ret;\n+}\n+\n+static int hideep_load_dwz(struct hideep_ts *ts)\n+{\n+\tint ret = 0;\n+\tstruct pgm_packet packet_r;\n+\n+\tret = hideep_enter_pgm(ts);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tmdelay(50);\n+\n+\thideep_pgm_r_mem(ts, HIDEEP_DWZ_INFO, &packet_r,\n+\t\tsizeof(struct dwz_info));\n+\n+\tmemcpy(&ts->dwz_info, packet_r.payload,\n+\t\tsizeof(struct dwz_info));\n+\n+\tSW_RESET_IN_PGM(10);\n+\n+\tif (get_unaligned_le16(&ts->dwz_info.product_code) & 0x60) {\n+\t\t/* Lime fw size */\n+\t\tdev_dbg(&ts->client->dev, \"used lime IC\");\n+\t\tts->fw_size = 1024 * 64;\n+\t\tts->nvm_mask = 0x0030027B;\n+\t} else if (get_unaligned_le16(&ts->dwz_info.product_code) & 0x40) {\n+\t\t/* Crimson IC */\n+\t\tdev_dbg(&ts->client->dev, \"used crimson IC\");\n+\t\tts->fw_size = 1024 * 48;\n+\t\tts->nvm_mask = 0x00310000;\n+\t}\n+\n+\tdev_dbg(&ts->client->dev, \"firmware release version : %04x\",\n+\t\tget_unaligned_le16(&ts->dwz_info.release_ver));\n+\n+\tmdelay(50);\n+\n+\treturn 0;\n+}\n+\n+static int hideep_i2c_read(struct hideep_ts *ts, unsigned short addr,\n+\tunsigned short len, unsigned char *buf)\n+{\n+\tint ret;\n+\tstruct i2c_msg msg[2];\n+\n+\tmutex_lock(&ts->i2c_mutex);\n+\n+\tdev_dbg(&ts->client->dev, \"addr = 0x%02x, len = %d\", addr, len);\n+\n+\tmsg[0].addr = ts->client->addr;\n+\tmsg[0].flags = 0;\n+\tmsg[0].len = 2;\n+\tmsg[0].buf = (u8 *)&addr;\n+\n+\tmsg[1].addr = ts->client->addr;\n+\tmsg[1].flags = I2C_M_RD;\n+\tmsg[1].len = len;\n+\tmsg[1].buf = buf;\n+\n+\tret = i2c_transfer(ts->client->adapter, msg, 2);\n+\n+\tmutex_unlock(&ts->i2c_mutex);\n+\treturn ret;\n+}\n+\n+static int hideep_i2c_write(struct hideep_ts *ts, unsigned short addr,\n+\tunsigned short len, unsigned char *buf)\n+{\n+\tint ret;\n+\tunsigned char *wbuf;\n+\tstruct i2c_msg msg;\n+\n+\tdev_dbg(&ts->client->dev, \"addr = 0x%02x, len = %d\", addr, len);\n+\n+\twbuf = kmalloc(len + 2, GFP_KERNEL);\n+\n+\tmutex_lock(&ts->i2c_mutex);\n+\n+\tput_unaligned_le16(addr, &wbuf[0]);\n+\tmemcpy(&wbuf[2], buf, len);\n+\n+\tmsg.addr = ts->client->addr;\n+\tmsg.flags = 0;\n+\tmsg.len = len + 2;\n+\tmsg.buf = wbuf;\n+\n+\tret = i2c_transfer(ts->client->adapter, &msg, 1);\n+\n+\tmutex_unlock(&ts->i2c_mutex);\n+\n+\tkfree(wbuf);\n+\n+\treturn  ret;\n+}\n+\n+static void hideep_reset_ic(struct hideep_ts *ts)\n+{\n+\tunsigned char cmd = 0x01;\n+\n+\tif (!ts->reset_gpio) {\n+\t\tdev_dbg(&ts->client->dev, \"hideep:enable the reset_gpio\");\n+\t\tgpiod_set_value(ts->reset_gpio, GPIOD_OUT_LOW);\n+\t\tmdelay(20);\n+\t\tgpiod_set_value(ts->reset_gpio, GPIOD_OUT_HIGH);\n+\t} else {\n+\t\thideep_i2c_write(ts, HIDEEP_RESET_CMD, 1, &cmd);\n+\t}\n+\tmdelay(50);\n+}\n+\n+static int hideep_pwr_on(struct hideep_ts *ts)\n+{\n+\tint ret = 0;\n+\n+\tif (!ts->vcc_vdd) {\n+\t\tdev_dbg(&ts->client->dev, \"hideep:vcc_vdd is enable\");\n+\t\tret = regulator_enable(ts->vcc_vdd);\n+\t\tif (ret)\n+\t\t\tdev_err(&ts->client->dev,\n+\t\t\t\t\"Regulator vdd enable failed ret=%d\", ret);\n+\t\tusleep_range(999, 1000);\n+\t}\n+\n+\n+\tif (!ts->vcc_vid) {\n+\t\tdev_dbg(&ts->client->dev, \"hideep:vcc_vid is enable\");\n+\t\tret = regulator_enable(ts->vcc_vid);\n+\t\tif (ret)\n+\t\t\tdev_err(&ts->client->dev,\n+\t\t\t\t\"Regulator vcc_vid enable failed ret=%d\", ret);\n+\t\tusleep_range(2999, 3000);\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static void hideep_pwr_off(void *data)\n+{\n+\tstruct hideep_ts *ts = data;\n+\n+\tif (!ts->reset_gpio)\n+\t\tgpiod_set_value(ts->reset_gpio, GPIOD_OUT_LOW);\n+\n+\tif (!ts->vcc_vid)\n+\t\tregulator_disable(ts->vcc_vid);\n+\n+\tif (!ts->vcc_vdd)\n+\t\tregulator_disable(ts->vcc_vdd);\n+}\n+\n+#define __GET_MT_TOOL_TYPE(X) ((X == 0x01) ? MT_TOOL_FINGER : MT_TOOL_PEN)\n+\n+static void push_mt(struct hideep_ts *ts)\n+{\n+\tint id;\n+\tint i;\n+\tbool btn_up = 0;\n+\tint evt = 0;\n+\tint offset = sizeof(struct hideep_event);\n+\tstruct hideep_event *event;\n+\n+\t/* load multi-touch event to input system */\n+\tfor (i = 0; i < ts->tch_count; i++) {\n+\t\tevent = (struct hideep_event *)&ts->touch_event[i * offset];\n+\t\tid = (event->index >> 0) & 0x0F;\n+\t\tbtn_up = (event->flag >> HIDEEP_MT_RELEASED) & 0x01;\n+\n+\t\tdev_dbg(&ts->client->dev,\n+\t\t\t\"type = %d, id = %d, i = %d, x = %d, y = %d, z = %d\",\n+\t\t\tevent->type, event->index, i,\n+\t\t\tget_unaligned_le16(&event->x),\n+\t\t\tget_unaligned_le16(&event->y),\n+\t\t\tget_unaligned_le16(&event->z));\n+\n+\t\tinput_mt_slot(ts->input_dev, id);\n+\t\tinput_mt_report_slot_state(ts->input_dev,\n+\t\t\t__GET_MT_TOOL_TYPE(event->type),\n+\t\t\t(btn_up == 0));\n+\n+\t\tif (btn_up == 0) {\n+\t\t\tinput_report_abs(ts->input_dev, ABS_MT_POSITION_X,\n+\t\t\t\tget_unaligned_le16(&event->x));\n+\t\t\tinput_report_abs(ts->input_dev, ABS_MT_POSITION_Y,\n+\t\t\t\tget_unaligned_le16(&event->y));\n+\t\t\tinput_report_abs(ts->input_dev, ABS_MT_PRESSURE,\n+\t\t\t\tget_unaligned_le16(&event->z));\n+\t\t\tinput_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,\n+\t\t\t\tevent->w);\n+\t\t\tevt++;\n+\t\t}\n+\t}\n+\n+\tinput_mt_sync_frame(ts->input_dev);\n+}\n+\n+static void push_ky(struct hideep_ts *ts)\n+{\n+\tint i;\n+\tint status;\n+\tint code;\n+\n+\tfor (i = 0; i < ts->key_count; i++) {\n+\t\tcode = ts->key_event[i + i * 2] & 0x0F;\n+\t\tstatus = ts->key_event[i + i * 2] & 0xF0;\n+\n+\t\tinput_report_key(ts->input_dev, ts->key_codes[code],\n+\t\t\tstatus & HIDEEP_KEY_PRESSED_MASK);\n+\t}\n+}\n+\n+static void hideep_put_event(struct hideep_ts *ts)\n+{\n+\t/* mangling touch information */\n+\tif (ts->tch_count > 0)\n+\t\tpush_mt(ts);\n+\n+\tif (ts->key_count > 0)\n+\t\tpush_ky(ts);\n+\n+\tinput_sync(ts->input_dev);\n+}\n+\n+static int hideep_get_event(struct hideep_ts *ts)\n+{\n+\tint ret;\n+\tint touch_count;\n+\tint event_size;\n+\n+\t/* get touch event count */\n+\tdev_dbg(&ts->client->dev, \"mt = %d, key = %d, lpm = %02x\",\n+\t\tts->tch_count, ts->key_count, ts->lpm_count);\n+\n+\t/* get touch event information */\n+\tif (ts->tch_count > HIDEEP_MT_MAX)\n+\t\tts->tch_count = 0;\n+\n+\tif (ts->key_count > HIDEEP_KEY_MAX)\n+\t\tts->key_count = 0;\n+\n+\ttouch_count = ts->tch_count + ts->key_count;\n+\n+\tif (ts->tch_count > 0) {\n+\t\tevent_size = ts->tch_count *\n+\t\t\tsizeof(struct hideep_event);\n+\t\tret = hideep_i2c_read(ts, HIDEEP_TOUCH_DATA_ADDR,\n+\t\t\tevent_size, ts->touch_event);\n+\n+\t\tif (ret < 0) {\n+\t\t\tdev_err(&ts->client->dev, \"read I2C error.\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\tif (ts->key_count > 0) {\n+\t\tevent_size = ts->key_count * 2;\n+\t\tret = hideep_i2c_read(ts, HIDEEP_KEY_DATA_ADDR,\n+\t\t\tevent_size, ts->key_event);\n+\t\tif (ret < 0) {\n+\t\t\tdev_err(&ts->client->dev, \"read I2C error.\");\n+\t\t\treturn ret;\n+\t\t}\n+\t}\n+\n+\treturn touch_count;\n+}\n+\n+static irqreturn_t hideep_irq_task(int irq, void *handle)\n+{\n+\tunsigned char buff[2];\n+\tint ret;\n+\n+\tstruct hideep_ts *ts = handle;\n+\n+\tdev_dbg(&ts->client->dev, \"state = 0x%x\", ts->dev_state);\n+\n+\tif (ts->dev_state == state_normal) {\n+\t\tret = hideep_i2c_read(ts, HIDEEP_EVENT_COUNT_ADDR,\n+\t\t\t2, buff);\n+\n+\t\tif (ret < 0) {\n+\t\t\tdisable_irq(ts->client->irq);\n+\t\t\treturn IRQ_HANDLED;\n+\t\t}\n+\n+\t\tts->tch_count = buff[0];\n+\t\tts->key_count = buff[1] & 0x0f;\n+\t\tts->lpm_count = buff[1] & 0xf0;\n+\n+\t\tret = hideep_get_event(ts);\n+\n+\t\tif (ret >= 0)\n+\t\t\thideep_put_event(ts);\n+\t}\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+static int hideep_capability(struct hideep_ts *ts)\n+{\n+\tint ret, i;\n+\n+\tts->input_dev->name = HIDEEP_TS_NAME;\n+\tts->input_dev->id.bustype = BUS_I2C;\n+\n+\tif (ts->key_num) {\n+\t\tts->input_dev->keycode = ts->key_codes;\n+\t\tts->input_dev->keycodesize = sizeof(ts->key_codes[0]);\n+\t\tts->input_dev->keycodemax = ts->key_num;\n+\t\tfor (i = 0; i < ts->key_num; i++)\n+\t\t\tinput_set_capability(ts->input_dev, EV_KEY,\n+\t\t\t\tts->key_codes[i]);\n+\t}\n+\n+\tinput_set_abs_params(ts->input_dev,\n+\t\tABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);\n+\tinput_set_abs_params(ts->input_dev,\n+\t\tABS_MT_POSITION_X, 0, ts->prop.max_x, 0, 0);\n+\tinput_set_abs_params(ts->input_dev,\n+\t\tABS_MT_POSITION_Y, 0, ts->prop.max_y, 0, 0);\n+\tinput_set_abs_params(ts->input_dev,\n+\t\tABS_MT_PRESSURE, 0, 65535, 0, 0);\n+\tinput_set_abs_params(ts->input_dev,\n+\t\tABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);\n+\n+\tret = input_mt_init_slots(ts->input_dev,\n+\t\tHIDEEP_MT_MAX, INPUT_MT_DIRECT);\n+\n+\treturn ret;\n+}\n+\n+static void hideep_get_info(struct hideep_ts *ts)\n+{\n+\tunsigned char val[4];\n+\n+\tif (ts->prop.max_x == 0 || ts->prop.max_y == 0) {\n+\t\thideep_i2c_read(ts, 0x28, 4, val);\n+\n+\t\tts->prop.max_x = get_unaligned_le16(&val[2]);\n+\t\tts->prop.max_y = get_unaligned_le16(&val[0]);\n+\n+\t\tdev_info(&ts->client->dev, \"X : %d, Y : %d\",\n+\t\t\tts->prop.max_x, ts->prop.max_y);\n+\t}\n+}\n+\n+static ssize_t hideep_update_fw(struct device *dev,\n+\tstruct device_attribute *attr, const char *buf, size_t count)\n+{\n+\tstruct hideep_ts *ts = dev_get_drvdata(dev);\n+\tint mode, ret;\n+\tchar *fw_name;\n+\n+\tret = kstrtoint(buf, 8, &mode);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tdisable_irq(ts->client->irq);\n+\n+\tts->dev_state = state_updating;\n+\tfw_name = kasprintf(GFP_KERNEL, \"hideep_ts_%04x.bin\",\n+\t\tget_unaligned_le16(&ts->dwz_info.product_id));\n+\tret = hideep_update_firmware(ts, fw_name);\n+\n+\tif (ret != 0)\n+\t\tdev_err(dev, \"The firmware update failed(%d)\", ret);\n+\n+\tkfree(fw_name);\n+\n+\tret = hideep_load_dwz(ts);\n+\n+\tif (ret < 0)\n+\t\tdev_err(&ts->client->dev, \"fail to load dwz, ret = 0x%x\", ret);\n+\n+\tenable_irq(ts->client->irq);\n+\n+\tts->dev_state = state_normal;\n+\n+\treturn count;\n+}\n+\n+static ssize_t hideep_fw_version_show(struct device *dev,\n+\tstruct device_attribute *attr, char *buf)\n+{\n+\tint len = 0;\n+\tstruct hideep_ts *ts = dev_get_drvdata(dev);\n+\n+\tdev_info(dev, \"release version : %04x\",\n+\t\tget_unaligned_le16(&ts->dwz_info.release_ver));\n+\n+\tmutex_lock(&ts->dev_mutex);\n+\tlen = scnprintf(buf, PAGE_SIZE,\n+\t\t\"%04x\\n\", get_unaligned_le16(&ts->dwz_info.release_ver));\n+\tmutex_unlock(&ts->dev_mutex);\n+\n+\treturn len;\n+}\n+\n+static ssize_t hideep_product_id_show(struct device *dev,\n+\tstruct device_attribute *attr, char *buf)\n+{\n+\tint len = 0;\n+\tstruct hideep_ts *ts = dev_get_drvdata(dev);\n+\n+\tdev_info(dev, \"product id : %04x\",\n+\t\tget_unaligned_le16(&ts->dwz_info.product_id));\n+\n+\tmutex_lock(&ts->dev_mutex);\n+\tlen = scnprintf(buf, PAGE_SIZE,\n+\t\t\"%04x\\n\", get_unaligned_le16(&ts->dwz_info.product_id));\n+\tmutex_unlock(&ts->dev_mutex);\n+\n+\treturn len;\n+}\n+\n+static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL);\n+static DEVICE_ATTR(product_id, 0664, hideep_product_id_show, NULL);\n+static DEVICE_ATTR(update_fw, 0664, NULL, hideep_update_fw);\n+\n+static struct attribute *hideep_ts_sysfs_entries[] = {\n+\t&dev_attr_version.attr,\n+\t&dev_attr_product_id.attr,\n+\t&dev_attr_update_fw.attr,\n+\tNULL,\n+};\n+\n+static struct attribute_group hideep_ts_attr_group = {\n+\t.attrs = hideep_ts_sysfs_entries,\n+};\n+\n+static int __maybe_unused hideep_resume(struct device *dev)\n+{\n+\tstruct hideep_ts *ts = dev_get_drvdata(dev);\n+\tunsigned char sleep_cmd = 0x00;\n+\n+\tmutex_lock(&ts->dev_mutex);\n+\n+\tif (ts->dev_state != state_normal)\n+\t\tts->dev_state = state_normal;\n+\n+\thideep_i2c_write(ts, HIDEEP_SLEEP_CMD, 1, &sleep_cmd);\n+\tenable_irq(ts->client->irq);\n+\n+\tmdelay(10);\n+\thideep_reset_ic(ts);\n+\n+\tmutex_unlock(&ts->dev_mutex);\n+\treturn 0;\n+}\n+\n+static int __maybe_unused hideep_suspend(struct device *dev)\n+{\n+\tstruct hideep_ts *ts = dev_get_drvdata(dev);\n+\tunsigned char sleep_cmd = 0x01;\n+\n+\tmutex_lock(&ts->dev_mutex);\n+\n+\tif (ts->dev_state != state_sleep)\n+\t\tts->dev_state = state_sleep;\n+\n+\t/* default deep sleep */\n+\thideep_i2c_write(ts, HIDEEP_SLEEP_CMD, 1, &sleep_cmd);\n+\tdisable_irq(ts->client->irq);\n+\n+\tmutex_unlock(&ts->dev_mutex);\n+\treturn 0;\n+}\n+\n+static int  hideep_parse_dts(struct device *dev, struct hideep_ts *ts)\n+{\n+\tint ret;\n+\n+\tts->reset_gpio = devm_gpiod_get_optional(dev, \"reset\",\n+\t\t\t\t\t\t\tGPIOD_OUT_HIGH);\n+\tif (IS_ERR(ts->reset_gpio))\n+\t\treturn PTR_ERR(ts->reset_gpio);\n+\n+\tts->vcc_vdd = devm_regulator_get(dev, \"vdd\");\n+\tif (IS_ERR(ts->vcc_vdd))\n+\t\treturn PTR_ERR(ts->vcc_vdd);\n+\n+\tts->vcc_vid = devm_regulator_get(dev, \"vid\");\n+\tif (IS_ERR(ts->vcc_vid))\n+\t\treturn PTR_ERR(ts->vcc_vid);\n+\n+\tts->key_num = device_property_read_u32_array(dev, \"linux,keycodes\",\n+\t\t\t\t\t\tNULL, 0);\n+\n+\tif (ts->key_num > HIDEEP_KEY_MAX) {\n+\t\tdev_err(dev, \"too many support key defined(%d)!!!\",\n+\t\t\tts->key_num);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tret = device_property_read_u32_array(dev, \"linux,keycodes\",\n+\t\t\t\tts->key_codes, ts->key_num);\n+\tif (ret) {\n+\t\tdev_dbg(dev, \"don't support touch key\");\n+\t\tts->key_num = 0;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int hideep_probe(struct i2c_client *client,\n+\tconst struct i2c_device_id *id)\n+{\n+\tint ret = 0;\n+\tstruct hideep_ts *ts;\n+\n+\t/* check i2c bus */\n+\tif (!i2c_check_functionality(client->adapter,\n+\t\tI2C_FUNC_I2C)) {\n+\t\tdev_err(&client->dev, \"check i2c device error\");\n+\t\treturn -ENODEV;\n+\t}\n+\n+\t/* init hideep_ts */\n+\tts = devm_kzalloc(&client->dev,\n+\t\tsizeof(*ts), GFP_KERNEL);\n+\tif (!ts)\n+\t\treturn -ENOMEM;\n+\n+\tret = hideep_parse_dts(&client->dev, ts);\n+\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tts->client = client;\n+\n+\ti2c_set_clientdata(client, ts);\n+\n+\tmutex_init(&ts->i2c_mutex);\n+\tmutex_init(&ts->dev_mutex);\n+\n+\t/* power on */\n+\tret = hideep_pwr_on(ts);\n+\tif (ret) {\n+\t\tdev_err(&ts->client->dev, \"power on failed\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = devm_add_action(&ts->client->dev, hideep_pwr_off, ts);\n+\tif (ret) {\n+\t\thideep_pwr_off(ts);\n+\t\treturn ret;\n+\t}\n+\n+\tts->dev_state = state_init;\n+\tmdelay(30);\n+\n+\t/* ic reset */\n+\thideep_reset_ic(ts);\n+\n+\t/* read info */\n+\tret = hideep_load_dwz(ts);\n+\tif (ret < 0) {\n+\t\tdev_err(&client->dev, \"fail to load dwz, ret = 0x%x\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\t/* init input device */\n+\tts->input_dev = devm_input_allocate_device(&client->dev);\n+\tif (!ts->input_dev) {\n+\t\tdev_err(&client->dev, \"can't allocate memory for input_dev\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\ttouchscreen_parse_properties(ts->input_dev, true, &ts->prop);\n+\thideep_get_info(ts);\n+\n+\tret = hideep_capability(ts);\n+\tif (ret) {\n+\t\tdev_err(&client->dev, \"can't init input properties\");\n+\t\treturn ret;\n+\t}\n+\n+\tret = input_register_device(ts->input_dev);\n+\tif (ret) {\n+\t\tdev_err(&client->dev, \"can't register input_dev\");\n+\t\treturn ret;\n+\t}\n+\n+\tinput_set_drvdata(ts->input_dev, ts);\n+\n+\tdev_info(&ts->client->dev, \"ts irq: %d\", ts->client->irq);\n+\tif (IS_ERR(&ts->client->irq)) {\n+\t\tdev_err(&client->dev, \"can't be assigned irq\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tret = devm_request_threaded_irq(&client->dev, ts->client->irq,\n+\t\tNULL, hideep_irq_task, IRQF_ONESHOT,\n+\t\tts->client->name, ts);\n+\n+\tdisable_irq(ts->client->irq);\n+\n+\tif (ret < 0) {\n+\t\tdev_err(&client->dev, \"fail to get irq, ret = 0x%08x\",\n+\t\t\tret);\n+\t\treturn ret;\n+\t}\n+\n+\tts->dev_state = state_normal;\n+\tenable_irq(ts->client->irq);\n+\n+\tret = devm_device_add_group(&client->dev, &hideep_ts_attr_group);\n+\n+\tif (ret) {\n+\t\tdev_err(&client->dev, \"fail init sys, ret = 0x%x\", ret);\n+\t\treturn ret;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);\n+\n+static const struct i2c_device_id hideep_dev_idtable[] = {\n+\t{ HIDEEP_I2C_NAME, 0 },\n+\t{}\n+};\n+MODULE_DEVICE_TABLE(i2c, hideep_dev_idtable);\n+\n+#ifdef CONFIG_ACPI\n+static const struct acpi_device_id hideep_acpi_id[] = {\n+\t{ \"HIDP0001\", 0 },\n+\t{}\n+};\n+MODULE_DEVICE_TABLE(acpi, hideep_acpi_id);\n+#endif\n+\n+#ifdef CONFIG_OF\n+static const struct of_device_id hideep_match_table[] = {\n+\t{ .compatible = \"hideep,hideep-ts\" },\n+\t{}\n+};\n+MODULE_DEVICE_TABLE(of, hideep_match_table);\n+#endif\n+\n+static struct i2c_driver hideep_driver = {\n+\t.probe = hideep_probe,\n+\t.id_table = hideep_dev_idtable,\n+\t.driver = {\n+\t\t.name = HIDEEP_I2C_NAME,\n+\t\t.of_match_table = of_match_ptr(hideep_match_table),\n+\t\t.acpi_match_table = ACPI_PTR(hideep_acpi_id),\n+\t\t.pm = &hideep_pm_ops,\n+\t},\n+};\n+\n+module_i2c_driver(hideep_driver);\n+\n+MODULE_DESCRIPTION(\"Driver for HiDeep Touchscreen Controller\");\n+MODULE_AUTHOR(\"anthony.kim@hideep.com\");\n+MODULE_LICENSE(\"GPL v2\");\n",
    "prefixes": []
}