Re: [PATCH] Input: add support for HiDeep touchscreen

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Dmitry,

Thank you very much for your mention.
I  feel to need answer of some your mention, so I reply.
And I will modify for all your mentions and resend patch soon.
Sure, I will apply most of the content your mentioned.

Thank you.
Anthony.

2017-08-10 8:49 GMT+09:00 Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>:
> Hi Anthony,
>
> On Tue, Jul 25, 2017 at 03:53:27PM +0900, Anthony Kim wrote:
>> The HiDeep touchscreen device is a capacitive multi-touch controller
>> mainly for multi-touch supported devices use. It use I2C interface for
>> communication to IC and provide axis X, Y, Z locations for ten finger
>> touch through input event interface to userspace.
>>
>> It support the Crimson and the Lime two type IC. They are different
>> the number of channel supported and FW size. But the working protocol
>> is same.
>>
>> Signed-off-by: Anthony Kim <anthony.kim@xxxxxxxxxx>
>> ---
>>  .../bindings/input/touchscreen/hideep.txt          |  35 +
>>  .../devicetree/bindings/vendor-prefixes.txt        |   1 +
>>  drivers/input/touchscreen/Kconfig                  |  11 +
>>  drivers/input/touchscreen/Makefile                 |   2 +
>>  drivers/input/touchscreen/hideep.h                 | 318 +++++++
>>  drivers/input/touchscreen/hideep_core.c            | 916 +++++++++++++++++++++
>>  drivers/input/touchscreen/hideep_dbg.c             | 405 +++++++++
>>  drivers/input/touchscreen/hideep_dbg.h             |  24 +
>>  drivers/input/touchscreen/hideep_isp.c             | 592 +++++++++++++
>>  drivers/input/touchscreen/hideep_isp.h             |  96 +++
>>  drivers/input/touchscreen/hideep_sysfs.c           | 245 ++++++
>>  11 files changed, 2645 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/hideep.txt
>>  create mode 100644 drivers/input/touchscreen/hideep.h
>>  create mode 100644 drivers/input/touchscreen/hideep_core.c
>>  create mode 100644 drivers/input/touchscreen/hideep_dbg.c
>>  create mode 100644 drivers/input/touchscreen/hideep_dbg.h
>>  create mode 100644 drivers/input/touchscreen/hideep_isp.c
>>  create mode 100644 drivers/input/touchscreen/hideep_isp.h
>>  create mode 100644 drivers/input/touchscreen/hideep_sysfs.c
>>
>> diff --git a/Documentation/devicetree/bindings/input/touchscreen/hideep.txt b/Documentation/devicetree/bindings/input/touchscreen/hideep.txt
>> new file mode 100644
>> index 0000000..5270426
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/input/touchscreen/hideep.txt
>> @@ -0,0 +1,35 @@
>> +* HiDeep Finger and Stylus touchscreen controller
>> +
>> +Required properties:
>> +- compatible         : must be "hideep,hideep-crimson"
>> +                                     or "hideep,hideep-lime".
>> +- reg                        : I2C slave address, (e.g. 0x6C).
>> +- interrupt-parent : Interrupt controller to which the chip is connected.
>> +- interrupts : Interrupt to which the chip is connected.
>> +
>> +Optional properties:
>> +- vdd-supply : It is the controller supply for controlling
>> +                                      main voltage(3.3V) through the regulator.
>> +- vid-supply : It is the controller supply for controlling
>> +                                     IO voltage(1.8V) through the regulator.
>> +- reset-gpios        : Define for reset gpio pin.
>> +                                             It is to use for reset IC.
>> +- hideep,max-coords  : Max value for axis X, Y, W, Z.
>> +
>> +Example:
>> +
>> +i2c@00000000 {
>> +
>> +     /* ... */
>> +
>> +     touchscreen@6c {
>> +             compatible = "hideep,hideep-lime";
>> +             reg = <0x6c>;
>> +             interrupt-parent = <&gpx1>;
>> +             interrupts = <2 0>;
>> +             vdd-supply = <&ldo15_reg>";
>> +             vid-supply = <&ldo18_reg>;
>> +             reset-gpios = <&gpx1 5 0>;
>> +             hideep,max-coords = <1080 1920 65535 65535>;
>> +     };
>> +};
>> diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> index c03d201..aa2a301 100644
>> --- a/Documentation/devicetree/bindings/vendor-prefixes.txt
>> +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
>> @@ -131,6 +131,7 @@ gw        Gateworks Corporation
>>  hannstar     HannStar Display Corporation
>>  haoyu        Haoyu Microelectronic Co. Ltd.
>>  hardkernel   Hardkernel Co., Ltd
>> +hideep       HiDeep Inc.
>>  himax        Himax Technologies, Inc.
>>  hisilicon    Hisilicon Limited.
>>  hit  Hitachi Ltd.
>> diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
>> index 64b30fe..13e11c7 100644
>> --- a/drivers/input/touchscreen/Kconfig
>> +++ b/drivers/input/touchscreen/Kconfig
>> @@ -1246,4 +1246,15 @@ config TOUCHSCREEN_ROHM_BU21023
>>         To compile this driver as a module, choose M here: the
>>         module will be called bu21023_ts.
>>
>> +config TOUCHSCREEN_HIDEEP
>> +     tristate "HiDeep Touch IC"
>> +     depends on I2C
>> +     help
>> +       Say Y here if you have a touchscreen using HiDeep.
>> +
>> +       If unsure, say N.
>> +
>> +       To compile this driver as a moudle, choose M here : the
>> +       module will be called hideep_ts.
>> +
>>  endif
>> diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
>> index 6badce8..3aab466 100644
>> --- a/drivers/input/touchscreen/Makefile
>> +++ b/drivers/input/touchscreen/Makefile
>> @@ -103,3 +103,5 @@ obj-$(CONFIG_TOUCHSCREEN_ZET6223) += zet6223.o
>>  obj-$(CONFIG_TOUCHSCREEN_ZFORCE)     += zforce_ts.o
>>  obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50)       += colibri-vf50-ts.o
>>  obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023)       += rohm_bu21023.o
>> +obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep_ts.o
>> +hideep_ts-$(CONFIG_TOUCHSCREEN_HIDEEP) := hideep_core.o hideep_sysfs.o hideep_isp.o hideep_dbg.o
>> diff --git a/drivers/input/touchscreen/hideep.h b/drivers/input/touchscreen/hideep.h
>> new file mode 100644
>> index 0000000..50306a1
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep.h
>> @@ -0,0 +1,318 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#ifndef _LINUX_HIDEEP_H
>> +#define _LINUX_HIDEEP_H
>> +
>> +/*************************************************************************
>> + * this is include special HEAD file.
>> + *************************************************************************/
>> +#ifdef CONFIG_FB
>> +#include <linux/fb.h>
>> +#include <linux/notifier.h>
>> +#endif
>> +
>> +/*************************************************************************
>> + * this is include normal HEAD file.
>> + *************************************************************************/
>> +#include <linux/of_gpio.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/input.h>
>> +#include <linux/uaccess.h>
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +#include <linux/proc_fs.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/firmware.h>
>> +#include <linux/pinctrl/consumer.h>
>> +#include <linux/pinctrl/pinctrl.h>
>> +#include <linux/pinctrl/machine.h>
>> +#include <linux/kthread.h>
>> +#include <linux/random.h>
>> +#include <linux/slab.h>
>> +#include <linux/sched.h>
>> +#include <linux/sched/rt.h>
>> +#include <linux/task_work.h>
>> +#include <linux/rtc.h>
>> +#include <linux/syscalls.h>
>> +#include <linux/timer.h>
>> +#include <linux/time.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio.h>
>> +#include <linux/hrtimer.h>
>> +#include <linux/i2c.h>
>> +#include <linux/irq.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/input/mt.h>
>> +#include <linux/fs.h>
>> +#include <linux/completion.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/init.h>
>> +#include <linux/gfp.h>
>> +#include <linux/kobject.h>
>> +#include <linux/string.h>
>> +#include <linux/sysfs.h>
>> +#include <linux/module.h>
>> +#include <linux/poll.h>
>> +#include <linux/fcntl.h>
>> +#include <linux/unistd.h>
>> +#include <linux/version.h>
>> +#include <linux/acpi.h>
>> +
>> +/*************************************************************************
>> + * definition part.
>> + * define is (open, set, enable) if not, is (close, clear, disable)
>> + * some special switch of functions.
>> + *************************************************************************/
>> +
>> +/* HIDEEP_PROTOCOL_2_0 is for protocol 2.0. */
>> +#define HIDEEP_PROTOCOL_2_0
>
> We should support both protocols simultaneously instead of being compile
> time option.
>
>> +
>> +/* HIDEEP_TYPE_B_PROTOCOL is for input_dev, if define , using TYPE_B,
>> + * otherwise TYPE_A.
>> + */
>> +#define HIDEEP_TYPE_B_PROTOCOL
>
> We only need Type-B support in new drivers.
>
>> +
>> +/* HIDEEP_DWZ_VERSION_CHECK if define, it will check dwz version. */
>> +#define HIDEEP_DWZ_VERSION_CHECK
>
> Why is this conditional?
>
>> +
>> +/* HIDEEP_SUPPORT_KE if define, it will use key button. */
>> +#define HIDEEP_SUPPORT_KEY
>
> Why is this compile-time decision?
>
>> +
>> +/* HIDEEP_SUPPORT_STYLUS if define, it will use stylus mode. */
>> +#define HIDEEP_SUPPORT_STYLUS
>
> Same here. We are looking for drivers to be usable on multitude of
> boards. The data should be comping form the board desciption (device
> tree, ACPI) so that the same kernel can work on multitude of boards.
>

Ok, got it. I will check again for many condition of my driver code and
modify all for these.

>> +
>> +/*************************************************************************
>> + * Buffer size
>> + *************************************************************************/
>> +#define FRAME_HEADER_SIZE                            8
>> +/* if size of system i2c buffer is smaller than this value, need to modify */
>> +#define MAX_I2C_BUFFER_SIZE                          512
>> +
>> +/*************************************************************************
>> + * board porting config
>> + *************************************************************************/
>> +#define HIDEEP_DEBUG_DEVICE_NAME             "hideep_debug"
>
> Why is this needed? I normally recommend userspace access over /dev/i2c
> if tuning is needed so that we do not have a large chunk of effectively
> dead code in the driver in production images.

Through the device, I get raw data of IC and access to registry of IC for
debugging and data analysis. Could I not use this device? If can not use,
I will remove it.

