^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Weida HiTech WDT87xx TouchScreen I2C driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2015 Weida Hi-Tech Co., Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * HN Chen <hn.chen@weidahitech.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * This software is licensed under the terms of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * License, as published by the Free Software Foundation, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * may be copied, distributed, and modified under those terms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/input.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/firmware.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/input/mt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/unaligned.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define WDT87XX_NAME "wdt87xx_i2c"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define WDT87XX_FW_NAME "wdt87xx_fw.bin"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MODE_ACTIVE 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define MODE_READY 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define MODE_IDLE 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define MODE_SLEEP 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define MODE_STOP 0xFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define WDT_MAX_FINGER 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define WDT_RAW_BUF_COUNT 54
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define WDT_V1_RAW_BUF_COUNT 74
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define WDT_FIRMWARE_ID 0xa9e368f5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define PG_SIZE 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define MAX_RETRIES 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define MAX_UNIT_AXIS 0x7FFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define PKT_READ_SIZE 72
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define PKT_WRITE_SIZE 80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) /* the finger definition of the report event */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define FINGER_EV_OFFSET_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) #define FINGER_EV_OFFSET_X 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define FINGER_EV_OFFSET_Y 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define FINGER_EV_SIZE 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define FINGER_EV_V1_OFFSET_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) #define FINGER_EV_V1_OFFSET_W 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define FINGER_EV_V1_OFFSET_P 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define FINGER_EV_V1_OFFSET_X 3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) #define FINGER_EV_V1_OFFSET_Y 5
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define FINGER_EV_V1_SIZE 7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* The definition of a report packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #define TOUCH_PK_OFFSET_REPORT_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define TOUCH_PK_OFFSET_EVENT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define TOUCH_PK_OFFSET_SCAN_TIME 51
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #define TOUCH_PK_OFFSET_FNGR_NUM 53
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define TOUCH_PK_V1_OFFSET_REPORT_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define TOUCH_PK_V1_OFFSET_EVENT 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define TOUCH_PK_V1_OFFSET_SCAN_TIME 71
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define TOUCH_PK_V1_OFFSET_FNGR_NUM 73
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) /* The definition of the controller parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #define CTL_PARAM_OFFSET_FW_ID 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) #define CTL_PARAM_OFFSET_PLAT_ID 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) #define CTL_PARAM_OFFSET_XMLS_ID1 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) #define CTL_PARAM_OFFSET_XMLS_ID2 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #define CTL_PARAM_OFFSET_PHY_CH_X 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) #define CTL_PARAM_OFFSET_PHY_CH_Y 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) #define CTL_PARAM_OFFSET_PHY_X0 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) #define CTL_PARAM_OFFSET_PHY_X1 14
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #define CTL_PARAM_OFFSET_PHY_Y0 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #define CTL_PARAM_OFFSET_PHY_Y1 18
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define CTL_PARAM_OFFSET_PHY_W 22
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define CTL_PARAM_OFFSET_PHY_H 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #define CTL_PARAM_OFFSET_FACTOR 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /* The definition of the device descriptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) #define WDT_GD_DEVICE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define DEV_DESC_OFFSET_VID 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define DEV_DESC_OFFSET_PID 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* Communication commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define PACKET_SIZE 56
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define VND_REQ_READ 0x06
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define VND_READ_DATA 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) #define VND_REQ_WRITE 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) #define VND_CMD_START 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) #define VND_CMD_STOP 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define VND_CMD_RESET 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) #define VND_CMD_ERASE 0x1A
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define VND_GET_CHECKSUM 0x66
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define VND_SET_DATA 0x83
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define VND_SET_COMMAND_DATA 0x84
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) #define VND_SET_CHECKSUM_CALC 0x86
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) #define VND_SET_CHECKSUM_LENGTH 0x87
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) #define VND_CMD_SFLCK 0xFC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) #define VND_CMD_SFUNL 0xFD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) #define CMD_SFLCK_KEY 0xC39B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #define CMD_SFUNL_KEY 0x95DA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) #define STRIDX_PLATFORM_ID 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) #define STRIDX_PARAMETERS 0x81
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) #define CMD_BUF_SIZE 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) #define PKT_BUF_SIZE 64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) /* The definition of the command packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #define CMD_REPORT_ID_OFFSET 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #define CMD_TYPE_OFFSET 0x1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) #define CMD_INDEX_OFFSET 0x2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define CMD_KEY_OFFSET 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) #define CMD_LENGTH_OFFSET 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) #define CMD_DATA_OFFSET 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) /* The definition of firmware chunk tags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define FOURCC_ID_RIFF 0x46464952
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define FOURCC_ID_WHIF 0x46494857
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) #define FOURCC_ID_FRMT 0x544D5246
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) #define FOURCC_ID_FRWR 0x52575246
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) #define FOURCC_ID_CNFG 0x47464E43
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) #define CHUNK_ID_FRMT FOURCC_ID_FRMT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) #define CHUNK_ID_FRWR FOURCC_ID_FRWR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #define CHUNK_ID_CNFG FOURCC_ID_CNFG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) #define FW_FOURCC1_OFFSET 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #define FW_SIZE_OFFSET 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) #define FW_FOURCC2_OFFSET 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) #define FW_PAYLOAD_OFFSET 40
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) #define FW_CHUNK_ID_OFFSET 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) #define FW_CHUNK_SIZE_OFFSET 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #define FW_CHUNK_TGT_START_OFFSET 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) #define FW_CHUNK_PAYLOAD_LEN_OFFSET 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #define FW_CHUNK_SRC_START_OFFSET 16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) #define FW_CHUNK_VERSION_OFFSET 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) #define FW_CHUNK_ATTR_OFFSET 24
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) #define FW_CHUNK_PAYLOAD_OFFSET 32
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Controller requires minimum 300us between commands */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #define WDT_COMMAND_DELAY_MS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) #define WDT_FLASH_WRITE_DELAY_MS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define WDT_FLASH_ERASE_DELAY_MS 200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) #define WDT_FW_RESET_TIME 2500
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct wdt87xx_sys_param {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) u16 fw_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) u16 plat_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) u16 xmls_id1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) u16 xmls_id2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) u16 phy_ch_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) u16 phy_ch_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) u16 phy_w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) u16 phy_h;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) u16 scaling_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) u32 max_x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) u32 max_y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) u16 vendor_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) u16 product_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) struct wdt87xx_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* Mutex for fw update to prevent concurrent access */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct mutex fw_mutex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) struct wdt87xx_sys_param param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) u8 phys[32];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int wdt87xx_i2c_xfer(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) void *txdata, size_t txlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) void *rxdata, size_t rxlen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct i2c_msg msgs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) .addr = client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) .flags = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) .len = txlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) .buf = txdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) .addr = client->addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) .flags = I2C_M_RD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) .len = rxlen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .buf = rxdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if (ret != ARRAY_SIZE(msgs)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) error = ret < 0 ? ret : -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) dev_err(&client->dev, "%s: i2c transfer failed: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) __func__, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static int wdt87xx_get_desc(struct i2c_client *client, u8 desc_idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) u8 *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) u8 tx_buf[] = { 0x22, 0x00, 0x10, 0x0E, 0x23, 0x00 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) tx_buf[2] |= desc_idx & 0xF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) buf, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) dev_err(&client->dev, "get desc failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (buf[0] != len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) dev_err(&client->dev, "unexpected response to get desc: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) buf[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) mdelay(WDT_COMMAND_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) static int wdt87xx_get_string(struct i2c_client *client, u8 str_idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) u8 *buf, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) u8 tx_buf[] = { 0x22, 0x00, 0x13, 0x0E, str_idx, 0x23, 0x00 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) u8 rx_buf[PKT_WRITE_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) size_t rx_len = len + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (rx_len > sizeof(rx_buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) rx_buf, rx_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) dev_err(&client->dev, "get string failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) if (rx_buf[1] != 0x03) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) dev_err(&client->dev, "unexpected response to get string: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) rx_buf[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) rx_len = min_t(size_t, len, rx_buf[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) memcpy(buf, &rx_buf[2], rx_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) mdelay(WDT_COMMAND_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int wdt87xx_get_feature(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) u8 *buf, size_t buf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) u8 tx_buf[8];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) u8 rx_buf[PKT_WRITE_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) size_t tx_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) size_t rx_len = buf_size + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (rx_len > sizeof(rx_buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) /* Get feature command packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) tx_buf[tx_len++] = 0x22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) tx_buf[tx_len++] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) if (buf[CMD_REPORT_ID_OFFSET] > 0xF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) tx_buf[tx_len++] = 0x30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) tx_buf[tx_len++] = 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) tx_buf[tx_len++] = buf[CMD_REPORT_ID_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) tx_buf[tx_len++] = 0x30 | buf[CMD_REPORT_ID_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) tx_buf[tx_len++] = 0x02;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) tx_buf[tx_len++] = 0x23;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) tx_buf[tx_len++] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) error = wdt87xx_i2c_xfer(client, tx_buf, tx_len, rx_buf, rx_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) dev_err(&client->dev, "get feature failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) rx_len = min_t(size_t, buf_size, get_unaligned_le16(rx_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) memcpy(buf, &rx_buf[2], rx_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) mdelay(WDT_COMMAND_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) static int wdt87xx_set_feature(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) const u8 *buf, size_t buf_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) u8 tx_buf[PKT_WRITE_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) int tx_len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) /* Set feature command packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) tx_buf[tx_len++] = 0x22;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) tx_buf[tx_len++] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (buf[CMD_REPORT_ID_OFFSET] > 0xF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) tx_buf[tx_len++] = 0x30;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) tx_buf[tx_len++] = 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) tx_buf[tx_len++] = buf[CMD_REPORT_ID_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) tx_buf[tx_len++] = 0x30 | buf[CMD_REPORT_ID_OFFSET];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) tx_buf[tx_len++] = 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) tx_buf[tx_len++] = 0x23;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) tx_buf[tx_len++] = 0x00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) tx_buf[tx_len++] = (buf_size & 0xFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) tx_buf[tx_len++] = ((buf_size & 0xFF00) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) if (tx_len + buf_size > sizeof(tx_buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) memcpy(&tx_buf[tx_len], buf, buf_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) tx_len += buf_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) error = i2c_master_send(client, tx_buf, tx_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) dev_err(&client->dev, "set feature failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) mdelay(WDT_COMMAND_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static int wdt87xx_send_command(struct i2c_client *client, int cmd, int value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) u8 cmd_buf[CMD_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) /* Set the command packet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) cmd_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) cmd_buf[CMD_TYPE_OFFSET] = VND_SET_COMMAND_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) put_unaligned_le16((u16)cmd, &cmd_buf[CMD_INDEX_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) switch (cmd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) case VND_CMD_START:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) case VND_CMD_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) case VND_CMD_RESET:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) /* Mode selector */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) put_unaligned_le32((value & 0xFF), &cmd_buf[CMD_LENGTH_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) case VND_CMD_SFLCK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) put_unaligned_le16(CMD_SFLCK_KEY, &cmd_buf[CMD_KEY_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) case VND_CMD_SFUNL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) put_unaligned_le16(CMD_SFUNL_KEY, &cmd_buf[CMD_KEY_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) case VND_CMD_ERASE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) case VND_SET_CHECKSUM_CALC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) case VND_SET_CHECKSUM_LENGTH:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) put_unaligned_le32(value, &cmd_buf[CMD_KEY_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) cmd_buf[CMD_REPORT_ID_OFFSET] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) dev_err(&client->dev, "Invalid command: %d\n", cmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return wdt87xx_set_feature(client, cmd_buf, sizeof(cmd_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static int wdt87xx_sw_reset(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) dev_dbg(&client->dev, "resetting device now\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) error = wdt87xx_send_command(client, VND_CMD_RESET, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) dev_err(&client->dev, "reset failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) /* Wait the device to be ready */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) msleep(WDT_FW_RESET_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static const void *wdt87xx_get_fw_chunk(const struct firmware *fw, u32 id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) size_t pos = FW_PAYLOAD_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) u32 chunk_id, chunk_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) while (pos < fw->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) chunk_id = get_unaligned_le32(fw->data +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) pos + FW_CHUNK_ID_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (chunk_id == id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) return fw->data + pos;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) chunk_size = get_unaligned_le32(fw->data +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) pos + FW_CHUNK_SIZE_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) pos += chunk_size + 2 * sizeof(u32); /* chunk ID + size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) static int wdt87xx_get_sysparam(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) struct wdt87xx_sys_param *param)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) u8 buf[PKT_READ_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) error = wdt87xx_get_desc(client, WDT_GD_DEVICE, buf, 18);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) dev_err(&client->dev, "failed to get device desc\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) param->vendor_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_VID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) param->product_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_PID);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 34);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) dev_err(&client->dev, "failed to get parameters\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) param->xmls_id1 = get_unaligned_le16(buf + CTL_PARAM_OFFSET_XMLS_ID1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) param->xmls_id2 = get_unaligned_le16(buf + CTL_PARAM_OFFSET_XMLS_ID2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) param->phy_ch_x = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_CH_X);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) param->phy_ch_y = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_CH_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) param->phy_w = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_W) / 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) param->phy_h = get_unaligned_le16(buf + CTL_PARAM_OFFSET_PHY_H) / 10;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* Get the scaling factor of pixel to logical coordinate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) param->scaling_factor =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) get_unaligned_le16(buf + CTL_PARAM_OFFSET_FACTOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) param->max_x = MAX_UNIT_AXIS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) param->max_y = DIV_ROUND_CLOSEST(MAX_UNIT_AXIS * param->phy_h,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) param->phy_w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) error = wdt87xx_get_string(client, STRIDX_PLATFORM_ID, buf, 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) dev_err(&client->dev, "failed to get platform id\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) param->plat_id = buf[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) buf[0] = 0xf2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) error = wdt87xx_get_feature(client, buf, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) dev_err(&client->dev, "failed to get firmware id\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (buf[0] != 0xf2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) dev_err(&client->dev, "wrong id of fw response: 0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) buf[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) param->fw_id = get_unaligned_le16(&buf[1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) dev_info(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) "fw_id: 0x%x, plat_id: 0x%x, xml_id1: %04x, xml_id2: %04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) param->fw_id, param->plat_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) param->xmls_id1, param->xmls_id2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) static int wdt87xx_validate_firmware(struct wdt87xx_data *wdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) const struct firmware *fw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) const void *fw_chunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) u32 data1, data2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) u32 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) u8 fw_chip_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) u8 chip_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) data1 = get_unaligned_le32(fw->data + FW_FOURCC1_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) data2 = get_unaligned_le32(fw->data + FW_FOURCC2_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (data1 != FOURCC_ID_RIFF || data2 != FOURCC_ID_WHIF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) dev_err(&wdt->client->dev, "check fw tag failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) size = get_unaligned_le32(fw->data + FW_SIZE_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (size != fw->size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) dev_err(&wdt->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) "fw size mismatch: expected %d, actual %zu\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) size, fw->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) * Get the chip_id from the firmware. Make sure that it is the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) * right controller to do the firmware and config update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) fw_chunk = wdt87xx_get_fw_chunk(fw, CHUNK_ID_FRWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) if (!fw_chunk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) dev_err(&wdt->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) "unable to locate firmware chunk\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) fw_chip_id = (get_unaligned_le32(fw_chunk +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) FW_CHUNK_VERSION_OFFSET) >> 12) & 0xF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) chip_id = (wdt->param.fw_id >> 12) & 0xF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) if (fw_chip_id != chip_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) dev_err(&wdt->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) "fw version mismatch: fw %d vs. chip %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) fw_chip_id, chip_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) static int wdt87xx_validate_fw_chunk(const void *data, int id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) if (id == CHUNK_ID_FRWR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) u32 fw_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) fw_id = get_unaligned_le32(data + FW_CHUNK_PAYLOAD_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (fw_id != WDT_FIRMWARE_ID)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int wdt87xx_write_data(struct i2c_client *client, const char *data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) u32 address, int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) u16 packet_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) u8 pkt_buf[PKT_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) /* Address and length should be 4 bytes aligned */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if ((address & 0x3) != 0 || (length & 0x3) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) "addr & len must be 4 bytes aligned %x, %x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) address, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) while (length) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) packet_size = min(length, PACKET_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) pkt_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_WRITE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) pkt_buf[CMD_TYPE_OFFSET] = VND_SET_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) put_unaligned_le16(packet_size, &pkt_buf[CMD_INDEX_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) put_unaligned_le32(address, &pkt_buf[CMD_LENGTH_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) memcpy(&pkt_buf[CMD_DATA_OFFSET], data, packet_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) error = wdt87xx_set_feature(client, pkt_buf, sizeof(pkt_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) length -= packet_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) data += packet_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) address += packet_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) /* Wait for the controller to finish the write */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) mdelay(WDT_FLASH_WRITE_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) if ((++count % 32) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) /* Delay for fw to clear watch dog */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) msleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) static u16 misr(u16 cur_value, u8 new_value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) u32 a, b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) u32 bit0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) u32 y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) a = cur_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) b = new_value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) bit0 = a ^ (b & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) bit0 ^= a >> 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) bit0 ^= a >> 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) bit0 ^= a >> 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) bit0 ^= a >> 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) bit0 ^= a >> 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) bit0 ^= a >> 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) bit0 ^= a >> 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) y = (a << 1) ^ b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) y = (y & ~1) | (bit0 & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) return (u16)y;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) static u16 wdt87xx_calculate_checksum(const u8 *data, size_t length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) u16 checksum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) size_t i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) for (i = 0; i < length; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) checksum = misr(checksum, data[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) return checksum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) static int wdt87xx_get_checksum(struct i2c_client *client, u16 *checksum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) u32 address, int length)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int time_delay;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) u8 pkt_buf[PKT_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) u8 cmd_buf[CMD_BUF_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) error = wdt87xx_send_command(client, VND_SET_CHECKSUM_LENGTH, length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) dev_err(&client->dev, "failed to set checksum length\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) error = wdt87xx_send_command(client, VND_SET_CHECKSUM_CALC, address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) dev_err(&client->dev, "failed to set checksum address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) /* Wait the operation to complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) time_delay = DIV_ROUND_UP(length, 1024);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) msleep(time_delay * 30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) memset(cmd_buf, 0, sizeof(cmd_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) cmd_buf[CMD_REPORT_ID_OFFSET] = VND_REQ_READ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) cmd_buf[CMD_TYPE_OFFSET] = VND_GET_CHECKSUM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) error = wdt87xx_set_feature(client, cmd_buf, sizeof(cmd_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) dev_err(&client->dev, "failed to request checksum\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) memset(pkt_buf, 0, sizeof(pkt_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) pkt_buf[CMD_REPORT_ID_OFFSET] = VND_READ_DATA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) error = wdt87xx_get_feature(client, pkt_buf, sizeof(pkt_buf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) dev_err(&client->dev, "failed to read checksum\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) *checksum = get_unaligned_le16(&pkt_buf[CMD_DATA_OFFSET]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) static int wdt87xx_write_firmware(struct i2c_client *client, const void *chunk)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) u32 start_addr = get_unaligned_le32(chunk + FW_CHUNK_TGT_START_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) u32 size = get_unaligned_le32(chunk + FW_CHUNK_PAYLOAD_LEN_OFFSET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) const void *data = chunk + FW_CHUNK_PAYLOAD_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) int err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) int page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) int retry = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) u16 device_checksum, firmware_checksum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) dev_dbg(&client->dev, "start 4k page program\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) error = wdt87xx_send_command(client, VND_CMD_STOP, MODE_STOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) dev_err(&client->dev, "stop report mode failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) error = wdt87xx_send_command(client, VND_CMD_SFUNL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) dev_err(&client->dev, "unlock failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) goto out_enable_reporting;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) while (size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) dev_dbg(&client->dev, "%s: %x, %x\n", __func__,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) start_addr, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) page_size = min_t(u32, size, PG_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) size -= page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) for (retry = 0; retry < MAX_RETRIES; retry++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) error = wdt87xx_send_command(client, VND_CMD_ERASE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) start_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) "erase failed at %#08x\n", start_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) msleep(WDT_FLASH_ERASE_DELAY_MS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) error = wdt87xx_write_data(client, data, start_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) "write failed at %#08x (%d bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) start_addr, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) error = wdt87xx_get_checksum(client, &device_checksum,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) start_addr, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) "failed to retrieve checksum for %#08x (len: %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) start_addr, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) firmware_checksum =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) wdt87xx_calculate_checksum(data, page_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (device_checksum == firmware_checksum)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) "checksum fail: %d vs %d, retry %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) device_checksum, firmware_checksum, retry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) if (retry == MAX_RETRIES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) dev_err(&client->dev, "page write failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) error = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) goto out_lock_device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) start_addr = start_addr + page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) data = data + page_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) out_lock_device:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) err1 = wdt87xx_send_command(client, VND_CMD_SFLCK, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (err1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) dev_err(&client->dev, "lock failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) mdelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) out_enable_reporting:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) err1 = wdt87xx_send_command(client, VND_CMD_START, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) if (err1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) dev_err(&client->dev, "start to report failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) return error ? error : err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) static int wdt87xx_load_chunk(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) const struct firmware *fw, u32 ck_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) const void *chunk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) chunk = wdt87xx_get_fw_chunk(fw, ck_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) if (!chunk) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) dev_err(&client->dev, "unable to locate chunk (type %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) ck_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) error = wdt87xx_validate_fw_chunk(chunk, ck_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) dev_err(&client->dev, "invalid chunk (type %d): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) ck_id, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) error = wdt87xx_write_firmware(client, chunk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) "failed to write fw chunk (type %d): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) ck_id, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) static int wdt87xx_do_update_firmware(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) const struct firmware *fw,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) unsigned int chunk_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) struct wdt87xx_data *wdt = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) error = wdt87xx_validate_firmware(wdt, fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) error = mutex_lock_interruptible(&wdt->fw_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) disable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) error = wdt87xx_load_chunk(client, fw, chunk_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) "firmware load failed (type: %d): %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) chunk_id, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) error = wdt87xx_sw_reset(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) dev_err(&client->dev, "soft reset failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) /* Refresh the parameters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) error = wdt87xx_get_sysparam(client, &wdt->param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) "failed to refresh system parameters: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) enable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) mutex_unlock(&wdt->fw_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) return error ? error : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) static int wdt87xx_update_firmware(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) const char *fw_name, unsigned int chunk_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) const struct firmware *fw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) error = request_firmware(&fw, fw_name, dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) dev_err(&client->dev, "unable to retrieve firmware %s: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) fw_name, error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) error = wdt87xx_do_update_firmware(client, fw, chunk_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) release_firmware(fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) return error ? error : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) static ssize_t config_csum_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) struct wdt87xx_data *wdt = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) u32 cfg_csum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) cfg_csum = wdt->param.xmls_id1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) cfg_csum = (cfg_csum << 16) | wdt->param.xmls_id2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return scnprintf(buf, PAGE_SIZE, "%x\n", cfg_csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) static ssize_t fw_version_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct wdt87xx_data *wdt = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.fw_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) static ssize_t plat_id_show(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) struct wdt87xx_data *wdt = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return scnprintf(buf, PAGE_SIZE, "%x\n", wdt->param.plat_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static ssize_t update_config_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) error = wdt87xx_update_firmware(dev, WDT87XX_CFG_NAME, CHUNK_ID_CNFG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) return error ? error : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) static ssize_t update_fw_store(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) error = wdt87xx_update_firmware(dev, WDT87XX_FW_NAME, CHUNK_ID_FRWR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) return error ? error : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) static DEVICE_ATTR_RO(config_csum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) static DEVICE_ATTR_RO(fw_version);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) static DEVICE_ATTR_RO(plat_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) static DEVICE_ATTR_WO(update_config);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) static DEVICE_ATTR_WO(update_fw);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) static struct attribute *wdt87xx_attrs[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) &dev_attr_config_csum.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) &dev_attr_fw_version.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) &dev_attr_plat_id.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) &dev_attr_update_config.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) &dev_attr_update_fw.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) static const struct attribute_group wdt87xx_attr_group = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) .attrs = wdt87xx_attrs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) static void wdt87xx_report_contact(struct input_dev *input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) struct wdt87xx_sys_param *param,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) u8 *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) int finger_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) u32 x, y, w;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) u8 p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) finger_id = (buf[FINGER_EV_V1_OFFSET_ID] >> 3) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (finger_id < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) /* Check if this is an active contact */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) if (!(buf[FINGER_EV_V1_OFFSET_ID] & 0x1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) w = buf[FINGER_EV_V1_OFFSET_W];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) w *= param->scaling_factor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) p = buf[FINGER_EV_V1_OFFSET_P];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) x = get_unaligned_le16(buf + FINGER_EV_V1_OFFSET_X);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) y = get_unaligned_le16(buf + FINGER_EV_V1_OFFSET_Y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) y = DIV_ROUND_CLOSEST(y * param->phy_h, param->phy_w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) /* Refuse incorrect coordinates */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) if (x > param->max_x || y > param->max_y)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) dev_dbg(input->dev.parent, "tip on (%d), x(%d), y(%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) finger_id, x, y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) input_mt_slot(input, finger_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) input_mt_report_slot_state(input, MT_TOOL_FINGER, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) input_report_abs(input, ABS_MT_TOUCH_MAJOR, w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) input_report_abs(input, ABS_MT_PRESSURE, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) input_report_abs(input, ABS_MT_POSITION_X, x);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) input_report_abs(input, ABS_MT_POSITION_Y, y);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) static irqreturn_t wdt87xx_ts_interrupt(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) struct wdt87xx_data *wdt = dev_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) struct i2c_client *client = wdt->client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) int i, fingers;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) u8 raw_buf[WDT_V1_RAW_BUF_COUNT] = {0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) error = i2c_master_recv(client, raw_buf, WDT_V1_RAW_BUF_COUNT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (error < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) dev_err(&client->dev, "read v1 raw data failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) goto irq_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) fingers = raw_buf[TOUCH_PK_V1_OFFSET_FNGR_NUM];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) if (!fingers)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) goto irq_exit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) for (i = 0; i < WDT_MAX_FINGER; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) wdt87xx_report_contact(wdt->input,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) &wdt->param,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) &raw_buf[TOUCH_PK_V1_OFFSET_EVENT +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) i * FINGER_EV_V1_SIZE]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) input_mt_sync_frame(wdt->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018) input_sync(wdt->input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) irq_exit:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) struct device *dev = &wdt->client->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) struct input_dev *input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) unsigned int res = DIV_ROUND_CLOSEST(MAX_UNIT_AXIS, wdt->param.phy_w);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) input = devm_input_allocate_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) if (!input) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) dev_err(dev, "failed to allocate input device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) wdt->input = input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) input->name = "WDT87xx Touchscreen";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) input->id.bustype = BUS_I2C;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) input->id.vendor = wdt->param.vendor_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) input->id.product = wdt->param.product_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) input->phys = wdt->phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) input_set_abs_params(input, ABS_MT_POSITION_X, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) wdt->param.max_x, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) wdt->param.max_y, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) input_abs_set_res(input, ABS_MT_POSITION_X, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) input_abs_set_res(input, ABS_MT_POSITION_Y, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) 0, wdt->param.max_x, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xFF, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) input_mt_init_slots(input, WDT_MAX_FINGER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) error = input_register_device(input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) dev_err(dev, "failed to register input device: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) static int wdt87xx_ts_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) struct wdt87xx_data *wdt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) dev_dbg(&client->dev, "adapter=%d, client irq: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) client->adapter->nr, client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) /* Check if the I2C function is ok in this adaptor */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) wdt = devm_kzalloc(&client->dev, sizeof(*wdt), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) if (!wdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) wdt->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) mutex_init(&wdt->fw_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) i2c_set_clientdata(client, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) snprintf(wdt->phys, sizeof(wdt->phys), "i2c-%u-%04x/input0",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) client->adapter->nr, client->addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) error = wdt87xx_get_sysparam(client, &wdt->param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) error = wdt87xx_ts_create_input_device(wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) error = devm_request_threaded_irq(&client->dev, client->irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) NULL, wdt87xx_ts_interrupt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) IRQF_ONESHOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) client->name, wdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) dev_err(&client->dev, "request irq failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) dev_err(&client->dev, "create sysfs failed: %d\n", error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) static int __maybe_unused wdt87xx_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) disable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) error = wdt87xx_send_command(client, VND_CMD_STOP, MODE_IDLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (error) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) enable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) "failed to stop device when suspending: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) static int __maybe_unused wdt87xx_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) * The chip may have been reset while system is resuming,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) * give it some time to settle.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) msleep(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) error = wdt87xx_send_command(client, VND_CMD_START, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) dev_err(&client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) "failed to start device when resuming: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) error);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) enable_irq(client->irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) static SIMPLE_DEV_PM_OPS(wdt87xx_pm_ops, wdt87xx_suspend, wdt87xx_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) static const struct i2c_device_id wdt87xx_dev_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) { WDT87XX_NAME, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) static const struct acpi_device_id wdt87xx_acpi_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) { "WDHT0001", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) static struct i2c_driver wdt87xx_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) .probe = wdt87xx_ts_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) .id_table = wdt87xx_dev_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) .name = WDT87XX_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) .pm = &wdt87xx_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) .acpi_match_table = ACPI_PTR(wdt87xx_acpi_id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) module_i2c_driver(wdt87xx_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) MODULE_AUTHOR("HN Chen <hn.chen@weidahitech.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) MODULE_DESCRIPTION("WeidaHiTech WDT87XX Touchscreen driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) MODULE_LICENSE("GPL");