>
>> +#define HIDEEP_TS_NAME                                       "HiDeep Touchscreen"
>> +#define HIDEEP_I2C_NAME                                      "hideep_ts"
>> +
>> +/*************************************************************************
>> + * register addr
>> + *************************************************************************/
>> +/* Touch & key event */
>> +#define HIDEEP_EVENT_COUNT_ADDR                      0x240
>> +#define HIDEEP_TOUCH_DATA_ADDR                       0x242
>> +#define HIDEEP_KEY_DATA_ADDR                 0x2A6
>> +#define HIDEEP_RAW_DATA_ADDR                 0x1000
>> +
>> +/* command list */
>> +#define HIDEEP_RESET_CMD                             0x9800
>> +#define HIDEEP_INTCLR_CMD                            0x9802
>> +#define HIDEEP_OPMODE_CMD                            0x9804
>> +#define HIDEEP_SWTICH_CMD                            0x9805
>> +#define HIDEEP_SLEEP_CMD                             0x980D
>> +
>> +/*************************************************************************
>> + * multi-touch & key definitions.
>> + *************************************************************************/
>> +#define HIDEEP_MT_MAX                                        10
>> +#define HIDEEP_KEY_MAX                                       3
>> +
>> +/* multi touch event bit */
>> +#define HIDEEP_MT_ALWAYS_REPORT                      0
>> +#define HIDEEP_MT_TOUCHED                            1
>> +#define HIDEEP_MT_FIRST_CONTACT                      2
>> +#define HIDEEP_MT_DRAG_MOVE                          3
>> +#define HIDEEP_MT_RELEASED                           4
>> +#define HIDEEP_MT_PINCH                                      5
>> +#define HIDEEP_MT_PRESSURE                           6
>> +
>> +/* key event bit */
>> +#define HIDEEP_KEY_RELEASED                          0x20
>> +#define HIDEEP_KEY_PRESSED                           0x40
>> +#define HIDEEP_KEY_FIRST_PRESSED             0x80
>> +#define HIDEEP_KEY_PRESSED_MASK                      0xC0
>> +
>> +/*************************************************************************
>> + * HIDEEP PROTOCOL
>> + *************************************************************************/
>> +#ifdef HIDEEP_PROTOCOL_2_0
>> +struct hideep_mt_t {
>
> Just drop _t in structure names. You can see that you are dealing with
> the type because there is "struct" preceding the name.
>
>> +     unsigned short x;
>> +     unsigned short y;
>> +     unsigned short z;
>> +     unsigned char w;
>> +     unsigned char flag;
>> +     unsigned char type;
>> +     unsigned char index;
>> +};
>> +#else
>> +struct hideep_mt_t {
>> +     unsigned char flag;
>> +     unsigned char index;
>> +     unsigned short x;
>> +     unsigned short y;
>> +     unsigned char z;
>> +     unsigned char w;
>> +};
>> +#endif
>> +
>> +struct hideep_key_t {
>> +     unsigned char flag;
>> +     unsigned int key;
>> +};
>> +
>> +/*************************************************************************
>> + * IC State
>> + *************************************************************************/
>> +enum e_dev_state {
>> +     state_init = 1,
>> +     state_normal,
>> +     state_sleep,
>> +     state_updating,
>> +     state_debugging,
>> +};
>> +
>> +/*************************************************************************
>> + * Firmware info
>> + *************************************************************************/
>> +struct dwz_info_t {
>> +     unsigned int code_start;
>> +     unsigned char code_crc[12];
>> +
>> +     unsigned int c_code_start;
>> +     unsigned short c_code_len;
>> +     unsigned short gen_ver;
>
> I think you need to annotate with proper endianness (__le16 I assume)
> and convert to CPU endianness when using. Same goes for other
> firmware/config/nvm data.
>
>> +
>> +     unsigned int vr_start;
>> +     unsigned short vr_len;
>> +     unsigned short rsv0;
>> +
>> +     unsigned int ft_start;
>> +     unsigned short ft_len;
>> +     unsigned short vr_version;
>> +
>> +     unsigned short boot_ver;
>> +     unsigned short core_ver;
>> +     unsigned short custom_ver;
>> +     unsigned short release_ver;
>> +
>> +     unsigned char factory_id;
>> +     unsigned char panel_type;
>> +     unsigned char model_name[6];
>> +     unsigned short product_code;
>> +     unsigned short extra_option;
>> +
>> +     unsigned short product_id;
>> +     unsigned short vendor_id;
>> +};
>> +
>> +/*************************************************************************
>> + * driver information for hideep_t by device tree
>> + *************************************************************************/
>> +struct hideep_platform_data_t {
>> +     unsigned int max_x;
>> +     unsigned int max_y;
>> +     unsigned int max_z;
>> +     unsigned int max_w;
>> +
>> +#ifdef CONFIG_OF
>> +     int reset_gpio;
>> +
>> +     struct regulator *vcc_vdd;
>> +     struct regulator *vcc_vid;
>> +#endif
>> +};
>> +
>> +struct hideep_debug_dev_t {
>> +     struct miscdevice misc;
>> +
>> +     wait_queue_head_t i_packet;
>> +
>> +     unsigned int ready;
>> +     unsigned char *vr_buff;
>> +     unsigned char *img_buff;
>> +     unsigned short vr_size;
>> +     unsigned short img_size;
>> +
>> +     bool debug_enable;
>> +     bool release_flag;
>> +
>> +     struct hideep_t *ts;
>> +};
>> +
>> +struct hideep_function_list_t {
>> +     //core
>> +     int (*i2c_read)(struct hideep_t *, unsigned short, unsigned short,
>> +             unsigned char *);
>> +     int (*i2c_write)(struct hideep_t *, unsigned short, unsigned short,
>> +             unsigned char *);
>> +     void (*reset_ic)(struct hideep_t *);
>> +     void (*power)(struct hideep_t *, int);
>> +
>> +     //isp
>> +     int (*update_all)(struct hideep_t *, const char *);
>> +     int (*update_part)(struct hideep_t *, unsigned char *, int, int, bool);
>> +     int (*get_dwz_info)(struct hideep_t *);
>> +     void (*sp_func)(struct hideep_t *, unsigned char *, int, int);
>> +};
>> +
>> +struct hideep_t {
>> +     struct i2c_client *client;
>> +     struct input_dev *input_dev;
>> +     struct hideep_platform_data_t *p_data;
>> +
>> +     struct mutex dev_mutex;
>> +     struct mutex i2c_mutex;
>> +
>> +     struct hideep_debug_dev_t debug_dev;
>> +     struct hideep_function_list_t *hideep_api;
>> +
>> +     struct task_struct *hthread_event;
>
> Why do you need both threaded interrupt and kernel therad? The threaded
> interrupt should suffice.
>

Sometimes, my driver interrupt process time was long at some system,
so I used kernel thread for less interrupt process time. If there have
any problem,
I will use only interrupt thread.

>> +
>> +     bool suspended;
>> +     enum e_dev_state dev_state;
>> +
>> +#ifdef CONFIG_FB
>> +     struct notifier_block fb_notif;
>> +#endif
>> +
>> +     long tch_bit;
>> +     unsigned int tch_count;
>> +     unsigned int key_count;
>> +     unsigned int lpm_count;
>> +
>> +     struct hideep_mt_t touch_evt[HIDEEP_MT_MAX];
>> +
>> +#ifdef HIDEEP_SUPPORT_KEY
>> +     struct hideep_key_t key_evt[HIDEEP_KEY_MAX];
>> +     int key_codes[HIDEEP_KEY_MAX];
>> +#endif
>> +
>> +     unsigned char i2c_buf[256];
>> +     struct dwz_info_t *dwz_info;
>> +
>> +     int interrupt_state;
>> +     int fw_size;
>> +};
>> +
>> +/*************************************************************************
>> + * function define
>> + *************************************************************************/
>> +int hideep_debug_init(struct hideep_t *ts);
>> +void hideep_debug_uninit(void);
>> +
>> +int hideep_sysfs_init(struct hideep_t *ts);
>> +int hideep_sysfs_exit(struct hideep_t *ts);
>> +
>> +void hideep_isp_init(struct hideep_t *ts);
>> +
>> +#endif
>> diff --git a/drivers/input/touchscreen/hideep_core.c b/drivers/input/touchscreen/hideep_core.c
>> new file mode 100644
>> index 0000000..d1b2c44
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_core.c
>> @@ -0,0 +1,916 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#include "hideep.h"
>> +
>> +#define GET_PAYLOAD_SIZE_FROM_HEADER(x) \
>> +     ((x[1]>>6) ? ((x[2]*256+x[3])*(x[7]+1)):(x[2]*x[3]*(x[7]+1)))
>> +
>> +static int hideep_pwr_on(struct hideep_t *ts)
>> +{
>> +     struct hideep_platform_data_t *pdata;
>> +     int ret = 0;
>> +
>> +     pdata = ts->p_data;
>> +
>> +#ifdef CONFIG_OF
>> +     if (!IS_ERR(pdata->vcc_vdd)) {
>> +             dev_info(&ts->client->dev, "hideep:vcc_vdd is enable");
>> +             ret = regulator_enable(pdata->vcc_vdd);
>> +             if (ret)
>> +                     dev_err(&ts->client->dev,
>> +                             "Regulator vdd enable failed ret=%d", ret);
>> +     }
>> +     usleep_range(999, 1000);
>> +
>> +     if (!IS_ERR(pdata->vcc_vid)) {
>> +             dev_info(&ts->client->dev, "hideep:vcc_vid is enable");
>> +             ret = regulator_enable(pdata->vcc_vid);
>> +             if (ret)
>> +                     dev_err(&ts->client->dev,
>> +                             "Regulator vcc_vid enable failed ret=%d", ret);
>> +     }
>> +     usleep_range(2999, 3000);
>> +#endif
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_pwr_off(struct hideep_t *ts)
>> +{
>> +     struct hideep_platform_data_t *pdata;
>> +     int ret = 0;
>> +
>> +     pdata = ts->p_data;
>> +
>> +#ifdef CONFIG_OF
>> +     if (pdata->reset_gpio > 0) {
>> +             dev_info(&ts->client->dev, "hideep:disable the reset_gpio");
>> +             gpio_set_value(pdata->reset_gpio, 0);
>> +     }
>> +
>> +     if (!IS_ERR(pdata->vcc_vid)) {
>> +             dev_info(&ts->client->dev, "hideep:vcc_vid is disable");
>> +             ret = regulator_disable(pdata->vcc_vid);
>> +             if (ret)
>> +                     dev_err(&ts->client->dev,
>> +                             "Regulator vcc_vid enable failed ret=%d", ret);
>> +     }
>> +
>> +     if (!IS_ERR(pdata->vcc_vdd)) {
>> +             dev_info(&ts->client->dev, "hideep:vcc_vdd is disable");
>> +             ret = regulator_disable(pdata->vcc_vdd);
>> +             if (ret)
>> +                     dev_err(&ts->client->dev,
>> +                             "Regulator vdd disable failed ret=%d", ret);
>> +     }
>> +#endif
>> +     return ret;
>> +}
>> +
>> +static void hideep_power(struct hideep_t *ts, int on)
>> +{
>> +     int ret = 0;
>> +
>> +     if (on) {
>> +             dev_info(&ts->client->dev, "power on");
>> +             ret = hideep_pwr_on(ts);
>> +     } else {
>> +             dev_info(&ts->client->dev, "power off");
>> +             ret = hideep_pwr_off(ts);
>> +     }
>> +}
>> +
>> +static int hideep_i2c_read(struct hideep_t *ts, unsigned short addr,
>> +     unsigned short len, unsigned char *buf)
>> +{
>> +     int ret = -1;
>> +     unsigned short r_len, raddr;
>> +     int length;
>> +
>> +     length = len;
>> +     raddr = addr;
>> +
>> +     dev_dbg(&ts->client->dev, "addr = 0x%02x, len = %d", addr, len);
>> +
>> +     mutex_lock(&ts->i2c_mutex);
>> +
>> +     do {
>> +             if (length > MAX_I2C_BUFFER_SIZE)
>> +                     r_len = MAX_I2C_BUFFER_SIZE;
>> +             else
>> +                     r_len = length;
>> +
>> +             dev_dbg(&ts->client->dev, "addr = 0x%02x, len = %d",
>> +                     raddr, r_len);
>> +
>> +             ret = i2c_master_send(ts->client, (char *)&raddr, 2);
>> +
>> +             if (ret < 0)
>> +                     goto i2c_err;
>> +
>> +             ret = i2c_master_recv(ts->client, (char *)buf, r_len);
>> +             length -= MAX_I2C_BUFFER_SIZE;
>> +             buf += MAX_I2C_BUFFER_SIZE;
>> +             raddr += MAX_I2C_BUFFER_SIZE;
>> +
>> +             if (ret < 0)
>> +                     goto i2c_err;
>> +     } while (length > 0);
>> +
>> +     mutex_unlock(&ts->i2c_mutex);
>> +
>> +     return  0;
>> +i2c_err:
>> +     mutex_unlock(&ts->i2c_mutex);
>> +     return -1;
>> +}
>> +
>> +static int hideep_i2c_write(struct hideep_t *ts, unsigned short addr,
>> +     unsigned short len, unsigned char *buf)
>> +{
>> +     int ret = -1;
>> +
>> +     dev_dbg(&ts->client->dev, "addr = 0x%02x, len = %d", addr, len);
>> +
>> +     mutex_lock(&ts->i2c_mutex);
>> +
>> +     // data mangling..
>> +     ts->i2c_buf[0] = (addr >> 0) & 0xFF;
>> +     ts->i2c_buf[1] = (addr >> 8) & 0xFF;
>> +     memcpy(&ts->i2c_buf[2], buf, len);
>> +
>> +     ret = i2c_master_send(ts->client, (char *)ts->i2c_buf, len + 2);
>> +
>> +     if (ret < 0)
>> +             goto i2c_err;
>> +
>> +     mutex_unlock(&ts->i2c_mutex);
>> +     return  0;
>> +
>> +i2c_err:
>> +     mutex_unlock(&ts->i2c_mutex);
>> +     return -1;
>> +}
>> +
>> +#define __GET_MT_TOOL_TYPE(X) ((X == 0x01) ? MT_TOOL_FINGER : MT_TOOL_PEN)
>> +
>> +static void pops_mt(struct hideep_t *ts)
>> +{
>> +#ifdef HIDEEP_TYPE_B_PROTOCOL
>> +     int id;
>> +     int i;
>> +
>> +     for (i = 0; i < ts->tch_count; i++) {
>> +             id = (ts->touch_evt[i].index >> 0) & 0x0F;
>> +             input_mt_slot(ts->input_dev, id);
>> +             input_mt_report_slot_state(ts->input_dev,
>> +                     __GET_MT_TOOL_TYPE(ts->touch_evt[i].type), false);
>> +             input_report_key(ts->input_dev, BTN_TOUCH, false);
>> +     }
>> +#else
>> +     input_report_key(ts->input_dev, BTN_TOUCH, false);
>> +     input_mt_sync(ts->input_dev);
>> +#endif
>> +
>> +     input_sync(ts->input_dev);
>> +}
>> +
>> +static void push_mt(struct hideep_t *ts)
>> +{
>> +     int id;
>> +     int i;
>> +     bool btn_up = 0;
>> +     bool btn_dn = 0;
>> +     bool btn_mv = 0;
>> +     int evt = 0;
>> +
>> +     /* load multi-touch event to input system */
>> +     for (i = 0; i < ts->tch_count; i++) {
>> +             id = (ts->touch_evt[i].index >> 0) & 0x0F;
>> +             btn_up = (ts->touch_evt[i].flag >> HIDEEP_MT_RELEASED) & 0x01;
>> +             btn_dn = (ts->touch_evt[i].flag >> HIDEEP_MT_FIRST_CONTACT)
>> +                     & 0x01;
>> +             btn_mv = (ts->touch_evt[i].flag >> HIDEEP_MT_DRAG_MOVE) & 0x01;
>> +
>> +             if (btn_up)
>> +                     clear_bit(id, &ts->tch_bit);
>> +             else
>> +                     __set_bit(id, &ts->tch_bit);
>> +
>> +             dev_dbg(&ts->client->dev,
>> +                     "type = %d, id = %d, i = %d, x = %d, y = %d, z = %d",
>> +                     ts->touch_evt[i].type, ts->touch_evt[i].index,
>> +                     i, ts->touch_evt[i].x, ts->touch_evt[i].y,
>> +                     ts->touch_evt[i].z);
>> +
>> +#ifdef HIDEEP_TYPE_B_PROTOCOL
>> +             input_mt_slot(ts->input_dev, id);
>> +             input_mt_report_slot_state(ts->input_dev,
>> +                     __GET_MT_TOOL_TYPE(ts->touch_evt[i].type),
>> +                     (btn_up == 0));
>> +
>> +             if (btn_up == 0) {
>> +                     input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
>> +                             ts->touch_evt[i].x);
>> +                     input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
>> +                             ts->touch_evt[i].y);
>> +                     input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
>> +                             ts->touch_evt[i].z);
>> +                     input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
>> +                             ts->touch_evt[i].w);
>> +                     evt++;
>> +             }
>> +#else
>> +             if (btn_up) {
>> +                     input_mt_sync(ts->input_dev);
>> +             } else {
>> +                     input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
>> +                     input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
>> +                             ts->touch_evt[i].x);
>> +                     input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
>> +                             ts->touch_evt[i].y);
>> +                     input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
>> +                             ts->touch_evt[i].z);
>> +                     input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
>> +                             ts->touch_evt[i].w);
>> +                     input_mt_sync(ts->input_dev);
>> +                     evt++;
>> +             }
>> +#endif
>> +     }
>> +
>> +     if (ts->tch_bit == 0)
>> +             evt = 0;
>> +
>> +     input_report_key(ts->input_dev, BTN_TOUCH, evt);
>> +     input_mt_sync_frame(ts->input_dev);
>> +     input_sync(ts->input_dev);
>> +}
>> +
>> +#ifdef HIDEEP_SUPPORT_KEY
>> +static void pops_ky(struct hideep_t *ts)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; i < ts->tch_count; i++) {
>> +             input_report_key(ts->input_dev, ts->key_codes[i], false);
>> +             input_report_key(ts->input_dev, BTN_TOUCH, false);
>> +     }
>> +
>> +     input_sync(ts->input_dev);
>> +}
>> +
>> +static void push_ky(struct hideep_t *ts)
>> +{
>> +     int i;
>> +     int pressed;
>> +     int key_code;
>> +     int key_status;
>> +
>> +     for (i = 0; i < ts->key_count; i++) {
>> +             key_code = ts->key_evt[i].flag & 0x0F;
>> +             key_status = ts->key_evt[i].flag & 0xF0;
>> +             pressed = false;
>> +
>> +             if (key_status & HIDEEP_KEY_PRESSED_MASK)
>> +                     pressed = true;
>> +             else
>> +                     pressed = false;
>> +
>> +             input_report_key(ts->input_dev, ts->key_codes[key_code],
>> +                     pressed);
>> +             input_report_key(ts->input_dev, BTN_TOUCH, pressed);
>> +     }
>> +
>> +     input_sync(ts->input_dev);
>> +}
>> +#endif
>> +
>> +static void hideep_put_event(struct hideep_t *ts)
>> +{
>> +     /* mangling touch information */
>> +     if (ts->tch_count > 0)
>> +             push_mt(ts);
>> +
>> +#ifdef HIDEEP_SUPPORT_KEY
>> +     if (ts->key_count > 0)
>> +             push_ky(ts);
>> +#endif
>> +}
>> +
>> +static int hideep_get_event(struct hideep_t *ts)
>> +{
>> +     int ret;
>> +     int touch_count;
>> +     int info_size;
>> +
>> +
>> +     /* get touch event count */
>> +     dev_dbg(&ts->client->dev, "mt = %d, key = %d, lpm = %02x",
>> +             ts->tch_count, ts->key_count, ts->lpm_count);
>> +
>> +     /* get touch event information */
>> +     if (ts->tch_count > HIDEEP_MT_MAX)
>> +             ts->tch_count = 0;
>> +
>> +     if (ts->key_count > HIDEEP_KEY_MAX)
>> +             ts->key_count = 0;
>> +
>> +     touch_count = ts->tch_count + ts->key_count;
>> +
>> +     if (ts->tch_count > 0) {
>> +             info_size = ts->tch_count * sizeof(struct hideep_mt_t);
>> +             ret = hideep_i2c_read(ts, HIDEEP_TOUCH_DATA_ADDR,
>> +                     info_size, (unsigned char *)ts->touch_evt);
>> +             if (ret < 0) {
>> +                     dev_err(&ts->client->dev, "read I2C error.");
>> +                     return -1;
>> +             }
>> +     }
>> +
>> +#ifdef HIDEEP_SUPPORT_KEY
>> +     if (ts->key_count > 0) {
>> +             info_size = ts->key_count * sizeof(struct hideep_key_t);
>> +             ret = hideep_i2c_read(ts, HIDEEP_KEY_DATA_ADDR,
>> +                     info_size, (unsigned char *)ts->key_evt);
>> +             if (ret < 0) {
>> +                     dev_err(&ts->client->dev, "read I2C error.");
>> +                     return -1;
>> +             }
>> +     }
>> +#endif
>> +
>> +     return touch_count;
>> +}
>> +
>> +static int hideep_event_thread(void *arg)
>> +{
>> +     int t_evt;
>> +
>> +     struct hideep_t *ts = arg;
>> +
>> +     dev_info(&ts->client->dev, "start event thread");
>> +
>> +     while (!kthread_should_stop()) {
>> +             set_current_state(TASK_INTERRUPTIBLE);
>> +
>> +             schedule();
>> +
>> +             t_evt = hideep_get_event(ts);
>> +
>> +             if (t_evt >= 0)
>> +                     hideep_put_event(ts);
>> +
>> +             if (kthread_should_stop())
>> +                     break;
>> +     }
>> +
>> +     dev_info(&ts->client->dev, "end thread");
>> +     return 0;
>> +}
>> +
>> +static irqreturn_t hideep_irq_task(int irq, void *handle)
>> +{
>> +     unsigned char i2c_buff[2];
>> +     int ret;
>> +
>> +     struct hideep_t *ts = (struct hideep_t *) handle;
>> +
>> +     dev_dbg(&ts->client->dev, "state = 0x%x, debug = %d",
>> +             ts->dev_state, ts->debug_dev.debug_enable);
>> +
>> +     if (ts->debug_dev.debug_enable == false &&
>> +             ts->dev_state == state_normal) {
>> +             ret = hideep_i2c_read(ts, HIDEEP_EVENT_COUNT_ADDR,
>> +                     2, (u8 *)&i2c_buff);
>> +             if (ret < 0) {
>> +                     disable_irq(ts->client->irq);
>> +                     ts->interrupt_state = 0;
>> +                     return IRQ_HANDLED;
>> +             }
>> +
>> +             ts->tch_count = i2c_buff[0];
>> +             ts->key_count = i2c_buff[1] & 0x0f;
>> +             ts->lpm_count = i2c_buff[1] & 0xf0;
>> +
>> +             wake_up_process(ts->hthread_event);
>> +
>> +     } else if (ts->debug_dev.debug_enable == true
>> +             && ts->dev_state == state_debugging) {
>> +             ret = ts->hideep_api->i2c_read(ts, HIDEEP_RAW_DATA_ADDR,
>> +                     FRAME_HEADER_SIZE + ts->debug_dev.img_size,
>> +                     ts->debug_dev.img_buff);
>> +             ts->debug_dev.img_size =
>> +                     GET_PAYLOAD_SIZE_FROM_HEADER(ts->debug_dev.img_buff);
>> +             ts->debug_dev.ready = 1;
>> +             wake_up_interruptible(&ts->debug_dev.i_packet);
>> +     }
>> +     dev_dbg(&ts->client->dev, "end.");
>> +
>> +     return IRQ_HANDLED;
>> +}
>> +
>> +static int hideep_capability(struct hideep_t *ts)
>> +{
>> +#ifdef HIDEEP_SUPPORT_KEY
>
> As I mentioned, read from device properties.
>
>> +     int i;
>> +
>> +     ts->key_codes[0] = KEY_MENU;
>> +     ts->key_codes[1] = KEY_HOME;
>> +     ts->key_codes[2] = KEY_BACK;
>> +
>> +     for (i = 0; i < HIDEEP_KEY_MAX; i++)
>> +             set_bit(ts->key_codes[i], ts->input_dev->keybit);
>> +#endif
>> +
>> +     ts->input_dev->name = HIDEEP_TS_NAME;
>> +     ts->input_dev->id.bustype = BUS_I2C;
>> +
>> +     set_bit(EV_ABS, ts->input_dev->evbit);
>> +     set_bit(EV_KEY, ts->input_dev->evbit);
>> +     set_bit(EV_SYN, ts->input_dev->evbit);
>> +     set_bit(BTN_TOUCH, ts->input_dev->keybit);
>
> Please use input_set_capability().
>
>> +     set_bit(MT_TOOL_FINGER, ts->input_dev->keybit);
>
> There is no such event.
>
>> +     set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
>> +
>> +     input_set_abs_params(ts->input_dev, ABS_X, 0, ts->p_data->max_x, 0, 0);
>> +     input_set_abs_params(ts->input_dev, ABS_Y, 0, ts->p_data->max_y, 0, 0);
>> +     input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0,
>> +             ts->p_data->max_z, 0, 0);
>> +
>> +#ifdef HIDEEP_TYPE_B_PROTOCOL
>
> Should not be conditional.
>
>> +     input_mt_init_slots(ts->input_dev,
>> +             HIDEEP_MT_MAX, INPUT_MT_DIRECT);
>
> Error handling needed.
>
>> +#else
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_TRACKING_ID, 0, 10, 0, 0);
>> +#endif
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_TOOL_TYPE, 0, MT_TOOL_MAX, 0, 0);
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_POSITION_X, 0, ts->p_data->max_x - 1, 0, 0);
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_POSITION_Y, 0, ts->p_data->max_y - 1, 0, 0);
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_PRESSURE, 0, ts->p_data->max_z, 0, 0);
>> +     input_set_abs_params(ts->input_dev,
>> +             ABS_MT_TOUCH_MAJOR, 0, ts->p_data->max_w, 0, 0);
>> +
>> +     return 0;
>> +}
>> +
>> +static void hideep_reset_ic(struct hideep_t *ts)
>> +{
>> +     struct hideep_platform_data_t *pdata;
>> +     int ret;
>> +     unsigned char cmd = 0x01;
>> +
>> +     pdata = ts->p_data;
>
> Move together with declaration:
>
>         struct hideep_platform_data_t *pdata = ts->p_data;
>
>> +
>> +     dev_info(&ts->client->dev, "start!!");
>
> dev_dbg() or drop.
>
>> +
>> +#ifdef CONFIG_OF
>
> This should not depend on CONFIG_OF.
>
>> +     if (pdata->reset_gpio > 0) {
>> +             dev_info(&ts->client->dev, "hideep:enable the reset_gpio");
>> +             gpio_set_value(pdata->reset_gpio, 0);
>> +             mdelay(20);
>> +             gpio_set_value(pdata->reset_gpio, 1);
>> +     } else
>> +#endif
>> +     {
>> +             ret = hideep_i2c_write(ts, HIDEEP_RESET_CMD, 1, &cmd);
>> +     }
>> +     mdelay(50);
>> +     dev_info(&ts->client->dev, "end!!");
>
> dev_dbg() or drop.
>
>> +}
>> +
>> +static void hideep_get_info(struct hideep_t *ts)
>> +{
>> +     struct hideep_platform_data_t *pdata;
>> +     unsigned char val[4];
>> +
>> +     pdata = ts->p_data;
>> +     ts->hideep_api->i2c_read(ts, 0x28, 4, val);
>> +
>> +     pdata->max_x = val[3] << 8 | val[2];
>> +     pdata->max_y = val[1] << 8 | val[0];
>> +     pdata->max_w = 255;
>> +     pdata->max_z = 255;
>> +
>> +     dev_info(&ts->client->dev, "X : %d, Y : %d",
>> +             pdata->max_x, pdata->max_y);
>> +}
>> +
>> +static void hideep_init_ic(struct hideep_t *ts)
>> +{
>> +     struct hideep_platform_data_t *pdata;
>> +     struct device dev;
>> +
>> +     pdata = ts->p_data;
>> +     dev = ts->client->dev;
>> +
>> +     /* power on */
>> +     ts->hideep_api->power(ts, true);
>> +     ts->dev_state = state_init;
>> +     mdelay(30);
>> +
>> +     /* ic reset */
>> +     ts->hideep_api->reset_ic(ts);
>> +}
>> +
>> +static int hideep_resume(struct device *dev)
>
> __maybe_unused
>
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     unsigned char sleep_cmd = 0x00;
>> +
>> +     dev_info(dev, "enter");
>> +
>> +     mutex_lock(&ts->dev_mutex);
>> +
>> +     if (ts->dev_state == state_normal)
>> +             goto hideep_resume_exit;
>> +
>> +     dev_info(dev, "not waiting.");
>> +     ts->dev_state = state_normal;
>> +
>> +     hideep_i2c_write(ts, HIDEEP_SLEEP_CMD, 1, &sleep_cmd);
>> +     enable_irq(ts->client->irq);
>> +     ts->interrupt_state = 1;
>> +
>> +hideep_resume_exit:
>> +     mdelay(10);
>> +     ts->hideep_api->reset_ic(ts);
>> +
>> +     mutex_unlock(&ts->dev_mutex);
>> +     dev_info(dev, "exit.");
>> +     return 0;
>> +}
>> +
>> +static int hideep_suspend(struct device *dev)
>
> __maybe_unused
>
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     unsigned char sleep_cmd = 0x01;
>> +
>> +     dev_info(dev, "enter");
>> +
>> +     mutex_lock(&ts->dev_mutex);
>> +     if (ts->dev_state == state_sleep)
>> +             goto hideep_suspend_exit;
>> +
>> +     dev_info(dev, "not waiting.");
>> +     ts->dev_state = state_sleep;
>> +
>> +     /* send sleep command.. */
>> +     pops_mt(ts);
>> +#ifdef HIDEEP_SUPPORT_KEY
>> +     pops_ky(ts);
>> +#endif
>> +
>> +     /* default deep sleep */
>> +     hideep_i2c_write(ts, HIDEEP_SLEEP_CMD, 1, &sleep_cmd);
>> +     disable_irq(ts->client->irq);
>> +     ts->interrupt_state = 0;
>> +
>> +hideep_suspend_exit:
>> +     mutex_unlock(&ts->dev_mutex);
>> +     dev_info(dev, "exit.");
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_FB
>> +static int fb_notifier_callback(struct notifier_block *self,
>> +     unsigned long event, void *data)
>> +{
>> +     struct fb_event *evdata = data;
>> +     int *blank;
>> +
>> +     struct hideep_t *ts = container_of(self, struct hideep_t, fb_notif);
>> +I have some question. As I remember, I got the consent of Rob about this.
Should I still use the standard method? What should I prioritize?

>> +     if ((evdata) && (evdata->data) &&
>> +             (event == FB_EVENT_BLANK) &&
>> +             (ts) && (ts->client)) {
>> +             blank = evdata->data;
>> +             if (*blank == FB_BLANK_UNBLANK) {
>> +                     dev_info(&ts->client->dev, "resume");
>> +                     if (ts->suspended == 1) {
>> +                             hideep_resume(&ts->client->dev);
>> +                             ts->suspended = 0;
>> +                     }
>> +             } else if (*blank == FB_BLANK_POWERDOWN) {
>> +                     dev_info(&ts->client->dev, "suspend");
>> +                     if (ts->suspended == 0) {
>> +                             ts->suspended = 1;
>> +                             hideep_suspend(&ts->client->dev);
>> +                     }
>> +             }
>> +     }
>> +
>> +     return 0;
>> +}
>> +#endif
>> +
>> +#ifdef CONFIG_OF
>> +static int hideep_parse_dts(struct device *dev,
>> +     struct hideep_platform_data_t *pdata)
>> +{
>> +     int ret = 0;
>> +     unsigned int coords[4];
>> +     struct device_node *np;
>> +
>> +     dev_info(dev, "enter");
>> +     np = dev->of_node;
>> +
>> +     ret = of_property_read_u32_array(np, "hideep,max-coords", coords, 4);
>> +     if (ret) {
>> +             dev_err(dev, "Failed to get max-coords property\n");
>> +             return ret;
>> +     }
>
> This should be using the standard touchscreen bindings from
> Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
>
>> +
>> +     pdata->max_x = coords[0];
>> +     pdata->max_y = coords[1];
>> +     pdata->max_w = coords[2];
>> +     pdata->max_z = coords[3];
>> +
>> +     dev_info(dev, "max coord data x : %d\n", pdata->max_x);
>> +     dev_info(dev, "max coord data y : %d\n", pdata->max_y);
>> +     dev_info(dev, "max coord data w : %d\n", pdata->max_w);
>> +     dev_info(dev, "max coord data z : %d\n", pdata->max_z);
>> +
>> +     /* device tree information get */
>> +     pdata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
>> +     dev_info(dev, "reset_gpio = %d, is %s specified",
>> +             pdata->reset_gpio, pdata->reset_gpio < 0 ? "not" : "");
>> +     if (pdata->reset_gpio)
>> +             ret = gpio_request_one(pdata->reset_gpio, GPIOF_OUT_INIT_HIGH,
>> +                     "reset-gpios");
>
> Please use gpiod API and request with:
>
>         pdata->reset_gpio = devm_gpiod_get_optional(dev, "reset",
>                                                     GPIOD_OUT_LOW);
>         if (IS_ERR(pdata->reset_gpio))
>                 return PTR_ERR(pdata->reset_gpio));
>
>> +
>> +     pdata->vcc_vdd = regulator_get(dev, "vdd");
>> +     pdata->vcc_vid = regulator_get(dev, "vid");
>
> Error handling is missing.
>
>> +
>> +     return ret;
>> +}
>> +#endif
>> +
>> +static int hideep_probe(struct i2c_client *client,
>> +     const struct i2c_device_id *id)
>> +{
>> +     int ret = 0;
>> +     struct hideep_platform_data_t *p_data;
>> +     struct dwz_info_t *dwz;
>> +     struct hideep_function_list_t *function;
>> +     struct hideep_t *ts;
>> +
>> +     dev_info(&client->dev, "enter");
>
> dev_dbg() or drop. Same goes for similar dev_info() uses.
>
>> +
>> +     /* check i2c bus */
>> +     if (!i2c_check_functionality(client->adapter,
>> +             I2C_FUNC_I2C)) {
>> +             dev_err(&client->dev, "check i2c device error");
>> +             ret = -ENODEV;
>> +             return ret;
>
>                 return -ENODEV;
>
>> +     }
>> +
>> +     /* init platform data */
>> +     p_data = devm_kzalloc(&client->dev,
>> +             sizeof(struct hideep_platform_data_t), GFP_KERNEL);
>> +
>> +#ifdef CONFIG_OF
>> +     if (client->dev.of_node) {
>> +             ret = hideep_parse_dts(&client->dev, p_data);
>> +             if (ret)
>> +                     return ret;
>> +     }
>
> Use generic device properties and drop dependency on CONFIG_OF.
>
>> +#endif
>> +
>> +     /* init hideep_t */
>> +     ts = devm_kzalloc(&client->dev,
>> +             sizeof(struct hideep_t), GFP_KERNEL);
>> +     dwz = devm_kzalloc(&client->dev,
>> +             sizeof(struct dwz_info_t), GFP_KERNEL);
>> +     function = devm_kzalloc(&client->dev,
>> +             sizeof(struct hideep_function_list_t), GFP_KERNEL);
>
> Why are the last 2 allocated separately instead of being sub-structures
> in hideep_t.
>
> Also, error handling is missing.
>
>> +
>> +     ts->client = client;
>> +     ts->p_data = p_data;
>> +     ts->dwz_info = dwz;
>> +     ts->hideep_api = function;
>> +
>> +     ts->hideep_api->i2c_read = hideep_i2c_read;
>> +     ts->hideep_api->i2c_write = hideep_i2c_write;
>
> Consider using regmap if you want to support SPI down the road.
>
>> +     ts->hideep_api->reset_ic = hideep_reset_ic;
>> +     ts->hideep_api->power = hideep_power;
>> +
>> +     /* init for isp function */
>> +     hideep_isp_init(ts);
>> +
>> +     i2c_set_clientdata(client, ts);
>> +
>> +     mutex_init(&ts->i2c_mutex);
>> +     mutex_init(&ts->dev_mutex);
>> +
>> +     if (!client->dev.of_node)
>> +             hideep_get_info(ts);
>> +
>> +     /* hardware init */
>> +     hideep_init_ic(ts);
>> +
>> +#ifdef HIDEEP_DWZ_VERSION_CHECK
>> +     /* read info */
>> +     ret = ts->hideep_api->get_dwz_info(ts);
>> +     if (ret < 0) {
>> +             dev_err(&client->dev, "fail to load dwz, ret = 0x%x", ret);
>> +             goto hideep_probe_read_dwz_err;
>> +     }
>> +#endif
>> +
>> +     /* init input device */
>> +     ts->input_dev = devm_input_allocate_device(&client->dev);
>> +     if (!ts->input_dev) {
>> +             dev_err(&client->dev, "can't allocate memory for input_dev");
>> +             ret = -ENOMEM;
>> +             goto hideep_probe_input_dev_memory_err;
>> +     }
>> +
>> +     hideep_capability(ts);
>> +
>> +     ret = input_register_device(ts->input_dev);
>> +     if (ret) {
>> +             dev_err(&client->dev, "can't register input_dev");
>> +             ret = -ENOMEM;
>> +             goto hideep_probe_register_input_dev_err;
>> +     }
>> +
>> +     input_set_drvdata(ts->input_dev, ts);
>> +
>> +     /* init event thread */
>> +     ts->hthread_event = kthread_run(hideep_event_thread,
>> +             ts, "hideep_event_thread");
>> +     if (IS_ERR(ts->hthread_event)) {
>> +             dev_err(&client->dev, "can't create event thread !!!");
>> +             ret = PTR_ERR(ts->hthread_event);
>> +             goto hideep_probe_create_thread_err;
>> +     }
>> +
>> +     dev_info(&ts->client->dev, "ts irq: %d", ts->client->irq);
>> +     if (ts->client->irq <= 0) {
>> +             dev_err(&client->dev, "can't be assigned irq");
>> +             goto hideep_probe_assigned_irq_err;
>> +     }
>> +
>> +     if (ts->client->irq) {
>
> This check is useless.
>
>> +             ret = request_threaded_irq(ts->client->irq, NULL,
>
> devm_request_threaded_irq
>
>> +                     hideep_irq_task,
>> +                     (IRQF_TRIGGER_LOW | IRQF_ONESHOT),
>
> Reply on platform supplying proper trigger, so simply IRQF_ONESHOT.
>
>> +                     ts->client->name, ts);
>> +             disable_irq(ts->client->irq);
>> +             ts->interrupt_state = 0;
>> +             if (ret < 0) {
>> +                     dev_err(&client->dev, "fail to get irq, ret = 0x%08x",
>> +                             ret);
>> +                     goto hideep_probe_request_irq_err;
>> +             }
>> +     }
>> +
>> +     ret = hideep_debug_init(ts);
>> +     if (ret) {
>> +             dev_err(&client->dev, "fail init debug, ret = 0x%x", ret);
>> +             ret = -1;
>> +             goto hideep_probe_debug_init_err;
>> +     }
>> +
>> +     ret = hideep_sysfs_init(ts);
>> +     if (ret) {
>> +             dev_err(&client->dev, "fail init sys, ret = 0x%x", ret);
>> +             ret = -1;
>> +             goto hideep_probe_sysfs_init_err;
>> +     }
>> +
>> +#ifdef CONFIG_FB
>> +     ts->suspended = 0;
>> +     ts->fb_notif.notifier_call = fb_notifier_callback;
>> +     ret = fb_register_client(&ts->fb_notif);
>> +     if (ret) {
>> +             dev_err(&client->dev, "Unable to register fb_notifier: ret = %d",
>> +                     ret);
>> +             ret = -1;
>> +             goto hideep_probe_register_fb_err;
>> +     }
>
> This does not belong to touchscreen driver at all. Kernel driver should
> not establish policy.
>
>> +#endif
>> +
>> +
>> +     ts->dev_state = state_normal;
>> +     enable_irq(ts->client->irq);
>> +     ts->interrupt_state = 1;
>> +
>> +     dev_info(&client->dev, "probe is ok!");
>> +     return 0;
>> +
>> +hideep_probe_register_fb_err:
>> +     hideep_sysfs_exit(ts);
>> +
>> +hideep_probe_sysfs_init_err:
>> +     hideep_debug_uninit();
>> +
>> +hideep_probe_debug_init_err:
>> +hideep_probe_request_irq_err:
>> +     free_irq(ts->client->irq, ts);
>> +
>> +hideep_probe_assigned_irq_err:
>> +hideep_probe_create_thread_err:
>> +     input_unregister_device(ts->input_dev);
>> +
>> +hideep_probe_register_input_dev_err:
>> +     if (ts->input_dev)
>> +             input_free_device(ts->input_dev);
>
> No calls to input_free_device() after input_unregister_device().
>
> Additionally, you are using devm, why do you unregister/free manually?

Ok, I will change to using devm.

>
>> +
>> +hideep_probe_input_dev_memory_err:
>> +#ifdef HIDEEP_DWZ_VERSION_CHECK
>> +hideep_probe_read_dwz_err:
>> +#endif
>> +
>> +#ifdef CONFIG_OF
>> +     ts->hideep_api->power(ts, false);
>> +#endif
>> +     dev_err(&client->dev, "probe err!");
>> +     return ret;
>> +}
>> +
>> +static int hideep_remove(struct i2c_client *client)
>> +{
>> +     struct hideep_t *ts = i2c_get_clientdata(client);
>> +
>> +     kthread_stop(ts->hthread_event);
>> +
>> +#ifdef CONFIG_FB
>> +     if (fb_unregister_client(&ts->fb_notif))
>> +             dev_info(&client->dev,
>> +                     "Error occurred while unregistering fb_notifier");
>> +#endif
>> +
>> +#ifdef CONFIG_OF
>> +     ts->hideep_api->power(ts, false);
>> +#endif
>> +     free_irq(client->irq, ts);
>> +
>> +     input_unregister_device(ts->input_dev);
>> +     hideep_sysfs_exit(ts);
>> +
>> +     hideep_debug_uninit();
>> +     devm_kfree(&client->dev, ts);
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM
>> +static const struct dev_pm_ops hideep_pm_ops = {
>> +     .suspend = hideep_suspend,
>> +     .resume = hideep_resume,
>> +};
>> +#endif
>
> Use SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
>
>
>> +
>> +static const struct i2c_device_id hideep_dev_idtable[] = {
>> +     { HIDEEP_I2C_NAME, 0 },
>> +     {}
>> +};
>> +MODULE_DEVICE_TABLE(i2c, hideep_dev_idtable);
>> +
>> +#ifdef CONFIG_ACPI
>> +static const struct acpi_device_id hideep_acpi_id[] = {
>> +     { "HIDP0001", 0 },
>> +     {}
>> +};
>> +MODULE_DEVICE_TABLE(acpi, hideep_acpi_id);
>> +#endif
>> +
>> +#ifdef CONFIG_OF
>> +static const struct of_device_id hideep_match_table[] = {
>> +     { .compatible = "hideep,hideep-lime" },
>> +     { .compatible = "hideep,hideep-crimson" },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(of, hideep_match_table);
>> +#endif
>> +
>> +static struct i2c_driver hideep_driver = {
>> +     .probe = hideep_probe,
>> +     .remove = hideep_remove,
>> +     .id_table = hideep_dev_idtable,
>> +     .driver = {
>> +             .name = HIDEEP_I2C_NAME,
>> +             .owner = THIS_MODULE,
>
> No need to set owner explicitly.
>
>> +             .of_match_table = of_match_ptr(hideep_match_table),
>> +             .acpi_match_table = ACPI_PTR(hideep_acpi_id),
>> +             .pm = &hideep_pm_ops,
>> +     },
>> +};
>> +
>> +module_i2c_driver(hideep_driver);
>> +
>> +MODULE_DESCRIPTION("Driver for HiDeep Touchscreen Controller");
>> +MODULE_AUTHOR("anthony.kim@xxxxxxxxxx");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/input/touchscreen/hideep_dbg.c b/drivers/input/touchscreen/hideep_dbg.c
>> new file mode 100644
>> index 0000000..549f2ad2
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_dbg.c
>> @@ -0,0 +1,405 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#include "hideep.h"
>> +#include "hideep_isp.h"
>> +#include "hideep_dbg.h"
>> +
>> +static struct hideep_debug_dev_t *hdd;
>> +
>> +static int hideep_i2c_recv(unsigned int len)
>> +{
>> +     int ret = 0;
>> +
>> +     mutex_lock(&hdd->ts->i2c_mutex);
>> +     ret = i2c_master_recv(hdd->ts->client, hdd->vr_buff, len);
>> +     mutex_unlock(&hdd->ts->i2c_mutex);
>> +     if (ret < 0)
>> +             goto i2c_err;
>> +
>> +     dev_info(&hdd->ts->client->dev, "(%d)", len);
>> +     return ret;
>> +
>> +i2c_err:
>> +     dev_err(&hdd->ts->client->dev, "i2c_err");
>> +     return ret;
>> +}
>> +
>> +static int hideep_i2c_send(unsigned int len)
>> +{
>> +     int ret = 0;
>> +     unsigned char *buff = hdd->vr_buff;
>> +
>> +     mutex_lock(&hdd->ts->i2c_mutex);
>> +     ret = i2c_master_send(hdd->ts->client, buff, len);
>> +     mutex_unlock(&hdd->ts->i2c_mutex);
>> +     if (ret < 0)
>> +             goto i2c_err;
>> +
>> +     dev_info(&hdd->ts->client->dev, "(%d)", len);
>> +     return ret;
>> +
>> +i2c_err:
>> +     dev_err(&hdd->ts->client->dev, "i2c_err");
>> +     return ret;
>> +}
>> +
>> +static int hideep_get_vreg(unsigned int addr, unsigned int len)
>> +{
>> +     int ret = 0;
>> +
>> +     ret = hdd->ts->hideep_api->i2c_read(hdd->ts, addr, len,
>> +             hdd->vr_buff);
>> +     if (ret < 0)
>> +             goto i2c_err;
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "(0x%02x:%d)", addr, len);
>> +     return ret;
>> +
>> +i2c_err:
>> +     dev_err(&hdd->ts->client->dev, "i2c_err");
>> +     return ret;
>> +}
>> +
>> +static int hideep_set_vreg(unsigned int addr, unsigned int len)
>> +{
>> +     int ret = 0;
>> +     int wr_remain = len;
>> +     int vr_addr = addr;
>> +     int wr_len = len;
>> +     unsigned char *buff = hdd->vr_buff;
>> +
>> +     do {
>> +             if (wr_remain >=  MAX_VR_BUFF)
>> +                     wr_len = MAX_VR_BUFF;
>> +             else
>> +                     wr_len = wr_remain;
>> +
>> +             ret = hdd->ts->hideep_api->i2c_write(hdd->ts, vr_addr,
>> +                     wr_len, buff);
>> +             if (ret < 0)
>> +                     goto i2c_err;
>> +
>> +             wr_remain -= MAX_VR_BUFF;
>> +             vr_addr += MAX_VR_BUFF;
>> +             buff += MAX_VR_BUFF;
>> +     } while (wr_remain > 0);
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "(0x%02x:%d)", addr, len);
>> +     return ret;
>> +
>> +i2c_err:
>> +     dev_err(&hdd->ts->client->dev, "i2c_err");
>> +     return ret;
>> +}
>> +
>> +static int hideep_download_uc(const char __user *uc, size_t count, int offset)
>> +{
>> +     int ret;
>> +     unsigned char *ucode;
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "count = %zu", count);
>> +
>> +     if (count > hdd->ts->fw_size) {
>> +             dev_err(&hdd->ts->client->dev, "over size data!!!");
>> +             return -1;
>> +     }
>> +
>> +     ucode = kmalloc(count, GFP_KERNEL);
>> +
>> +     ret = copy_from_user(ucode + offset, uc, count);
>> +     if (ret < 0) {
>> +             dev_err(&hdd->ts->client->dev, "ADDR_UC : copy_to_user");
>> +             kfree(ucode);
>> +             return 0;
>> +     }
>> +
>> +     disable_irq(hdd->ts->client->irq);
>> +     hdd->ts->interrupt_state = 0;
>> +     hdd->ts->hideep_api->update_part(hdd->ts, ucode, count, offset, false);
>> +     enable_irq(hdd->ts->client->irq);
>> +     hdd->ts->interrupt_state = 1;
>> +     kfree(ucode);
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "Download_uc(%zu)", count);
>> +
>> +     return count;
>> +}
>> +
>> +static int hideep_debug_open(struct inode *inode, struct file *file)
>> +{
>> +     hdd->release_flag = false;
>> +
>> +     file->private_data = hdd;
>> +     dev_dbg(&hdd->ts->client->dev, "hideep_debug_open");
>> +
>> +     return 0;
>> +}
>> +
>> +static int hideep_debug_release(struct inode *inode, struct file *file)
>> +{
>> +     if (!hdd->release_flag)
>> +             return -1;
>> +     hdd->release_flag = false;
>> +     file->private_data = NULL;
>> +     return 0;
>> +}
>> +
>> +static unsigned int hideep_debug_poll(struct file *file,
>> +     struct poll_table_struct *wait)
>> +{
>> +     unsigned int mask = 0;
>> +     struct hideep_debug_dev_t *drv_info;
>> +
>> +     if (file->private_data == NULL)
>> +             return 0;
>> +
>> +     drv_info = file->private_data;
>> +
>> +     poll_wait(file, &drv_info->i_packet, wait);
>> +
>> +     if (drv_info->ready) {
>> +             disable_irq(drv_info->ts->client->irq);
>> +             drv_info->ts->interrupt_state = 0;
>> +             mask |= POLLIN | POLLRDNORM;
>> +             drv_info->ready = 0;
>> +     }
>> +
>> +     return mask;
>> +}
>> +
>> +static ssize_t hideep_debug_read(struct file *file, char __user *buf,
>> +     size_t count, loff_t *offset)
>> +{
>> +     int ret = -1;
>> +     ssize_t rd_len = 0;
>> +     unsigned char *rd_buffer = NULL;
>> +     unsigned char *data = NULL;
>> +     struct hideep_debug_dev_t *drv_info = file->private_data;
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "count = %zu", count);
>> +
>> +     if (file->private_data == NULL)
>> +             return 0;
>> +
>> +     drv_info->vr_size = count;
>> +     rd_len = count;
>> +
>> +     data = kmalloc(rd_len, GFP_KERNEL);
>> +
>> +     if (*offset <= HIDEEP_VR_ADDR_LEN) {
>> +             // if offset is not belong to any special command
>> +             if ((*offset & HIDEEP_MAX_RAW_LEN) &&
>> +                     (*offset < HIDEEP_MAX_RAW_LEN) &&
>> +                     (drv_info->debug_enable == true)) {
>> +                     mutex_lock(&drv_info->ts->dev_mutex);
>> +                     rd_buffer = drv_info->img_buff;
>> +                     ret = 0;
>> +                     mutex_unlock(&drv_info->ts->dev_mutex);
>> +             } else {
>> +                     ret = hideep_get_vreg(*offset, rd_len);
>> +                     rd_buffer = drv_info->vr_buff;
>> +             }
>> +             if (ret < 0)
>> +                     rd_len = 0;
>> +     } else if (*offset & (HIDEEP_I2C_BYPASS)) {
>> +             // if offset is belong to special command "i2c bypass"
>> +             ret = hideep_i2c_recv(rd_len);
>> +             if (ret < 0) {
>> +                     dev_err(&hdd->ts->client->dev, "ret = %d", ret);
>> +                     rd_len = 0;
>> +             } else {
>> +                     rd_buffer = drv_info->vr_buff;
>> +             }
>> +     } else if (*offset & HIDEEP_NVM_DOWNLOAD) {
>> +             // if offset is belong to special command "nvm download"
>> +             rd_len = count;
>> +             memset(data, 0x0, rd_len);
>> +
>> +             disable_irq(drv_info->ts->client->irq);
>> +             drv_info->ts->interrupt_state = 0;
>> +             mutex_lock(&drv_info->ts->dev_mutex);
>> +             mutex_lock(&drv_info->ts->i2c_mutex);
>> +
>> +             drv_info->ts->hideep_api->sp_func(drv_info->ts, data, rd_len,
>> +                     *offset & 0xfffff);
>> +
>> +             mutex_unlock(&drv_info->ts->dev_mutex);
>> +             mutex_unlock(&drv_info->ts->i2c_mutex);
>> +             enable_irq(drv_info->ts->client->irq);
>> +             drv_info->ts->interrupt_state = 1;
>> +
>> +             rd_buffer = data;
>> +     } else {
>> +             dev_err(&hdd->ts->client->dev, "undefined address");
>> +             kfree(data);
>> +             return 0;
>> +     }
>> +
>> +     ret = copy_to_user(buf, rd_buffer, rd_len);
>> +
>> +     if (drv_info->debug_enable == true && drv_info->ready == 0) {
>> +             enable_irq(drv_info->ts->client->irq);
>> +             drv_info->ts->interrupt_state = 1;
>> +     }
>> +
>> +     if (ret < 0) {
>> +             dev_err(&hdd->ts->client->dev, "error : copy_to_user");
>> +             kfree(data);
>> +             return -EFAULT;
>> +     }
>> +
>> +     kfree(data);
>> +     return rd_len;
>> +}
>> +
>> +static ssize_t hideep_debug_write(struct file *file, const char __user *buf,
>> +     size_t count, loff_t *offset)
>> +{
>> +     int ret;
>> +     struct hideep_debug_dev_t *drv_info = file->private_data;
>> +     int wr_len = 0;
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "count = %zu", count);
>> +     if (file->private_data == NULL)
>> +             return 0;
>> +
>> +     if (*offset <= HIDEEP_VR_ADDR_LEN) {
>> +             // if offset is not belong to any special command
>> +             wr_len = count;
>> +
>> +             ret = copy_from_user(drv_info->vr_buff, buf, wr_len);
>> +             if (ret < 0) {
>> +                     dev_err(&hdd->ts->client->dev, "error : copy_to_user");
>> +                     return -EFAULT;
>> +             }
>> +
>> +             ret = hideep_set_vreg(*offset, wr_len);
>> +             if (ret < 0)
>> +                     wr_len = 0;
>> +     } else if (*offset & (HIDEEP_I2C_BYPASS)) {
>> +             // if offset is belong to special command "i2c bypass"
>> +             wr_len = count;
>> +             ret = copy_from_user(drv_info->vr_buff, buf, wr_len);
>> +             ret = hideep_i2c_send(wr_len);
>> +     } else if (*offset & HIDEEP_NVM_DOWNLOAD) {
>> +             // if offset is belong to special command "nvm download"
>> +             wr_len = hideep_download_uc(buf, count, *offset & 0xfffff);
>> +     } else {
>> +             dev_err(&hdd->ts->client->dev,
>> +                     "hideep_write : undefined address, 0x%08x",
>> +                     (int)*offset);
>> +             return 0;
>> +     }
>> +
>> +     return wr_len;
>> +}
>> +
>> +static loff_t hideep_debug_llseek(struct file *file, loff_t off, int whence)
>> +{
>> +     loff_t newpos;
>> +     struct hideep_debug_dev_t *drv_info = file->private_data;
>> +
>> +     dev_dbg(&hdd->ts->client->dev, "off = 0x%08x, whence = %d",
>> +             (unsigned int)off, whence);
>> +     if (file->private_data == NULL)
>> +             return -EFAULT;
>> +
>> +     switch (whence) {
>> +     /* SEEK_SET */
>> +     case 0:
>> +             newpos = off;
>> +             break;
>> +     /* SEEK_CUR */
>> +     case 1:
>> +             dev_dbg(&hdd->ts->client->dev, "set mode off = 0x%08x",
>> +                     (unsigned int)off);
>> +             if (off & HIDEEP_RELEASE_FLAG) {
>> +                     dev_dbg(&hdd->ts->client->dev, "set release flag");
>> +                     drv_info->release_flag = true;
>> +             }
>> +             newpos = file->f_pos;
>> +             break;
>> +     /* SEEK_END */
>> +     case 2:
>> +             newpos = file->f_pos;
>> +             break;
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     if (newpos < 0)
>> +             return -EINVAL;
>> +
>> +     file->f_pos = newpos;
>> +
>> +     return newpos;
>> +}
>> +
>> +static const struct file_operations hideep_debug_fops = {
>> +     .owner = THIS_MODULE,
>> +     .open = hideep_debug_open,
>> +     .poll = hideep_debug_poll,
>> +     .release = hideep_debug_release,
>> +     .read = hideep_debug_read,
>> +     .write = hideep_debug_write,
>> +     .llseek = hideep_debug_llseek,
>> +};
>> +
>> +static struct miscdevice hideep_debug_dev = {
>> +     .minor = MISC_DYNAMIC_MINOR,
>> +     .name = HIDEEP_DEBUG_DEVICE_NAME,
>> +     .fops = &hideep_debug_fops
>> +};
>> +
>> +void hideep_debug_uninit(void)
>> +{
>> +     kfree(hdd->vr_buff);
>> +     kfree(hdd->img_buff);
>> +
>> +     misc_deregister(&hideep_debug_dev);
>> +}
>> +
>> +int hideep_debug_init(struct hideep_t *ts)
>> +{
>> +     int ret = 0;
>> +
>> +     hdd = &ts->debug_dev;
>> +
>> +     ret = misc_register(&hideep_debug_dev);
>> +     if (ret) {
>> +             dev_err(&ts->client->dev,
>> +                     "hideep debug device register fail!!!");
>> +             goto fail;
>> +     }
>> +
>> +     init_waitqueue_head(&hdd->i_packet);
>> +
>> +     hdd->ts = ts;
>> +     hdd->debug_enable = false;
>> +
>> +     hdd->img_size = 0;
>> +     hdd->vr_size = 0;
>> +
>> +     hdd->vr_buff = kmalloc(MAX_VR_BUFF, GFP_KERNEL);
>> +     hdd->img_buff = kmalloc(MAX_RAW_SIZE, GFP_KERNEL);
>> +
>> +     memset(hdd->vr_buff, 0x0, MAX_VR_BUFF);
>> +     memset(hdd->img_buff, 0x0, MAX_RAW_SIZE);
>> +
>> +     if (!hdd->vr_buff || !hdd->img_buff)
>> +             goto fail;
>> +
>> +     dev_info(&ts->client->dev, "debug init....");
>> +     return 0;
>> +
>> +fail:
>> +     kfree(hdd->vr_buff);
>> +     kfree(hdd->img_buff);
>> +     return ret;
>> +}
>> diff --git a/drivers/input/touchscreen/hideep_dbg.h b/drivers/input/touchscreen/hideep_dbg.h
>> new file mode 100644
>> index 0000000..f18a09f
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_dbg.h
>> @@ -0,0 +1,24 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#ifndef _LINUX_HIDEEP_DBG_H
>> +#define _LINUX_HIDEEP_DBG_H
>> +
>> +/* Device Driver <==> Application */
>> +/* lseek(), write(), read() command */
>> +#define HIDEEP_RELEASE_FLAG                          0x8000
>> +#define HIDEEP_VR_ADDR_LEN                           0xFFFF
>> +#define HIDEEP_MAX_RAW_LEN                           0x3000
>> +#define HIDEEP_READ_WRITE_VR                 0xF000
>> +#define HIDEEP_I2C_BYPASS                            0x20000000
>> +
>> +#define MAX_VR_BUFF                                          2048
>> +
>> +/* max tx * max rx * 2 + 8 + 1, 1 is magin size */
>> +#define MAX_RAW_SIZE                                 7369
>> +#endif /* _LINUX_HIDEEP_DBG_H */
>> diff --git a/drivers/input/touchscreen/hideep_isp.c b/drivers/input/touchscreen/hideep_isp.c
>> new file mode 100644
>> index 0000000..c8d2e932
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_isp.c
>> @@ -0,0 +1,592 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#include "hideep.h"
>> +#include "hideep_isp.h"
>> +
>> +static struct pgm_packet packet_w;
>> +static struct pgm_packet packet_r;
>> +
>> +static int hideep_pgm_w_mem(struct hideep_t *ts, unsigned int addr,
>> +     struct pgm_packet *packet, unsigned int len)
>> +{
>> +     int ret = 0;
>> +     int i;
>> +
>> +     if ((len % 4) != 0)
>> +             return -1;
>> +
>> +     mutex_lock(&ts->i2c_mutex);
>> +
>> +     packet->header.w[0] = htonl((0x80 | (len / 4-1)));
>> +     packet->header.w[1] = htonl(addr);
>> +
>> +     for (i = 0; i < NVM_PAGE_SIZE / sizeof(unsigned int); i++)
>> +             packet->payload[i] = htonl(packet->payload[i]);
>> +
>> +     ret = i2c_master_send(ts->client, (unsigned char *)&packet->header.b[3],
>> +             (len+5));
>> +
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +err:
>> +     mutex_unlock(&ts->i2c_mutex);
>> +     return ret;
>> +}
>> +
>> +static int hideep_pgm_r_mem(struct hideep_t *ts, unsigned int addr,
>> +     struct pgm_packet *packet, unsigned int len)
>> +{
>> +     int ret = 0;
>> +     int i;
>> +
>> +     if ((len % 4) != 0)
>> +             return -1;
>> +
>> +     mutex_lock(&ts->i2c_mutex);
>> +
>> +     packet->header.w[0] = htonl((0x00 | (len / 4-1)));
>> +     packet->header.w[1] = htonl(addr);
>> +
>> +     ret = i2c_master_send(ts->client, (unsigned char *)&packet->header.b[3],
>> +             5);
>> +
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     ret = i2c_master_recv(ts->client, (unsigned char *)packet->payload,
>> +             len);
>> +
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     for (i = 0; i < NVM_PAGE_SIZE / sizeof(unsigned int); i++)
>> +             packet->payload[i] = htonl(packet->payload[i]);
>> +
>> +err:
>> +     mutex_unlock(&ts->i2c_mutex);
>> +     return ret;
>> +}
>> +
>> +static int hideep_pgm_r_reg(struct hideep_t *ts, unsigned int addr,
>> +     unsigned int *val)
>> +{
>> +     int ret = 0;
>> +     struct pgm_packet packet;
>> +
>> +     packet.header.w[0] = htonl(0x00);
>> +     packet.header.w[1] = htonl(addr);
>> +
>> +     ret = hideep_pgm_r_mem(ts, addr, &packet, 4);
>> +
>> +     if (ret < 0)
>> +             goto err;
>> +
>> +     *val = packet.payload[0];
>> +
>> +err:
>> +     return ret;
>> +}
>> +
>> +static int hideep_pgm_w_reg(struct hideep_t *ts, unsigned int addr,
>> +     unsigned int data)
>> +{
>> +     int ret = 0;
>> +     struct pgm_packet packet;
>> +
>> +     packet.header.w[0] = htonl(0x80);
>> +     packet.header.w[1] = htonl(addr);
>> +     packet.payload[0] = data;
>> +
>> +     ret = hideep_pgm_w_mem(ts, addr, &packet, 4);
>> +
>> +     return ret;
>> +}
>> +
>> +#define SW_RESET_IN_PGM(CLK) \
>> +{ \
>> +     hideep_pgm_w_reg(ts, SYSCON_WDT_CNT, CLK); \
>> +     hideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x03); \
>> +     hideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x01); \
>> +}
>> +
>> +#define SET_FLASH_PIO(CE) \
>> +     hideep_pgm_w_reg(ts, FLASH_CON, 0x01 | ((CE) << 1))
>> +#define SET_PIO_SIG(X, Y) \
>> +     hideep_pgm_w_reg(ts, FLASH_BASE + PIO_SIG + (X), Y)
>> +#define SET_FLASH_HWCONTROL() \
>> +     hideep_pgm_w_reg(ts, FLASH_CON, 0x00000000)
>> +
>> +#define NVM_W_SFR(x, y) \
>> +{ \
>> +     SET_FLASH_PIO(1); \
>> +     SET_PIO_SIG(x, y); \
>> +     SET_FLASH_PIO(0); \
>> +}
>> +
>> +static void get_dwz_from_binary(unsigned char *pres,
>> +     struct dwz_info_t *dwz_info)
>> +{
>> +     memcpy(dwz_info, pres + HIDEEP_DWZ_INFO_OFS,
>> +             sizeof(struct dwz_info_t));
>> +}
>> +
>> +static void hideep_sw_reset(struct hideep_t *ts, unsigned int food)
>> +{
>> +     SW_RESET_IN_PGM(food);
>> +}
>> +
>> +static int hideep_enter_pgm(struct hideep_t *ts)
>> +{
>> +     int ret = 0;
>> +     int retry_count = 10;
>> +     int retry = 0;
>> +     unsigned int status;
>> +     unsigned int pattern = 0xDF9DAF39;
>> +
>> +     while (retry < retry_count) {
>> +             i2c_master_send(ts->client, (unsigned char *)&pattern, 4);
>> +             mdelay(1);
>> +
>> +             /* flush invalid Tx load register */
>> +             hideep_pgm_w_reg(ts, ESI_TX_INVALID, 0x01);
>> +
>> +             hideep_pgm_r_reg(ts, SYSCON_PGM_ID, &status);
>> +
>> +             if (status != htonl(pattern)) {
>> +                     retry++;
>> +                     dev_err(&ts->client->dev, "enter_pgm : error(%08x):",
>> +                             status);
>> +             } else {
>> +                     dev_dbg(&ts->client->dev, "found magic code");
>> +                     break;
>> +             }
>> +     }
>> +
>> +     if (retry < retry_count) {
>> +             hideep_pgm_w_reg(ts, SYSCON_WDT_CON, 0x00);
>> +             hideep_pgm_w_reg(ts, SYSCON_SPC_CON, 0x00);
>> +             hideep_pgm_w_reg(ts, SYSCON_CLK_ENA, 0xFF);
>> +             hideep_pgm_w_reg(ts, SYSCON_CLK_CON, 0x01);
>> +             hideep_pgm_w_reg(ts, SYSCON_PWR_CON, 0x01);
>> +             hideep_pgm_w_reg(ts, FLASH_TIM, 0x03);
>> +             hideep_pgm_w_reg(ts, FLASH_CACHE_CFG, 0x00);
>> +             hideep_pgm_w_reg(ts, FLASH_CACHE_CFG, 0x02);
>> +
>> +             mdelay(1);
>> +     } else {
>> +             ret = -1;
>> +     }
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_load_dwz(struct hideep_t *ts)
>> +{
>> +     int ret = 0;
>> +     struct pgm_packet packet_r;
>> +
>> +     ret = hideep_enter_pgm(ts);
>> +
>> +     mdelay(50);
>> +
>> +     ret = hideep_pgm_r_mem(ts, HIDEEP_DWZ_INFO_OFS, &packet_r,
>> +             sizeof(struct dwz_info_t));
>> +
>> +     memcpy((unsigned char *)ts->dwz_info, packet_r.payload,
>> +             sizeof(struct dwz_info_t));
>> +     hideep_sw_reset(ts, 10);
>> +
>> +     if (ts->dwz_info->product_code & 0x40) {
>> +             /* Crimson IC */
>> +             ts->fw_size = 1024 * 48;
>> +     } else {
>> +             /* default fw size */
>> +             ts->fw_size = 1024 * 64;
>> +     }
>> +
>> +     dev_dbg(&ts->client->dev, "firmware release version : %04x",
>> +             ts->dwz_info->release_ver);
>> +
>> +     mdelay(50);
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_nvm_unlock(struct hideep_t *ts)
>> +{
>> +     int ret = 0;
>> +     unsigned int unmask_code = 0;
>> +
>> +     ret = hideep_pgm_w_reg(ts, FLASH_CFG, NVM_SFR_RPAGE);
>> +
>> +     ret = hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
>> +
>> +     ret = hideep_pgm_w_reg(ts, FLASH_CFG, NVM_DEFAULT_PAGE);
>> +
>> +     /* make it unprotected code */
>> +     unmask_code &= (~_PROT_MODE);
>> +
>> +     /* compare unmask code */
>> +     if (unmask_code != NVM_MASK)
>> +             dev_dbg(&ts->client->dev, "read mask code different 0x%x",
>> +                     unmask_code);
>> +
>> +     ret = hideep_pgm_w_reg(ts, FLASH_CFG, NVM_SFR_WPAGE);
>> +     SET_FLASH_PIO(0);
>> +
>> +     NVM_W_SFR(NVM_MASK_OFS, NVM_MASK);
>> +     SET_FLASH_HWCONTROL();
>> +     ret = hideep_pgm_w_reg(ts, FLASH_CFG, NVM_DEFAULT_PAGE);
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_program_page(struct hideep_t *ts,
>> +     unsigned int addr, struct pgm_packet *packet_w)
>> +{
>> +     int ret = 0;
>> +     unsigned int pio_cmd = WRONLY;
>> +     unsigned int pio_cmd_page_erase = PERASE;
>> +     unsigned int status;
>> +     int time_out = 0;
>> +     int inf_en = 0;
>> +     unsigned int end_flag = 124;
>> +#ifndef PGM_BURST_WR
>> +     unsigned int i;
>> +#endif
>> +
>> +     hideep_pgm_r_reg(ts, FLASH_STA, &status);
>> +     ret = (status == 0) ? -1:0;
>> +
>> +     addr = addr & ~(NVM_PAGE_SIZE - 1);
>> +
>> +     if (addr > INF_SECTION) {
>> +             /* added INF flag set in pio_cmd */
>> +             addr -= INF_SECTION;
>> +             pio_cmd |= INF;
>> +             pio_cmd_page_erase |= INF;
>> +             inf_en = 1;
>> +     }
>> +
>> +     SET_FLASH_PIO(0);
>> +     SET_FLASH_PIO(1);
>> +
>> +     /* first erase */
>> +     SET_PIO_SIG(pio_cmd_page_erase  + addr, 0xFFFFFFFF);
>> +
>> +     SET_FLASH_PIO(0);
>> +     time_out = 0;
>> +
>> +     while (1) {
>> +             mdelay(1);
>> +             hideep_pgm_r_reg(ts, FLASH_STA, &status);
>> +             if ((status) != 0)
>> +                     break;
>> +             if (time_out++ > 100)
>> +                     break;
>> +     }
>> +     SET_FLASH_PIO(1);
>> +     /* first erase end*/
>> +
>> +     SET_PIO_SIG(pio_cmd + addr, htonl(packet_w->payload[0]));
>> +
>> +#ifdef PGM_BURST_WR
>> +     hideep_pgm_w_mem(ts, (FLASH_BASE + 0x400000) + pio_cmd,
>> +             packet_w, NVM_PAGE_SIZE);
>> +#else
>> +     for (i = 0; i < NVM_PAGE_SIZE / 4; i++)
>> +             SET_PIO_SIG(pio_cmd + (i<<2), packet_w->payload[i]);
>> +#endif
>> +     if (inf_en == 0)
>> +             SET_PIO_SIG(end_flag, htonl(packet_w->payload[31]));
>> +     else
>> +             SET_PIO_SIG(end_flag | INF, htonl(packet_w->payload[31]));
>> +
>> +     SET_FLASH_PIO(0);
>> +
>> +     mdelay(1);
>> +
>> +     while (1) {
>> +             hideep_pgm_r_reg(ts, FLASH_STA, &status);
>> +             if ((status) != 0)
>> +                     break;
>> +     }
>> +     /* write routine end */
>> +
>> +     SET_FLASH_HWCONTROL();
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_program_nvm(struct hideep_t *ts, const unsigned char *ucode,
>> +     int len, int offset, unsigned char *old_fw)
>> +{
>> +     int i;
>> +     int ret = 0;
>> +     int len_r;
>> +     int len_w;
>> +     int addr = 0;
>> +     unsigned int pages;
>> +
>> +     ret = hideep_enter_pgm(ts);
>> +
>> +     hideep_nvm_unlock(ts);
>> +
>> +     pages = (len + NVM_PAGE_SIZE - 1) / NVM_PAGE_SIZE;
>> +     addr = offset;
>> +     len_r = len;
>> +     len_w = len_r;
>> +
>> +     dev_dbg(&ts->client->dev, "pages : %d", pages);
>> +     for (i = 0; i < pages; i++) {
>> +             if (len_r >= NVM_PAGE_SIZE)
>> +                     len_w = NVM_PAGE_SIZE;
>> +
>> +             /* compare */
>> +             if (old_fw != NULL)
>> +                     ret = memcmp(&ucode[addr], &old_fw[addr], len_w);
>> +
>> +             if (ret != 0 || old_fw == NULL) {
>> +                     /* write page */
>> +                     memcpy(packet_w.payload, &(ucode[addr]), len_w);
>> +
>> +                     ret = hideep_program_page(ts, addr, &packet_w);
>> +                     mdelay(1);
>> +                     if (ret < 0)
>> +                             dev_err(&ts->client->dev,
>> +                                     "hideep_program_nvm : error(%08x):",
>> +                                     addr);
>> +             }
>> +
>> +             addr += NVM_PAGE_SIZE;
>> +             len_r -= NVM_PAGE_SIZE;
>> +             len_w = len_r;
>> +     }
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_verify_nvm(struct hideep_t *ts, const unsigned char *ucode,
>> +     int len, int offset)
>> +{
>> +     int i, j;
>> +     int ret = 0;
>> +     unsigned char page_chk = 0;
>> +     unsigned int addr = offset;
>> +     unsigned int pages = (len + NVM_PAGE_SIZE - 1) / NVM_PAGE_SIZE;
>> +     int len_r = len;
>> +     int len_v = len_r;
>> +
>> +     for (i = 0; i < pages; i++) {
>> +             if (len_r >= NVM_PAGE_SIZE)
>> +                     len_v = NVM_PAGE_SIZE;
>> +
>> +#ifdef PGM_BURST_WR
>> +             hideep_pgm_r_mem(ts, 0x00000000 + addr, &packet_r,
>> +                     NVM_PAGE_SIZE);
>> +#else
>> +             for (j = 0; j < (NVM_PAGE_SIZE >> 2); j++)
>> +                     hideep_pgm_r_reg(ts, addr + (j << 2),
>> +                             &(packet_r.payload[j]));
>> +#endif
>> +             page_chk = memcmp(&(ucode[addr]), packet_r.payload, len_v);
>> +
>> +             if (page_chk != 0) {
>> +                     u8 *read = (u8 *)packet_r.payload;
>> +
>> +                     for (j = 0; j < NVM_PAGE_SIZE; j++)
>> +                             dev_err(&ts->client->dev, "%02x : %02x",
>> +                                             ucode[addr+j], read[j]);
>> +
>> +                     dev_err(&ts->client->dev, "verify : error(addr : %d)",
>> +                             addr);
>> +
>> +                     ret = -1;
>> +             }
>> +
>> +             addr += NVM_PAGE_SIZE;
>> +             len_r -= NVM_PAGE_SIZE;
>> +             len_v = len_r;
>> +     }
>> +
>> +     return ret;
>> +}
>> +
>> +static void hideep_read_nvm(struct hideep_t *ts, unsigned char *data, int len,
>> +     int offset)
>> +{
>> +     int ret = 0;
>> +     int pages, i;
>> +     int len_r, len_v;
>> +     int addr = offset;
>> +#ifndef PGM_BURST_WR
>> +     int j;
>> +#endif
>> +
>> +     pages = (len + NVM_PAGE_SIZE - 1) / NVM_PAGE_SIZE;
>> +     len_r = len;
>> +     len_v = len_r;
>> +
>> +     ts->hideep_api->reset_ic(ts);
>> +
>> +     ret = hideep_enter_pgm(ts);
>> +
>> +     hideep_nvm_unlock(ts);
>> +
>> +     for (i = 0; i < pages; i++) {
>> +             if (len_r >= NVM_PAGE_SIZE)
>> +                     len_v = NVM_PAGE_SIZE;
>> +
>> +#ifdef PGM_BURST_WR
>> +             hideep_pgm_r_mem(ts, 0x00000000 + addr, &packet_r,
>> +                     NVM_PAGE_SIZE);
>> +#else
>> +             for (j = 0; j < NVM_PAGE_SIZE / 4; j++)
>> +                     hideep_pgm_r_reg(ts, addr + (j << 2),
>> +                             &(packet_r.payload[j]));
>> +#endif
>> +             memcpy(&(data[i * NVM_PAGE_SIZE]), &packet_r.payload[0], len_v);
>> +
>> +             addr += NVM_PAGE_SIZE;
>> +             len_r -= NVM_PAGE_SIZE;
>> +             len_v = len_r;
>> +     }
>> +
>> +     hideep_sw_reset(ts, 1000);
>> +}
>> +
>> +static int hideep_fw_verify_run(struct hideep_t *ts, unsigned char *fw,
>> +     size_t len, int offset)
>> +{
>> +     int ret = 0;
>> +     int retry = 3;
>> +
>> +     while (retry--) {
>> +             ret = hideep_verify_nvm(ts, fw, len, offset);
>> +             if (ret == 0) {
>> +                     dev_dbg(&ts->client->dev, "update success");
>> +                     break;
>> +             }
>> +             dev_err(&ts->client->dev, "download fw failed(%d)", retry);
>> +     }
>> +
>> +     ret = (retry == 0) ? -1:0;
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_wr_firmware(struct hideep_t *ts, unsigned char *code,
>> +     int len, int offset, bool mode)
>> +{
>> +     int ret = 0;
>> +     int firm_len;
>> +     unsigned char *ic_fw;
>> +     unsigned char *dwz_info;
>> +
>> +     ic_fw = kmalloc(ts->fw_size, GFP_KERNEL);
>> +     dwz_info = kmalloc(sizeof(struct dwz_info_t) + 64, GFP_KERNEL);
>> +
>> +     memset(dwz_info, 0x0, sizeof(struct dwz_info_t) + 64);
>> +
>> +     firm_len = len;
>> +     dev_dbg(&ts->client->dev, "fw len : %d, define size : %d",
>> +             firm_len, ts->fw_size);
>> +
>> +     if (firm_len > ts->fw_size)
>> +             firm_len = ts->fw_size;
>> +
>> +     dev_dbg(&ts->client->dev, "enter");
>> +     /* memory dump of target IC */
>> +     hideep_read_nvm(ts, ic_fw, firm_len, offset);
>> +     /* comparing & programming each page, if the memory of specified
>> +      * page is exactly same, no need to update.
>> +      */
>> +     ret = hideep_program_nvm(ts, code, firm_len, offset, ic_fw);
>> +
>> +#ifdef PGM_VERIFY
>> +     hideep_fw_verify_run(ts, code, firm_len, offset);
>> +     if (ret < 0) {
>> +             if (mode == true) {
>> +                     /* clear dwz version, it will be store once again
>> +                      * after update success
>> +                      */
>> +                     ts->dwz_info->release_ver = 0;
>> +                     memcpy(&dwz_info[64], ts->dwz_info,
>> +                             sizeof(struct dwz_info_t));
>> +                     ret = hideep_program_nvm(ts, dwz_info, HIDEEP_DWZ_LEN,
>> +                             0x280, NULL);
>> +             }
>> +     }
>> +#endif
>> +     get_dwz_from_binary(code, ts->dwz_info);
>> +
>> +     hideep_sw_reset(ts, 1000);
>> +
>> +     kfree(ic_fw);
>> +     kfree(dwz_info);
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_update_all_firmware(struct hideep_t *ts, const char *fn)
>> +{
>> +     int ret = 0;
>> +     const struct firmware *fw_entry;
>> +     unsigned char *fw_buf;
>> +     unsigned int fw_length;
>> +
>> +     dev_dbg(&ts->client->dev, "enter");
>> +     ret = request_firmware(&fw_entry, fn, &ts->client->dev);
>> +
>> +     if (ret != 0) {
>> +             dev_err(&ts->client->dev, "request_firmware : fail(%d)", ret);
>> +             return ret;
>> +     }
>> +
>> +     fw_buf = (unsigned char *)fw_entry->data;
>> +     fw_length = (unsigned int)fw_entry->size;
>> +
>> +     /* chip specific code for flash fuse */
>> +     mutex_lock(&ts->dev_mutex);
>> +
>> +     ts->dev_state = state_updating;
>> +
>> +     ret = hideep_wr_firmware(ts, fw_buf, fw_length, 0, true);
>> +
>> +     ts->dev_state = state_normal;
>> +
>> +     mutex_unlock(&ts->dev_mutex);
>> +
>> +     release_firmware(fw_entry);
>> +
>> +     return ret;
>> +}
>> +
>> +static int hideep_update_part_firmware(struct hideep_t *ts,
>> +     unsigned char *code, int len, int offset, bool mode)
>> +{
>> +     int ret = 0;
>> +
>> +     mutex_lock(&ts->dev_mutex);
>> +
>> +     ret = hideep_wr_firmware(ts, code, len, offset, false);
>> +
>> +     mutex_unlock(&ts->dev_mutex);
>> +
>> +     return ret;
>> +}
>> +
>> +void hideep_isp_init(struct hideep_t *ts)
>> +{
>> +     ts->hideep_api->update_all = hideep_update_all_firmware;
>> +     ts->hideep_api->update_part = hideep_update_part_firmware;
>> +     ts->hideep_api->get_dwz_info = hideep_load_dwz;
>> +     ts->hideep_api->sp_func = hideep_read_nvm;
>> +}
>> diff --git a/drivers/input/touchscreen/hideep_isp.h b/drivers/input/touchscreen/hideep_isp.h
>> new file mode 100644
>> index 0000000..648f271
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_isp.h
>> @@ -0,0 +1,96 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#ifndef _LINUX_HIDEEP_ISP_H
>> +#define _LINUX_HIDEEP_ISP_H
>> +
>> +#define PGM_BURST_WR
>> +#define PGM_VERIFY
>> +
>> +#define NVM_DEFAULT_PAGE             0
>> +#define NVM_SFR_WPAGE                        1
>> +#define NVM_SFR_RPAGE                        2
>> +
>> +#define PIO_SIG                                      0x00400000
>> +#define _PROT_MODE                           0x03400000
>> +
>> +#define NVM_PAGE_SIZE                        128
>> +
>> +#define HIDEEP_NVM_DOWNLOAD          0x10000000
>> +
>> +/*************************************************************************
>> + * register map
>> + *************************************************************************/
>> +#define YRAM_BASE                            0x40000000
>> +#define PERIPHERAL_BASE                      0x50000000
>> +#define ESI_BASE                             (PERIPHERAL_BASE + 0x00000000)
>> +#define FLASH_BASE                           (PERIPHERAL_BASE + 0x01000000)
>> +#define SYSCON_BASE                          (PERIPHERAL_BASE + 0x02000000)
>> +
>> +#define SYSCON_MOD_CON                       (SYSCON_BASE + 0x0000)
>> +#define SYSCON_SPC_CON                       (SYSCON_BASE + 0x0004)
>> +#define SYSCON_CLK_CON                       (SYSCON_BASE + 0x0008)
>> +#define SYSCON_CLK_ENA                       (SYSCON_BASE + 0x000C)
>> +#define SYSCON_RST_CON                       (SYSCON_BASE + 0x0010)
>> +#define SYSCON_WDT_CON                       (SYSCON_BASE + 0x0014)
>> +#define SYSCON_WDT_CNT                       (SYSCON_BASE + 0x0018)
>> +#define SYSCON_PWR_CON                       (SYSCON_BASE + 0x0020)
>> +#define SYSCON_PGM_ID                        (SYSCON_BASE + 0x00F4)
>> +
>> +#define FLASH_CON                            (FLASH_BASE + 0x0000)
>> +#define FLASH_STA                            (FLASH_BASE + 0x0004)
>> +#define FLASH_CFG                            (FLASH_BASE + 0x0008)
>> +#define FLASH_TIM                            (FLASH_BASE + 0x000C)
>> +#define FLASH_CACHE_CFG                      (FLASH_BASE + 0x0010)
>> +
>> +#define ESI_TX_INVALID                       (ESI_BASE + 0x0008)
>> +
>> +/*************************************************************************
>> + * flash commands
>> + *************************************************************************/
>> +#define MERASE                                       0x00010000
>> +#define SERASE                                       0x00020000
>> +#define PERASE                                       0x00040000
>> +#define PROG                                 0x00080000
>> +#define WRONLY                                       0x00100000
>> +#define INF                                          0x00200000
>> +
>> +/*************************************************************************
>> + * NVM Mask
>> + *************************************************************************/
>> +#ifdef CONFIG_TOUCHSCREEN_HIDEEP_CRIMSON
>> +#define NVM_MASK_OFS                 0x0000000C
>> +#define NVM_MASK                             0x00310000
>> +#define INF_SECTION                          0x0000C000
>> +#endif
>> +#ifdef CONFIG_TOUCHSCREEN_HIDEEP_LIME
>> +#define NVM_MASK_OFS                 0x0000000C
>> +#define NVM_MASK                             0x0030027B
>> +#define INF_SECTION                          0x00010000
>> +#endif
>> +
>> +/*************************************************************************
>> + * DWZ info
>> + *************************************************************************/
>> +#define HIDEEP_BOOT_SECTION          0x00000400
>> +#define HIDEEP_BOOT_LEN                      0x00000400
>> +#define HIDEEP_DWZ_SECTION           0x00000280
>> +#define HIDEEP_DWZ_INFO_OFS          0x000002C0
>> +#define HIDEEP_DWZ_LEN                       (HIDEEP_BOOT_SECTION \
>> +                                                     - HIDEEP_DWZ_SECTION)
>> +
>> +struct pgm_packet {
>> +     union {
>> +             unsigned char b[8];
>> +             unsigned int w[2];
>> +     } header;
>> +
>> +     unsigned int payload[NVM_PAGE_SIZE / sizeof(unsigned int)];
>> +};
>> +
>> +#endif /* _LINUX_HIDEEP_ISP_H */
>> diff --git a/drivers/input/touchscreen/hideep_sysfs.c b/drivers/input/touchscreen/hideep_sysfs.c
>> new file mode 100644
>> index 0000000..7f28fb4
>> --- /dev/null
>> +++ b/drivers/input/touchscreen/hideep_sysfs.c
>> @@ -0,0 +1,245 @@
>> +/*
>> + * Copyright (C) 2012-2017 Hideep, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2
>> + * as published by the Free Software Foudation.
>> + */
>> +
>> +#include "hideep.h"
>> +
>> +static ssize_t update_fw(struct device *dev, struct device_attribute *attr,
>> +     const char *buf, size_t count)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int mode, ret;
>> +     char *fw_name;
>> +
>> +     ret = kstrtoint(buf, 8, &mode);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (mode == 1) {
>> +             disable_irq(ts->client->irq);
>> +
>> +             ts->dev_state = state_updating;
>> +             fw_name = kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin",
>> +                     ts->dwz_info->product_id);
>> +             ret = ts->hideep_api->update_all(ts, fw_name);
>> +
>> +             kfree(fw_name);
>> +
>> +             enable_irq(ts->client->irq);
>> +
>> +             ts->dev_state = state_normal;
>> +             if (ret != 0)
>> +                     dev_err(dev, "The firmware update failed(%d)", ret);
>> +     }
>> +
>> +     return count;
>> +}
>> +
>> +static ssize_t fw_version_show(struct device *dev,
>> +     struct device_attribute *attr, char *buf)
>> +{
>> +     int len = 0;
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +
>> +     dev_info(dev, "release version : %04x",
>> +             ts->dwz_info->release_ver);
>> +
>> +     mutex_lock(&ts->dev_mutex);
>> +     len = scnprintf(buf, PAGE_SIZE,
>> +             "%04x\n", ts->dwz_info->release_ver);
>> +     mutex_unlock(&ts->dev_mutex);
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t product_id_show(struct device *dev,
>> +     struct device_attribute *attr, char *buf)
>> +{
>> +     int len = 0;
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +
>> +     dev_info(dev, "product id : %04x",
>> +             ts->dwz_info->product_id);
>> +
>> +     mutex_lock(&ts->dev_mutex);
>> +     len = scnprintf(buf, PAGE_SIZE,
>> +             "%04x\n", ts->dwz_info->product_id);
>> +     mutex_unlock(&ts->dev_mutex);
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t power_status(struct device *dev, struct device_attribute *attr,
>> +     char *buf)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int len;
>> +
>> +     len = scnprintf(buf, PAGE_SIZE, "power status : %s\n",
>> +             (ts->dev_state == state_init) ? "off" : "on");
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t power_control(struct device *dev, struct device_attribute *attr,
>> +     const char *buf, size_t count)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int on, ret;
>> +
>> +     ret = kstrtoint(buf, 8, &on);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (on) {
>> +             ts->hideep_api->power(ts, on);
>> +             ts->dev_state = state_normal;
>> +             ts->hideep_api->reset_ic(ts);
>> +     } else {
>> +             ts->hideep_api->power(ts, on);
>> +             ts->dev_state = state_init;
>> +     }
>> +
>> +     return count;
>> +}
>> +
>> +#ifdef HIDEEP_SUPPORT_STYLUS
>> +static ssize_t stylus_status(struct device *dev, struct device_attribute *attr,
>> +     char *buf)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int len;
>> +     unsigned char status[1];
>> +
>> +     ts->hideep_api->i2c_read(ts, 0xB00C, 1, status);
>> +
>> +     len = scnprintf(buf, PAGE_SIZE, "stylus mode enable : %s\n",
>> +             (status[0] == 0x00) ? "off" : "on");
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t stylus_enable(struct device *dev, struct device_attribute *attr,
>> +     const char *buf, size_t count)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int on, ret;
>> +     unsigned char data[2];
>> +
>> +     ret = kstrtoint(buf, 8, &on);
>> +     if (ret)
>> +             return ret;
>> +
>> +     data[0] = 0x04;
>> +
>> +     if (on) {
>> +             data[1] = 0x01;
>> +             ts->hideep_api->i2c_write(ts, HIDEEP_SWTICH_CMD, 2, data);
>> +     } else {
>> +             data[1] = 0x00;
>> +             ts->hideep_api->i2c_write(ts, HIDEEP_SWTICH_CMD, 2, data);
>> +     }
>> +
>> +     return count;
>> +}
>> +#endif
>> +
>> +static ssize_t debug_status(struct device *dev, struct device_attribute *attr,
>> +     char *buf)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int len;
>> +
>> +     len = scnprintf(buf, PAGE_SIZE, "debug mode : %s\n",
>> +             (ts->debug_dev.debug_enable == 0) ? "off" : "on");
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t debug_mode(struct device *dev, struct device_attribute *attr,
>> +     const char *buf, size_t count)
>> +{
>> +     struct hideep_t *ts = dev_get_drvdata(dev);
>> +     int on, ret;
>> +     unsigned char data[2];
>> +
>> +     ret = kstrtoint(buf, 8, &on);
>> +     if (ret)
>> +             return ret;
>> +
>> +     if (on) {
>> +             ts->debug_dev.debug_enable = 1;
>> +             ts->dev_state = state_debugging;
>> +     } else {
>> +             ts->debug_dev.debug_enable = 0;
>> +             ts->dev_state = state_normal;
>> +             /* set touch mode */
>> +             data[0] = 0x00;
>> +             data[1] = 0x00;
>> +             ts->hideep_api->i2c_write(ts, HIDEEP_OPMODE_CMD, 2, data);
>> +             if (ts->interrupt_state == 0) {
>> +                     data[0] = 0x5A;
>> +                     ts->hideep_api->i2c_write(ts, HIDEEP_INTCLR_CMD, 1,
>> +                             data);
>> +                     enable_irq(ts->client->irq);
>> +                     ts->interrupt_state = 1;
>> +             }
>> +     }
>> +
>> +     return count;
>> +}
>> +
>> +static DEVICE_ATTR(update_fw, 0664, NULL, update_fw);
>> +static DEVICE_ATTR(version, 0664, fw_version_show, NULL);
>> +static DEVICE_ATTR(product_id, 0664, product_id_show, NULL);
>> +static DEVICE_ATTR(power_en, 0664, power_status, power_control);
>
> Why does this need to be exported?

Sorry, it is just for debug, I will remove it.

>
>> +static DEVICE_ATTR(debug_en, 0664, debug_status, debug_mode);
>
> I do not think we want it in mainline.
>
>> +#ifdef HIDEEP_SUPPORT_STYLUS
>> +static DEVICE_ATTR(stylus_en, 0664, stylus_status, stylus_enable);
>
> Why do we need to disable stylus?

Some customers want to enable/disable for stylus function at user space.
So I added it. If don't want to add mainline, I will remove it.

>
>> +#endif
>> +
>> +static struct attribute *hideep_ts_sysfs_entries[] = {
>> +     &dev_attr_update_fw.attr,
>> +     &dev_attr_version.attr,
>> +     &dev_attr_product_id.attr,
>> +     &dev_attr_power_en.attr,
>> +     &dev_attr_debug_en.attr,
>> +#ifdef HIDEEP_SUPPORT_STYLUS
>> +     &dev_attr_stylus_en.attr,
>> +#endif
>> +     NULL
>> +};
>> +
>> +static struct attribute_group hideep_ts_attr_group = {
>> +     .attrs = hideep_ts_sysfs_entries,
>> +};
>> +
>> +int hideep_sysfs_init(struct hideep_t *ts)
>> +{
>> +     int ret;
>> +     struct i2c_client *client = ts->client;
>> +
>> +     /* Create the files associated with this kobject */
>> +     ret = sysfs_create_group(&client->dev.kobj, &hideep_ts_attr_group);
>> +
>> +     dev_info(&ts->client->dev, "device : %s ", client->dev.kobj.name);
>> +
>> +     if (ret)
>> +             dev_err(&ts->client->dev, "%s: Fail create link error = %d\n",
>> +                      __func__, ret);
>> +
>> +     return ret;
>> +}
>> +
>> +int hideep_sysfs_exit(struct hideep_t *ts)
>> +{
>> +     struct i2c_client *client = ts->client;
>> +
>> +     sysfs_remove_group(&client->dev.kobj, &hideep_ts_attr_group);
>> +
>> +     return 0;
>> +}
>> --
>> 2.7.4
>>
>
> Thanks.
>
> --
> Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux