From patchwork Wed May 29 13:06:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangshuaijie@awinic.com X-Patchwork-Id: 13678820 Received: from out198-11.us.a.mail.aliyun.com (out198-11.us.a.mail.aliyun.com [47.90.198.11]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 71BC9DDAB; Wed, 29 May 2024 13:06:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.11 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988010; cv=none; b=C+s8QAig3jT5HRbXKho2/KBz2F6I4Xm123p5Gsf/tebzWcflwCNVzVPP+1DycP+Xh3ZxDp5IXtB2F+Osb8bShOsq1SSJO+8IN79wKnA9L2t6eyfgwQ9tiDYH2V1DPkDrA0TqYxBXF7S5rkZvn4TdilAHy9ev6gTPhh23t7fEHt8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988010; c=relaxed/simple; bh=UNYgwRsC/DcJD432DmuGTrbp3zABC/67odF/gbKNxzY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cWeI1qHT7xofOqRcEZZOTWuZhEkhLTRNw56CqXK9Y+8BbVgfADxjR1vTgUbuRePwjzmW6Vv3IBQWpa2eCw4V2ItXA8CEkHm8LoYdh6jCI1GyLydZL8Q7GvobQS3xiRqS+GKpCZVnPUcsC+1ydcNaDfOZGMPzAEACyvHJh0E2b8w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com; spf=pass smtp.mailfrom=awinic.com; arc=none smtp.client-ip=47.90.198.11 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=awinic.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436429|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.435426-0.000639855-0.563934;FP=0|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033045002061;MF=wangshuaijie@awinic.com;NM=1;PH=DS;RN=11;RT=11;SR=0;TI=SMTPD_---.XqPpuA1_1716987984; Received: from awinic..(mailfrom:wangshuaijie@awinic.com fp:SMTPD_---.XqPpuA1_1716987984) by smtp.aliyun-inc.com; Wed, 29 May 2024 21:06:31 +0800 From: wangshuaijie@awinic.com To: dmitry.torokhov@gmail.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jeff@labundy.com, linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: wangshuaijie@awinic.com, liweilei@awinic.com, kangjiajun@awinic.com Subject: [PATCH V1 1/5] dt-bindings: input: Add YAML to Awinic sar sensor. Date: Wed, 29 May 2024 13:06:04 +0000 Message-ID: <20240529130608.783624-2-wangshuaijie@awinic.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240529130608.783624-1-wangshuaijie@awinic.com> References: <20240529130608.783624-1-wangshuaijie@awinic.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: shuaijie wang Add the awinic,aw_sar.yaml file to adapt to the awinic sar sensor driver. Signed-off-by: shuaijie wang --- .../bindings/input/awinic,aw_sar.yaml | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/awinic,aw_sar.yaml diff --git a/Documentation/devicetree/bindings/input/awinic,aw_sar.yaml b/Documentation/devicetree/bindings/input/awinic,aw_sar.yaml new file mode 100644 index 000000000000..ed4ec29c9b4d --- /dev/null +++ b/Documentation/devicetree/bindings/input/awinic,aw_sar.yaml @@ -0,0 +1,110 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/awinic,aw_sar.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Awinic sar sensor driver family + +maintainers: + - Shuaijie Wang + +properties: + compatible: + enum: + - awinic,aw_aw96103 + - awinic,aw_aw96105 + - awinic,aw_aw96303 + - awinic,aw_aw96305 + - awinic,aw_aw96308 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + sar-num: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + set the index of the sar sensor. + + vcc0-supply: + description: + Optional regulator for chip, 1.7V-3.6V. + + channel_use_flag: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + The flag of channels used. + Configure according to the specific chip channel used. + Bit[31:0] Each bit represents a channel. + If the customer uses ch0 and ch2, then channel_use_flag=<0x05> + + aw_sar,update_fw: + type: boolean + description: + Choose if you want to update the firmware. + + aw_sar,monitor_esd: + type: boolean + description: + Choose if you want to monitor ESD. + + aw_sar,pin_set_inter_pull-up: + type: boolean + description: + Choose if you want to set the interrupt pin to internal pull-up. + + aw_sar,using_pm_ops: + type: boolean + description: + Choose if you want to use suspend and resume related function. + + aw_sar,use_plug_cail: + type: boolean + description: + Choose If you want to perform calibration when plugging and unplugging the charger. + + start-mode: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + When connecting to aw963xx, select the location where the firmware starts. + set 0 if start in rom. + set 1 if start in ram + + irq-mux: + $ref: /schemas/types.yaml#/definitions/uint32 + description: + set csx as irq pin. config this field when connect to aw96308/aw96305BFOR + +required: + - compatible + - reg + - sar-num + - interrupts + - channel_use_flag + +unevaluatedProperties: false + +examples: + - | + #include + #include + i2c { + #address-cells = <1>; + #size-cells = <0>; + awinic_sar@12 { + compatible = "awinic,aw_sar"; + reg = <0x12>; + sar-num = < 0 >; + interrupt-parent = < &tlmm >; + interrupts = <72 0>; + //vcc0-supply = <&pm660l_l4>; + channel_use_flag = <0xff>; + aw_sar,update_fw; + //aw_sar,monitor_esd; + start-mode = < 1 >; + irq-mux = < 2 >; + }; + }; From patchwork Wed May 29 13:06:05 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangshuaijie@awinic.com X-Patchwork-Id: 13678819 Received: from out28-196.mail.aliyun.com (out28-196.mail.aliyun.com [115.124.28.196]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 557C49474; Wed, 29 May 2024 13:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.196 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988008; cv=none; b=lYA5lbkkf5FHSMosT+psvHxR6fAA9tjtgu0JGLi36XXwg46TNNg8Ks7LRdqtDvb5gPSDO0CBZVPqY2XFScuZJsElwZamLmRRcj8pNYufuYU6vRuxvag8MWIrHqbK+Sx6z9gL5FUYCrBtwbnXJH1pO+/BZ20vlUweQyMHmAojApM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988008; c=relaxed/simple; bh=fUgaWG4YTG2UF6mO3IU0FJKp/bhoLLxuLpJiAM/Kdwc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=icAZS4UvCXwgjWJa+G48SyyRyC0HoW+O2VyD53rO2VurYY0tc4efN2LOobwZMqFfoOpXpFU9oodcUxgkNVTgfFTsiVDe1/hLhPi85vF14ZHsm0REtLnH/g/uBznfZNYG8NpQW8B3lZJ5Ps6MKuWKOVMsIpV3K3Q61NHeAoITPCc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com; spf=pass smtp.mailfrom=awinic.com; arc=none smtp.client-ip=115.124.28.196 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=awinic.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_alarm|0.0641415-0.000130344-0.935728;FP=0|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033037135125;MF=wangshuaijie@awinic.com;NM=1;PH=DS;RN=11;RT=11;SR=0;TI=SMTPD_---.XqPpuGT_1716987991; Received: from awinic..(mailfrom:wangshuaijie@awinic.com fp:SMTPD_---.XqPpuGT_1716987991) by smtp.aliyun-inc.com; Wed, 29 May 2024 21:06:32 +0800 From: wangshuaijie@awinic.com To: dmitry.torokhov@gmail.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jeff@labundy.com, linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: wangshuaijie@awinic.com, liweilei@awinic.com, kangjiajun@awinic.com Subject: [PATCH V1 2/5] Add universal interface for the aw_sar driver. Date: Wed, 29 May 2024 13:06:05 +0000 Message-ID: <20240529130608.783624-3-wangshuaijie@awinic.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240529130608.783624-1-wangshuaijie@awinic.com> References: <20240529130608.783624-1-wangshuaijie@awinic.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: shuaijie wang Add i2c read-write interfaces and interfaces for parsing bin files. Signed-off-by: shuaijie wang --- .../misc/aw_sar/comm/aw_sar_chip_interface.h | 27 + .../misc/aw_sar/comm/aw_sar_comm_interface.c | 656 ++++++++++++++++++ .../misc/aw_sar/comm/aw_sar_comm_interface.h | 172 +++++ drivers/input/misc/aw_sar/comm/aw_sar_type.h | 396 +++++++++++ 4 files changed, 1251 insertions(+) create mode 100644 drivers/input/misc/aw_sar/comm/aw_sar_chip_interface.h create mode 100644 drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.c create mode 100644 drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.h create mode 100644 drivers/input/misc/aw_sar/comm/aw_sar_type.h diff --git a/drivers/input/misc/aw_sar/comm/aw_sar_chip_interface.h b/drivers/input/misc/aw_sar/comm/aw_sar_chip_interface.h new file mode 100644 index 000000000000..d406e48e8136 --- /dev/null +++ b/drivers/input/misc/aw_sar/comm/aw_sar_chip_interface.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _SAR_SUPPORT_CHIP_H_ +#define _SAR_SUPPORT_CHIP_H_ +#include "aw_sar_type.h" + +enum aw_sar_driver_list_t { + AW_SAR_AW9610X, + AW_SAR_AW963XX, + + AW_SAR_DRIVER_MAX, +}; + +int32_t aw9610x_check_chipid(void *data); +int32_t aw9610x_init(struct aw_sar *p_sar); +void aw9610x_deinit(struct aw_sar *p_sar); + +int32_t aw963xx_check_chipid(void *data); +int32_t aw963xx_init(struct aw_sar *p_sar); +void aw963xx_deinit(struct aw_sar *p_sar); + + +static const struct aw_sar_driver_type g_aw_sar_driver_list[] = { + { AW_SAR_AW9610X, aw9610x_check_chipid, aw9610x_init, aw9610x_deinit }, + { AW_SAR_AW963XX, aw963xx_check_chipid, aw963xx_init, aw963xx_deinit }, +}; + +#endif diff --git a/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.c b/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.c new file mode 100644 index 000000000000..1d62ebb60acc --- /dev/null +++ b/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.c @@ -0,0 +1,656 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "aw_sar_comm_interface.h" + +#define AW_I2C_RW_RETRY_TIME_MIN (2000) +#define AW_I2C_RW_RETRY_TIME_MAX (3000) +#define AW_RETRIES (5) + +static int32_t awinic_i2c_write(struct i2c_client *i2c, uint8_t *tr_data, uint16_t len) +{ + struct i2c_msg msg; + + msg.addr = i2c->addr; + msg.flags = 0; + msg.len = len; + msg.buf = tr_data; + + return i2c_transfer(i2c->adapter, &msg, 1); +} + +static int32_t awinic_i2c_read(struct i2c_client *i2c, uint8_t *addr, + uint8_t addr_len, uint8_t *data, uint16_t data_len) +{ + struct i2c_msg msg[2]; + + msg[0].addr = i2c->addr; + msg[0].flags = 0; + msg[0].len = addr_len; + msg[0].buf = addr; + + msg[1].addr = i2c->addr; + msg[1].flags = 1; + msg[1].len = data_len; + msg[1].buf = data; + + return i2c_transfer(i2c->adapter, msg, 2); +} + +/** + * @brief Read register interface + * + * @param i2c: i2c client. + * @param reg_addr16: 16 bit register address. + * @param *reg_data32: 32 bit register data. + * @return 0 if init succeeded. + */ +int32_t aw_sar_i2c_read(struct i2c_client *i2c, uint16_t reg_addr16, uint32_t *reg_data32) +{ + uint8_t r_buf[6] = { 0 }; + int8_t cnt = 5; + int32_t ret; + + if (!i2c) + return -EINVAL; + + r_buf[0] = (unsigned char)(reg_addr16 >> OFFSET_BIT_8); + r_buf[1] = (unsigned char)(reg_addr16); + + do { + ret = awinic_i2c_read(i2c, r_buf, 2, &r_buf[2], 4); + if (ret < 0) + dev_err(&i2c->dev, "i2c read error reg: 0x%04x, ret= %d cnt= %d", + reg_addr16, ret, cnt); + else + break; + usleep_range(2000, 3000); + } while (cnt--); + + if (cnt < 0) { + dev_err(&i2c->dev, "i2c read error!"); + return ret; + } + + *reg_data32 = ((uint32_t)r_buf[5] << OFFSET_BIT_0) | ((uint32_t)r_buf[4] << OFFSET_BIT_8) | + ((uint32_t)r_buf[3] << OFFSET_BIT_16) | ((uint32_t)r_buf[2] << OFFSET_BIT_24); + + return 0; +} + +/** + * @brief write register interface + * + * @param i2c: i2c client. + * @param reg_addr16: 16 bit register address. + * @param reg_data32: 32 bit register data. + * @return 0 if init succeeded. + */ +int32_t aw_sar_i2c_write(struct i2c_client *i2c, uint16_t reg_addr16, uint32_t reg_data32) +{ + uint8_t w_buf[6] = { 0 }; + int8_t cnt = 5; + int32_t ret; + + if (!i2c) + return -EINVAL; + + /*reg_addr*/ + w_buf[0] = (uint8_t)(reg_addr16 >> OFFSET_BIT_8); + w_buf[1] = (uint8_t)(reg_addr16); + /*data*/ + w_buf[2] = (uint8_t)(reg_data32 >> OFFSET_BIT_24); + w_buf[3] = (uint8_t)(reg_data32 >> OFFSET_BIT_16); + w_buf[4] = (uint8_t)(reg_data32 >> OFFSET_BIT_8); + w_buf[5] = (uint8_t)(reg_data32); + + do { + ret = awinic_i2c_write(i2c, w_buf, ARRAY_SIZE(w_buf)); + if (ret < 0) { + dev_err(&i2c->dev, + "i2c write error reg: 0x%04x data: 0x%08x, ret= %d cnt= %d", + reg_addr16, reg_data32, ret, cnt); + } else { + break; + } + } while (cnt--); + + if (cnt < 0) { + dev_err(&i2c->dev, "i2c write error!"); + return ret; + } + + return 0; +} + +/** + * @brief Write the corresponding bit of the register + * + * @param i2c:i2c client. + * @param reg_addr16: 16 bit register address. + * @param mask: Write the corresponding bit as 0 + * @param val: Write corresponding data to the register + * @return 0 if init succeeded. + */ +int32_t +aw_sar_i2c_write_bits(struct i2c_client *i2c, uint16_t reg_addr16, uint32_t mask, uint32_t val) +{ + uint32_t reg_val; + + aw_sar_i2c_read(i2c, reg_addr16, ®_val); + reg_val &= mask; + reg_val |= (val & (~mask)); + aw_sar_i2c_write(i2c, reg_addr16, reg_val); + + return 0; +} + +/** + * @brief Continuously write data to the chip + * + * @param i2c:i2c client. + * @param *tr_data: Data written + * @param len: Length of data written + * @return 0 if init succeeded. + */ +int32_t aw_sar_i2c_write_seq(struct i2c_client *i2c, uint8_t *tr_data, uint16_t len) +{ + int8_t cnt = AW_RETRIES; + int32_t ret; + + do { + ret = awinic_i2c_write(i2c, tr_data, len); + if (ret < 0) + dev_err(&i2c->dev, "awinic i2c write seq error %d", ret); + else + break; + usleep_range(AW_I2C_RW_RETRY_TIME_MIN, AW_I2C_RW_RETRY_TIME_MAX); + } while (cnt--); + + if (cnt < 0) { + dev_err(&i2c->dev, "awinic i2c write error!"); + return ret; + } + + return 0; +} + +/** + * @brief Continuously Read data from chip + * + * @param i2c:i2c client. + * @param *addr: Read address + * @param addr_len: Length of read address (byte) + * @param *data: Data written + * @param data_len: Length of data written + * @return 0 if init succeeded. + */ +int32_t aw_sar_i2c_read_seq(struct i2c_client *i2c, uint8_t *addr, + uint8_t addr_len, uint8_t *data, uint16_t data_len) +{ + int8_t cnt = AW_RETRIES; + int32_t ret; + + do { + ret = awinic_i2c_read(i2c, addr, addr_len, data, data_len); + if (ret < 0) + dev_err(&i2c->dev, "awinic sar i2c write error %d", ret); + else + break; + usleep_range(AW_I2C_RW_RETRY_TIME_MIN, AW_I2C_RW_RETRY_TIME_MAX); + } while (cnt--); + + if (cnt < 0) { + dev_err(&i2c->dev, "awinic sar i2c read error!"); + return ret; + } + + return 0; +} + +/******************************Parse bin file code start****************************************/ + +#define AWINIC_CODE_VERSION "V0.0.7-V1.0.4" /* "code version"-"excel version" */ + +enum bin_header_version_enum { + HEADER_VERSION_1_0_0 = 0x01000000, +}; + +enum data_type_enum { + DATA_TYPE_REGISTER = 0x00000000, + DATA_TYPE_DSP_REG = 0x00000010, + DATA_TYPE_DSP_CFG = 0x00000011, + DATA_TYPE_SOC_REG = 0x00000020, + DATA_TYPE_SOC_APP = 0x00000021, + DATA_TYPE_MULTI_BINS = 0x00002000, +}; + +#define BigLittleSwap16(A) ((((unsigned short int)(A) & 0xff00) >> 8) | \ + (((unsigned short int)(A) & 0x00ff) << 8)) + +#define BigLittleSwap32(A) ((((unsigned long)(A) & 0xff000000) >> 24) | \ + (((unsigned long)(A) & 0x00ff0000) >> 8) | \ + (((unsigned long)(A) & 0x0000ff00) << 8) | \ + (((unsigned long)(A) & 0x000000ff) << 24)) + +static int aw_parse_bin_header_1_0_0(struct aw_bin *bin); + +/** + * + * Interface function + * + * return value: + * value = 0 :success; + * value = -1 :check bin header version + * value = -2 :check bin data type + * value = -3 :check sum or check bin data len error + * value = -4 :check data version + * value = -5 :check register num + * value = -6 :check dsp reg num + * value = -7 :check soc app num + * value = -8 :bin is NULL point + * + **/ + +/******************************************************** + * + * check sum data + * + ********************************************************/ +static enum aw_bin_err_val aw_check_sum(struct aw_bin *bin, int bin_num) +{ + unsigned char *p_check_sum; + unsigned int sum_data = 0; + unsigned int check_sum; + unsigned int i; + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr - + bin->header_info[bin_num].header_len)]); + check_sum = AW_SAR_GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + + for (i = 4; i < bin->header_info[bin_num].bin_data_len + + bin->header_info[bin_num].header_len; i++) + sum_data += *(p_check_sum + i); + + if (sum_data != check_sum) { + p_check_sum = NULL; + return AW_BIN_ERROR_SUM_OR_DATA_LEN; + } + p_check_sum = NULL; + + return AW_BIN_ERROR_NONE; +} + +static enum aw_bin_err_val aw_check_register_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_register_num; + unsigned int parse_register_num; + char *p_check_sum; + + p_check_sum = + &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + parse_register_num = AW_SAR_GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + check_register_num = (bin->header_info[bin_num].bin_data_len - 4) / + (bin->header_info[bin_num].reg_byte_len + + bin->header_info[bin_num].data_byte_len); + if (parse_register_num != check_register_num) { + p_check_sum = NULL; + return AW_BIN_ERROR_REGISTER_NUM; + } + bin->header_info[bin_num].reg_num = parse_register_num; + bin->header_info[bin_num].valid_data_len = bin->header_info[bin_num].bin_data_len - 4; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 4; + + return AW_BIN_ERROR_NONE; +} + +static enum aw_bin_err_val aw_check_dsp_reg_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_dsp_reg_num; + unsigned int parse_dsp_reg_num; + char *p_check_sum; + + p_check_sum = + &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + parse_dsp_reg_num = AW_SAR_GET_32_DATA(*(p_check_sum + 7), + *(p_check_sum + 6), + *(p_check_sum + 5), + *(p_check_sum + 4)); + bin->header_info[bin_num].reg_data_byte_len = + AW_SAR_GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_dsp_reg_num = (bin->header_info[bin_num].bin_data_len - + 12) / bin->header_info[bin_num].reg_data_byte_len; + if (parse_dsp_reg_num != check_dsp_reg_num) { + p_check_sum = NULL; + return AW_BIN_ERROR_DSP_REG_NUM; + } + bin->header_info[bin_num].download_addr = + AW_SAR_GET_32_DATA(*(p_check_sum + 3), *(p_check_sum + 2), + *(p_check_sum + 1), *(p_check_sum)); + bin->header_info[bin_num].reg_num = parse_dsp_reg_num; + bin->header_info[bin_num].valid_data_len = bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + + return AW_BIN_ERROR_NONE; +} + +static enum aw_bin_err_val aw_check_soc_app_num_v1(struct aw_bin *bin, int bin_num) +{ + unsigned int check_soc_app_num; + unsigned int parse_soc_app_num; + char *p_check_sum; + + p_check_sum = &(bin->info.data[(bin->header_info[bin_num].valid_data_addr)]); + bin->header_info[bin_num].app_version = AW_SAR_GET_32_DATA(*(p_check_sum + 3), + *(p_check_sum + 2), + *(p_check_sum + 1), + *(p_check_sum)); + parse_soc_app_num = AW_SAR_GET_32_DATA(*(p_check_sum + 11), *(p_check_sum + 10), + *(p_check_sum + 9), *(p_check_sum + 8)); + check_soc_app_num = bin->header_info[bin_num].bin_data_len - 12; + if (parse_soc_app_num != check_soc_app_num) { + p_check_sum = NULL; + return AW_BIN_ERROR_SOC_APP_NUM; + } + bin->header_info[bin_num].reg_num = parse_soc_app_num; + bin->header_info[bin_num].download_addr = + AW_SAR_GET_32_DATA(*(p_check_sum + 7), *(p_check_sum + 6), + *(p_check_sum + 5), *(p_check_sum + 4)); + bin->header_info[bin_num].valid_data_len = + bin->header_info[bin_num].bin_data_len - 12; + p_check_sum = NULL; + bin->header_info[bin_num].valid_data_addr = + bin->header_info[bin_num].valid_data_addr + 12; + + return AW_BIN_ERROR_NONE; +} + +/************************ + * + ***bin header 1_0_0 + *** + ************************/ +static void aw_get_single_bin_header_1_0_0(struct aw_bin *bin) +{ + int i; + + bin->header_info[bin->all_bin_parse_num].header_len = 60; + bin->header_info[bin->all_bin_parse_num].check_sum = + AW_SAR_GET_32_DATA(*(bin->p_addr + 3), *(bin->p_addr + 2), + *(bin->p_addr + 1), *(bin->p_addr)); + bin->header_info[bin->all_bin_parse_num].header_ver = + AW_SAR_GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + bin->header_info[bin->all_bin_parse_num].bin_data_type = + AW_SAR_GET_32_DATA(*(bin->p_addr + 11), *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + bin->header_info[bin->all_bin_parse_num].bin_data_ver = + AW_SAR_GET_32_DATA(*(bin->p_addr + 15), *(bin->p_addr + 14), + *(bin->p_addr + 13), *(bin->p_addr + 12)); + bin->header_info[bin->all_bin_parse_num].bin_data_len = + AW_SAR_GET_32_DATA(*(bin->p_addr + 19), *(bin->p_addr + 18), + *(bin->p_addr + 17), *(bin->p_addr + 16)); + bin->header_info[bin->all_bin_parse_num].ui_ver = + AW_SAR_GET_32_DATA(*(bin->p_addr + 23), *(bin->p_addr + 22), + *(bin->p_addr + 21), *(bin->p_addr + 20)); + bin->header_info[bin->all_bin_parse_num].reg_byte_len = + AW_SAR_GET_32_DATA(*(bin->p_addr + 35), *(bin->p_addr + 34), + *(bin->p_addr + 33), *(bin->p_addr + 32)); + bin->header_info[bin->all_bin_parse_num].data_byte_len = + AW_SAR_GET_32_DATA(*(bin->p_addr + 39), *(bin->p_addr + 38), + *(bin->p_addr + 37), *(bin->p_addr + 36)); + bin->header_info[bin->all_bin_parse_num].device_addr = + AW_SAR_GET_32_DATA(*(bin->p_addr + 43), *(bin->p_addr + 42), + *(bin->p_addr + 41), *(bin->p_addr + 40)); + for (i = 0; i < 8; i++) { + bin->header_info[bin->all_bin_parse_num].chip_type[i] = + *(bin->p_addr + 24 + i); + } +// bin->header_info[bin->all_bin_parse_num].chip_type[i] = '\0'; +// DBG("enter chip_type is %s\n", bin->header_info[bin->all_bin_parse_num].chip_type); + + bin->header_info[bin->all_bin_parse_num].reg_num = 0x00000000; + bin->header_info[bin->all_bin_parse_num].reg_data_byte_len = 0x00000000; + bin->header_info[bin->all_bin_parse_num].download_addr = 0x00000000; + bin->header_info[bin->all_bin_parse_num].app_version = 0x00000000; + bin->header_info[bin->all_bin_parse_num].valid_data_len = 0x00000000; + bin->all_bin_parse_num += 1; +} + +static enum aw_bin_err_val aw_parse_each_of_multi_bins_1_0_0(unsigned int bin_num, + int bin_serial_num, struct aw_bin *bin) +{ + unsigned int bin_start_addr; + unsigned int valid_data_len; + enum aw_bin_err_val ret; + + if (!bin_serial_num) { + bin_start_addr = AW_SAR_GET_32_DATA(*(bin->p_addr + 67), + *(bin->p_addr + 66), + *(bin->p_addr + 65), + *(bin->p_addr + 64)); + bin->p_addr += (60 + bin_start_addr); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - + 1].valid_data_addr + 4 + 8 * bin_num + 60; + } else { + valid_data_len = + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len; + bin->p_addr += (60 + valid_data_len); + bin->header_info[bin->all_bin_parse_num].valid_data_addr = + bin->header_info[bin->all_bin_parse_num - + 1].valid_data_addr + + bin->header_info[bin->all_bin_parse_num - 1].bin_data_len + + 60; + } + + ret = aw_parse_bin_header_1_0_0(bin); + return ret; +} + +/* Get the number of bins in multi bins, and set a for loop, loop processing each bin data */ +static enum aw_bin_err_val aw_get_multi_bin_header_1_0_0(struct aw_bin *bin) +{ + unsigned int bin_num; + enum aw_bin_err_val ret; + int i; + + bin_num = AW_SAR_GET_32_DATA(*(bin->p_addr + 63), + *(bin->p_addr + 62), + *(bin->p_addr + 61), *(bin->p_addr + 60)); + if (bin->multi_bin_parse_num == 1) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + aw_get_single_bin_header_1_0_0(bin); + + for (i = 0; i < bin_num; i++) { + ret = aw_parse_each_of_multi_bins_1_0_0(bin_num, i, bin); + if (ret < 0) + return ret; + } + return AW_BIN_ERROR_NONE; +} + +/******************************************************** + * + * If the bin framework header version is 1.0.0, + * determine the data type of bin, and then perform different processing + * according to the data type + * If it is a single bin data type, write the data directly into the structure array + * If it is a multi-bin data type, first obtain the number of bins, + * and then recursively call the bin frame header processing function + * according to the bin number to process the frame header information of each bin separately + * + ********************************************************/ +static enum aw_bin_err_val aw_parse_bin_header_1_0_0(struct aw_bin *bin) +{ + unsigned int bin_data_type; + enum aw_bin_err_val ret; + + bin_data_type = AW_SAR_GET_32_DATA(*(bin->p_addr + 11), + *(bin->p_addr + 10), + *(bin->p_addr + 9), *(bin->p_addr + 8)); + switch (bin_data_type) { + case DATA_TYPE_REGISTER: + case DATA_TYPE_DSP_REG: + case DATA_TYPE_SOC_APP: + // Divided into two processing methods, + // one is single bin processing, + // and the other is single bin processing in multi bin + bin->single_bin_parse_num += 1; + if (!bin->multi_bin_parse_num) + bin->header_info[bin->all_bin_parse_num].valid_data_addr = 60; + aw_get_single_bin_header_1_0_0(bin); + break; + case DATA_TYPE_MULTI_BINS: + /* Get the number of times to enter multi bins */ + bin->multi_bin_parse_num += 1; + ret = aw_get_multi_bin_header_1_0_0(bin); + if (ret < 0) + return ret; + break; + default: + return AW_BIN_ERROR_DATA_TYPE; + } + return AW_BIN_ERROR_NONE; +} + +/* get the bin's header version */ +static enum aw_bin_err_val aw_check_bin_header_version(struct aw_bin *bin) +{ + unsigned int header_version; + enum aw_bin_err_val ret; + + header_version = AW_SAR_GET_32_DATA(*(bin->p_addr + 7), *(bin->p_addr + 6), + *(bin->p_addr + 5), *(bin->p_addr + 4)); + + + // Write data to the corresponding structure array + // according to different formats of the bin frame header version + switch (header_version) { + case HEADER_VERSION_1_0_0: + ret = aw_parse_bin_header_1_0_0(bin); + return ret; + default: + return AW_BIN_ERROR_HEADER_VERSION; + } +} + +/** + * @brief Parse bin file + * + * @param bin: Store the contents of the parsed bin file + * @return 0 if init succeeded, other if error + */ +enum aw_bin_err_val aw_sar_parsing_bin_file(struct aw_bin *bin) +{ + enum aw_bin_err_val ret; + int i; + + if (!bin) + return AW_BIN_ERROR_NULL_POINT; + bin->p_addr = bin->info.data; + bin->all_bin_parse_num = 0; + bin->multi_bin_parse_num = 0; + bin->single_bin_parse_num = 0; + + /* filling bins header info */ + ret = aw_check_bin_header_version(bin); + if (ret < 0) + return ret; + bin->p_addr = NULL; + + /* check bin header info */ + for (i = 0; i < bin->all_bin_parse_num; i++) { + /* check sum */ + ret = aw_check_sum(bin, i); + if (ret < 0) + return ret; + + /* check register num */ + if (bin->header_info[i].bin_data_type == DATA_TYPE_REGISTER) { + ret = aw_check_register_num_v1(bin, i); + if (ret < 0) + return ret; + /* check dsp reg num */ + } else if (bin->header_info[i].bin_data_type == DATA_TYPE_DSP_REG) { + ret = aw_check_dsp_reg_num_v1(bin, i); + if (ret < 0) + return ret; + /* check soc app num */ + } else if (bin->header_info[i].bin_data_type == DATA_TYPE_SOC_APP) { + ret = aw_check_soc_app_num_v1(bin, i); + if (ret < 0) + return ret; + } else { + bin->header_info[i].valid_data_len = bin->header_info[i].bin_data_len; + } + } + + return AW_BIN_ERROR_NONE; +} +/*********************************Parse bin file code end************************************/ + +/** + * @brief Calculate the second power + * + * @param cnt: ifrequency + * @return the second power + */ +uint32_t aw_sar_pow2(uint32_t cnt) +{ + uint32_t sum = 1; + uint32_t i; + + if (cnt == 0) { + sum = 1; + } else { + for (i = 0; i < cnt; i++) + sum *= 2; + } + + return sum; +} + +/** + * @brief Calculate the second power + * + * @param *aw_bin: Information after parsing bin file + * @param *i2c: i2c client. + * @return 0 if init succeeded. + */ +int32_t aw_sar_load_reg(struct aw_bin *aw_bin, struct i2c_client *i2c) +{ + uint32_t start_addr = aw_bin->header_info[0].valid_data_addr; + uint16_t reg_addr; + uint32_t reg_data; + int32_t ret; + uint32_t i; + + for (i = 0; i < aw_bin->header_info[0].valid_data_len; i += 6, start_addr += 6) { + reg_addr = (aw_bin->info.data[start_addr]) | + aw_bin->info.data[start_addr + 1] << OFFSET_BIT_8; + reg_data = aw_bin->info.data[start_addr + 2] | + (aw_bin->info.data[start_addr + 3] << OFFSET_BIT_8) | + (aw_bin->info.data[start_addr + 4] << OFFSET_BIT_16) | + (aw_bin->info.data[start_addr + 5] << OFFSET_BIT_24); + + ret = aw_sar_i2c_write(i2c, reg_addr, reg_data); + if (ret < 0) { + dev_err(&i2c->dev, "i2c write err"); + return ret; + } + } + + return 0; +} + +void aw_sar_delay_ms(uint32_t ms) +{ + mdelay(ms); +} + diff --git a/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.h b/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.h new file mode 100644 index 000000000000..6f35193f2aee --- /dev/null +++ b/drivers/input/misc/aw_sar/comm/aw_sar_comm_interface.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _AW_SAR_PLAT_HW_INTERFACE_H_ +#define _AW_SAR_PLAT_HW_INTERFACE_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum aw_sar_chip_list_t { + AW_SAR_NONE_CHECK_CHIP, + + SAR_AW9610X = 1 << 1, + SAR_AW9610XA = 1 << 2, + + SAR_AW96303 = 1 << 6, + SAR_AW96305 = 1 << 7, + SAR_AW96308 = 1 << 8, + SAR_AW96310 = 1 << 9, + SAR_AW96312 = 1 << 10, +}; + +enum AW_SAR_UPDATE_FW_MODE { + PROT_UPDATE_FW, + REG_UPDATE_FW, +}; + +#ifndef AW_TRUE +#define AW_TRUE (1) +#endif + +#ifndef AW_FALSE +#define AW_FALSE (0) +#endif + +#define AW_ERR_IRQ_INIT_OVER (0xAA) + +enum aw_sar_rst_val { + AW_OK, + AW_BIN_PARA_INVALID, + AW_PROT_UPDATE_ERR, + AW_REG_LOAD_ERR, +}; + +#ifndef OFFSET_BIT_0 +#define OFFSET_BIT_0 (0) +#endif + +#ifndef OFFSET_BIT_8 +#define OFFSET_BIT_8 (8) +#endif + +#ifndef OFFSET_BIT_16 +#define OFFSET_BIT_16 (16) +#endif + +#ifndef OFFSET_BIT_24 +#define OFFSET_BIT_24 (24) +#endif + +#define AW_SAR_GET_32_DATA(w, x, y, z) ((unsigned int)(((w) << 24) | ((x) << 16) | ((y) << 8) | (z))) + +enum AW_SAR_HOST_IRQ_STAT { + IRQ_ENABLE, + IRQ_DISABLE, +}; + +#define AW_SAR_BIN_NUM_MAX 100 + +enum aw_bin_err_val { + AW_BIN_ERROR_NONE = 0, + AW_BIN_ERROR_HEADER_VERSION = -1, + AW_BIN_ERROR_DATA_TYPE = -2, + AW_BIN_ERROR_SUM_OR_DATA_LEN = -3, + AW_BIN_ERROR_DATA_VERSION = -4, + AW_BIN_ERROR_REGISTER_NUM = -5, + AW_BIN_ERROR_DSP_REG_NUM = -6, + AW_BIN_ERROR_SOC_APP_NUM = -7, + AW_BIN_ERROR_NULL_POINT = -8, +}; + +/** + * struct bin_header_info - + * @header_len: Frame header length + * @check_sum: Frame header information-Checksum + * @header_ver: Frame header information-Frame header version + * @bin_data_type: Frame header information-Data type + * @bin_data_ver: Frame header information-Data version + * @bin_data_len: Frame header information-Data length + * @ui_ver: Frame header information-ui version + * @chip_type: Frame header information-chip type + * @reg_byte_len: Frame header information-reg byte len + * @data_byte_len: Frame header information-data byte len + * @device_addr: Frame header information-device addr + * @valid_data_len: Length of valid data obtained after parsing + * @valid_data_addr: The offset address of the valid data obtained + * after parsing relative to info + * @reg_num: The number of registers obtained after parsing + * @reg_data_byte_len: The byte length of the register obtained after parsing + * @download_addr: The starting address or download address obtained after parsing + * @app_version: The software version number obtained after parsing + */ +struct bin_header_info { + unsigned int header_len; + unsigned int check_sum; + unsigned int header_ver; + unsigned int bin_data_type; + unsigned int bin_data_ver; + unsigned int bin_data_len; + unsigned int ui_ver; + unsigned char chip_type[8]; + unsigned int reg_byte_len; + unsigned int data_byte_len; + unsigned int device_addr; + unsigned int valid_data_len; + unsigned int valid_data_addr; + unsigned int reg_num; + unsigned int reg_data_byte_len; + unsigned int download_addr; + unsigned int app_version; +}; + +/** + * struct bin_container - + * @len: The size of the bin file obtained from the firmware + * @data: Store the bin file obtained from the firmware + */ +struct bin_container { + unsigned int len; + unsigned char data[]; +}; + +/** + * struct aw_bin - + * @p_addr: Offset pointer (backward offset pointer to obtain frame header information and + * important information) + * @all_bin_parse_num: The number of all bin files + * @multi_bin_parse_num: The number of single bin files + * @single_bin_parse_num: The number of multiple bin files + * @header_info: Frame header information and + * other important data obtained after parsing + * @info: Obtained bin file data that needs to be parsed + */ +struct aw_bin { + char *p_addr; + unsigned int all_bin_parse_num; + unsigned int multi_bin_parse_num; + unsigned int single_bin_parse_num; + struct bin_header_info header_info[AW_SAR_BIN_NUM_MAX]; + struct bin_container info; +}; + +//I2C communication API +extern int32_t aw_sar_i2c_read(struct i2c_client *i2c, uint16_t reg_addr16, uint32_t *reg_data32); +extern int32_t aw_sar_i2c_write(struct i2c_client *i2c, uint16_t reg_addr16, uint32_t reg_data32); +extern int32_t aw_sar_i2c_write_bits(struct i2c_client *i2c, uint16_t reg_addr16, + uint32_t mask, uint32_t val); +extern int32_t aw_sar_i2c_write_seq(struct i2c_client *i2c, uint8_t *tr_data, uint16_t len); +extern int32_t aw_sar_i2c_read_seq(struct i2c_client *i2c, uint8_t *addr, + uint8_t addr_len, uint8_t *data, uint16_t data_len); +extern void aw_sar_delay_ms(uint32_t ms); + +extern enum aw_bin_err_val aw_sar_parsing_bin_file(struct aw_bin *bin); +extern uint32_t aw_sar_pow2(uint32_t cnt); +extern int32_t aw_sar_load_reg(struct aw_bin *aw_bin, struct i2c_client *i2c); + +#endif diff --git a/drivers/input/misc/aw_sar/comm/aw_sar_type.h b/drivers/input/misc/aw_sar/comm/aw_sar_type.h new file mode 100644 index 000000000000..8f217f8e21dd --- /dev/null +++ b/drivers/input/misc/aw_sar/comm/aw_sar_type.h @@ -0,0 +1,396 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _SAR_TYPE_H_ +#define _SAR_TYPE_H_ + +#include "aw_sar_comm_interface.h" + +typedef int32_t (*aw_sar_chip_other_operation_t)(void *data); +typedef void (*aw_sar_chip_other_opera_free_t)(void *data); + +enum aw_i2c_flags { + AW_SAR_I2C_WR, + AW_SAR_I2C_RD, + AW_SAR_PACKAGE_RD, +}; + +enum sar_health_check { + AW_SAR_HEALTHY = 0, + AW_SAR_UNHEALTHY = 1, +}; +typedef int32_t (*aw_sar_bin_opera_t)(struct aw_bin *aw_bin, void *load_bin_para); +typedef int32_t (*aw_sar_bin_load_fail_opera_t)(struct aw_bin *aw_bin, void *load_bin_para); + +struct aw_sar_get_chip_info_t { + void (*p_get_chip_info_node_fn)(void *data, char *buf, ssize_t *p_len); +}; + +struct aw_sar_load_bin_t { + const uint8_t *bin_name; + aw_sar_bin_opera_t bin_opera_func; + aw_sar_bin_load_fail_opera_t bin_load_fail_opera; + + void (*p_get_prot_update_fw_node_fn)(void *data, char *buf, ssize_t *p_len); + + /*Perform different operations to update parameters*/ + int32_t (*p_update_fn)(void *data); +}; + +struct aw_sar_reg_data { + unsigned char rw; + unsigned short reg; +}; + +struct aw_sar_awrw_t { + ssize_t (*p_set_awrw_node_fn)(void *data, const char *buf, size_t count); + ssize_t (*p_get_awrw_node_fn)(void *data, char *buf); +}; + +struct aw_sar_reg_list_t { + uint8_t reg_none_access; + uint8_t reg_rd_access; + uint8_t reg_wd_access; + const struct aw_sar_reg_data *reg_perm; + uint32_t reg_num; +}; + +typedef void (*aw_sar_update_work_t)(struct work_struct *work); +struct aw_sar_update_static_t { + aw_sar_update_work_t update_work_func; + uint32_t delay_ms; +}; + +typedef irqreturn_t (*aw_sar_irq_t)(int irq, void *data); +typedef uint32_t (*sar_rc_irqscr_t)(void *i2c); +/* + * If the return value is 1, there is an initialization completion interrupt; + * if the return value is 0, there is no + */ +typedef uint32_t (*aw_sar_is_init_over_irq)(uint32_t irq_status); +typedef void (*aw_sar_irq_spec_handler_t)(uint32_t irq_status, void *data); + +struct aw_sar_check_chipid_t { + /*Read chipid and check chipid, Must be implemented externally*/ + int32_t (*p_check_chipid_fn)(void *data); +}; + +struct aw_sar_irq_init_t { + unsigned long flags; + unsigned long irq_flags; + irq_handler_t handler; + irq_handler_t thread_fn; + /*Interrupt processing parameters*/ + sar_rc_irqscr_t rc_irq_fn; + //aw_sar_is_init_over_irq is_init_over_irq_fn; + aw_sar_irq_spec_handler_t irq_spec_handler_fn; + + /*Use a different initialization interrupt to initialize the operation*/ + int32_t (*p_irq_init_fn)(void *data); + /*Release interrupt resource*/ +// void const (*p_irq_deinit_fn)(void *data); + int (*p_irq_deinit_fn)(void *data); +}; + +struct aw_sar_pm_t { + uint32_t suspend_set_mode; + uint32_t resume_set_mode; + uint32_t shutdown_set_mode; + //system api + int32_t (*p_suspend_fn)(void *data); + int32_t (*p_resume_fn)(void *data); + int32_t (*p_shutdown_fn)(void *data); +}; + +struct aw_sar_chip_mode_t { + uint32_t init_mode; + uint32_t active; + uint32_t pre_init_mode; +}; + +struct aw_sar_regulator_config_t { + //Note that "_sar_num" after VCC name is defined by SAR C auto add + const uint8_t *vcc_name; + int32_t min_uV; + int32_t max_uV; +}; + +struct aw_channels_info { + uint16_t used; + uint32_t last_channel_info; + struct input_dev *input; + uint8_t name[20]; +}; + +struct aw_sar_dts_info { + uint32_t sar_num; + int32_t irq_gpio; + uint32_t channel_use_flag; + bool use_regulator_flag; + bool use_inter_pull_up; + bool use_pm; + bool update_fw_flag; + bool use_plug_cail_flag; + bool monitor_esd_flag; +}; + +struct aw_sar_irq_init_comm_t { + int32_t to_irq; + uint8_t host_irq_stat; + void *data; + uint8_t label[30]; + uint8_t dev_id[30]; +}; + +struct aw_sar_load_bin_comm_t { + uint8_t bin_name[30]; + uint32_t bin_data_ver; + aw_sar_bin_opera_t bin_opera_func; + aw_sar_bin_load_fail_opera_t bin_load_fail_opera_func; +}; + +struct aw_awrw_info { + uint8_t rw_flag; + uint8_t addr_len; + uint8_t data_len; + uint8_t reg_num; + uint32_t i2c_tranfar_data_len; + uint8_t *p_i2c_tranfar_data; +}; + +/****************mode set start******************/ +typedef void (*sar_enable_clock_t)(void *i2c); +typedef void (*sar_operation_irq_t)(int to_irq); +typedef void (*sar_mode_update_t)(void *i2c); + +struct aw_sar_mode_switch_ops { + sar_enable_clock_t enable_clock; + sar_rc_irqscr_t rc_irqscr; + sar_mode_update_t mode_update; +}; + +struct aw_sar_chip_mode { + uint8_t curr_mode; + uint8_t last_mode; +}; + +struct aw_sar_mode_set_t { + uint8_t chip_id; + struct aw_sar_chip_mode chip_mode; + struct aw_sar_mode_switch_ops mode_switch_ops; +}; + +struct aw_sar_mode_t { + const struct aw_sar_mode_set_t *mode_set_arr; + uint8_t mode_set_arr_len; + ssize_t (*p_set_mode_node_fn)(void *data, uint8_t curr_mode); + ssize_t (*p_get_mode_node_fn)(void *data, char *buf); +}; +/********************mode set end****************/ + +struct aw_sar_init_over_irq_t { + int16_t wait_times; + uint8_t daley_step; + uint32_t reg_irqsrc; + uint32_t irq_offset_bit; + uint32_t irq_mask; + uint32_t irq_flag; + /* + * Perform different verification initialization + * to complete the interrupt operation + */ + int32_t (*p_check_init_over_irq_fn)(void *data); + /* + * When initialization fails, get the corresponding error type and + * apply it to the chip with flash + */ + int32_t (*p_get_err_type_fn)(void *data); +}; + +struct aw_sar_soft_rst_t { + uint16_t reg_rst; + uint32_t reg_rst_val; + uint32_t delay_ms; + /*Perform different soft reset operations*/ + int32_t (*p_soft_reset_fn)(void *data); +}; + +struct aw_sar_aot_t { + uint32_t aot_reg; + uint32_t aot_mask; + uint32_t aot_flag; + ssize_t (*p_set_aot_node_fn)(void *data); +}; + +struct aw_sar_diff_t { + uint16_t diff0_reg; + uint16_t diff_step; + //Data format:S21.10, Floating point types generally need to be removed + uint32_t rm_float; + ssize_t (*p_get_diff_node_fn)(void *data, char *buf); +}; + +struct aw_sar_offset_t { + ssize_t (*p_get_offset_node_fn)(void *data, char *buf); +}; + +struct aw_sar_pinctrl { + struct pinctrl *pinctrl; + struct pinctrl_state *default_sta; + struct pinctrl_state *int_out_high; + struct pinctrl_state *int_out_low; +}; + +//update reg node +struct aw_sar_para_load_t { + const uint32_t *reg_arr; + uint32_t reg_arr_len; +}; + +struct aw_sar_platform_config { + /*The chip needs to parse more DTS contents for addition*/ + int32_t (*p_add_parse_dts_fn)(void *data); + + const struct aw_sar_regulator_config_t *p_regulator_config; + + /*The chip needs to add more nodes*/ + int32_t (*p_add_node_create_fn)(void *data); + /*Release the added node*/ + int32_t (*p_add_node_free_fn)(void *data); + + /*Use a different initialization interrupt to initialize the operation*/ + int32_t (*p_input_init_fn)(void *data); + /*Release input resource*/ + int32_t (*p_input_deinit_fn)(void *data); + + //The parameters passed in are required for interrupt initialization + const struct aw_sar_irq_init_t *p_irq_init; + + //The chip is set to different modes in different power management interfaces + const struct aw_sar_pm_t *p_pm_chip_mode; +}; + +struct aw_sar_power_on_prox_detection_t { + //en_flag is true enable + void (*p_power_on_prox_detection_en_fn)(void *data, uint8_t en_flag); + uint32_t irq_en_cali_bit; + uint8_t power_on_prox_en_flag; +}; + + +/*Parameter passed in by different SAR sensors. + *It must be implemented in each sensor code. + *If it is not necessary that some members can be assigned null, + *the corresponding function will not be implemented + */ +struct aw_sar_chip_config { + uint8_t ch_num_max; //Number of channels of the chip + + //Chip related platform content configuration + const struct aw_sar_platform_config *p_platform_config; + //Parameters required for verification of chipid + const struct aw_sar_check_chipid_t *p_check_chipid; + //Parameters required for soft reset + const struct aw_sar_soft_rst_t *p_soft_rst; + //Verify the parameters required to initialize a complete interrupt + const struct aw_sar_init_over_irq_t *p_init_over_irq; + //Parameters required for load boot bin file, + //If the chip does not have flash, please ignore and assign the value to null + const struct aw_sar_load_bin_t *p_fw_bin; + //Parameters required for load register bin file + const struct aw_sar_load_bin_t *p_reg_bin; + //The mode set before and after the initialization of the chip + const struct aw_sar_chip_mode_t *p_chip_mode; + + //Node usage parameters + //Register permission table + const struct aw_sar_reg_list_t *p_reg_list; + //Default register table + const struct aw_sar_para_load_t *p_reg_arr; + //Parameters required for set Auto-Offset-Tuning(aot) + const struct aw_sar_aot_t *p_aot; + //Parameters required for get chip diff val + const struct aw_sar_diff_t *p_diff; + //Parameters required for get chip offset val + const struct aw_sar_offset_t *p_offset; + //Set the parameters of different working modes of the chip + const struct aw_sar_mode_t *p_mode; + //Upgrading firmware using the debug node protocol + const struct aw_sar_load_bin_t *p_prox_fw; + //Upgrading firmware using the debug node reg + const struct aw_sar_load_bin_t *p_reg_fw; + //Obtain the necessary information of the chip + const struct aw_sar_get_chip_info_t *p_get_chip_info; + //Continuous read/write register interface + const struct aw_sar_awrw_t *p_aw_sar_awrw; + //Parameters required for load boot bin file, + //If the chip does not have flash, please ignore and assign the value to null + const struct aw_sar_load_bin_t *p_boot_bin; + + /*Other operations during initialization, Add according to different usage*/ + aw_sar_chip_other_operation_t p_other_operation; + /*If requested by resources, please release*/ + aw_sar_chip_other_opera_free_t p_other_opera_free; + + const struct aw_sar_power_on_prox_detection_t *power_on_prox_detection; +}; + +struct aw_sar { + struct i2c_client *i2c; + struct device *dev; + struct regulator *vcc; + struct delayed_work update_work; + //Set pin pull-up mode + struct aw_sar_pinctrl pinctrl; + /* eds work */ + struct delayed_work monitor_work; + struct workqueue_struct *monitor_wq; + + uint8_t chip_type; + uint8_t chip_name[20]; + + bool power_enable; + bool fw_fail_flag; + uint8_t last_mode; + + /*handler_anomalies*/ + uint8_t fault_flag; + uint8_t driver_code_initover_flag; + /*handler_anomalies*/ + + uint8_t ret_val; + uint8_t curr_use_driver_type; + int32_t prot_update_state; + + uint8_t aot_irq_num; + uint8_t enter_irq_handle_num; + uint8_t exit_power_on_prox_detection; + + struct work_struct ps_notify_work; + struct notifier_block ps_notif; + bool ps_is_present; + + //Parameters related to platform logic + struct aw_sar_dts_info dts_info; + struct aw_sar_load_bin_comm_t load_bin; + struct aw_sar_irq_init_comm_t irq_init; + struct aw_awrw_info awrw_info; + struct aw_channels_info *channels_arr; + + //Private arguments required for public functions + const struct aw_sar_chip_config *p_sar_para; + //Private arguments required for private functions + void *priv_data; +}; + +//Determine whether the chip exists by verifying chipid +typedef int32_t (*aw_sar_who_am_i_t)(void *data); +typedef int32_t (*aw_sar_chip_init_t)(struct aw_sar *p_sar); +typedef void (*aw_sar_chip_deinit_t)(struct aw_sar *p_sar); + +struct aw_sar_driver_type { + uint8_t driver_type; + aw_sar_who_am_i_t p_who_am_i; + aw_sar_chip_init_t p_chip_init; + aw_sar_chip_deinit_t p_chip_deinit; +}; + +#endif From patchwork Wed May 29 13:06:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangshuaijie@awinic.com X-Patchwork-Id: 13678821 Received: from out198-14.us.a.mail.aliyun.com (out198-14.us.a.mail.aliyun.com [47.90.198.14]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFD7017C6A; Wed, 29 May 2024 13:06:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.14 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988019; cv=none; b=TUuYNh+LybYiDWnZJRnRLxaluchcJqDsDbKXOtKyHFGqn53+XPn1V4SlfirJg3FPqErEdYDiNj6oXGCCe+3+IMdcBz/awv3TRvdJ92iBLKld2tkrtR4mB6RWk4e0JHDrbmWDLMgyimc+ntjAWWahZNTwZVaN4tuYeuF4YMNCe8A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988019; c=relaxed/simple; bh=zr+TIIDKulpPZjWtTCvrfvomP9BCJEdzqifIwI55UmQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TU5vn2PBw7HHmKGNh9rPoydXHF57AsoJxtiVCWceRqnumkSkuosDFHS8i3J8rtA/WN2QaR9AjVQ/TSYNBPYX7IsPM5i/PYnjUHSDox8vqF89/w4d+/Wrci3rH2BfeIWnIxpM4SCGOZ+LxdeNuDNJxuOLmDjcBqHmC9NAPo2VTNM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com; spf=pass smtp.mailfrom=awinic.com; arc=none smtp.client-ip=47.90.198.14 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=awinic.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.187612-0.000368851-0.812019;FP=0|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033070021165;MF=wangshuaijie@awinic.com;NM=1;PH=DS;RN=11;RT=11;SR=0;TI=SMTPD_---.XqPpuI1_1716987993; Received: from awinic..(mailfrom:wangshuaijie@awinic.com fp:SMTPD_---.XqPpuI1_1716987993) by smtp.aliyun-inc.com; Wed, 29 May 2024 21:06:34 +0800 From: wangshuaijie@awinic.com To: dmitry.torokhov@gmail.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jeff@labundy.com, linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: wangshuaijie@awinic.com, liweilei@awinic.com, kangjiajun@awinic.com Subject: [PATCH V1 3/5] Add aw9610x series related interfaces to the aw_sar driver. Date: Wed, 29 May 2024 13:06:06 +0000 Message-ID: <20240529130608.783624-4-wangshuaijie@awinic.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240529130608.783624-1-wangshuaijie@awinic.com> References: <20240529130608.783624-1-wangshuaijie@awinic.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: shuaijie wang Signed-off-by: shuaijie wang --- drivers/input/misc/aw_sar/aw9610x/aw9610x.c | 884 ++++++++++++++++++++ drivers/input/misc/aw_sar/aw9610x/aw9610x.h | 324 +++++++ 2 files changed, 1208 insertions(+) create mode 100644 drivers/input/misc/aw_sar/aw9610x/aw9610x.c create mode 100644 drivers/input/misc/aw_sar/aw9610x/aw9610x.h diff --git a/drivers/input/misc/aw_sar/aw9610x/aw9610x.c b/drivers/input/misc/aw_sar/aw9610x/aw9610x.c new file mode 100644 index 000000000000..a7745649813f --- /dev/null +++ b/drivers/input/misc/aw_sar/aw9610x/aw9610x.c @@ -0,0 +1,884 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AWINIC sar sensor driver (aw9610x) + * + * Author: Shuaijie Wang + * + * Copyright (c) 2024 awinic Technology CO., LTD + */ +#include "aw9610x.h" + +#define AW9610X_I2C_NAME "aw9610x_sar" + +static struct aw_sar *g_aw_sar; + +static int32_t aw9610x_baseline_filter(struct aw_sar *p_sar) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t status0; + uint32_t status1; + uint8_t i; + + aw_sar_i2c_read(p_sar->i2c, REG_STAT1, &status1); + aw_sar_i2c_read(p_sar->i2c, REG_STAT0, &status0); + + for (i = 0; i < AW9610X_CHANNEL_MAX; i++) { + if (((status1 >> i) & 0x01) == 1) { + if (aw9610x->satu_flag[i] == 0) { + aw_sar_i2c_read(p_sar->i2c, REG_BLFILT_CH0 + i * AW_CL1SPE_DEAL_OS, + &aw9610x->satu_data[i]); + aw_sar_i2c_write(p_sar->i2c, REG_BLFILT_CH0 + i * AW_CL1SPE_DEAL_OS, + ((aw9610x->satu_data[i] | 0x1fc) & 0x3fffffff)); + aw9610x->satu_flag[i] = 1; + } + } else if (((status1 >> i) & 0x01) == 0) { + if (aw9610x->satu_flag[i] == 1) { + if (((status0 >> (i + 24)) & 0x01) == 0) { + aw_sar_i2c_write(p_sar->i2c, + REG_BLFILT_CH0 + i * AW_CL1SPE_DEAL_OS, + aw9610x->satu_data[i]); + aw9610x->satu_flag[i] = 0; + } + } + } + } + + return 0; +} + +static void aw9610x_saturat_release_handle(struct aw_sar *p_sar) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t satu_irq; + uint32_t status0; + uint8_t i; + + satu_irq = (aw9610x->irq_status >> 7) & 0x01; + if (satu_irq == 1) { + aw9610x_baseline_filter(p_sar); + } else { + aw_sar_i2c_read(p_sar->i2c, REG_STAT0, &status0); + for (i = 0; i < AW9610X_CHANNEL_MAX; i++) { + if (aw9610x->satu_flag[i] == 1) { + if (((status0 >> (i + 24)) & 0x01) == 0) { + aw_sar_i2c_write(p_sar->i2c, + REG_BLFILT_CH0 + i * AW_CL1SPE_DEAL_OS, + aw9610x->satu_data[i]); + aw9610x->satu_flag[i] = 0; + } + } + } + } +} + +static void aw9610x_irq_handle(struct aw_sar *p_sar) +{ + uint32_t curr_status_val; + uint32_t curr_status; + uint8_t i; + + aw_sar_i2c_read(p_sar->i2c, REG_STAT0, &curr_status_val); + if (!p_sar->channels_arr) { + dev_err(p_sar->dev, "input err!!!"); + return; + } + + for (i = 0; i < AW9610X_CHANNEL_MAX; i++) { + curr_status = + (((uint8_t)(curr_status_val >> (24 + i)) & 0x1)) +#ifdef AW_INPUT_TRIGGER_TH1 + | (((uint8_t)(curr_status_val >> (16 + i)) & 0x1) << 1) +#endif +#ifdef AW_INPUT_TRIGGER_TH2 + | (((uint8_t)(curr_status_val >> (8 + i)) & 0x1) << 2) +#endif +#ifdef AW_INPUT_TRIGGER_TH3 + | (((uint8_t)(curr_status_val >> (i)) & 0x1) << 3) +#endif + ; + + if (p_sar->channels_arr[i].used == AW_FALSE) + continue; + + if (p_sar->channels_arr[i].last_channel_info == curr_status) + continue; + + switch (curr_status) { + case AW9610X_FAR: + input_report_abs(p_sar->channels_arr[i].input, ABS_DISTANCE, 0); + break; + case AW9610X_TRIGGER_TH0: + input_report_abs(p_sar->channels_arr[i].input, ABS_DISTANCE, 1); + break; +#ifdef AW_INPUT_TRIGGER_TH1 + case AW9610X_TRIGGER_TH1: + input_report_abs(p_sar->channels_arr[i].input, ABS_DISTANCE, 2); + break; +#endif +#ifdef AW_INPUT_TRIGGER_TH2 + case AW9610X_TRIGGER_TH2: + input_report_abs(p_sar->channels_arr[i].input, ABS_DISTANCE, 3); + break; +#endif +#ifdef AW_INPUT_TRIGGER_TH3 + case AW9610X_TRIGGER_TH3: + input_report_abs(p_sar->channels_arr[i].input, ABS_DISTANCE, 4); + break; +#endif + default: + dev_err(p_sar->dev, "error abs distance"); + return; + } + input_sync(p_sar->channels_arr[i].input); + + p_sar->channels_arr[i].last_channel_info = curr_status; + } +} + +static void aw9610x_version_aw9610x_private(struct aw_sar *p_sar) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + + if (aw9610x->satu_release == AW9610X_FUNC_ON) + aw9610x_saturat_release_handle(p_sar); +} + +static void aw9610x_irq_handle_func(uint32_t irq_status, void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + + dev_info(p_sar->dev, "IRQSRC = 0x%x", irq_status); + + switch (aw9610x->vers) { + case AW9610X: + aw9610x_version_aw9610x_private(p_sar); + break; + case AW9610XA: + break; + default: + break; + } + + aw9610x_irq_handle(p_sar); +} + +int32_t aw9610x_check_chipid(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t reg_val; + int32_t ret; + + if (!p_sar) + return -EINVAL; + + ret = aw_sar_i2c_read(p_sar->i2c, REG_CHIPID, ®_val); + if (ret < 0) { + dev_err(p_sar->dev, "read CHIP ID failed: %d", ret); + return ret; + } + reg_val = reg_val >> 16; + + if (reg_val != AW9610X_CHIP_ID) { + dev_err(p_sar->dev, "unsupport dev, chipid is (0x%04x)", reg_val); + return -EINVAL; + } + dev_info(p_sar->dev, "aw9610x detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, "AW9610X", 8); + + return 0; +} + +static const struct aw_sar_check_chipid_t g_aw9610x_check_chipid = { + .p_check_chipid_fn = aw9610x_check_chipid, +}; + +static ssize_t aw9610x_operation_mode_get(void *data, char *buf) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + ssize_t len = 0; + + if (p_sar->last_mode == AW9610X_ACTIVE_MODE) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Active\n"); + else if (p_sar->last_mode == AW9610X_SLEEP_MODE) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Sleep\n"); + else if ((p_sar->last_mode == AW9610X_DEEPSLEEP_MODE) && (aw9610x->vers == AW9610XA)) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: DeepSleep\n"); + else + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Unconfirmed\n"); + + return len; +} + +static void aw9610x_chip_info_get(void *data, char *buf, ssize_t *p_len) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t reg_data; + + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, + "sar%u\n", p_sar->dts_info.sar_num); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "The driver supports UI\n"); + + aw_sar_i2c_read(p_sar->i2c, REG_CHIPID, ®_data); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "chipid is 0x%08x\n", reg_data); + + aw_sar_i2c_read(p_sar->i2c, REG_IRQEN, ®_data); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "REG_HOSTIRQEN is 0x%08x\n", reg_data); + + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, + "chip_name:%s bin_prase_chip_name:%s\n", + aw9610x->chip_name, aw9610x->chip_type); +} + +static const struct aw_sar_get_chip_info_t g_aw9610x_get_chip_info = { + .p_get_chip_info_node_fn = aw9610x_chip_info_get, +}; + +static void aw9610x_reg_version_comp(struct aw_sar *p_sar, struct aw_bin *aw_bin) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t blfilt1_data; + uint32_t blfilt1_tmp; + uint8_t i; + + if ((aw9610x->chip_name[7] == 'A') && + (aw_bin->header_info[0].chip_type[7] == '\0')) { + for (i = 0; i < 6; i++) { + aw_sar_i2c_read(p_sar->i2c, REG_BLFILT_CH0 + (0x3c * i), &blfilt1_data); + blfilt1_tmp = (blfilt1_data >> 25) & 0x1; + if (blfilt1_tmp == 1) + aw_sar_i2c_write_bits(p_sar->i2c, REG_BLRSTRNG_CH0 + (0x3c * i), + ~(0x3f), 1 << i); + } + } +} + +static int32_t aw9610x_load_reg_bin(struct aw_bin *aw_bin, void *load_bin_para) +{ + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + int32_t ret; + + dev_info(p_sar->dev, "reg chip name: %s, soc chip name: %s, len = %d", + p_sar->chip_name, aw_bin->header_info[0].chip_type, aw_bin->info.len); + + snprintf(aw9610x->chip_type, sizeof(aw9610x->chip_type), "%s", + aw_bin->header_info[0].chip_type); + ret = strncmp(aw9610x->chip_name, aw_bin->header_info[0].chip_type, + sizeof(aw_bin->header_info[0].chip_type)); + if (ret != 0) + dev_err(p_sar->dev, "load_binname(%s) incompatible with chip type(%s)", + p_sar->chip_name, aw_bin->header_info[0].chip_type); + + p_sar->load_bin.bin_data_ver = aw_bin->header_info[0].bin_data_ver; + + ret = aw_sar_load_reg(aw_bin, p_sar->i2c); + aw9610x_reg_version_comp(p_sar, aw_bin); + + return ret; +} + +static ssize_t aw9610x_get_self_cap_offset(void *data, char *buf) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint8_t temp_data[20] = { 0 }; + uint32_t coff_data_int; + uint32_t coff_data_dec; + uint32_t coff_data; + uint32_t reg_val; + ssize_t len = 0; + uint8_t i; + + for (i = 0; i < AW9610X_CHANNEL_MAX; i++) { + aw_sar_i2c_read(p_sar->i2c, + REG_AFECFG1_CH0 + i * AW_CL1SPE_CALI_OS, ®_val); + coff_data = (reg_val >> 24) * 900 + ((reg_val >> 16) & 0xff) * 13; + coff_data_int = coff_data / 1000; + coff_data_dec = coff_data % 1000; + snprintf(temp_data, sizeof(temp_data), "%u.%u", coff_data_int, coff_data_dec); + len += snprintf(buf+len, PAGE_SIZE-len, "PARASITIC_DATA_CH%d = %s pf\n", + i, temp_data); + } + + return len; +} + +static const struct aw_sar_offset_t g_aw9610x_offset = { + .p_get_offset_node_fn = aw9610x_get_self_cap_offset, +}; + +static uint32_t attr_buf[] = { + 8, 10, + 9, 100, + 10, 1000, +}; + +static void aw9610x_addrblock_load(struct aw_sar *p_sar, const char *buf) +{ + struct aw9610x *aw9610x = p_sar->priv_data; + uint8_t addr_bytes = aw9610x->aw_i2c_package.addr_bytes; + uint8_t reg_num = aw9610x->aw_i2c_package.reg_num; + uint32_t addrbuf[4] = { 0 }; + uint8_t temp_buf[2] = { 0 }; + uint32_t i; + + for (i = 0; i < addr_bytes; i++) { + if (reg_num < attr_buf[1]) { + temp_buf[0] = buf[attr_buf[0] + i * 5]; + temp_buf[1] = buf[attr_buf[0] + i * 5 + 1]; + } else if (reg_num >= attr_buf[1] && reg_num < attr_buf[3]) { + temp_buf[0] = buf[attr_buf[2] + i * 5]; + temp_buf[1] = buf[attr_buf[2] + i * 5 + 1]; + } else if (reg_num >= attr_buf[3] && reg_num < attr_buf[5]) { + temp_buf[0] = buf[attr_buf[4] + i * 5]; + temp_buf[1] = buf[attr_buf[4] + i * 5 + 1]; + } + if (sscanf(temp_buf, "%02x", &addrbuf[i]) == 1) + aw9610x->aw_i2c_package.init_addr[i] = (uint8_t)addrbuf[i]; + } +} + +static int32_t aw9610x_awrw_write_seq(struct aw_sar *p_sar) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint8_t addr_bytes = aw9610x->aw_i2c_package.addr_bytes; + uint8_t data_bytes = aw9610x->aw_i2c_package.data_bytes; + uint8_t reg_num = aw9610x->aw_i2c_package.reg_num; + uint8_t *p_reg_data = aw9610x->aw_i2c_package.p_reg_data; + uint8_t w_buf[228]; + uint32_t msg_idx; + uint8_t msg_cnt; + + for (msg_idx = 0; msg_idx < addr_bytes; msg_idx++) + w_buf[msg_idx] = aw9610x->aw_i2c_package.init_addr[msg_idx]; + + msg_cnt = addr_bytes; + for (msg_idx = 0; msg_idx < data_bytes * reg_num; msg_idx++) { + w_buf[msg_cnt] = *p_reg_data++; + msg_cnt++; + } + + return aw_sar_i2c_write_seq(p_sar->i2c, w_buf, msg_cnt); +} + +static void aw9610x_datablock_load(struct aw_sar *p_sar, const char *buf) +{ + struct aw9610x *aw9610x = p_sar->priv_data; + uint8_t addr_bytes = aw9610x->aw_i2c_package.addr_bytes; + uint8_t data_bytes = aw9610x->aw_i2c_package.data_bytes; + uint8_t reg_num = aw9610x->aw_i2c_package.reg_num; + uint8_t reg_data[220] = { 0 }; + uint32_t databuf[220] = { 0 }; + uint8_t temp_buf[2] = { 0 }; + uint32_t i; + + for (i = 0; i < data_bytes * reg_num; i++) { + if (reg_num < attr_buf[1]) { + temp_buf[0] = buf[attr_buf[0] + (addr_bytes + i) * 5]; + temp_buf[1] = + buf[attr_buf[0] + (addr_bytes + i) * 5 + 1]; + } else if (reg_num >= attr_buf[1] && reg_num < attr_buf[3]) { + temp_buf[0] = buf[attr_buf[2] + (addr_bytes + i) * 5]; + temp_buf[1] = + buf[attr_buf[2] + (addr_bytes + i) * 5 + 1]; + } else if (reg_num >= attr_buf[3] && reg_num < attr_buf[5]) { + temp_buf[0] = buf[attr_buf[4] + (addr_bytes + i) * 5]; + temp_buf[1] = + buf[attr_buf[4] + (addr_bytes + i) * 5 + 1]; + } + sscanf(temp_buf, "%02x", &databuf[i]); + reg_data[i] = (uint8_t)databuf[i]; + } + aw9610x->aw_i2c_package.p_reg_data = reg_data; + aw9610x_awrw_write_seq(p_sar); +} + +static int32_t aw9610x_awrw_read_seq(struct aw_sar *p_sar, uint8_t *reg_data) +{ + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint8_t data_bytes = aw9610x->aw_i2c_package.data_bytes; + uint8_t addr_bytes = aw9610x->aw_i2c_package.addr_bytes; + uint8_t reg_num = aw9610x->aw_i2c_package.reg_num; + uint16_t msg_cnt = (uint16_t)(data_bytes * reg_num); + uint8_t w_buf[4]; + uint8_t buf[228]; + uint32_t msg_idx; + int32_t ret; + + for (msg_idx = 0; msg_idx < addr_bytes; msg_idx++) + w_buf[msg_idx] = aw9610x->aw_i2c_package.init_addr[msg_idx]; + + ret = aw_sar_i2c_read_seq(p_sar->i2c, w_buf, 2, (uint8_t *)buf, msg_cnt); + + for (msg_idx = 0; msg_idx < msg_cnt; msg_idx++) + reg_data[msg_idx] = buf[msg_idx]; + + return ret; +} + +static ssize_t aw9610x_awrw_get(void *data, char *buf) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint8_t data_bytes = aw9610x->aw_i2c_package.data_bytes; + uint8_t reg_num = aw9610x->aw_i2c_package.reg_num; + uint8_t reg_data[228] = { 0 }; + ssize_t len = 0; + uint8_t i; + + aw9610x_awrw_read_seq(p_sar, reg_data); + for (i = 0; i < reg_num * data_bytes; i++) + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", reg_data[i]); + + snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + + return len; +}; + +static ssize_t aw9610x_awrw_set(void *data, const char *buf, size_t count) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t datatype[3] = { 0 }; + + if (sscanf(buf, "%u %u %u", &datatype[0], &datatype[1], &datatype[2]) == 3) { + aw9610x->aw_i2c_package.addr_bytes = (uint8_t)datatype[0]; + aw9610x->aw_i2c_package.data_bytes = (uint8_t)datatype[1]; + aw9610x->aw_i2c_package.reg_num = (uint8_t)datatype[2]; + + aw9610x_addrblock_load(p_sar, buf); + if (count > 7 + 5 * aw9610x->aw_i2c_package.addr_bytes) + aw9610x_datablock_load(p_sar, buf); + } + + return count; +} + +static int32_t aw9610x_get_chip_version(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t firmvers; + uint32_t fw_ver; + int32_t ret; + + aw_sar_i2c_read(p_sar->i2c, REG_FWVER, &firmvers); + + ret = aw_sar_i2c_read(p_sar->i2c, REG_FWVER2, &fw_ver); + if (ret < 0) { + dev_err(p_sar->dev, "read REG_FWVER2 err!"); + return ret; + } + snprintf(aw9610x->chip_name, sizeof(aw9610x->chip_name), "AW9610X"); + p_sar->chip_type = AW_SAR_NONE_CHECK_CHIP; + + if (fw_ver == AW_CHIP_AW9610XA) { + aw9610x->vers = AW9610XA; + memcpy(aw9610x->chip_name + strlen(aw9610x->chip_name), "A", 2); + p_sar->chip_type = SAR_AW9610XA; + } else { + aw9610x->vers = AW9610X; + p_sar->chip_type = SAR_AW9610X; + aw9610x->chip_name[7] = '\0'; + } + dev_info(p_sar->dev, "the IC is = %s", aw9610x->chip_name); + + return 0; +} + +#ifdef AW9610X_TVS_ABNORMAL_CAIL +static ssize_t aw9610x_set_aot(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint32_t max_delay_ms = AW9610X_AOT_OVER_DELAY_MAX_MS; + uint32_t irqen_reg_val; + uint32_t reg_val_tmp; + uint32_t scan_over_cnt; + uint32_t scan_over_en; + uint32_t ch_en; + uint32_t i; + + //1. disable chip irq + aw_sar_i2c_read(p_sar->i2c, REG_IRQEN, &irqen_reg_val); + aw_sar_i2c_write(p_sar->i2c, REG_IRQEN, AW_REG_IRQEN_CLOSE); + + //2. aot cail + aw_sar_i2c_write_bits(p_sar->i2c, REG_SCANCTRL0, ~(AW9610X_AOT_MASK << AW9610X_AOT_BIT), + AW9610X_AOT_MASK << AW9610X_AOT_BIT); + // aot over + for (i = 0; i < max_delay_ms; i++) { + aw_sar_i2c_read(p_sar->i2c, REG_IRQSRC, ®_val_tmp); + if (((reg_val_tmp >> AW_REG_IRQSRC_AOT_OVER_BIT) & 0x01) == 1) + break; + mdelay(1); + } + + //3. scan 8 cnt over + aw_sar_i2c_read(p_sar->i2c, REG_SCANCTRL0, &ch_en); + aw_sar_i2c_read(p_sar->i2c, REG_CHINTEN, &scan_over_en); + if ((ch_en & AW9610X_AOT_MASK) != (scan_over_en & AW9610X_AOT_MASK)) + aw_sar_i2c_write_bits(p_sar->i2c, REG_CHINTEN, ~(AW9610X_AOT_MASK), + ch_en & (AW9610X_AOT_MASK)); + + for (scan_over_cnt = 0; scan_over_cnt < AW9610X_AOT_SCAN_OVER_CNT; scan_over_cnt++) { + for (i = 0; i < max_delay_ms; i++) { + aw_sar_i2c_read(p_sar->i2c, REG_IRQSRC, ®_val_tmp); + if (((reg_val_tmp >> REG_IRQSRC_SCAN_OVER_BIT) & 0x01) == 1) + break; + mdelay(1); + } + } + if ((ch_en & AW9610X_AOT_MASK) != (scan_over_en & AW9610X_AOT_MASK)) + aw_sar_i2c_write_bits(p_sar->i2c, REG_CHINTEN, ~(AW9610X_AOT_MASK), + ch_en & (AW9610X_AOT_MASK)); + + if (aw9610x->vers == AW9610XA) + //4. chip set sleep mode + aw_sar_i2c_write(p_sar->i2c, REG_CMD, AW9610X_SLEEP_MODE); + else if (aw9610x->vers == AW9610X) + aw_sar_i2c_write(p_sar->i2c, REG_CMD, AW9610X_DEEPSLEEP_MODE); + + for (i = 0; i < max_delay_ms; i++) { + aw_sar_i2c_read(p_sar->i2c, REG_WST, ®_val_tmp); + if ((reg_val_tmp & 0xFF) == REG_REG_WST_SLEEP_MODE) + break; + mdelay(1); + } + + //5. write baseline data + for (i = 0; i < AW9610X_CHANNEL_MAX; i++) { + aw_sar_i2c_read(p_sar->i2c, REG_COMP_CH0 + i * AW9610X_REG_OFFSET_STEP, + ®_val_tmp); + aw_sar_i2c_write(p_sar->i2c, REG_BASELINE_CH0 + i * AW9610X_REG_OFFSET_STEP, + reg_val_tmp); + } + + //6. chip set active, irq recovery + aw_sar_i2c_write(p_sar->i2c, REG_CMD, AW9610X_ACTIVE_MODE); + aw_sar_i2c_write(p_sar->i2c, REG_IRQEN, irqen_reg_val); + + return 0; +} +#else +static ssize_t aw9610x_set_aot(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + + aw_sar_i2c_write_bits(p_sar->i2c, REG_SCANCTRL0, ~(AW9610X_AOT_MASK << AW9610X_AOT_BIT), + (AW9610X_AOT_MASK) << AW9610X_AOT_BIT); + return 0; +} +#endif + +static const struct aw_sar_aot_t g_aw9610x_aot = { + .p_set_aot_node_fn = aw9610x_set_aot, +}; + +/**********************mode operation start*******************************/ +static void aw9610x_enable_clock(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_OSCEN, AW9610X_CPU_WORK_MASK); +} + +static uint32_t aw9610x_rc_irqscr(void *i2c) +{ + uint32_t val; + + aw_sar_i2c_read(i2c, REG_IRQSRC, &val); + + return val; +} + +//Note: TVS exceptions need to be handled after active +static void aw9610x_set_active_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW9610X_ACTIVE_MODE); + +#ifdef AW9610X_TVS_ABNORMAL_CAIL + if (g_aw_sar != NULL) + aw9610x_set_aot(g_aw_sar); +#endif +} + +static void aw9610x_set_sleep_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW9610X_SLEEP_MODE); +} + +static void aw9610x_set_deepsleep_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW9610X_DEEPSLEEP_MODE); +} + +static const struct aw_sar_mode_set_t g_aw9610x_mode_set[] = { + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_ACTIVE_MODE, + .last_mode = AW9610X_DEEPSLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = aw9610x_enable_clock, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_active_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_ACTIVE_MODE, + .last_mode = AW9610X_SLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_active_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_ACTIVE_MODE, + .last_mode = AW9610X_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_active_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_SLEEP_MODE, + .last_mode = AW9610X_DEEPSLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = aw9610x_enable_clock, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_sleep_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_SLEEP_MODE, + .last_mode = AW9610X_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_sleep_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA | SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_DEEPSLEEP_MODE, + .last_mode = AW9610X_SLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw9610x_set_deepsleep_cmd, + }, + }, + { + .chip_id = SAR_AW9610XA, + .chip_mode = { + .curr_mode = AW9610X_DEEPSLEEP_MODE, + .last_mode = AW9610X_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = aw9610x_rc_irqscr, + .mode_update = aw9610x_set_deepsleep_cmd, + }, + }, + { + .chip_id = SAR_AW9610X, + .chip_mode = { + .curr_mode = AW9610X_DEEPSLEEP_MODE, + .last_mode = AW9610X_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = NULL, + }, + }, +}; +/**********************mode operation end*******************************/ + +static const struct aw_sar_irq_init_t g_aw9610x_irq_init = { + .flags = GPIOF_DIR_IN | GPIOF_INIT_HIGH, + .irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + .handler = NULL, + .thread_fn = NULL, + .rc_irq_fn = aw9610x_rc_irqscr, + .irq_spec_handler_fn = aw9610x_irq_handle_func, +}; + +static const struct aw_sar_soft_rst_t g_aw9610x_soft_rst = { + .reg_rst = REG_RESET, + .reg_rst_val = 0, + .delay_ms = 20, +}; + +static const struct aw_sar_init_over_irq_t g_aw9610x_init_over_irq = { + .wait_times = 20, + .daley_step = 1, + .reg_irqsrc = REG_IRQSRC, + .irq_offset_bit = 0, + .irq_mask = 0x1, + .irq_flag = 0x1, +}; + +static const struct aw_sar_load_bin_t g_aw9610x_load_reg_bin = { + .bin_name = "aw9610x", + .bin_opera_func = aw9610x_load_reg_bin, + .p_update_fn = NULL, +}; + +static const struct aw_sar_para_load_t g_aw9610x_reg_arr_para = { + .reg_arr = aw9610x_reg_default, + .reg_arr_len = ARRAY_SIZE(aw9610x_reg_default), +}; + +static const struct aw_sar_diff_t g_aw9610x_diff = { + .diff0_reg = REG_DIFF_CH0, + .diff_step = 4, + .rm_float = AW9610x_DATA_PROCESS_FACTOR, +}; + +static const struct aw_sar_mode_t g_aw9610x_mode = { + .mode_set_arr = &g_aw9610x_mode_set[0], + .mode_set_arr_len = ARRAY_SIZE(g_aw9610x_mode_set), + .p_set_mode_node_fn = NULL, + .p_get_mode_node_fn = aw9610x_operation_mode_get, +}; + +static const struct aw_sar_reg_list_t g_aw9610x_reg_list = { + .reg_none_access = REG_NONE_ACCESS, + .reg_rd_access = REG_RD_ACCESS, + .reg_wd_access = REG_WR_ACCESS, + .reg_perm = (struct aw_sar_reg_data *)&g_aw9610x_reg_access[0], + .reg_num = ARRAY_SIZE(g_aw9610x_reg_access), +}; + +static const struct aw_sar_pm_t g_aw9610x_pm_chip_mode = { + .suspend_set_mode = AW9610X_SLEEP_MODE, + .resume_set_mode = AW9610X_ACTIVE_MODE, + .shutdown_set_mode = AW9610X_SLEEP_MODE, +}; + +static const struct aw_sar_chip_mode_t g_aw9610x_chip_mode = { + .init_mode = AW9610X_ACTIVE_MODE, + .active = AW9610X_ACTIVE_MODE, + .pre_init_mode = AW9610X_SLEEP_MODE, +}; + +static const struct aw_sar_regulator_config_t g_regulator_config = { + .vcc_name = "vcc", + .min_uV = AW9610X_SAR_VCC_MIN_UV, + .max_uV = AW9610X_SAR_VCC_MAX_UV, +}; + +struct aw_sar_awrw_t g_aw9610x_awrw = { + .p_set_awrw_node_fn = aw9610x_awrw_set, + .p_get_awrw_node_fn = aw9610x_awrw_get, +}; + +static const struct aw_sar_platform_config g_aw9610x_platform_config = { + .p_regulator_config = &g_regulator_config, + .p_irq_init = &g_aw9610x_irq_init, + .p_pm_chip_mode = &g_aw9610x_pm_chip_mode, +}; + +static void aw9610x_power_on_prox_detection(void *data, uint8_t en_flag) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw9610x *aw9610x = (struct aw9610x *)p_sar->priv_data; + uint8_t ch; + + if (en_flag == true) { + for (ch = 0; ch < AW9610X_CHANNEL_MAX; ch++) { + aw_sar_i2c_read(p_sar->i2c, + REG_BLFILT_CH0 + (REG_BLFILT_CH1 - REG_BLFILT_CH0) * ch, + &(aw9610x->last_blfilta[ch])); + aw_sar_i2c_write_bits(p_sar->i2c, + REG_BLFILT_CH0 + (REG_BLFILT_CH1 - REG_BLFILT_CH0) * ch, + ~(0x3f << 13), (1 << 13)); + } + aw_sar_i2c_read(p_sar->i2c, REG_IRQEN, &aw9610x->last_irq_en); + aw_sar_i2c_write_bits(p_sar->i2c, REG_IRQEN, ~(1 << 3), 1 << 3); + } else if (en_flag == false) { + for (ch = 0; ch < AW9610X_CHANNEL_MAX; ch++) { + aw_sar_i2c_write(p_sar->i2c, + REG_BLFILT_CH0 + (REG_BLFILT_CH1 - REG_BLFILT_CH0) * ch, + aw9610x->last_blfilta[ch]); + } + aw_sar_i2c_write(p_sar->i2c, REG_IRQEN, aw9610x->last_irq_en); + } +} + +static const struct aw_sar_power_on_prox_detection_t g_aw9610x_power_on_prox_detection = { + .p_power_on_prox_detection_en_fn = aw9610x_power_on_prox_detection, + .irq_en_cali_bit = 3, + .power_on_prox_en_flag = true, +}; + +static const struct aw_sar_chip_config g_aw9610x_chip_config = { + .ch_num_max = AW9610X_CHANNEL_MAX, + + .p_platform_config = &g_aw9610x_platform_config, + + .p_check_chipid = &g_aw9610x_check_chipid, + .p_soft_rst = &g_aw9610x_soft_rst, + .p_init_over_irq = &g_aw9610x_init_over_irq, + .p_fw_bin = NULL, + .p_reg_bin = &g_aw9610x_load_reg_bin, + .p_chip_mode = &g_aw9610x_chip_mode, + + //Node usage parameters + .p_reg_list = &g_aw9610x_reg_list, + .p_reg_arr = &g_aw9610x_reg_arr_para, + .p_aot = &g_aw9610x_aot, + .p_diff = &g_aw9610x_diff, + .p_offset = &g_aw9610x_offset, + .p_mode = &g_aw9610x_mode, + .p_prox_fw = NULL, + .p_get_chip_info = &g_aw9610x_get_chip_info, + .p_aw_sar_awrw = &g_aw9610x_awrw, + .p_boot_bin = NULL, + + .p_other_operation = aw9610x_get_chip_version, + .p_other_opera_free = NULL, + .power_on_prox_detection = &g_aw9610x_power_on_prox_detection, +}; + +int32_t aw9610x_init(struct aw_sar *p_sar) +{ + if (!p_sar) + return -EINVAL; + + g_aw_sar = p_sar; + + p_sar->priv_data = devm_kzalloc(p_sar->dev, sizeof(struct aw9610x), GFP_KERNEL); + if (!p_sar->priv_data) + return -ENOMEM; + + //Chip private function operation + p_sar->p_sar_para = &g_aw9610x_chip_config; + + return 0; +} + +void aw9610x_deinit(struct aw_sar *p_sar) +{ + if (p_sar->priv_data != NULL) + devm_kfree(p_sar->dev, p_sar->priv_data); +} diff --git a/drivers/input/misc/aw_sar/aw9610x/aw9610x.h b/drivers/input/misc/aw_sar/aw9610x/aw9610x.h new file mode 100644 index 000000000000..6f72e4c20374 --- /dev/null +++ b/drivers/input/misc/aw_sar/aw9610x/aw9610x.h @@ -0,0 +1,324 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef _AW9610X_H_ +#define _AW9610X_H_ +#include "../comm/aw_sar_type.h" + +//#define AW9610X_TVS_ABNORMAL_CAIL +#define AW9610X_AOT_SCAN_OVER_CNT (32) + +#define AW9610X_CHIP_ID (0xa961) +#define AW9610x_DATA_PROCESS_FACTOR (1024) +#define AW_CHIP_AW9610XA (0x03000b00) +#define AW9610X_CPU_WORK_MASK (1) + +#define AW9610X_SAR_VCC_MIN_UV (1700000) +#define AW9610X_SAR_VCC_MAX_UV (3600000) + +#define AW_REG_IRQEN_CLOSE (0) +#define AW_REG_IRQSRC_AOT_OVER_BIT (3) +#define REG_IRQSRC_SCAN_OVER_BIT (4) +#define REG_REG_WST_SLEEP_MODE (0x3) +#define AW9610X_AOT_OVER_DELAY_MAX_MS (6000) +#define AW9610X_AOT_MASK (0x3f) +#define AW9610X_AOT_BIT (8) +#define AW9610X_REG_OFFSET_STEP (4) + +enum aw9610x_sar_vers { + AW9610X = 2, + AW9610XA = 6, + AW9610XB = 0xa, +}; + +enum aw9610x_operation_mode { + AW9610X_ACTIVE_MODE = 1, + AW9610X_SLEEP_MODE, + AW9610X_DEEPSLEEP_MODE, + AW9610XB_DEEPSLEEP_MODE, +}; + +/********************************************** + *spereg addr offset + **********************************************/ +enum aw9610x_spereg_addr_offset { + AW_CL1SPE_CALI_OS = 20, + AW_CL1SPE_DEAL_OS = 60, + AW_CL2SPE_CALI_OS = 4, + AW_CL2SPE_DEAL_OS = 4, +}; + + +/********************************************** + *the flag of i2c read/write + **********************************************/ +enum aw9610x_function_flag { + AW9610X_FUNC_OFF, + AW9610X_FUNC_ON, +}; + +/********************************************** + * multiple sar define + **********************************************/ +enum aw9610x_multiple_sar { + AW_SAR0, + AW_SAR1, + AW_SAR_MAX, +}; + +#define AW9610X_CHANNEL_MAX (6) + +enum aw9610x_irq_trigger_position { + AW9610X_FAR, + AW9610X_TRIGGER_TH0, + AW9610X_TRIGGER_TH1 = 0x03, + AW9610X_TRIGGER_TH2 = 0x07, + AW9610X_TRIGGER_TH3 = 0x0f, +}; + +struct aw_i2c_package { + uint8_t addr_bytes; + uint8_t data_bytes; + uint8_t reg_num; + uint8_t init_addr[4]; + uint8_t *p_reg_data; +}; + +struct aw9610x { + uint8_t vers; + uint8_t channel; + uint32_t irq_status; + uint8_t chip_name[9]; + uint8_t chip_type[9]; + bool satu_release; + + struct aw_i2c_package aw_i2c_package; + + uint8_t satu_flag[6]; + uint32_t satu_data[6]; + uint32_t last_blfilta[AW9610X_CHANNEL_MAX]; + uint32_t last_irq_en; +}; + +/******************************************** + * Register List + ********************************************/ +#define AFE_BASE_ADDR (0x0000) +#define DSP_BASE_ADDR (0x0000) +#define STAT_BASE_ADDR (0x0000) +#define SFR_BASE_ADDR (0x0000) +#define DATA_BASE_ADDR (0x0000) + +#define REG_SCANCTRL0 ((0x0000) + AFE_BASE_ADDR) +#define REG_AFECFG1_CH0 ((0x0014) + AFE_BASE_ADDR) + +#define REG_FWVER ((0x0088) + STAT_BASE_ADDR) +#define REG_WST ((0x008C) + STAT_BASE_ADDR) +#define REG_STAT0 ((0x0090) + STAT_BASE_ADDR) +#define REG_STAT1 ((0x0094) + STAT_BASE_ADDR) +#define REG_CHINTEN ((0x009C) + STAT_BASE_ADDR) + +#define REG_BLFILT_CH0 ((0x00A8) + DSP_BASE_ADDR) +#define REG_BLRSTRNG_CH0 ((0x00B4) + DSP_BASE_ADDR) +#define REG_BLFILT_CH1 ((0x00E4) + DSP_BASE_ADDR) + +#define REG_COMP_CH0 ((0x0210) + DATA_BASE_ADDR) +#define REG_BASELINE_CH0 ((0x0228) + DATA_BASE_ADDR) +#define REG_DIFF_CH0 ((0x0240) + DATA_BASE_ADDR) +#define REG_FWVER2 ((0x0410) + DATA_BASE_ADDR) + +#define REG_CMD ((0xF008) + SFR_BASE_ADDR) +#define REG_IRQSRC ((0xF080) + SFR_BASE_ADDR) +#define REG_IRQEN ((0xF084) + SFR_BASE_ADDR) +#define REG_OSCEN ((0xFF00) + SFR_BASE_ADDR) +#define REG_RESET ((0xFF0C) + SFR_BASE_ADDR) +#define REG_CHIPID ((0xFF10) + SFR_BASE_ADDR) + +struct aw_reg_data { + unsigned char rw; + unsigned short reg; +}; +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) + +static const struct aw_reg_data g_aw9610x_reg_access[] = { + { .reg = REG_SCANCTRL0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG1_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + + { .reg = REG_FWVER, .rw = REG_RD_ACCESS, }, + { .reg = REG_WST, .rw = REG_RD_ACCESS, }, + { .reg = REG_STAT0, .rw = REG_RD_ACCESS, }, + { .reg = REG_STAT1, .rw = REG_RD_ACCESS, }, + { .reg = REG_CHINTEN, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + + { .reg = REG_BLFILT_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_BLRSTRNG_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_BLFILT_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + + + { .reg = REG_COMP_CH0, .rw = REG_RD_ACCESS, }, + { .reg = REG_BASELINE_CH0, .rw = REG_RD_ACCESS, }, + { .reg = REG_DIFF_CH0, .rw = REG_RD_ACCESS, }, + { .reg = REG_FWVER2, .rw = REG_RD_ACCESS, }, + + { .reg = REG_CMD, .rw = REG_NONE_ACCESS, }, + { .reg = REG_IRQSRC, .rw = REG_RD_ACCESS, }, + { .reg = REG_IRQEN, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_OSCEN, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_RESET, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_CHIPID, .rw = REG_RD_ACCESS, }, +}; + + +/****************************************************** + * Register Detail + ******************************************************/ +static const uint32_t aw9610x_reg_default[] = { + 0x0000, 0x00003f3f, + 0x0004, 0x00000064, + 0x0008, 0x0017c11e, + 0x000c, 0x05000000, + 0x0010, 0x00093ffd, + 0x0014, 0x19240009, + 0x0018, 0xd81c0207, + 0x001c, 0xff000000, + 0x0020, 0x00241900, + 0x0024, 0x00093ff7, + 0x0028, 0x58020009, + 0x002c, 0xd81c0207, + 0x0030, 0xff000000, + 0x0034, 0x00025800, + 0x0038, 0x00093fdf, + 0x003c, 0x7d3b0009, + 0x0040, 0xd81c0207, + 0x0044, 0xff000000, + 0x0048, 0x003b7d00, + 0x004c, 0x00093f7f, + 0x0050, 0xe9310009, + 0x0054, 0xd81c0207, + 0x0058, 0xff000000, + 0x005c, 0x0031e900, + 0x0060, 0x00093dff, + 0x0064, 0x1a0c0009, + 0x0068, 0xd81c0207, + 0x006c, 0xff000000, + 0x0070, 0x000c1a00, + 0x0074, 0x80093fff, + 0x0078, 0x043d0009, + 0x007c, 0xd81c0207, + 0x0080, 0xff000000, + 0x0084, 0x003d0400, + 0x00a0, 0xe6400000, + 0x00a4, 0x00000000, + 0x00a8, 0x010408d2, + 0x00ac, 0x00000000, + 0x00b0, 0x00000000, + 0x00b8, 0x00005fff, + 0x00bc, 0x00000000, + 0x00c0, 0x00000000, + 0x00c4, 0x00000000, + 0x00c8, 0x00000000, + 0x00cc, 0x00000000, + 0x00d0, 0x00000000, + 0x00d4, 0x00000000, + 0x00d8, 0x00000000, + 0x00dc, 0xe6447800, + 0x00e0, 0x78000000, + 0x00e4, 0x010408d2, + 0x00e8, 0x00000000, + 0x00ec, 0x00000000, + 0x00f4, 0x00005fff, + 0x00f8, 0x00000000, + 0x00fc, 0x00000000, + 0x0100, 0x00000000, + 0x0104, 0x00000000, + 0x0108, 0x00000000, + 0x010c, 0x02000000, + 0x0110, 0x00000000, + 0x0114, 0x00000000, + 0x0118, 0xe6447800, + 0x011c, 0x78000000, + 0x0120, 0x010408d2, + 0x0124, 0x00000000, + 0x0128, 0x00000000, + 0x0130, 0x00005fff, + 0x0134, 0x00000000, + 0x0138, 0x00000000, + 0x013c, 0x00000000, + 0x0140, 0x00000000, + 0x0144, 0x00000000, + 0x0148, 0x02000000, + 0x014c, 0x00000000, + 0x0150, 0x00000000, + 0x0154, 0xe6447800, + 0x0158, 0x78000000, + 0x015c, 0x010408d2, + 0x0160, 0x00000000, + 0x0164, 0x00000000, + 0x016c, 0x00005fff, + 0x0170, 0x00000000, + 0x0174, 0x00000000, + 0x0178, 0x00000000, + 0x017c, 0x00000000, + 0x0180, 0x00000000, + 0x0184, 0x02000000, + 0x0188, 0x00000000, + 0x018c, 0x00000000, + 0x0190, 0xe6447800, + 0x0194, 0x78000000, + 0x0198, 0x010408d2, + 0x019c, 0x00000000, + 0x01a0, 0x00000000, + 0x01a8, 0x00005fff, + 0x01ac, 0x00000000, + 0x01b0, 0x00000000, + 0x01b4, 0x00000000, + 0x01b8, 0x00000000, + 0x01bc, 0x00000000, + 0x01c0, 0x02000000, + 0x01c4, 0x00000000, + 0x01c8, 0x00000000, + 0x01cc, 0xe6407800, + 0x01d0, 0x78000000, + 0x01d4, 0x010408d2, + 0x01d8, 0x00000000, + 0x01dc, 0x00000000, + 0x01e4, 0x00005fff, + 0x01e8, 0x00000000, + 0x01ec, 0x00000000, + 0x01f0, 0x00000000, + 0x01f4, 0x00000000, + 0x01f8, 0x00000000, + 0x01fc, 0x02000000, + 0x0200, 0x00000000, + 0x0204, 0x00000000, + 0x0208, 0x00000008, + 0x020c, 0x0000000d, + 0x41fc, 0x00000000, + 0x4400, 0x00000000, + 0x4410, 0x00000000, + 0x4420, 0x00000000, + 0x4430, 0x00000000, + 0x4440, 0x00000000, + 0x4450, 0x00000000, + 0x4460, 0x00000000, + 0x4470, 0x00000000, + 0xf080, 0x00003018, + 0xf084, 0x00000fff, + 0xf800, 0x00000000, + 0xf804, 0x00002e00, + 0xf8d0, 0x00000001, + 0xf8d4, 0x00000000, + 0xff00, 0x00000301, + 0xff0c, 0x01000000, + 0xffe0, 0x00000000, + 0xfff4, 0x00004011, + 0x0090, 0x00000000, + 0x0094, 0x00000000, + 0x0098, 0x00000000, + 0x009c, 0x3f3f3f3f, +}; + +#endif From patchwork Wed May 29 13:06:07 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangshuaijie@awinic.com X-Patchwork-Id: 13678818 Received: from out28-53.mail.aliyun.com (out28-53.mail.aliyun.com [115.124.28.53]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1B2A819; Wed, 29 May 2024 13:06:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.53 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988006; cv=none; b=R51PY22ZjUIZ3Lw+f4byHsU/VZXbkXVyiiP3r0fNjosuJAI7cNBCSmQCN06RjC5EWqFbGnyMKPTIDhrkFe6gmMvfEPPduAxIe8M7MVCiBDaa50q8S5Xn7hrVFSAKRVNSpuTm2mRHI+5U8x5lPGFTQFIUnoHZEoMo0L91g9Dv0YQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988006; c=relaxed/simple; bh=fW7ch+kBpeeulrsf3Lb6gteTH5agfBBB3nsP0pArmSE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PBIVtDrnxyaD+qZ9mPSn7XiY3ELqSGeYZfjmKKA9EEYsiUPgryPHmUc7prKtYbC7IeQVr8+j8hnTQqSLuc5ObZCHeDlJ1/crxcokfR5RnTw2xKo6n1/Jjs7PKcSQ+VMIwAPZtJ6CnKGctR8bcrOkEJBOYErWTGhU7UzWyybOkkU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com; spf=pass smtp.mailfrom=awinic.com; arc=none smtp.client-ip=115.124.28.53 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=awinic.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_system_inform|0.158036-0.000322952-0.841641;FP=0|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033068155186;MF=wangshuaijie@awinic.com;NM=1;PH=DS;RN=11;RT=11;SR=0;TI=SMTPD_---.XqPpuJV_1716987994; Received: from awinic..(mailfrom:wangshuaijie@awinic.com fp:SMTPD_---.XqPpuJV_1716987994) by smtp.aliyun-inc.com; Wed, 29 May 2024 21:06:36 +0800 From: wangshuaijie@awinic.com To: dmitry.torokhov@gmail.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jeff@labundy.com, linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: wangshuaijie@awinic.com, liweilei@awinic.com, kangjiajun@awinic.com Subject: [PATCH V1 4/5] Add aw963xx series related interfaces to the aw_sar driver. Date: Wed, 29 May 2024 13:06:07 +0000 Message-ID: <20240529130608.783624-5-wangshuaijie@awinic.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240529130608.783624-1-wangshuaijie@awinic.com> References: <20240529130608.783624-1-wangshuaijie@awinic.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: shuaijie wang Signed-off-by: shuaijie wang --- drivers/input/misc/aw_sar/aw963xx/aw963xx.c | 986 ++++++++++++++++++++ drivers/input/misc/aw_sar/aw963xx/aw963xx.h | 749 +++++++++++++++ 2 files changed, 1735 insertions(+) create mode 100644 drivers/input/misc/aw_sar/aw963xx/aw963xx.c create mode 100644 drivers/input/misc/aw_sar/aw963xx/aw963xx.h diff --git a/drivers/input/misc/aw_sar/aw963xx/aw963xx.c b/drivers/input/misc/aw_sar/aw963xx/aw963xx.c new file mode 100644 index 000000000000..4105756749d7 --- /dev/null +++ b/drivers/input/misc/aw_sar/aw963xx/aw963xx.c @@ -0,0 +1,986 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AWINIC sar sensor driver (aw963xx) + * + * Author: Shuaijie Wang + * + * Copyright (c) 2024 awinic Technology CO., LTD + */ +#include "aw963xx.h" +#include "../aw_sar.h" + +#define AW963XX_I2C_NAME "aw963xx_sar" + +static void aw963xx_set_cs_as_irq(struct aw_sar *p_sar, int flag); +static void aw963xx_get_ref_ch_enable(struct aw_sar *p_sar); + +static int32_t aw963xx_read_init_over_irq(void *load_bin_para) +{ + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + uint32_t cnt = 1000; + uint32_t reg; + int32_t ret; + + while (cnt--) { + ret = aw_sar_i2c_read(p_sar->i2c, REG_IRQSRC, ®); + if (ret != 0) { + dev_err(p_sar->dev, "i2c error %d", ret); + return ret; + } + if ((reg & 0x01) == 0x01) { + aw_sar_i2c_read(p_sar->i2c, REG_FWVER, ®); + return 0; + } + mdelay(1); + } + + aw_sar_i2c_read(p_sar->i2c, REG_FWVER, ®); + + return -EINVAL; +} + +static void aw963xx_convert_little_endian_2_big_endian(struct aw_bin *aw_bin) +{ + uint32_t start_index = aw_bin->header_info[0].valid_data_addr; + uint32_t fw_len = aw_bin->header_info[0].reg_num; + uint32_t uints = fw_len / AW963XX_SRAM_UPDATE_ONE_UINT_SIZE; + uint8_t tmp1; + uint8_t tmp2; + uint8_t tmp3; + uint8_t tmp4; + int i; + + for (i = 0; i < uints; i++) { + tmp1 = aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 3]; + tmp2 = aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 2]; + tmp3 = aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 1]; + tmp4 = aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE]; + aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE] = tmp1; + aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 1] = tmp2; + aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 2] = tmp3; + aw_bin->info.data[start_index + i * AW963XX_SRAM_UPDATE_ONE_UINT_SIZE + 3] = tmp4; + } +} + +/** + * @brief |----------------code ram-----------------| + * 0x2000 0x4fff + * |--- app wrote here ---|--fill with 0xff--| + * + * if the size of app is less than the size of code ram, the rest of the + * ram is filled with 0xff. + * @param load_bin_para + * @param offset the rear addr of app + * @return int32_t + */ +static int32_t aw963xx_sram_fill_not_wrote_area(void *load_bin_para, uint32_t offset) +{ + uint32_t last_pack_len = (AW963XX_SRAM_END_ADDR - offset) % + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE; + uint32_t pack_cnt = last_pack_len == 0 ? + ((AW963XX_SRAM_END_ADDR - offset) / AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) : + ((AW963XX_SRAM_END_ADDR - offset) / AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) + 1; + uint8_t buf[AW963XX_SRAM_UPDATE_ONE_PACK_SIZE + 2] = { 0 }; + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + uint32_t download_addr_with_ofst; + uint8_t *r_buf; + int32_t ret; + uint32_t i; + + r_buf = devm_kzalloc(p_sar->dev, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE, GFP_KERNEL); + if (!r_buf) + return -ENOMEM; + + memset(buf, 0xff, sizeof(buf)); + for (i = 0; i < pack_cnt; i++) { + memset(r_buf, 0, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE); + download_addr_with_ofst = offset + i * AW963XX_SRAM_UPDATE_ONE_PACK_SIZE; + buf[0] = (uint8_t)(download_addr_with_ofst >> OFFSET_BIT_8); + buf[1] = (uint8_t)(download_addr_with_ofst); + if (i != (pack_cnt - 1)) { + ret = aw_sar_i2c_write_seq(p_sar->i2c, buf, + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE + 2); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, write_seq error!", i); + devm_kfree(p_sar->dev, r_buf); + return ret; + } + ret = aw_sar_i2c_read_seq(p_sar->i2c, buf, 2, r_buf, + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, read_seq error!", i); + devm_kfree(p_sar->dev, r_buf); + return ret; + } + if (memcmp(&buf[2], r_buf, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) != 0) { + dev_err(p_sar->dev, "read is not equal to write "); + devm_kfree(p_sar->dev, r_buf); + return -EINVAL; + } + } else { + ret = aw_sar_i2c_write_seq(p_sar->i2c, buf, last_pack_len + 2); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, write_seq error!", i); + devm_kfree(p_sar->dev, r_buf); + return ret; + } + ret = aw_sar_i2c_read_seq(p_sar->i2c, buf, 2, r_buf, last_pack_len); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, read_seq error!", i); + devm_kfree(p_sar->dev, r_buf); + return ret; + } + if (memcmp(&buf[2], r_buf, last_pack_len) != 0) { + dev_err(p_sar->dev, "read is not equal to write "); + devm_kfree(p_sar->dev, r_buf); + return -EINVAL; + } + } + } + + devm_kfree(p_sar->dev, r_buf); + + return 0; +} + +static int32_t aw963xx_sram_data_write(struct aw_bin *aw_bin, void *load_bin_para) +{ + uint8_t buf[AW963XX_SRAM_UPDATE_ONE_PACK_SIZE + 2] = { 0 }; + uint32_t start_index = aw_bin->header_info[0].valid_data_addr; + uint32_t fw_bin_version = aw_bin->header_info[0].app_version; + uint32_t download_addr = AW963XX_RAM_START_ADDR; + uint32_t fw_len = aw_bin->header_info[0].reg_num; + uint32_t last_pack_len = fw_len % AW963XX_SRAM_UPDATE_ONE_PACK_SIZE; + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + uint32_t download_addr_with_ofst = 0; + uint32_t pack_cnt; + uint8_t *r_buf; + int32_t ret; + uint32_t i; + + r_buf = devm_kzalloc(p_sar->dev, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE, GFP_KERNEL); + if (!r_buf) + return -ENOMEM; + + pack_cnt = ((fw_len % AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) == 0) ? + (fw_len / AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) : + (fw_len / AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) + 1; + + dev_info(p_sar->dev, "fw_bin_version = 0x%x", fw_bin_version); + for (i = 0; i < pack_cnt; i++) { + memset(r_buf, 0, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE); + download_addr_with_ofst = download_addr + i * AW963XX_SRAM_UPDATE_ONE_PACK_SIZE; + buf[0] = (uint8_t)(download_addr_with_ofst >> OFFSET_BIT_8); + buf[1] = (uint8_t)(download_addr_with_ofst); + if (i != (pack_cnt - 1)) { + memcpy(&buf[2], &aw_bin->info.data[start_index + + i * AW963XX_SRAM_UPDATE_ONE_PACK_SIZE], + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE); + ret = aw_sar_i2c_write_seq(p_sar->i2c, buf, + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE + 2); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, write_seq error!", i); + goto err_out; + } + ret = aw_sar_i2c_read_seq(p_sar->i2c, buf, 2, r_buf, + AW963XX_SRAM_UPDATE_ONE_PACK_SIZE); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, read_seq error!", i); + goto err_out; + } + if (memcmp(&buf[2], r_buf, AW963XX_SRAM_UPDATE_ONE_PACK_SIZE) != 0) { + dev_err(p_sar->dev, "read is not equal to write "); + ret = -EIO; + goto err_out; + } + } else { // last pack process + memcpy(&buf[2], &aw_bin->info.data[start_index + + i * AW963XX_SRAM_UPDATE_ONE_PACK_SIZE], last_pack_len); + ret = aw_sar_i2c_write_seq(p_sar->i2c, buf, last_pack_len + 2); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, write_seq error!", i); + goto err_out; + } + ret = aw_sar_i2c_read_seq(p_sar->i2c, buf, 2, r_buf, last_pack_len); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, read_seq error!", i); + goto err_out; + } + if (memcmp(&buf[2], r_buf, last_pack_len) != 0) { + dev_err(p_sar->dev, "read is not equal to write "); + ret = -EIO; + goto err_out; + } + /* fill 0xff in the area that not worte. */ + ret = aw963xx_sram_fill_not_wrote_area(load_bin_para, + download_addr_with_ofst + last_pack_len); + if (ret != 0) { + dev_err(p_sar->dev, "cnt%d, sram_fill_not_wrote_area error!", i); + goto err_out; + } + } + } + +err_out: + devm_kfree(p_sar->dev, r_buf); + + return ret; +} + +static int32_t aw963xx_update_firmware(struct aw_bin *aw_bin, void *load_bin_para) +{ + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + struct aw963xx *aw963xx = (struct aw963xx *)p_sar->priv_data; + struct i2c_client *i2c = p_sar->i2c; + int32_t ret; + + if (aw963xx->start_mode == AW963XX_ROM_MODE) { + dev_info(p_sar->dev, "no need to update fw."); + return 0; + } + + //step1: close coderam shutdown mode + aw_sar_i2c_write(i2c, 0xfff4, 0x3c00d11f); + aw_sar_i2c_write(i2c, 0xc400, 0x21660000); + + // step 2: reset mcu only and set boot mode to 1. (0xf800 0x00010100) + aw_sar_i2c_write(i2c, REG_CPU_MODE_SET, AW963XX_RESET_CPU_SET_BOOT_SATRT); + + // step 3: enable data ram. (0xFFE4 0x3C000000) + aw_sar_i2c_write(i2c, REG_RAM_PASSWORD, AW963XX_NO_ENCRYPTION); + + // setp 4: convert LD to BD + aw963xx_convert_little_endian_2_big_endian(aw_bin); + + // step 5: write ram data. + ret = aw963xx_sram_data_write(aw_bin, load_bin_para); + if (ret == 0) + dev_info(p_sar->dev, "sram_data_write OK"); + else + dev_err(p_sar->dev, "sram_data_write error"); + + mdelay(3); + + // step 6: exit reset mcu and boot cpu in ram. (0xf800 0x00000100) + aw_sar_i2c_write(i2c, REG_CPU_MODE_SET, AW963XX_EXIT_RESET_CPU_SET_BOOT_SATRT); + + // step 7: reset cpu (0xFF0C 0x0) + aw_sar_i2c_write(i2c, REG_CPU_RESET, AW963XX_RESET_SET); + + //step 8: Wait for chip initialization to complete + msleep(AW963XX_CHIP_INIT_MAX_TIME_MS); + + return aw963xx_read_init_over_irq(load_bin_para); +} + +static int32_t aw963xx_load_reg_bin(struct aw_bin *aw_bin, void *load_bin_para) +{ + struct aw_sar *p_sar = (struct aw_sar *)load_bin_para; + struct aw963xx *aw963xx = (struct aw963xx *)p_sar->priv_data; + int32_t ret; + + dev_dbg(p_sar->dev, "reg chip name: %s, soc chip name: %s, len = %d", + p_sar->chip_name, aw_bin->header_info[0].chip_type, aw_bin->info.len); + + ret = strncmp(p_sar->chip_name, aw_bin->header_info[0].chip_type, + sizeof(aw_bin->header_info[0].chip_type)); + if (ret != 0) + dev_err(p_sar->dev, "load_binname(%s) incompatible with chip type(%s)", + p_sar->chip_name, aw_bin->header_info[0].chip_type); + + p_sar->load_bin.bin_data_ver = aw_bin->header_info[0].bin_data_ver; + + ret = aw_sar_load_reg(aw_bin, p_sar->i2c); + + if (!strncmp(p_sar->chip_name, AW96308, sizeof(AW96308)) || + !strncmp(p_sar->chip_name, AW96305BFOR, sizeof(AW96305BFOR))) { + dev_dbg(p_sar->dev, "set cs%d as irq", aw963xx->irq_mux); + aw963xx_set_cs_as_irq(p_sar, aw963xx->irq_mux); + } + + return ret; +} + +static void aw963xx_irq_handle_func(uint32_t irq_status, void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t ch_th[AW963XX_CHANNEL_NUM_MAX] = { 0 }; + uint32_t curr_status_val[4] = { 0 }; + int32_t ret; + int8_t i; + int8_t j; + + if (((irq_status & 0x01) == 1) && (p_sar->driver_code_initover_flag == 1)) { + dev_dbg(p_sar->dev, "not healthy!"); + p_sar->fault_flag = AW_SAR_UNHEALTHY; + } + + for (i = 0; i < AW963XX_VALID_TH; i++) + ret = aw_sar_i2c_read(p_sar->i2c, REG_STAT0 + i * (REG_STAT1 - REG_STAT0), + &curr_status_val[i]); + + for (j = 0; j < AW963XX_CHANNEL_NUM_MAX; j++) { + if (!p_sar->channels_arr[j].input) + continue; + + for (i = 0; i < AW963XX_VALID_TH; i++) + ch_th[j] |= ((curr_status_val[i] >> j) & 0x01) << i; + + if (p_sar->channels_arr[j].last_channel_info != ch_th[j]) { + if ((ch_th[j] >> 3 & 0x01) == 1) { //th3 + input_report_abs(p_sar->channels_arr[j].input, ABS_DISTANCE, 4); + } else if ((ch_th[j] >> 2 & 0x01) == 1) { //th2 + input_report_abs(p_sar->channels_arr[j].input, ABS_DISTANCE, 3); + } else if ((ch_th[j] >> 1 & 0x01) == 1) { //th1 + input_report_abs(p_sar->channels_arr[j].input, ABS_DISTANCE, 2); + } else if ((ch_th[j] >> 0 & 0x01) == 1) { //th0 + input_report_abs(p_sar->channels_arr[j].input, ABS_DISTANCE, 1); + } else { //far + input_report_abs(p_sar->channels_arr[j].input, ABS_DISTANCE, 0); + } + input_sync(p_sar->channels_arr[j].input); + p_sar->channels_arr[j].last_channel_info = ch_th[j]; + } + } +} + +static ssize_t aw963xx_operation_mode_get(void *data, char *buf) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + ssize_t len = 0; + + if (p_sar->last_mode == AW963XX_ACTIVE_MODE) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Active\n"); + else if (p_sar->last_mode == AW963XX_SLEEP_MODE) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Sleep\n"); + else if (p_sar->last_mode == AW963XX_DEEPSLEEP_MODE) + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: DeepSleep\n"); + else + len += snprintf(buf + len, PAGE_SIZE - len, "operation mode: Unconfirmed\n"); + + return len; +} + +static void aw963xx_sar_chip_info_get(void *data, char *buf, ssize_t *p_len) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t reg_data; + + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, + "sar%u\n", p_sar->dts_info.sar_num); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "The driver supports UI\n"); + + aw_sar_i2c_read(p_sar->i2c, REG_CHIP_ID0, ®_data); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "chipid is 0x%08x\n", reg_data); + + aw_sar_i2c_read(p_sar->i2c, REG_IRQEN, ®_data); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "REG_HOSTIRQEN is 0x%08x\n", reg_data); + + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "aw963xx Bin data version:0x%08x\n", + p_sar->load_bin.bin_data_ver); +} + +static int32_t aw963xx_get_signed_cap(void *data, uint16_t reg_addr) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + int32_t s_ofst_c = 0; + uint32_t off_m_bit; + uint32_t off_c_bit; + uint32_t reg_data; + uint32_t off_c; + uint32_t off_m; + int32_t off_f; + uint32_t i; + + aw_sar_i2c_read(p_sar->i2c, reg_addr, ®_data); + + off_f = ((reg_data >> AW_BIT16) & ONE_WORD) * AW963XX_STEP_LEN_UNSIGNED_CAP_FINE_ADJ; + off_c = (reg_data >> AW_BIT8) & ONE_WORD; + off_m = reg_data & ONE_WORD; + + for (i = 0; i < 8; i++) { + off_m_bit = (off_m >> i) & 0x01; + off_c_bit = (off_c >> i) & 0x01; + s_ofst_c += ((1 - 2 * off_m_bit) * off_c_bit * aw_sar_pow2(i)) * + AW963XX_STEP_LEN_UNSIGNED_CAP_ROUGH_ADJ; + } + + return (s_ofst_c + off_f); +} + +static uint32_t aw963xx_get_unsigned_cap(void *data, uint16_t reg_addr) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t reg_data; + uint32_t rough; + uint32_t fine; + + aw_sar_i2c_read(p_sar->i2c, reg_addr, ®_data); + + rough = ((reg_data >> AW_BIT8) & ONE_WORD) * AW963XX_STEP_LEN_UNSIGNED_CAP_ROUGH_ADJ; + fine = ((reg_data >> AW_BIT16) & ONE_WORD) * AW963XX_STEP_LEN_UNSIGNED_CAP_FINE_ADJ; + + return (rough + fine); +} + +static void aw963xx_get_ref_ch_enable(struct aw_sar *p_sar) +{ + struct aw963xx *aw963xx = (struct aw963xx *)p_sar->priv_data; + uint32_t refa_ch; + uint32_t refb_ch; + uint32_t reg_data; + int32_t i; + + for (i = 0; i < AW963XX_CHANNEL_NUM_MAX; i++) { + aw_sar_i2c_read(p_sar->i2c, + REG_FILTCTRL0_CH0 + + i * (REG_FILTCTRL0_CH1 - REG_FILTCTRL0_CH0), + ®_data); + if ((reg_data >> AW963XX_FILTCTRL0_CHX_REFAEN) & 0x01) { + refa_ch = (reg_data >> AW963XX_FILTCTRL0_CHX_REFASEL) & 0x1f; + aw963xx->ref_ch_en[refa_ch] = AW963XX_REF_EN; + } + if ((reg_data >> AW963XX_FILTCTRL0_CHX_REFBEN) & 0x01) { + refb_ch = (reg_data >> AW963XX_FILTCTRL0_CHX_REFBSEL) & 0x1f; + aw963xx->ref_ch_en[refb_ch] = AW963XX_REF_EN; + } + } +} + +//Note: Because the kernel cannot handle floating-point types, it expands mul by 10 times +static uint8_t aw963xx_get_offset_multiple(struct aw_sar *p_sar, uint8_t ch) +{ + uint32_t reg_data; + uint8_t mul = 1; + + aw_sar_i2c_read(p_sar->i2c, REG_AFECFG2_CH0 + ch * (REG_AFECFG2_CH1 - REG_AFECFG2_CH0), + ®_data); + if ((reg_data >> 27) & 0x1) { + if (((reg_data >> 29) & 0x3) == 0) + mul = 16; + else if (((reg_data >> 29) & 0x3) == 1) + mul = 20; + else if (((reg_data >> 29) & 0x3) == 2) + mul = 26; + else if (((reg_data >> 29) & 0x3) == 3) + mul = 40; + return mul; + } + + aw_sar_i2c_read(p_sar->i2c, REG_AFECFG3_CH0 + + ch * (REG_AFECFG3_CH1 - REG_AFECFG3_CH0), + ®_data); + if ((reg_data >> 11) & 0x1) + mul = 20; + else + mul = 10; + + return mul; +} + +static ssize_t aw963xx_get_cap_offset(void *data, char *buf) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw963xx *aw963xx = (struct aw963xx *)p_sar->priv_data; + int32_t signed_cap_ofst; + uint32_t mode = 0xff; + uint32_t reg_data; + uint32_t cap_ofst; + uint8_t mul = 10; + ssize_t len = 0; + uint32_t tmp; + uint32_t i; + + aw963xx_get_ref_ch_enable(p_sar); + + for (i = 0; i < AW963XX_CHANNEL_NUM_MAX; i++) { + aw_sar_i2c_read(p_sar->i2c, + REG_AFESOFTCFG0_CH0 + + i * (REG_AFESOFTCFG0_CH1 - REG_AFESOFTCFG0_CH0), + ®_data); + mul = aw963xx_get_offset_multiple(p_sar, i); + mode = reg_data & 0x0ff; + switch (mode) { + case AW963XX_UNSIGNED_CAP: //self-capacitance mode unsigned cail + cap_ofst = aw963xx_get_unsigned_cap(p_sar, + REG_AFECFG1_CH0 + i * (REG_AFECFG1_CH1 - REG_AFECFG1_CH0)); + //Because it has been expanded by 1000 times before, + //the accuracy of removing mul's expansion loss can be ignored + cap_ofst = cap_ofst * mul / 10; + len += snprintf(buf + len, PAGE_SIZE - len, + "unsigned cap ofst ch%u: %u.%u pf\r\n", + i, + cap_ofst / AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + cap_ofst % AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + break; + case AW963XX_SIGNED_CAP: //self-capacitance mode signed cail + signed_cap_ofst = aw963xx_get_signed_cap(p_sar, + REG_AFECFG1_CH0 + i * (REG_AFECFG1_CH1 - REG_AFECFG1_CH0)); + signed_cap_ofst = signed_cap_ofst * mul / 10; + if (signed_cap_ofst < 0) { + tmp = -signed_cap_ofst; + dev_info(p_sar->dev, "cap_ofst2 = 0x%x", + signed_cap_ofst); + len += snprintf(buf + len, PAGE_SIZE - len, + "signed cap ofst ch%u: -%u.%upf\r\n", + i, + tmp / AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + tmp % AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + } else { + len += snprintf(buf + len, PAGE_SIZE - len, + "signed cap ofst ch%u: %d.%dpf\r\n", + i, + signed_cap_ofst / + AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + signed_cap_ofst % + AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + } + break; + case AW963XX_MUTUAL_CAP: //mutual-capacitance mode + if (aw963xx->ref_ch_en[i] == AW963XX_REF_EN) { + cap_ofst = aw963xx_get_unsigned_cap(p_sar, + REG_AFECFG1_M_CH0 + + i * (REG_AFECFG1_M_CH1 - REG_AFECFG1_M_CH0)); + cap_ofst = cap_ofst * mul / 10; + len += snprintf(buf + len, PAGE_SIZE - len, + "ref unsigned cap ofst ch%u: %u.%udpf\r\n", + i, + cap_ofst / AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + cap_ofst % AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + } else { + signed_cap_ofst = aw963xx_get_signed_cap(p_sar, + REG_AFECFG1_CH0 + + i * (REG_AFECFG1_CH1 - REG_AFECFG1_CH0)); + signed_cap_ofst = signed_cap_ofst * mul / 10; + if (signed_cap_ofst < 0) { + tmp = -signed_cap_ofst; + dev_info(p_sar->dev, + "cap_ofst2 = 0x%x", + signed_cap_ofst); + len += snprintf(buf + len, PAGE_SIZE - len, + "mutual cap ofst ch%u: -%u.%udpf\r\n", + i, + tmp / AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + tmp % AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + } else { + len += snprintf(buf + len, PAGE_SIZE - len, + "mutual cap ofst ch%u: %d.%dpf\r\n", + i, + signed_cap_ofst / + AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE, + signed_cap_ofst % + AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE); + } + } + break; + default: + dev_info(p_sar->dev, "aw963xx ofst error 0x%x", reg_data & 0x0f); + break; + } + } + + return len; +} + +static void aw963xx_set_cs_as_irq(struct aw_sar *p_sar, int flag) +{ + if (flag == AW963XX_CS2_IRQ) { + aw_sar_i2c_write(p_sar->i2c, 0xfff4, 0x3c00d013); + aw_sar_i2c_write(p_sar->i2c, 0xc100, 0x00000020); + aw_sar_i2c_write(p_sar->i2c, 0xe018, 0x00000004); + } else if (flag == AW963XX_CS5_IRQ) { + aw_sar_i2c_write(p_sar->i2c, 0xfff4, 0x3c00d013); + aw_sar_i2c_write(p_sar->i2c, 0xc100, 0x00000800); + aw_sar_i2c_write(p_sar->i2c, 0xe018, 0x00000020); + } else { + aw_sar_i2c_write(p_sar->i2c, 0xfff4, 0x3c00d013); + aw_sar_i2c_write(p_sar->i2c, 0xc100, 0x00000000); + aw_sar_i2c_write(p_sar->i2c, 0xe018, 0x00000000); + } +} + +int32_t aw963xx_check_chipid(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t reg_val; + int32_t ret; + + if (!p_sar) + return -EINVAL; + + ret = aw_sar_i2c_read(p_sar->i2c, REG_CHIP_ID0, ®_val); + if (ret < 0) { + dev_err(p_sar->dev, "read CHIP ID failed: %d", ret); + return ret; + } + + switch (reg_val) { + case AW96303_CHIP_ID: + dev_info(p_sar->dev, "aw96303 detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, AW96303, 8); + ret = 0; + break; + case AW96305_CHIP_ID: + dev_info(p_sar->dev, "aw96305 detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, AW96305, 8); + ret = 0; + break; + case AW96305BFOR_CHIP_ID: + dev_info(p_sar->dev, "aw96305bfor detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, AW96305BFOR, 8); + ret = 0; + break; + case AW96308_CHIP_ID: + dev_info(p_sar->dev, "aw96308 detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, AW96308, 8); + ret = 0; + break; + case AW96310_CHIP_ID: + dev_info(p_sar->dev, "aw96310 detected, 0x%04x", reg_val); + memcpy(p_sar->chip_name, AW96310, 8); + ret = 0; + break; + default: + dev_info(p_sar->dev, "chip id error, 0x%04x", reg_val); + ret = -EIO; + break; + } + + return ret; +} + +/**********************mode operation start*******************************/ +static void aw963xx_enable_clock(void *i2c) +{ + aw_sar_i2c_write_bits(i2c, REG_CHIPSTAT, ~AW963XX_CPU_OSC_CTRL_MASK, + AW963XX_CPU_OSC_CTRL_MASK); +} + +static uint32_t aw963xx_rc_irqscr(void *i2c) +{ + uint32_t val; + + aw_sar_i2c_read(i2c, REG_IRQSRC, &val); + + return val; +} + +static void aw963xx_set_active_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW963XX_ACTIVE_MODE); +} + +static void aw963xx_set_sleep_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW963XX_SLEEP_MODE); +} + +static void aw963xx_set_deepsleep_cmd(void *i2c) +{ + aw_sar_i2c_write(i2c, REG_CMD, AW963XX_DEEPSLEEP_MODE); +} + +static const struct aw_sar_mode_set_t g_aw963xx_mode_set[] = { + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_ACTIVE_MODE, + .last_mode = AW963XX_DEEPSLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = aw963xx_enable_clock, + .rc_irqscr = NULL, + .mode_update = aw963xx_set_active_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_ACTIVE_MODE, + .last_mode = AW963XX_SLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw963xx_set_active_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_ACTIVE_MODE, + .last_mode = AW963XX_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = NULL, + .mode_update = aw963xx_set_active_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_SLEEP_MODE, + .last_mode = AW963XX_DEEPSLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = aw963xx_enable_clock, + .rc_irqscr = aw963xx_rc_irqscr, + .mode_update = aw963xx_set_sleep_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_SLEEP_MODE, + .last_mode = AW963XX_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = aw963xx_rc_irqscr, + .mode_update = aw963xx_set_sleep_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_DEEPSLEEP_MODE, + .last_mode = AW963XX_SLEEP_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = aw963xx_rc_irqscr, + .mode_update = aw963xx_set_deepsleep_cmd, + }, + }, + { + .chip_id = AW_SAR_NONE_CHECK_CHIP, + .chip_mode = { + .curr_mode = AW963XX_DEEPSLEEP_MODE, + .last_mode = AW963XX_ACTIVE_MODE, + }, + .mode_switch_ops = { + .enable_clock = NULL, + .rc_irqscr = aw963xx_rc_irqscr, + .mode_update = aw963xx_set_deepsleep_cmd, + }, + }, +}; + +static void aw963xx_sar_get_firmware_info(void *data, char *buf, ssize_t *p_len) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t reg_data; + + aw_sar_i2c_read(p_sar->i2c, REG_FWVER, ®_data); + *p_len += snprintf(buf + *p_len, PAGE_SIZE - *p_len, "firmware is 0x%08x\n", reg_data); +} + +static int32_t aw963xx_parse_dts(void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + struct aw963xx *aw963xx = (struct aw963xx *)p_sar->priv_data; + struct device_node *np = p_sar->i2c->dev.of_node; + int32_t val; + + val = of_property_read_u32(np, "irq-mux", &aw963xx->irq_mux); + if (val != 0) + dev_err(p_sar->dev, "irq-mux not detected"); + else + dev_info(p_sar->dev, "irq-mux = %d", aw963xx->irq_mux); + + val = of_property_read_u32(np, "start-mode", &aw963xx->start_mode); + if (val != 0) + dev_err(p_sar->dev, "start-mode not detected"); + else + dev_info(p_sar->dev, "start-mode = %d", aw963xx->start_mode); + + return 0; +} + +static const struct aw_sar_mode_t g_aw963xx_mode = { + .mode_set_arr = &g_aw963xx_mode_set[0], + .mode_set_arr_len = ARRAY_SIZE(g_aw963xx_mode_set), + .p_set_mode_node_fn = NULL, + .p_get_mode_node_fn = aw963xx_operation_mode_get, +}; + +static const struct aw_sar_diff_t g_aw963xx_diff = { + .diff0_reg = REG_DIFF_CH0, + .diff_step = REG_DIFF_CH1 - REG_DIFF_CH0, + .rm_float = AW963XX_DATA_PROCESS_FACTOR, + .p_get_diff_node_fn = NULL, +}; + +static const struct aw_sar_offset_t g_aw963xx_offset = { + .p_get_offset_node_fn = aw963xx_get_cap_offset, +}; + +static const struct aw_sar_aot_t g_aw963xx_aot = { + .aot_reg = REG_SCANCTRL1, + .aot_mask = ~0xfff, + .aot_flag = 0xfff, +}; + +static const struct aw_sar_para_load_t g_aw963xx_reg_arr_para = { + .reg_arr = aw963xx_reg_default, + .reg_arr_len = ARRAY_SIZE(aw963xx_reg_default), +}; + +static const struct aw_sar_regulator_config_t g_regulator_config = { + .vcc_name = "vcc", + .min_uV = AW963XX_SAR_VCC_MIN_UV, + .max_uV = AW963XX_SAR_VCC_MAX_UV, +}; + +static const struct aw_sar_reg_list_t g_aw963xx_reg_list = { + .reg_none_access = REG_NONE_ACCESS, + .reg_rd_access = REG_RD_ACCESS, + .reg_wd_access = REG_WR_ACCESS, + .reg_perm = (struct aw_sar_reg_data *)&g_aw963xx_reg_access[0], + .reg_num = ARRAY_SIZE(g_aw963xx_reg_access), +}; + +static const struct aw_sar_chip_mode_t g_aw963xx_chip_mode = { + .init_mode = AW963XX_ACTIVE_MODE, + .active = AW963XX_ACTIVE_MODE, + .pre_init_mode = AW963XX_SLEEP_MODE, +}; + +static const struct aw_sar_load_bin_t g_aw963xx_load_reg_bin = { + .bin_name = "aw963xx_reg", + .bin_opera_func = aw963xx_load_reg_bin, + .p_update_fn = NULL, +}; + +static const struct aw_sar_load_bin_t g_aw963xx_load_fw_bin = { + .bin_name = "aw963xx_fw", + .bin_opera_func = aw963xx_update_firmware, + .p_get_prot_update_fw_node_fn = aw963xx_sar_get_firmware_info, + .bin_load_fail_opera = NULL, +}; + +static const struct aw_sar_get_chip_info_t g_aw963xx_get_chip_info = { + .p_get_chip_info_node_fn = aw963xx_sar_chip_info_get, +}; + +static const struct aw_sar_check_chipid_t g_aw963xx_check_chipid = { + .p_check_chipid_fn = aw963xx_check_chipid, +}; + +static const struct aw_sar_irq_init_t g_aw963xx_irq_init = { + .flags = GPIOF_DIR_IN | GPIOF_INIT_HIGH, + .irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + .handler = NULL, + .thread_fn = NULL, + .rc_irq_fn = aw963xx_rc_irqscr, + .irq_spec_handler_fn = aw963xx_irq_handle_func, + + .p_irq_init_fn = NULL, + .p_irq_deinit_fn = NULL, +}; + +static const struct aw_sar_soft_rst_t g_aw963xx_soft_rst = { + .reg_rst = REG_SA_RSTNALL, + .reg_rst_val = AW963XX_SOFT_RST_EN, + .delay_ms = AW963XX_CHIP_INIT_MAX_TIME_MS, + .p_soft_reset_fn = NULL, +}; + +static const struct aw_sar_init_over_irq_t g_aw963xx_init_over_irq = { + .wait_times = 100, + .daley_step = 1, + .reg_irqsrc = REG_IRQSRC, + .irq_offset_bit = 0, + .irq_mask = 0x1, + .irq_flag = 0x1, + + .p_check_init_over_irq_fn = NULL, + .p_get_err_type_fn = NULL, +}; + +static const struct aw_sar_pm_t g_aw963xx_pm_chip_mode = { + .suspend_set_mode = AW963XX_SLEEP_MODE, + .resume_set_mode = AW963XX_ACTIVE_MODE, + .shutdown_set_mode = AW963XX_SLEEP_MODE, +}; + +static const struct aw_sar_platform_config g_aw963xx_platform_config = { + .p_add_parse_dts_fn = &aw963xx_parse_dts, + .p_regulator_config = &g_regulator_config, + .p_irq_init = &g_aw963xx_irq_init, + .p_pm_chip_mode = &g_aw963xx_pm_chip_mode, +}; + +static void aw963xx_power_on_prox_detection(void *data, uint8_t en_flag) +{ + +} + +static const struct aw_sar_power_on_prox_detection_t g_aw933xx_power_on_prox_detection = { + .p_power_on_prox_detection_en_fn = aw963xx_power_on_prox_detection, + .irq_en_cali_bit = 3, + .power_on_prox_en_flag = true, +}; + +static const struct aw_sar_chip_config g_aw963xx_chip_config = { + .ch_num_max = AW963XX_CHANNEL_NUM_MAX, + .p_platform_config = &g_aw963xx_platform_config, + + .p_check_chipid = &g_aw963xx_check_chipid, + .p_soft_rst = &g_aw963xx_soft_rst, + .p_init_over_irq = &g_aw963xx_init_over_irq, + .p_fw_bin = &g_aw963xx_load_fw_bin, + .p_reg_bin = &g_aw963xx_load_reg_bin, + .p_chip_mode = &g_aw963xx_chip_mode, + + //Node usage parameters + .p_reg_list = &g_aw963xx_reg_list, + .p_reg_arr = &g_aw963xx_reg_arr_para, + .p_aot = &g_aw963xx_aot, + .p_diff = &g_aw963xx_diff, + .p_offset = &g_aw963xx_offset, + .p_mode = &g_aw963xx_mode, + .p_prox_fw = &g_aw963xx_load_fw_bin, + .p_get_chip_info = &g_aw963xx_get_chip_info, + .p_aw_sar_awrw = NULL, + .p_boot_bin = NULL, + + .p_other_operation = NULL, + .p_other_opera_free = NULL, + + .power_on_prox_detection = &g_aw933xx_power_on_prox_detection, +}; + +int32_t aw963xx_init(struct aw_sar *p_sar) +{ + struct aw963xx *aw963xx; + + if (!p_sar) + return -EINVAL; + + p_sar->priv_data = devm_kzalloc(p_sar->dev, sizeof(struct aw963xx), GFP_KERNEL); + if (!p_sar->priv_data) + return -ENOMEM; + + //Chip private function operation + p_sar->p_sar_para = &g_aw963xx_chip_config; + + aw963xx = (struct aw963xx *)p_sar->priv_data; + + return 0; +} + +void aw963xx_deinit(struct aw_sar *p_sar) +{ + struct aw963xx *aw963xx; + + if ((!p_sar) || (!p_sar->priv_data)) + return; + + aw963xx = (struct aw963xx *)p_sar->priv_data; + + + if (p_sar->priv_data != NULL) + devm_kfree(p_sar->dev, p_sar->priv_data); +} diff --git a/drivers/input/misc/aw_sar/aw963xx/aw963xx.h b/drivers/input/misc/aw_sar/aw963xx/aw963xx.h new file mode 100644 index 000000000000..a9ebbf2334b2 --- /dev/null +++ b/drivers/input/misc/aw_sar/aw963xx/aw963xx.h @@ -0,0 +1,749 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef AW963XX_H_ +#define AW963XX_H_ +#include "../comm/aw_sar_type.h" + +#define AW963XX_CHANNEL_NUM_MAX (12) +#define AW963XX_VALID_TH (2) +#define AW963XX_DATA_PROCESS_FACTOR (1024) +#define AW963XX_SAR_VCC_MIN_UV (1700000) +#define AW963XX_SAR_VCC_MAX_UV (3600000) +#define AW963XX_SRAM_UPDATE_ONE_PACK_SIZE (1024) +#define AW963XX_SRAM_UPDATE_ONE_UINT_SIZE (4) +#define AW963XX_SRAM_START_ADDR (0x2000) +#define AW963XX_SRAM_END_ADDR (0x4ff4 + 4) +#define AW963XX_SRAM_SIZE (AW963XX_SRAM_END_ADDR - AW963XX_SRAM_START_ADDR) + +#define AW963XX_STEP_LEN_UNSIGNED_CAP_ROUGH_ADJ (9900) +#define AW963XX_STEP_LEN_UNSIGNED_CAP_FINE_ADJ (152) +#define AW963XX_STEP_LEN_UNSIGNED_CAP_ENLARGE (10000) + +#define AW963XX_CPU_OSC_CTRL_MASK (1) + +#define ONE_WORD (0xff) +#define AW_BIT8 (8) +#define AW_BIT16 (16) +#define AW96303 ("AW96303") +#define AW96305 ("AW96305") +#define AW96305BFOR ("AW96305BFOR") +#define AW96308 ("AW96308") +#define AW96310 ("AW96310") + +enum aw963xx_cap_mode { + AW963XX_UNSIGNED_CAP = 0, + AW963XX_SIGNED_CAP = 4, + AW963XX_MUTUAL_CAP = 5, +}; + +enum aw963xx_approach_state { + AW963XX_FAR_AWAY = 0, + AW963XX_APPROACH = 1, +}; + +enum aw963xx_cs_2_irq { + AW963XX_CS2_IRQ = 2, + AW963XX_CS5_IRQ = 5, +}; + +enum aw963xx_operation_mode { + AW963XX_ACTIVE_MODE = 0x01, + AW963XX_SLEEP_MODE = 0x02, + AW963XX_DEEPSLEEP_MODE = 0x03, +}; + +enum aw963xx_chip_id { + AW96303_CHIP_ID = 0xA9630340, + AW96305_CHIP_ID = 0xA9630520, + AW96305BFOR_CHIP_ID = 0xA9630500, + AW96308_CHIP_ID = 0xA9630810, + AW96310_CHIP_ID = 0xA9631010, +}; + +enum aw963xx_boot_mode { + AW963XX_ROM_MODE = 0, + AW963XX_RAM_MODE = 1, +}; + +struct aw963xx { + uint32_t irq_mux; + uint32_t start_mode; + uint32_t ref_ch_en[AW963XX_CHANNEL_NUM_MAX]; + void *p_aw_sar; + + uint32_t last_blfilta[AW963XX_CHANNEL_NUM_MAX]; + uint32_t last_irq_en; + +}; + +#define REG_CPU_MODE_SET (0xf800) +#define AW963XX_RESET_CPU_SET_BOOT_SATRT (0x00010100) +#define AW963XX_EXIT_RESET_CPU_SET_BOOT_SATRT (0x00000100) +#define REG_CPU_RESET (0XFF0C) +#define AW963XX_RESET_SET (0) +#define REG_RAM_PASSWORD (0xFFE4) +#define AW963XX_NO_ENCRYPTION (0x3C000000) +#define AW963XX_FILTCTRL0_CHX_REFAEN (16) +#define AW963XX_FILTCTRL0_CHX_REFASEL (11) +#define AW963XX_FILTCTRL0_CHX_REFBEN (9) +#define AW963XX_FILTCTRL0_CHX_REFBSEL (4) +#define AW963XX_REF_EN (1) +#define REG_SA_RSTNALL (0xFF0C) +#define AW963XX_SOFT_RST_EN (0) +#define AW963XX_CHIP_INIT_MAX_TIME_MS (30) + +#define AW963XX_RAM_START_ADDR (0x2000) + +#define AFE_BASE_ADDR (0x0000) +#define DSP_BASE_ADDR (0x0000) +#define STAT_BASE_ADDR (0x0000) +#define DATA_BASE_ADDR (0x0000) +#define SFR_BASE_ADDR (0x0000) +#define HIDDEN_BASE_ADDR (0x0000) + +#define REG_STAT0 ((0x0020) + STAT_BASE_ADDR) +#define REG_STAT1 ((0x0024) + STAT_BASE_ADDR) +#define REG_FWVER ((0x005C) + STAT_BASE_ADDR) + +#define REG_DIFF_CH0 ((0x01EC) + DATA_BASE_ADDR) +#define REG_DIFF_CH1 ((0x0304) + DATA_BASE_ADDR) + +#define REG_FILTCTRL0_CH0 ((0x0130) + DSP_BASE_ADDR) +#define REG_FILTCTRL0_CH1 ((0x0248) + DSP_BASE_ADDR) + +#define REG_SCANCTRL1 ((0x0004) + AFE_BASE_ADDR) +#define REG_AFESOFTCFG0_CH0 ((0x010C) + AFE_BASE_ADDR) +#define REG_AFECFG1_CH0 ((0x0118) + AFE_BASE_ADDR) +#define REG_AFECFG3_CH0 ((0x0120) + AFE_BASE_ADDR) +#define REG_AFESOFTCFG0_CH1 ((0x0224) + AFE_BASE_ADDR) +#define REG_AFECFG1_CH1 ((0x0230) + AFE_BASE_ADDR) +#define REG_AFECFG3_CH1 ((0x0238) + AFE_BASE_ADDR) + +#define REG_AFECFG1_M_CH0 ((0x10F8) + HIDDEN_BASE_ADDR) +#define REG_AFECFG1_M_CH1 ((0x1184) + HIDDEN_BASE_ADDR) + +#define REG_IRQSRC ((0xF080) + SFR_BASE_ADDR) +#define REG_IRQEN ((0xF084) + SFR_BASE_ADDR) +#define REG_CHIPSTAT ((0xFF00) + SFR_BASE_ADDR) +#define REG_CHIP_ID0 ((0xFF10) + SFR_BASE_ADDR) + +#define REG_CMD ((0xf008) + SFR_BASE_ADDR) +#define REG_AFECFG2_CH0 ((0x011c) + AFE_BASE_ADDR) +#define REG_AFECFG2_CH1 ((0x0234) + AFE_BASE_ADDR) + +struct reg_data { + unsigned char rw; + unsigned short reg; +}; +/******************************************** + * Register Access + *******************************************/ +#define REG_NONE_ACCESS (0) +#define REG_RD_ACCESS (1 << 0) +#define REG_WR_ACCESS (1 << 1) +static const struct reg_data g_aw963xx_reg_access[] = { + { .reg = REG_SCANCTRL1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFESOFTCFG0_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG1_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG3_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFESOFTCFG0_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG1_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG3_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_STAT0, .rw = REG_RD_ACCESS, }, + { .reg = REG_STAT1, .rw = REG_RD_ACCESS, }, + { .reg = REG_FWVER, .rw = REG_RD_ACCESS, }, + { .reg = REG_DIFF_CH0, .rw = REG_RD_ACCESS, }, + { .reg = REG_DIFF_CH1, .rw = REG_RD_ACCESS, }, + { .reg = REG_FILTCTRL0_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_FILTCTRL0_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG1_M_CH0, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_AFECFG1_M_CH1, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_IRQSRC, .rw = REG_RD_ACCESS, }, + { .reg = REG_IRQEN, .rw = REG_RD_ACCESS | REG_WR_ACCESS, }, + { .reg = REG_CHIPSTAT, .rw = REG_RD_ACCESS, }, + { .reg = REG_CHIP_ID0, .rw = REG_RD_ACCESS, }, +}; +static const uint32_t aw963xx_reg_default[] = { + 0x0000, 0x000000FF, + 0x0004, 0x00000FFF, + 0x0008, 0x00000FFF, + 0x000C, 0x00000064, + 0x0010, 0x0000705F, + 0x0014, 0x80000000, + 0x0060, 0x00000000, + 0x0064, 0x00000000, + 0x0068, 0x00000000, + 0x006C, 0x00000000, + 0x0070, 0x00000000, + 0x0074, 0x00000000, + 0x0078, 0x00000000, + 0x007C, 0x00000000, + 0x0080, 0x00000000, + 0x0084, 0x00000000, + 0x0088, 0x00000000, + 0x008C, 0x00000000, + 0x0168, 0x00000000, + 0x016C, 0x003F0000, + 0x0170, 0x00050100, + 0x0174, 0x00000000, + 0x0178, 0x341C9207, + 0x017C, 0x00008000, + 0x0180, 0x00000909, + 0x0184, 0x00000001, + 0x0188, 0x00000000, + 0x0318, 0x00000000, + 0x031C, 0x003F0000, + 0x0320, 0x00050100, + 0x0324, 0x00000000, + 0x0328, 0x341C9207, + 0x032C, 0x00008000, + 0x0330, 0x00000909, + 0x0334, 0x00000008, + 0x0338, 0x00000000, + 0x04C8, 0x00000000, + 0x04CC, 0x003F0000, + 0x04D0, 0x00050100, + 0x04D4, 0x00000000, + 0x04D8, 0x341C9207, + 0x04DC, 0x00008000, + 0x04E0, 0x00000909, + 0x04E4, 0x00000040, + 0x04E8, 0x00000000, + 0x0678, 0x00000000, + 0x067C, 0x003F0000, + 0x0680, 0x00050100, + 0x0684, 0x00000000, + 0x0688, 0x341C9207, + 0x068C, 0x00008000, + 0x0690, 0x00000909, + 0x0694, 0x00000200, + 0x0698, 0x00000000, + 0x0828, 0x00000000, + 0x082C, 0x003F0000, + 0x0830, 0x00050100, + 0x0834, 0x00000000, + 0x0838, 0x341C9207, + 0x083C, 0x00008000, + 0x0840, 0x00000909, + 0x0844, 0x00001000, + 0x0848, 0x00000000, + 0x09D8, 0x00000000, + 0x09DC, 0x003F0000, + 0x09E0, 0x00050100, + 0x09E4, 0x00000000, + 0x09E8, 0x341C9207, + 0x09EC, 0x00008000, + 0x09F0, 0x00000909, + 0x09F4, 0x00008000, + 0x09F8, 0x00000000, + 0x0B88, 0x00000000, + 0x0B8C, 0x003F0000, + 0x0B90, 0x00050100, + 0x0B94, 0x00000000, + 0x0B98, 0x341C9207, + 0x0B9C, 0x00008000, + 0x0BA0, 0x00000909, + 0x0BA4, 0x00040000, + 0x0BA8, 0x00000000, + 0x0D38, 0x00000000, + 0x0D3C, 0x003F0000, + 0x0D40, 0x00050100, + 0x0D44, 0x00000000, + 0x0D48, 0x341C9207, + 0x0D4C, 0x00008000, + 0x0D50, 0x00000909, + 0x0D54, 0x00200000, + 0x0D58, 0x00000000, + 0x0EE8, 0x00000000, + 0x0EEC, 0x003F0000, + 0x0EF0, 0x00050100, + 0x0EF4, 0x00000000, + 0x0EF8, 0x341C9207, + 0x0EFC, 0x00008000, + 0x0F00, 0x00000909, + 0x0F04, 0x00000000, + 0x0F08, 0x00000000, + 0x1098, 0x00000000, + 0x109C, 0x003F0000, + 0x10A0, 0x00050100, + 0x10A4, 0x00000000, + 0x10A8, 0x341C9207, + 0x10AC, 0x00008000, + 0x10B0, 0x00000909, + 0x10B4, 0x00000000, + 0x10B8, 0x00000000, + 0x1248, 0x00000000, + 0x124C, 0x003F0000, + 0x1250, 0x00050100, + 0x1254, 0x00000000, + 0x1258, 0x341C9207, + 0x125C, 0x00008000, + 0x1260, 0x00000909, + 0x1264, 0x00000000, + 0x1268, 0x00000000, + 0x13F8, 0x00000000, + 0x13FC, 0x003F0000, + 0x1400, 0x00050100, + 0x1404, 0x00000000, + 0x1408, 0x341C9207, + 0x140C, 0x00008000, + 0x1410, 0x00000909, + 0x1414, 0x00000000, + 0x1418, 0x00000000, + 0x018C, 0xE0400000, + 0x0190, 0x00000000, + 0x0194, 0x00000000, + 0x0198, 0x000A0000, + 0x019C, 0x000008D2, + 0x01A0, 0x00000000, + 0x01A4, 0x00000040, + 0x01A8, 0x000186A0, + 0x01AC, 0x00030D40, + 0x01B0, 0x00061A80, + 0x01B4, 0x000C3500, + 0x01B8, 0x00000000, + 0x01BC, 0x00000000, + 0x01C0, 0x00000000, + 0x01C4, 0x00000000, + 0x01C8, 0x00000000, + 0x01CC, 0x00000000, + 0x033C, 0xE0400000, + 0x0340, 0x00000000, + 0x0344, 0x00000000, + 0x0348, 0x000A0000, + 0x034C, 0x000008D2, + 0x0350, 0x00000000, + 0x0354, 0x00000040, + 0x0358, 0x000186A0, + 0x035C, 0x00030D40, + 0x0360, 0x00061A80, + 0x0364, 0x000C3500, + 0x0368, 0x00000000, + 0x036C, 0x00000000, + 0x0370, 0x00000000, + 0x0374, 0x00000000, + 0x0378, 0x00000000, + 0x037C, 0x00000000, + 0x04EC, 0xE0400000, + 0x04F0, 0x00000000, + 0x04F4, 0x00000000, + 0x04F8, 0x000A0000, + 0x04FC, 0x000008D2, + 0x0500, 0x00000000, + 0x0504, 0x00000040, + 0x0508, 0x000186A0, + 0x050C, 0x00030D40, + 0x0510, 0x00061A80, + 0x0514, 0x000C3500, + 0x0518, 0x00000000, + 0x051C, 0x00000000, + 0x0520, 0x00000000, + 0x0524, 0x00000000, + 0x0528, 0x00000000, + 0x052C, 0x00000000, + 0x069C, 0xE0400000, + 0x06A0, 0x00000000, + 0x06A4, 0x00000000, + 0x06A8, 0x000A0000, + 0x06AC, 0x000008D2, + 0x06B0, 0x00000000, + 0x06B4, 0x00000040, + 0x06B8, 0x000186A0, + 0x06BC, 0x00030D40, + 0x06C0, 0x00061A80, + 0x06C4, 0x000C3500, + 0x06C8, 0x00000000, + 0x06CC, 0x00000000, + 0x06D0, 0x00000000, + 0x06D4, 0x00000000, + 0x06D8, 0x00000000, + 0x06DC, 0x00000000, + 0x084C, 0xE0400000, + 0x0850, 0x00000000, + 0x0854, 0x00000000, + 0x0858, 0x000A0000, + 0x085C, 0x000008D2, + 0x0860, 0x00000000, + 0x0864, 0x00000040, + 0x0868, 0x000186A0, + 0x086C, 0x00030D40, + 0x0870, 0x00061A80, + 0x0874, 0x000C3500, + 0x0878, 0x00000000, + 0x087C, 0x00000000, + 0x0880, 0x00000000, + 0x0884, 0x00000000, + 0x0888, 0x00000000, + 0x088C, 0x00000000, + 0x09FC, 0xE0400000, + 0x0A00, 0x00000000, + 0x0A04, 0x00000000, + 0x0A08, 0x000A0000, + 0x0A0C, 0x000008D2, + 0x0A10, 0x00000000, + 0x0A14, 0x00000040, + 0x0A18, 0x000186A0, + 0x0A1C, 0x00030D40, + 0x0A20, 0x00061A80, + 0x0A24, 0x000C3500, + 0x0A28, 0x00000000, + 0x0A2C, 0x00000000, + 0x0A30, 0x00000000, + 0x0A34, 0x00000000, + 0x0A38, 0x00000000, + 0x0A3C, 0x00000000, + 0x0BAC, 0xE0400000, + 0x0BB0, 0x00000000, + 0x0BB4, 0x00000000, + 0x0BB8, 0x000A0000, + 0x0BBC, 0x000008D2, + 0x0BC0, 0x00000000, + 0x0BC4, 0x00000040, + 0x0BC8, 0x000186A0, + 0x0BCC, 0x00030D40, + 0x0BD0, 0x00061A80, + 0x0BD4, 0x000C3500, + 0x0BD8, 0x00000000, + 0x0BDC, 0x00000000, + 0x0BE0, 0x00000000, + 0x0BE4, 0x00000000, + 0x0BE8, 0x00000000, + 0x0BEC, 0x00000000, + 0x0D5C, 0xE0400000, + 0x0D60, 0x00000000, + 0x0D64, 0x00000000, + 0x0D68, 0x000A0000, + 0x0D6C, 0x000008D2, + 0x0D70, 0x00000000, + 0x0D74, 0x00000040, + 0x0D78, 0x000186A0, + 0x0D7C, 0x00030D40, + 0x0D80, 0x00061A80, + 0x0D84, 0x000C3500, + 0x0D88, 0x00000000, + 0x0D8C, 0x00000000, + 0x0D90, 0x00000000, + 0x0D94, 0x00000000, + 0x0D98, 0x00000000, + 0x0D9C, 0x00000000, + 0x0F0C, 0xE0400000, + 0x0F10, 0x00000000, + 0x0F14, 0x00000000, + 0x0F18, 0x000A0000, + 0x0F1C, 0x000008D2, + 0x0F20, 0x00000000, + 0x0F24, 0x00000040, + 0x0F28, 0x000186A0, + 0x0F2C, 0x00000000, + 0x0F30, 0x00000000, + 0x0F34, 0x00000000, + 0x0F38, 0x00000000, + 0x0F3C, 0x00000000, + 0x0F40, 0x00000000, + 0x0F44, 0x00000000, + 0x0F48, 0x00000000, + 0x0F4C, 0x00000000, + 0x10BC, 0xE0400000, + 0x10C0, 0x00000000, + 0x10C4, 0x00000000, + 0x10C8, 0x000A0000, + 0x10CC, 0x000008D2, + 0x10D0, 0x00000000, + 0x10D4, 0x00000040, + 0x10D8, 0x00000000, + 0x10DC, 0x00000000, + 0x10E0, 0x00000000, + 0x10E4, 0x00000000, + 0x10E8, 0x00000000, + 0x10EC, 0x00000000, + 0x10F0, 0x00000000, + 0x10F4, 0x00000000, + 0x10F8, 0x00000000, + 0x10FC, 0x00000000, + 0x126C, 0xE0400000, + 0x1270, 0x00000000, + 0x1274, 0x00000000, + 0x1278, 0x000A0000, + 0x127C, 0x000008D2, + 0x1280, 0x00000000, + 0x1284, 0x00000040, + 0x1288, 0x00000000, + 0x128C, 0x00000000, + 0x1290, 0x00000000, + 0x1294, 0x00000000, + 0x1298, 0x00000000, + 0x129C, 0x00000000, + 0x12A0, 0x00000000, + 0x12A4, 0x00000000, + 0x12A8, 0x00000000, + 0x12AC, 0x00000000, + 0x141C, 0xE0400000, + 0x1420, 0x00000000, + 0x1424, 0x00000000, + 0x1428, 0x000A0000, + 0x142C, 0x000008D2, + 0x1430, 0x00000000, + 0x1434, 0x00000040, + 0x1438, 0x00000000, + 0x143C, 0x00000000, + 0x1440, 0x00000000, + 0x1444, 0x00000000, + 0x1448, 0x00000000, + 0x144C, 0x00000000, + 0x1450, 0x00000000, + 0x1454, 0x00000000, + 0x1458, 0x00000000, + 0x145C, 0x00000000, + 0x01D0, 0x00000000, + 0x01D4, 0x00000000, + 0x01D8, 0x00000000, + 0x01DC, 0x00000000, + 0x01E0, 0x00000000, + 0x01E4, 0xFFFFFFFF, + 0x01E8, 0x00000000, + 0x01EC, 0x00000000, + 0x01F0, 0x00000000, + 0x01F4, 0x00000000, + 0x01F8, 0x070004B0, + 0x01FC, 0x0E000000, + 0x0200, 0xF2000000, + 0x0204, 0x02000000, + 0x0208, 0x02000000, + 0x020C, 0x00002000, + 0x0210, 0x00010000, + 0x0214, 0x80007530, + 0x0220, 0x00000000, + 0x0224, 0x00000000, + 0x0380, 0x00000000, + 0x0384, 0x00000000, + 0x0388, 0x00000000, + 0x038C, 0x00000000, + 0x0390, 0x00000000, + 0x0394, 0xFFFFFFFF, + 0x0398, 0x00000000, + 0x039C, 0x00000000, + 0x03A0, 0x00000000, + 0x03A4, 0x00000000, + 0x03A8, 0x070004B0, + 0x03AC, 0x0E000000, + 0x03B0, 0xF2000000, + 0x03B4, 0x02000000, + 0x03B8, 0x02000000, + 0x03BC, 0x00002000, + 0x03C0, 0x00010000, + 0x03C4, 0x80007530, + 0x03D0, 0x00000000, + 0x03D4, 0x00000000, + 0x0530, 0x00000000, + 0x0534, 0x00000000, + 0x0538, 0x00000000, + 0x053C, 0x00000000, + 0x0540, 0x00000000, + 0x0544, 0xFFFFFFFF, + 0x0548, 0x00000000, + 0x054C, 0x00000000, + 0x0550, 0x00000000, + 0x0554, 0x00000000, + 0x0558, 0x070004B0, + 0x055C, 0x0E000000, + 0x0560, 0xF2000000, + 0x0564, 0x02000000, + 0x0568, 0x02000000, + 0x056C, 0x00002000, + 0x0570, 0x00010000, + 0x0574, 0x80007530, + 0x0580, 0x00000000, + 0x0584, 0x00000000, + 0x06E0, 0x00000000, + 0x06E4, 0x00000000, + 0x06E8, 0x00000000, + 0x06EC, 0x00000000, + 0x06F0, 0x00000000, + 0x06F4, 0xFFFFFFFF, + 0x06F8, 0x00000000, + 0x06FC, 0x00000000, + 0x0700, 0x00000000, + 0x0704, 0x00000000, + 0x0708, 0x070004B0, + 0x070C, 0x0E000000, + 0x0710, 0xF2000000, + 0x0714, 0x02000000, + 0x0718, 0x02000000, + 0x071C, 0x00002000, + 0x0720, 0x00010000, + 0x0724, 0x80007530, + 0x0730, 0x00000000, + 0x0734, 0x00000000, + 0x0890, 0x00000000, + 0x0894, 0x00000000, + 0x0898, 0x00000000, + 0x089C, 0x00000000, + 0x08A0, 0x00000000, + 0x08A4, 0xFFFFFFFF, + 0x08A8, 0x00000000, + 0x08AC, 0x00000000, + 0x08B0, 0x00000000, + 0x08B4, 0x00000000, + 0x08B8, 0x070004B0, + 0x08BC, 0x0E000000, + 0x08C0, 0xF2000000, + 0x08C4, 0x02000000, + 0x08C8, 0x02000000, + 0x08CC, 0x00002000, + 0x08D0, 0x00010000, + 0x08D4, 0x80007530, + 0x08E0, 0x00000000, + 0x08E4, 0x00000000, + 0x0A40, 0x00000000, + 0x0A44, 0x00000000, + 0x0A48, 0x00000000, + 0x0A4C, 0x00000000, + 0x0A50, 0x00000000, + 0x0A54, 0xFFFFFFFF, + 0x0A58, 0x00000000, + 0x0A5C, 0x00000000, + 0x0A60, 0x00000000, + 0x0A64, 0x00000000, + 0x0A68, 0x070004B0, + 0x0A6C, 0x0E000000, + 0x0A70, 0xF2000000, + 0x0A74, 0x02000000, + 0x0A78, 0x02000000, + 0x0A7C, 0x00002000, + 0x0A80, 0x00010000, + 0x0A84, 0x80007530, + 0x0A90, 0x00000000, + 0x0A94, 0x00000000, + 0x0BF0, 0x00000000, + 0x0BF4, 0x00000000, + 0x0BF8, 0x00000000, + 0x0BFC, 0x00000000, + 0x0C00, 0x00000000, + 0x0C04, 0xFFFFFFFF, + 0x0C08, 0x00000000, + 0x0C0C, 0x00000000, + 0x0C10, 0x00000000, + 0x0C14, 0x00000000, + 0x0C18, 0x070004B0, + 0x0C1C, 0x0E000000, + 0x0C20, 0xF2000000, + 0x0C24, 0x02000000, + 0x0C28, 0x02000000, + 0x0C2C, 0x00002000, + 0x0C30, 0x00010000, + 0x0C34, 0x80007530, + 0x0C40, 0x00000000, + 0x0C44, 0x00000000, + 0x0DA0, 0x00000000, + 0x0DA4, 0x00000000, + 0x0DA8, 0x00000000, + 0x0DAC, 0x00000000, + 0x0DB0, 0x00000000, + 0x0DB4, 0xFFFFFFFF, + 0x0DB8, 0x00000000, + 0x0DBC, 0x00000000, + 0x0DC0, 0x00000000, + 0x0DC4, 0x00000000, + 0x0DC8, 0x070004B0, + 0x0DCC, 0x0E000000, + 0x0DD0, 0xF2000000, + 0x0DD4, 0x02000000, + 0x0DD8, 0x02000000, + 0x0DDC, 0x00002000, + 0x0DE0, 0x00010000, + 0x0DE4, 0x80007530, + 0x0DF0, 0x00000000, + 0x0DF4, 0x00000000, + 0x0F50, 0x00000000, + 0x0F54, 0x00000000, + 0x0F58, 0x00000000, + 0x0F5C, 0x00000000, + 0x0F60, 0x00000000, + 0x0F64, 0xFFFFFFFF, + 0x0F68, 0x00000000, + 0x0F6C, 0x00000000, + 0x0F70, 0x00000000, + 0x0F74, 0x00000000, + 0x0F78, 0x070004B0, + 0x0F7C, 0x0E000000, + 0x0F80, 0xF2000000, + 0x0F84, 0x02000000, + 0x0F88, 0x02000000, + 0x0F8C, 0x00002000, + 0x0F90, 0x00010000, + 0x0F94, 0x80007530, + 0x0FA0, 0x00000000, + 0x0FA4, 0x00000000, + 0x1100, 0x00000000, + 0x1104, 0x00000000, + 0x1108, 0x00000000, + 0x110C, 0x00000000, + 0x1110, 0x00000000, + 0x1114, 0xFFFFFFFF, + 0x1118, 0x00000000, + 0x111C, 0x00000000, + 0x1120, 0x00000000, + 0x1124, 0x00000000, + 0x1128, 0x070004B0, + 0x112C, 0x0E000000, + 0x1130, 0xF2000000, + 0x1134, 0x02000000, + 0x1138, 0x02000000, + 0x113C, 0x00002000, + 0x1140, 0x00010000, + 0x1144, 0x80007530, + 0x1150, 0x00000000, + 0x1154, 0x00000000, + 0x12B0, 0x00000000, + 0x12B4, 0x00000000, + 0x12B8, 0x00000000, + 0x12BC, 0x00000000, + 0x12C0, 0x00000000, + 0x12C4, 0xFFFFFFFF, + 0x12C8, 0x00000000, + 0x12CC, 0x00000000, + 0x12D0, 0x00000000, + 0x12D4, 0x00000000, + 0x12D8, 0x070004B0, + 0x12DC, 0x0E000000, + 0x12E0, 0xF2000000, + 0x12E4, 0x02000000, + 0x12E8, 0x02000000, + 0x12EC, 0x00002000, + 0x12F0, 0x00010000, + 0x12F4, 0x80007530, + 0x1300, 0x00000000, + 0x1304, 0x00000000, + 0x1460, 0x00000000, + 0x1464, 0x00000000, + 0x1468, 0x00000000, + 0x146C, 0x00000000, + 0x1470, 0x00000000, + 0x1474, 0xFFFFFFFF, + 0x1478, 0x00000000, + 0x147C, 0x00000000, + 0x1480, 0x00000000, + 0x1484, 0x00000000, + 0x1488, 0x070004B0, + 0x148C, 0x0E000000, + 0x1490, 0xF2000000, + 0x1494, 0x02000000, + 0x1498, 0x02000000, + 0x149C, 0x00002000, + 0x14A0, 0x00010000, + 0x14A4, 0x80007530, + 0x14B0, 0x00000000, + 0x14B4, 0x00000000, + 0xF084, 0x00000006, + 0x004C, 0xFFFFFFFF, + 0x0050, 0xFFFFFFFF, + 0x0054, 0xFFFFFFFF, + 0x0058, 0xFFFFFFFF, + 0x0090, 0x00000000, + 0x0094, 0x00000064, + 0x0098, 0x40000000, + 0x009C, 0x00000000, + 0x00A0, 0x00140014, + 0x00A4, 0x0019000D, + 0x00A8, 0x0096004B, +}; +#endif From patchwork Wed May 29 13:06:08 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wangshuaijie@awinic.com X-Patchwork-Id: 13678823 Received: from out28-194.mail.aliyun.com (out28-194.mail.aliyun.com [115.124.28.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 504E8DDD4; Wed, 29 May 2024 13:12:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988334; cv=none; b=OjCFg3IwHlmgODM0Nf8AlIBn2eL3y0Mh/bhWtmNcqEkQfP1wDQ8+lIvft5M2QY7lJ9AB/uNZ3+OO995IwQZOuKvsuZk7k3Z+PykR92G58MMzpIIvRe/j8nkxLMY7BtMRyQ+n9RwmQPZI5TWDsFQ+1Z0+yg8u58sd3IUY7m1g9AQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1716988334; c=relaxed/simple; bh=OMJ9PB36IBjjWKfvIPxohdafw5pUCCIH5qbW9cqa9Uo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TMKXIT8hGHBMVhw5k6ukFJ4FYCvxx/5MkWCkTV9UeaISTMwkpUkQTpbPTWe/5LOx9K/jWyB04a16V2E9XBvUmh99+lczZOJNzbFYv/ylmLtjRss5itaxmB+ATsMCsc6Qlp3wUPz9k8HaWbggEFsRAh9tKPbxeubOvfwyjhdtUHY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com; spf=pass smtp.mailfrom=awinic.com; arc=none smtp.client-ip=115.124.28.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=awinic.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=awinic.com X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=green;DM=|CONTINUE|false|;DS=CONTINUE|ham_regular_dialog|0.0378758-0.000531947-0.961592;FP=0|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033040120151;MF=wangshuaijie@awinic.com;NM=1;PH=DS;RN=11;RT=11;SR=0;TI=SMTPD_---.XqPpuL8_1716987996; Received: from awinic..(mailfrom:wangshuaijie@awinic.com fp:SMTPD_---.XqPpuL8_1716987996) by smtp.aliyun-inc.com; Wed, 29 May 2024 21:06:37 +0800 From: wangshuaijie@awinic.com To: dmitry.torokhov@gmail.com, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, jeff@labundy.com, linux-input@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: wangshuaijie@awinic.com, liweilei@awinic.com, kangjiajun@awinic.com Subject: [PATCH V1 5/5] Add support for Awinic sar sensor. Date: Wed, 29 May 2024 13:06:08 +0000 Message-ID: <20240529130608.783624-6-wangshuaijie@awinic.com> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20240529130608.783624-1-wangshuaijie@awinic.com> References: <20240529130608.783624-1-wangshuaijie@awinic.com> Precedence: bulk X-Mailing-List: linux-input@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 From: shuaijie wang Signed-off-by: shuaijie wang --- drivers/input/misc/Kconfig | 9 + drivers/input/misc/Makefile | 1 + drivers/input/misc/aw_sar/Makefile | 2 + drivers/input/misc/aw_sar/aw_sar.c | 2039 ++++++++++++++++++++++++++++ drivers/input/misc/aw_sar/aw_sar.h | 15 + 5 files changed, 2066 insertions(+) create mode 100644 drivers/input/misc/aw_sar/Makefile create mode 100644 drivers/input/misc/aw_sar/aw_sar.c create mode 100644 drivers/input/misc/aw_sar/aw_sar.h diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 6ba984d7f0b1..ac56fdd21839 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -939,4 +939,13 @@ config INPUT_STPMIC1_ONKEY To compile this driver as a module, choose M here: the module will be called stpmic1_onkey. +config AWINIC_SAR + tristate "Awinic sar sensor support" + depends on I2C + help + Say Y to enable support for the Awinic sar sensor driver. + + To compile this driver as a module, choose M here: the + module will be called awinic_sar. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 04296a4abe8e..6ee1870ea677 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -90,3 +90,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o +obj-$(CONFIG_AWINIC_SAR) += aw_sar/ diff --git a/drivers/input/misc/aw_sar/Makefile b/drivers/input/misc/aw_sar/Makefile new file mode 100644 index 000000000000..c357ecaa4f98 --- /dev/null +++ b/drivers/input/misc/aw_sar/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_AWINIC_SAR) += awinic_sar.o +awinic_sar-objs := ./comm/aw_sar_comm_interface.o aw_sar.o ./aw9610x/aw9610x.o ./aw963xx/aw963xx.o diff --git a/drivers/input/misc/aw_sar/aw_sar.c b/drivers/input/misc/aw_sar/aw_sar.c new file mode 100644 index 000000000000..c0c37658a482 --- /dev/null +++ b/drivers/input/misc/aw_sar/aw_sar.c @@ -0,0 +1,2039 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AWINIC sar sensor driver + * + * Author: Shuaijie Wang + * + * Copyright (c) 2024 awinic Technology CO., LTD + */ +#include "./comm/aw_sar_chip_interface.h" +#include "aw_sar.h" + +#define AW_SAR_I2C_NAME "awinic_sar" + +/* + * Please check which power_supply on your platform + * can get the charger insertion information, then select it. + * eg: "usb"/"charger"/"mtk-master-charger"/"mtk_charger_type" + */ +#define USB_POWER_SUPPLY_NAME "charger" +/* + * Check which of your power_supply properties is available + * for the charger insertion information and select it. + * eg: POWER_SUPPLY_PROP_ONLINE/POWER_SUPPLY_PROP_PRESENT + */ +#define AW_USB_PROP_ONLINE POWER_SUPPLY_PROP_ONLINE + +#define AW_I2C_RW_RETRY_TIME_MIN (2000) +#define AW_I2C_RW_RETRY_TIME_MAX (3000) +#define AW_RETRIES (5) + +#define AW_SAR_AWRW_OffSET (20) +#define AW_SAR_AWRW_DATA_WIDTH (5) +#define AW_DATA_OffSET_2 (2) +#define AW_DATA_OffSET_3 (3) +#define AW_POWER_ON_SYSFS_DELAY_MS (5000) +#define AW_SAR_MONITOR_ESD_DELAY_MS (5000) +#define AW_SAR_OFFSET_LEN (15) +#define AW_SAR_VCC_MIN_UV (1700000) +#define AW_SAR_VCC_MAX_UV (3600000) + +static struct mutex aw_sar_lock; + +static int32_t aw_sar_get_chip_info(struct aw_sar *p_sar); +static void aw_sar_sensor_free(struct aw_sar *p_sar); + +//Because disable/enable_irq api Therefore, IRQ is embedded +void aw_sar_disable_irq(struct aw_sar *p_sar) +{ + if (p_sar->irq_init.host_irq_stat == IRQ_ENABLE) { + disable_irq(p_sar->irq_init.to_irq); + p_sar->irq_init.host_irq_stat = IRQ_DISABLE; + } +} + +void aw_sar_enable_irq(struct aw_sar *p_sar) +{ + if (p_sar->irq_init.host_irq_stat == IRQ_DISABLE) { + enable_irq(p_sar->irq_init.to_irq); + p_sar->irq_init.host_irq_stat = IRQ_ENABLE; + } +} + +//Chip logic part start +//Load default array function +static int32_t +aw_sar_para_loaded_func(struct i2c_client *i2c, const struct aw_sar_para_load_t *para_load) +{ + int32_t ret; + int32_t i; + + for (i = 0; i < para_load->reg_arr_len; i = i + 2) { + ret = aw_sar_i2c_write(i2c, (uint16_t)para_load->reg_arr[i], + para_load->reg_arr[i + 1]); + if (ret != 0) + return ret; + } + + return 0; +} + +//Mode setting function +static void aw_sar_mode_set_func(struct i2c_client *i2c, int to_irq, + struct aw_sar_mode_set_t *mode_set_para, + const struct aw_sar_mode_set_t *mode_set, uint8_t len) +{ + uint8_t i; + + for (i = 0; i < len; i++) { + if ((mode_set[i].chip_mode.curr_mode == mode_set_para->chip_mode.curr_mode) && + (mode_set[i].chip_mode.last_mode == mode_set_para->chip_mode.last_mode) && + ((mode_set[i].chip_id == AW_SAR_NONE_CHECK_CHIP) || + ((mode_set[i].chip_id & mode_set_para->chip_id) != 0))) { + if (mode_set[i].mode_switch_ops.enable_clock != NULL) + mode_set[i].mode_switch_ops.enable_clock(i2c); + if (mode_set[i].mode_switch_ops.rc_irqscr != NULL) + mode_set[i].mode_switch_ops.rc_irqscr(i2c); + if (mode_set[i].mode_switch_ops.mode_update != NULL) + mode_set[i].mode_switch_ops.mode_update(i2c); + break; + } + } +} + +static int32_t aw_sar_check_init_over_irq_func(struct i2c_client *i2c, + const struct aw_sar_init_over_irq_t *p_check_irq) +{ + int16_t cnt = p_check_irq->wait_times; + uint32_t irq_stat; + int32_t ret; + + do { + ret = aw_sar_i2c_read(i2c, p_check_irq->reg_irqsrc, &irq_stat); + if (ret < 0) + return ret; + if (((irq_stat >> p_check_irq->irq_offset_bit) & p_check_irq->irq_mask) == + p_check_irq->irq_flag) + return 0; + mdelay(1); + } while (cnt--); + + if (cnt < 0) + dev_err(&i2c->dev, "init over irq error!"); + + return AW_ERR_IRQ_INIT_OVER; +} + +static int32_t +aw_sar_soft_reset_func(struct i2c_client *i2c, const struct aw_sar_soft_rst_t *p_soft_rst) +{ + int32_t ret; + + ret = aw_sar_i2c_write(i2c, p_soft_rst->reg_rst, p_soft_rst->reg_rst_val); + if (ret < 0) { + dev_err(&i2c->dev, "soft_reset error: %d", ret); + return ret; + } + + msleep(p_soft_rst->delay_ms); + + return 0; +} +//Chip logic part end + +static int32_t aw_sar_parse_bin(const struct firmware *cont, struct aw_sar *p_sar) +{ + enum aw_bin_err_val bin_ret; + struct aw_bin *aw_bin; + int32_t ret; + + if (!cont) { + dev_err(p_sar->dev, "def_reg_bin request error!"); + return -EINVAL; + } + + dev_dbg(p_sar->dev, "Bin file size: %d", (uint32_t)cont->size); + + aw_bin = devm_kzalloc(p_sar->dev, cont->size + sizeof(struct aw_bin), GFP_KERNEL); + if (!aw_bin) { + release_firmware(cont); + dev_err(p_sar->dev, "failed to allcating memory!"); + return -ENOMEM; + } + + aw_bin->info.len = cont->size; + memcpy(aw_bin->info.data, cont->data, cont->size); + + bin_ret = aw_sar_parsing_bin_file(aw_bin); + if (bin_ret < 0) { + dev_err(p_sar->dev, "parse bin fail! bin_ret = %d", bin_ret); + goto err; + } + + //Write bin file execution process + if (p_sar->load_bin.bin_opera_func != NULL) { + ret = p_sar->load_bin.bin_opera_func(aw_bin, p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "load_bin_to_chip error!"); + if (p_sar->load_bin.bin_load_fail_opera_func != NULL) { + ret = p_sar->load_bin.bin_load_fail_opera_func(aw_bin, p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "bin_load_fail_opera_func error!"); + goto err; + } + } else { + goto err; + } + } + } else { + dev_err(p_sar->dev, "bin_opera_func is null error!"); + } + + if (aw_bin != NULL) + devm_kfree(p_sar->dev, aw_bin); + + return 0; +err: + if (aw_bin != NULL) + devm_kfree(p_sar->dev, aw_bin); + + return -EINVAL; +} + +static int32_t aw_sar_load_bin_comm(struct aw_sar *p_sar) +{ + const struct firmware *fw; + int32_t ret; + + ret = request_firmware(&fw, p_sar->load_bin.bin_name, p_sar->dev); + if (ret != 0) { + dev_err(p_sar->dev, "parse %s error!", p_sar->load_bin.bin_name); + return ret; + } + + ret = aw_sar_parse_bin(fw, p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "reg_bin %s load error!", p_sar->load_bin.bin_name); + return ret; + } + release_firmware(fw); + + return 0; +} + +static int32_t aw_sar_parse_dts_comm(struct device *dev, struct device_node *np, + struct aw_sar_dts_info *p_dts_info) +{ + int32_t val; + + val = of_property_read_u32(np, "sar-num", &p_dts_info->sar_num); + dev_info(dev, "sar num = %d", p_dts_info->sar_num); + if (val != 0) { + dev_err(dev, "multiple sar failed!"); + return -EINVAL; + } + + p_dts_info->irq_gpio = of_get_named_gpio(np, "irq-gpio", 0); + if (p_dts_info->irq_gpio < 0) { + p_dts_info->irq_gpio = -1; + dev_err(dev, "no irq gpio provided."); + return -EINVAL; + } + + val = of_property_read_u32(np, "channel_use_flag", &p_dts_info->channel_use_flag); + if (val != 0) { + dev_err(dev, "channel_use_flag failed!"); + return -EINVAL; + } + + //GPIO is set as internal pull-up input + p_dts_info->use_inter_pull_up = of_property_read_bool(np, "aw_sar,pin_set_inter_pull-up"); + p_dts_info->use_pm = of_property_read_bool(np, "aw_sar,using_pm_ops"); + p_dts_info->update_fw_flag = of_property_read_bool(np, "aw_sar,update_fw"); + p_dts_info->use_plug_cail_flag = of_property_read_bool(np, "aw_sar,use_plug_cail"); + p_dts_info->monitor_esd_flag = of_property_read_bool(np, "aw_sar,monitor_esd"); + + return 0; +} + +static int32_t aw_sar_parse_dts(struct aw_sar *p_sar) +{ + int32_t ret; + + ret = aw_sar_parse_dts_comm(p_sar->dev, p_sar->i2c->dev.of_node, &p_sar->dts_info); + + //Special requirements of SAR chip + if (p_sar->p_sar_para->p_platform_config->p_add_parse_dts_fn != NULL) + ret |= p_sar->p_sar_para->p_platform_config->p_add_parse_dts_fn(p_sar); + + return ret; +} + +static irqreturn_t aw_sar_irq(int32_t irq, void *data) +{ + struct aw_sar *p_sar = (struct aw_sar *)data; + uint32_t irq_status; + + //step1: read clear interrupt + if (p_sar->p_sar_para->p_platform_config->p_irq_init->rc_irq_fn != NULL) + irq_status = p_sar->p_sar_para->p_platform_config->p_irq_init->rc_irq_fn(p_sar->i2c); + + //step2: Read the status register for status reporting + if (p_sar->p_sar_para->p_platform_config->p_irq_init->irq_spec_handler_fn != NULL) + p_sar->p_sar_para->p_platform_config->p_irq_init->irq_spec_handler_fn(irq_status, + p_sar); + + //step3: The chip + + if ((!p_sar->dts_info.monitor_esd_flag) && (p_sar->fault_flag == AW_SAR_UNHEALTHY)) { + p_sar->fault_flag = AW_SAR_HEALTHY; + disable_irq_nosync(p_sar->irq_init.to_irq); + p_sar->irq_init.host_irq_stat = IRQ_DISABLE; + //aw_sar_soft_reset(p_sar); + schedule_delayed_work(&p_sar->update_work, msecs_to_jiffies(500)); + } + + return IRQ_HANDLED; +} + +static int32_t aw_sar_irq_init_comm(struct aw_sar *p_sar, const struct aw_sar_irq_init_t *p_irq_init) +{ + irq_handler_t thread_fn = p_irq_init->thread_fn; + int32_t ret; + + snprintf(p_sar->irq_init.label, sizeof(p_sar->irq_init.label), + "aw_sar%u_gpio", p_sar->dts_info.sar_num); + snprintf(p_sar->irq_init.dev_id, sizeof(p_sar->irq_init.dev_id), + "aw_sar%u_irq", p_sar->dts_info.sar_num); + + if (gpio_is_valid(p_sar->dts_info.irq_gpio)) { + p_sar->irq_init.to_irq = gpio_to_irq(p_sar->dts_info.irq_gpio); + ret = devm_gpio_request_one(p_sar->dev, + p_sar->dts_info.irq_gpio, + p_irq_init->flags, + p_sar->irq_init.label); + if (ret) { + dev_err(p_sar->dev, + "request irq gpio failed, ret = %d", ret); + return ret; + } + if (!thread_fn) + thread_fn = aw_sar_irq; + ret = devm_request_threaded_irq(p_sar->dev, + p_sar->irq_init.to_irq, + p_irq_init->handler, + thread_fn, + p_irq_init->irq_flags, + p_sar->irq_init.dev_id, + p_sar); + if (ret != 0) { + dev_err(p_sar->dev, + "failed to request IRQ %d: %d", + p_sar->irq_init.to_irq, ret); + return ret; + } + } else { + dev_err(p_sar->dev, "irq gpio invalid!"); + return -EINVAL; + } + + p_sar->irq_init.host_irq_stat = IRQ_DISABLE; + disable_irq(p_sar->irq_init.to_irq); + + return 0; +} + +static int32_t aw_sar_irq_init(struct aw_sar *p_sar) +{ + + if (!p_sar->p_sar_para->p_platform_config->p_irq_init) { + dev_err(p_sar->dev, "AW_INVALID_PARA"); + return -EINVAL; + } + + if (p_sar->p_sar_para->p_platform_config->p_irq_init->p_irq_init_fn != NULL) { + dev_err(p_sar->dev, "p_irq_init_fn"); + return p_sar->p_sar_para->p_platform_config->p_irq_init->p_irq_init_fn(p_sar); + } + + return aw_sar_irq_init_comm(p_sar, p_sar->p_sar_para->p_platform_config->p_irq_init); +} + +static void aw_sar_irq_free(struct aw_sar *p_sar) +{ + if ((p_sar->p_sar_para->p_platform_config != NULL) && + (p_sar->p_sar_para->p_platform_config->p_irq_init != NULL) && + (p_sar->p_sar_para->p_platform_config->p_irq_init->p_irq_deinit_fn != NULL)) { + p_sar->p_sar_para->p_platform_config->p_irq_init->p_irq_deinit_fn(p_sar); + dev_err(p_sar->dev, "AW_INVALID_PARA"); + return; + } +} + +static int32_t aw_sar_input_init_comm(struct aw_sar *p_sar) +{ + int32_t ret; + uint32_t i; + + p_sar->channels_arr = devm_kzalloc(p_sar->dev, + sizeof(struct aw_channels_info) * + p_sar->p_sar_para->ch_num_max, + GFP_KERNEL); + if (!p_sar->channels_arr) { + dev_err(p_sar->dev, "devm_kzalloc err"); + return -ENOMEM; + } + + for (i = 0; i < p_sar->p_sar_para->ch_num_max; i++) { + snprintf(p_sar->channels_arr[i].name, + sizeof(p_sar->channels_arr->name), + "aw_sar%u_ch%ud", + p_sar->dts_info.sar_num, i); + + p_sar->channels_arr[i].last_channel_info = 0; + + if ((p_sar->dts_info.channel_use_flag >> i) & 0x01) { + p_sar->channels_arr[i].used = AW_TRUE; + p_sar->channels_arr[i].input = devm_input_allocate_device(p_sar->dev); + if (!p_sar->channels_arr[i].input) + return -EINVAL; + p_sar->channels_arr[i].input->name = p_sar->channels_arr[i].name; + input_set_abs_params(p_sar->channels_arr[i].input, + ABS_DISTANCE, -1, 100, 0, 0); + ret = input_register_device(p_sar->channels_arr[i].input); + if (ret) { + dev_err(p_sar->dev, "failed to register input device"); + return ret; + } + } else { + p_sar->channels_arr[i].used = AW_FALSE; + p_sar->channels_arr[i].input = NULL; + } + } + + return 0; +} + +static int32_t aw_sar_input_init(struct aw_sar *p_sar) +{ + if (p_sar->p_sar_para->p_platform_config->p_input_init_fn != NULL) + return p_sar->p_sar_para->p_platform_config->p_input_init_fn(p_sar); + + return aw_sar_input_init_comm(p_sar); +} + +static void aw_sar_input_free(struct aw_sar *p_sar) +{ + if ((p_sar->p_sar_para->p_platform_config != NULL) && + (p_sar->p_sar_para->p_platform_config->p_input_deinit_fn != NULL)) { + p_sar->p_sar_para->p_platform_config->p_input_deinit_fn(p_sar); + } +} + +static int32_t aw_sar_check_init_over_irq_comm(struct aw_sar *p_sar) +{ + int32_t ret; + + if (!p_sar->p_sar_para->p_init_over_irq) + return -EINVAL; + + ret = aw_sar_check_init_over_irq_func(p_sar->i2c, p_sar->p_sar_para->p_init_over_irq); + if (ret == AW_ERR_IRQ_INIT_OVER) { + if (p_sar->p_sar_para->p_init_over_irq->p_get_err_type_fn != NULL) { + //Consider the abnormality reasonable + if (p_sar->p_sar_para->p_init_over_irq->p_get_err_type_fn(p_sar) == 0) { + p_sar->fw_fail_flag = AW_TRUE; + return 0; + } + } + return -EINVAL; + } + + return ret; +} + +//If there is no special operation on the chip, execute the common process +int32_t aw_sar_check_init_over_irq(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para->p_init_over_irq) + return -EINVAL; + + if (p_sar->p_sar_para->p_init_over_irq->p_check_init_over_irq_fn != NULL) + return p_sar->p_sar_para->p_init_over_irq->p_check_init_over_irq_fn(p_sar); + + return aw_sar_check_init_over_irq_comm(p_sar); +} + +static int32_t aw_sar_chip_other_operation(struct aw_sar *p_sar) +{ + if (p_sar->p_sar_para->p_other_operation != NULL) + return p_sar->p_sar_para->p_other_operation(p_sar); + + return 0; +} + +static void aw_sar_chip_other_operation_free(struct aw_sar *p_sar) +{ + if (p_sar->p_sar_para->p_other_opera_free != NULL) + p_sar->p_sar_para->p_other_opera_free(p_sar); +} + +int32_t aw_sar_soft_reset(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para->p_soft_rst) + return -EINVAL; + + //If a private interface is defined, the private interface is used + if (p_sar->p_sar_para->p_soft_rst->p_soft_reset_fn != NULL) + return p_sar->p_sar_para->p_soft_rst->p_soft_reset_fn(p_sar); + + return aw_sar_soft_reset_func(p_sar->i2c, p_sar->p_sar_para->p_soft_rst); +} + +static int32_t aw_sar_check_chipid(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para) + return -EINVAL; + + if (p_sar->p_sar_para->p_check_chipid != NULL) { + if (p_sar->p_sar_para->p_check_chipid->p_check_chipid_fn != NULL) + return p_sar->p_sar_para->p_check_chipid->p_check_chipid_fn(p_sar); + } + + return -EINVAL; +} + +int32_t aw_sar_load_def_reg_bin(struct aw_sar *p_sar) +{ + if ((!p_sar->p_sar_para->p_reg_bin) || + (!p_sar->p_sar_para->p_reg_bin->bin_name)) { + dev_err(p_sar->dev, "p_reg_bin is NULL or bin_name is NULL error"); + p_sar->ret_val = AW_BIN_PARA_INVALID; + return -EINVAL; + } + + snprintf(p_sar->load_bin.bin_name, sizeof(p_sar->load_bin.bin_name), + "%s_%u.bin", p_sar->p_sar_para->p_reg_bin->bin_name, + p_sar->dts_info.sar_num); + + p_sar->load_bin.bin_opera_func = p_sar->p_sar_para->p_reg_bin->bin_opera_func; + + return aw_sar_load_bin_comm(p_sar); +} + +static int32_t aw_sar_para_loaded(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para->p_reg_arr) + return -EINVAL; + + aw_sar_para_loaded_func(p_sar->i2c, p_sar->p_sar_para->p_reg_arr); + + return 0; +} + +static int32_t aw_sar_reg_update_boot_work(struct aw_sar *p_sar) +{ + if ((!p_sar->p_sar_para->p_boot_bin) || (!p_sar->p_sar_para->p_boot_bin->bin_name)) + return -EINVAL; + + snprintf(p_sar->load_bin.bin_name, sizeof(p_sar->load_bin.bin_name), + "%s_%u.bin", p_sar->p_sar_para->p_boot_bin->bin_name, + p_sar->dts_info.sar_num); + + p_sar->load_bin.bin_opera_func = p_sar->p_sar_para->p_boot_bin->bin_opera_func; + + return aw_sar_load_bin_comm(p_sar); +} + +static int32_t aw_sar_update_fw_para(struct aw_sar *p_sar, const struct aw_sar_load_bin_t *p_bin) +{ + if ((!p_bin) || (!p_bin->bin_name)) + return -EINVAL; + + p_sar->load_bin.bin_opera_func = p_bin->bin_opera_func; + p_sar->load_bin.bin_load_fail_opera_func = p_bin->bin_load_fail_opera; + + snprintf(p_sar->load_bin.bin_name, sizeof(p_sar->load_bin.bin_name), + "%s_%u.bin", p_bin->bin_name, p_sar->dts_info.sar_num); + + return 0; +} + +int32_t aw_sar_update_fw(struct aw_sar *p_sar) +{ + if (aw_sar_update_fw_para(p_sar, p_sar->p_sar_para->p_fw_bin) != 0) + return -EINVAL; + + return aw_sar_load_bin_comm(p_sar); +} + +static int32_t aw_sar_node_prox_update_fw(struct aw_sar *p_sar) +{ + if (aw_sar_update_fw_para(p_sar, p_sar->p_sar_para->p_prox_fw) != 0) + return -EINVAL; + + return aw_sar_load_bin_comm(p_sar); +} + +static int32_t aw_sar_node_reg_update_fw(struct aw_sar *p_sar) +{ + if (aw_sar_update_fw_para(p_sar, p_sar->p_sar_para->p_reg_fw)) + return -EINVAL; + + return aw_sar_load_bin_comm(p_sar); +} + +static int32_t aw_sar_awrw_data_analysis(struct aw_sar *p_sar, const char *buf, uint8_t len) +{ + uint32_t theory_len = len * AW_SAR_AWRW_DATA_WIDTH + AW_SAR_AWRW_OffSET; + uint32_t actual_len = strlen(buf); + uint8_t data_temp[2] = { 0 }; + uint32_t tranfar_data_temp; + uint8_t index = 0; + uint32_t i; + + if (theory_len != actual_len) { + dev_err(p_sar->dev, "error theory_len = %d actual_len = %d", + theory_len, actual_len); + return -EINVAL; + } + + for (i = 0; i < len * AW_SAR_AWRW_DATA_WIDTH; i += AW_SAR_AWRW_DATA_WIDTH) { + data_temp[0] = buf[AW_SAR_AWRW_OffSET + i + AW_DATA_OffSET_2]; + data_temp[1] = buf[AW_SAR_AWRW_OffSET + i + AW_DATA_OffSET_3]; + + if (sscanf(data_temp, "%02x", &tranfar_data_temp) == 1) + p_sar->awrw_info.p_i2c_tranfar_data[index] = (uint8_t)tranfar_data_temp; + index++; + } + + return 0; +} + +static int32_t aw_sar_awrw_write(struct aw_sar *p_sar, const char *buf) +{ + int32_t ret; + + ret = aw_sar_awrw_data_analysis(p_sar, buf, p_sar->awrw_info.i2c_tranfar_data_len); + if (ret == 0) + aw_sar_i2c_write_seq(p_sar->i2c, p_sar->awrw_info.p_i2c_tranfar_data, + p_sar->awrw_info.i2c_tranfar_data_len); + + return ret; +} + +static int32_t aw_sar_awrw_read(struct aw_sar *p_sar, const char *buf) +{ + int32_t ret = 0; + uint8_t *p_buf = p_sar->awrw_info.p_i2c_tranfar_data + p_sar->awrw_info.addr_len; + uint32_t len = (uint16_t)(p_sar->awrw_info.data_len * p_sar->awrw_info.reg_num); + + ret = aw_sar_awrw_data_analysis(p_sar, buf, p_sar->awrw_info.addr_len); + if (ret == 0) { + ret = aw_sar_i2c_read_seq(p_sar->i2c, + p_sar->awrw_info.p_i2c_tranfar_data, + p_sar->awrw_info.addr_len, + p_sar->awrw_info.p_i2c_tranfar_data + p_sar->awrw_info.addr_len, + (uint16_t)(p_sar->awrw_info.data_len * p_sar->awrw_info.reg_num)); + if (ret != 0) + memset(p_buf, 0xff, len); + } + + return ret; +} + +static int32_t aw_sar_awrw_get_func(struct aw_sar *p_sar, char *buf) +{ + uint32_t len = 0; + uint32_t i; + + if (!p_sar->awrw_info.p_i2c_tranfar_data) { + dev_err(p_sar->dev, "p_i2c_tranfar_data is NULL"); + return len; + } + + if (p_sar->awrw_info.rw_flag == AW_SAR_PACKAGE_RD) { + for (i = 0; i < p_sar->awrw_info.i2c_tranfar_data_len; i++) { + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", + p_sar->awrw_info.p_i2c_tranfar_data[i]); + } + } else { + for (i = 0; i < (p_sar->awrw_info.data_len) * (p_sar->awrw_info.reg_num); i++) { + len += snprintf(buf + len, PAGE_SIZE - len, "0x%02x,", + p_sar->awrw_info.p_i2c_tranfar_data[p_sar->awrw_info.addr_len + i]); + } + } + snprintf(buf + len - 1, PAGE_SIZE - len, "\n"); + + devm_kfree(p_sar->dev, p_sar->awrw_info.p_i2c_tranfar_data); + p_sar->awrw_info.p_i2c_tranfar_data = NULL; + + return len; +} + +//Function: continuous read register interface +static ssize_t awrw_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + ssize_t ret; + + mutex_lock(&aw_sar_lock); + if ((p_sar->p_sar_para->p_aw_sar_awrw != NULL) && + (p_sar->p_sar_para->p_aw_sar_awrw->p_get_awrw_node_fn != NULL)) { + ret = (ssize_t)p_sar->p_sar_para->p_aw_sar_awrw->p_get_awrw_node_fn(p_sar, buf); + mutex_unlock(&aw_sar_lock); + return ret; + } + + ret = (ssize_t)aw_sar_awrw_get_func(p_sar, buf); + + mutex_unlock(&aw_sar_lock); + + return ret; +} + +static int32_t aw_sar_awrw_handle(struct aw_sar *p_sar, const char *buf) +{ + int32_t ret; + + p_sar->awrw_info.i2c_tranfar_data_len = p_sar->awrw_info.addr_len + + p_sar->awrw_info.data_len * + p_sar->awrw_info.reg_num; + + if (p_sar->awrw_info.p_i2c_tranfar_data != NULL) { + devm_kfree(p_sar->dev, p_sar->awrw_info.p_i2c_tranfar_data); + p_sar->awrw_info.p_i2c_tranfar_data = NULL; + } + + p_sar->awrw_info.p_i2c_tranfar_data = devm_kzalloc(p_sar->dev, + p_sar->awrw_info.i2c_tranfar_data_len, GFP_KERNEL); + if (!p_sar->awrw_info.p_i2c_tranfar_data) + return -ENOMEM; + + if (p_sar->awrw_info.rw_flag == AW_SAR_I2C_WR) { + ret = aw_sar_awrw_write(p_sar, buf); + if (ret != 0) + dev_err(p_sar->dev, "awrw_write error"); + if (p_sar->awrw_info.p_i2c_tranfar_data != NULL) { + devm_kfree(p_sar->dev, p_sar->awrw_info.p_i2c_tranfar_data); + p_sar->awrw_info.p_i2c_tranfar_data = NULL; + } + } else if (p_sar->awrw_info.rw_flag == AW_SAR_I2C_RD) { + ret = aw_sar_awrw_read(p_sar, buf); + if (ret != 0) + dev_err(p_sar->dev, "awrw_read error"); + } else { + return -EINVAL; + } + + return 0; +} + +static int32_t aw_sar_awrw_set_func(struct aw_sar *p_sar, const char *buf) +{ + uint32_t rw_flag; + uint32_t addr_bytes; + uint32_t data_bytes; + uint32_t package_nums; + uint32_t addr_tmp; + uint32_t buf_index0; + uint32_t buf_index1; + uint32_t r_buf_len = 0; + uint32_t tr_offset = 0; + uint8_t addr[4] = { 0 }; + uint32_t theory_len; + uint32_t actual_len; + uint32_t reg_num; + uint32_t i; + uint32_t j; + + //step1: Parse frame header + if (sscanf(buf, "0x%02x 0x%02x 0x%02x ", &rw_flag, &addr_bytes, &data_bytes) != 3) { + dev_err(p_sar->dev, "sscanf0 parse error!"); + return -EINVAL; + } + p_sar->awrw_info.rw_flag = (uint8_t)rw_flag; + p_sar->awrw_info.addr_len = (uint8_t)addr_bytes; + p_sar->awrw_info.data_len = (uint8_t)data_bytes; + + if (addr_bytes > 4) { + dev_err(p_sar->dev, "para error!"); + return -EINVAL; + } + + if ((rw_flag == AW_SAR_I2C_WR) || (rw_flag == AW_SAR_I2C_RD)) { + if (sscanf(buf + AW_SAR_OFFSET_LEN, "0x%02x ", ®_num) != 1) { + dev_err(p_sar->dev, "sscanf1 parse error!"); + return -EINVAL; + } + p_sar->awrw_info.reg_num = (uint8_t)reg_num; + aw_sar_awrw_handle(p_sar, buf); + } else if (rw_flag == AW_SAR_PACKAGE_RD) { + //step2: Get number of packages + if (sscanf(buf + AW_SAR_OFFSET_LEN, "0x%02x ", &package_nums) != 1) { + dev_err(p_sar->dev, "sscanf2 parse error!"); + return -EINVAL; + } + theory_len = AW_SAR_OFFSET_LEN + AW_SAR_AWRW_DATA_WIDTH + + package_nums * (AW_SAR_AWRW_DATA_WIDTH + + AW_SAR_AWRW_DATA_WIDTH * addr_bytes); + actual_len = strlen(buf); + if (theory_len != actual_len) { + dev_err(p_sar->dev, "theory_len:%d, actual_len:%d error!", + theory_len, actual_len); + return -EINVAL; + } + + //step3: Get the size of read data and apply for space + for (i = 0; i < package_nums; i++) { + buf_index0 = AW_SAR_OFFSET_LEN + AW_SAR_AWRW_DATA_WIDTH + + (AW_SAR_AWRW_DATA_WIDTH * addr_bytes + + AW_SAR_AWRW_DATA_WIDTH) * i; + if (sscanf(buf + buf_index0, "0x%02x", ®_num) != 1) { + dev_err(p_sar->dev, "sscanf3 parse error!"); + return -EINVAL; + } + r_buf_len += reg_num * data_bytes; + } + + p_sar->awrw_info.i2c_tranfar_data_len = r_buf_len; + + if (p_sar->awrw_info.p_i2c_tranfar_data != NULL) { + devm_kfree(p_sar->dev, p_sar->awrw_info.p_i2c_tranfar_data); + p_sar->awrw_info.p_i2c_tranfar_data = NULL; + } + p_sar->awrw_info.p_i2c_tranfar_data = devm_kzalloc(p_sar->dev, + r_buf_len, GFP_KERNEL); + if (!p_sar->awrw_info.p_i2c_tranfar_data) + return -ENOMEM; + + //step3: Resolve register address and read data in packets + for (i = 0; i < package_nums; i++) { + buf_index0 = AW_SAR_OFFSET_LEN + AW_SAR_AWRW_DATA_WIDTH + + (AW_SAR_AWRW_DATA_WIDTH * addr_bytes + AW_SAR_AWRW_DATA_WIDTH) * i; + if (sscanf(buf + buf_index0, "0x%02x", ®_num) != 1) { + dev_err(p_sar->dev, "sscanf4 parse error!"); + return -EINVAL; + } + + for (j = 0; j < addr_bytes; j += 1) { + buf_index1 = buf_index0 + AW_SAR_AWRW_DATA_WIDTH + + (j * AW_SAR_AWRW_DATA_WIDTH); + if (sscanf(buf + buf_index1, "0x%02x", &addr_tmp) == 1) { + addr[j] = (uint8_t)addr_tmp; + } else { + dev_err(p_sar->dev, "sscanf5 parse error!"); + return -EINVAL; + } + } + aw_sar_i2c_read_seq(p_sar->i2c, + addr, + addr_bytes, + p_sar->awrw_info.p_i2c_tranfar_data + tr_offset, + (uint16_t)(data_bytes * reg_num)); + tr_offset += data_bytes * reg_num; + } + } + + return 0; +} + +//Function: continuous write register interface +static ssize_t +awrw_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + + mutex_lock(&aw_sar_lock); + + if ((p_sar->p_sar_para->p_aw_sar_awrw != NULL) && + (p_sar->p_sar_para->p_aw_sar_awrw->p_set_awrw_node_fn != NULL)) { + p_sar->p_sar_para->p_aw_sar_awrw->p_set_awrw_node_fn(p_sar, buf, count); + mutex_unlock(&aw_sar_lock); + return count; + } + + aw_sar_awrw_set_func(p_sar, buf); + + mutex_unlock(&aw_sar_lock); + + return count; +} +//Print all readable register values +static ssize_t reg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint8_t reg_rd_access; + uint32_t reg_data; + ssize_t len = 0; + int32_t ret; + uint16_t i; + + if (!p_sar->p_sar_para->p_reg_list) + return len; + + reg_rd_access = p_sar->p_sar_para->p_reg_list->reg_rd_access; + + for (i = 0; i < p_sar->p_sar_para->p_reg_list->reg_num; i++) { + if (p_sar->p_sar_para->p_reg_list->reg_perm[i].rw & reg_rd_access) { + ret = aw_sar_i2c_read(p_sar->i2c, + p_sar->p_sar_para->p_reg_list->reg_perm[i].reg, ®_data); + if (ret < 0) + len += snprintf(buf + len, PAGE_SIZE - len, + "i2c read error ret = %d\n", ret); + len += snprintf(buf + len, PAGE_SIZE - len, + "%x,%x\n", + p_sar->p_sar_para->p_reg_list->reg_perm[i].reg, + reg_data); + } + } + + return len; +} + +//Write register interface with write permission +static ssize_t +reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint32_t databuf[2] = { 0, 0 }; + uint8_t reg_wd_access; + uint16_t i; + + if (!p_sar->p_sar_para->p_reg_list) { + dev_err(p_sar->dev, "AW_INVALID_PARA"); + return count; + } + + reg_wd_access = p_sar->p_sar_para->p_reg_list->reg_wd_access; + + if (sscanf(buf, "%x %x", &databuf[0], &databuf[1]) != 2) + return count; + + for (i = 0; i < p_sar->p_sar_para->p_reg_list->reg_num; i++) { + if ((uint16_t)databuf[0] == p_sar->p_sar_para->p_reg_list->reg_perm[i].reg) { + if (p_sar->p_sar_para->p_reg_list->reg_perm[i].rw & reg_wd_access) { + aw_sar_i2c_write(p_sar->i2c, + (uint16_t)databuf[0], (uint32_t)databuf[1]); + } + break; + } + } + + return count; +} + +//set chip Soft reset +static ssize_t +soft_rst_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint32_t flag; + + if (kstrtouint(buf, 0, &flag) != 0) { + dev_err(p_sar->dev, "kstrtouint parse err"); + return count; + } + + if (flag == AW_TRUE) + aw_sar_soft_reset(p_sar); + + return count; +} + +static int32_t aw_sar_aot(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para->p_aot) + return -EINVAL; + + if (p_sar->p_sar_para->p_aot->p_set_aot_node_fn != NULL) + return p_sar->p_sar_para->p_aot->p_set_aot_node_fn(p_sar); + + return aw_sar_i2c_write_bits(p_sar->i2c, p_sar->p_sar_para->p_aot->aot_reg, + p_sar->p_sar_para->p_aot->aot_mask, + p_sar->p_sar_para->p_aot->aot_flag); +} + +//Perform Auto-Offset-Tuning (AOT) +static ssize_t +aot_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint32_t cali_flag; + + if (kstrtouint(buf, 0, &cali_flag) != 0) + return count; + + if (cali_flag == AW_TRUE) + aw_sar_aot(p_sar); + else + dev_err(p_sar->dev, "fail to set aot cali"); + + return count; +} + +//update Register configuration and set the chip active mode +int32_t aw_sar_update_reg_set_func(struct aw_sar *p_sar) +{ + aw_sar_load_def_reg_bin(p_sar); + aw_sar_mode_set(p_sar, p_sar->p_sar_para->p_chip_mode->active); + + return 0; +} + +//Update register configuration +static ssize_t +update_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint32_t flag; + + if (kstrtouint(buf, 0, &flag) != 0) { + dev_err(p_sar->dev, "kstrtouint parse error"); + return count; + } + + if (flag == AW_TRUE) { + mutex_lock(&aw_sar_lock); + aw_sar_soft_reset(p_sar); + aw_sar_update_reg_set_func(p_sar); + mutex_unlock(&aw_sar_lock); + } + + return count; +} + +//get chip diff val +static ssize_t aw_sar_get_diff(struct aw_sar *p_sar, char *buf) +{ + const struct aw_sar_diff_t *diff = p_sar->p_sar_para->p_diff; + int32_t diff_val; + ssize_t len = 0; + uint32_t data; + int32_t ret; + uint32_t i; + + if (!p_sar->p_sar_para->p_diff) + return -EINVAL; + + //If a private interface is defined, the private interface is used + if (p_sar->p_sar_para->p_diff->p_get_diff_node_fn != NULL) + return p_sar->p_sar_para->p_diff->p_get_diff_node_fn(p_sar, buf); + + for (i = 0; i < p_sar->p_sar_para->ch_num_max; i++) { + ret = aw_sar_i2c_read(p_sar->i2c, diff->diff0_reg + i * diff->diff_step, &data); + if (ret != 0) { + dev_err(p_sar->dev, "read diff err: %d", ret); + return ret; + } + diff_val = (int32_t)data / (int32_t)diff->rm_float; + len += snprintf(buf + len, PAGE_SIZE - len, "DIFF_CH%u = %d\n", i, diff_val); + } + + return len; +} + + +//Print diff values of all channels of the chip. +static ssize_t diff_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + + return aw_sar_get_diff(p_sar, buf); +} + +void aw_sar_mode_set(struct aw_sar *p_sar, uint8_t curr_mode) +{ + struct aw_sar_mode_set_t mode_set_para; + + if (!p_sar->p_sar_para->p_mode) + return; + + //If a private interface is defined, the private interface is used + if (p_sar->p_sar_para->p_mode->p_set_mode_node_fn != NULL) { + p_sar->p_sar_para->p_mode->p_set_mode_node_fn(p_sar, curr_mode); + return; + } + + mode_set_para.chip_id = p_sar->chip_type; + mode_set_para.chip_mode.curr_mode = curr_mode; + mode_set_para.chip_mode.last_mode = p_sar->last_mode; + + aw_sar_mode_set_func(p_sar->i2c, p_sar->irq_init.to_irq, &mode_set_para, + p_sar->p_sar_para->p_mode->mode_set_arr, + p_sar->p_sar_para->p_mode->mode_set_arr_len); + p_sar->last_mode = curr_mode; +} + +//Set the chip to enter different modes +static ssize_t mode_operation_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + uint32_t mode; + + if (kstrtouint(buf, 0, &mode) != 0) { + dev_err(p_sar->dev, "kstrtouint parse err"); + return count; + } + aw_sar_mode_set(p_sar, mode); + + return count; +} + +//Get the current mode of the chip +static ssize_t mode_operation_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + ssize_t len = 0; + + if (!p_sar->p_sar_para->p_mode) + return len; + + if (p_sar->p_sar_para->p_mode->p_get_mode_node_fn != NULL) + len = p_sar->p_sar_para->p_mode->p_get_mode_node_fn(p_sar, buf); + + return len; +} + +//Print information related information +static ssize_t chip_info_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "reg_load_state: %d\n", p_sar->ret_val); + + if ((p_sar->p_sar_para->p_get_chip_info != NULL) && + (p_sar->p_sar_para->p_get_chip_info->p_get_chip_info_node_fn != NULL)) { + p_sar->p_sar_para->p_get_chip_info->p_get_chip_info_node_fn(p_sar, buf, &len); + } + + return len; +} + +static ssize_t offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + ssize_t len = 0; + + if ((p_sar->p_sar_para->p_offset != NULL) && + (p_sar->p_sar_para->p_offset->p_get_offset_node_fn != NULL)) + len = (ssize_t)p_sar->p_sar_para->p_offset->p_get_offset_node_fn(p_sar, buf); + + return len; +} + +static DEVICE_ATTR_RW(awrw); +static DEVICE_ATTR_RW(reg); +static DEVICE_ATTR_WO(soft_rst); +static DEVICE_ATTR_WO(aot); +static DEVICE_ATTR_WO(update_reg); +static DEVICE_ATTR_RO(diff); +static DEVICE_ATTR_RW(mode_operation); +static DEVICE_ATTR_RO(chip_info); +static DEVICE_ATTR_RO(offset); + +static struct attribute *aw_sar_attributes[] = { + &dev_attr_awrw.attr, + &dev_attr_reg.attr, + &dev_attr_soft_rst.attr, + &dev_attr_aot.attr, + &dev_attr_update_reg.attr, + &dev_attr_diff.attr, + &dev_attr_mode_operation.attr, + &dev_attr_chip_info.attr, + &dev_attr_offset.attr, + NULL +}; + +static const struct attribute_group aw_sar_attribute_group = { + .attrs = aw_sar_attributes, +}; + +//firmware upgrade through write register mode, and the operation is supported by flash chip +static ssize_t prot_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + + + mutex_lock(&aw_sar_lock); + aw_sar_disable_irq(p_sar); + + p_sar->prot_update_state = aw_sar_node_prox_update_fw(p_sar); + + aw_sar_enable_irq(p_sar); + mutex_unlock(&aw_sar_lock); + + return count; +} + +//firmware upgrade throughr Write register mode,and the operation is supported by flash chip +static ssize_t reg_update_fw_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + + mutex_lock(&aw_sar_lock); + aw_sar_disable_irq(p_sar); + + aw_sar_node_reg_update_fw(p_sar); + + aw_sar_enable_irq(p_sar); + mutex_unlock(&aw_sar_lock); + + return count; +} + +//boot upgrade throughr Write register mode,and the operation is supported by flash chip +static ssize_t reg_update_boot_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + + if (!p_sar->p_sar_para->p_boot_bin) + return count; + + mutex_lock(&aw_sar_lock); + aw_sar_disable_irq(p_sar); + + aw_sar_reg_update_boot_work(p_sar); + + aw_sar_enable_irq(p_sar); + mutex_unlock(&aw_sar_lock); + + return count; +} + +//Print the protocol upgrade status. 0 is success, Not 0 is failure +//Print the current firmware version number +static ssize_t prot_update_fw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct aw_sar *p_sar = dev_get_drvdata(dev); + ssize_t len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, + "protocol update state:%s!\n", + (p_sar->prot_update_state == 0) ? "ok" : "error"); + if ((p_sar->p_sar_para->p_prox_fw != NULL) && + (p_sar->p_sar_para->p_prox_fw->p_get_prot_update_fw_node_fn != NULL)) + p_sar->p_sar_para->p_prox_fw->p_get_prot_update_fw_node_fn(p_sar, buf, &len); + + return len; +} + +static DEVICE_ATTR_RW(prot_update_fw); +static DEVICE_ATTR_WO(reg_update_fw); +static DEVICE_ATTR_WO(reg_update_boot); + +static struct attribute *aw_sar_update_attributes[] = { + &dev_attr_prot_update_fw.attr, + &dev_attr_reg_update_fw.attr, + &dev_attr_reg_update_boot.attr, + NULL +}; + +static const struct attribute_group aw_sar_update_attribute_group = { + .attrs = aw_sar_update_attributes, +}; + +static void aw_sar_update_work(struct work_struct *work) +{ + struct aw_sar *p_sar = container_of(work, struct aw_sar, update_work.work); + int32_t ret; + + mutex_lock(&aw_sar_lock); + + if (p_sar->dts_info.update_fw_flag == true) { + ret = aw_sar_update_fw(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "protocol upgrade firmware error!"); + p_sar->ret_val = AW_PROT_UPDATE_ERR; + } + } + + //2.Parse the bin file and load the register configuration + ret = aw_sar_load_def_reg_bin(p_sar); + if (ret != 0) { + p_sar->ret_val = AW_REG_LOAD_ERR; + dev_err(p_sar->dev, "reg_bin load err!"); + aw_sar_para_loaded(p_sar); + } + + //3.active chip + aw_sar_mode_set(p_sar, p_sar->p_sar_para->p_chip_mode->init_mode); + if (p_sar->irq_init.host_irq_stat == IRQ_DISABLE) { + enable_irq(p_sar->irq_init.to_irq); + p_sar->irq_init.host_irq_stat = IRQ_ENABLE; + } + p_sar->driver_code_initover_flag = 1; + mutex_unlock(&aw_sar_lock); +} + +static void aw_sar_update(struct aw_sar *p_sar) +{ + if (!p_sar->p_sar_para->p_reg_bin) + return; + + if (p_sar->p_sar_para->p_reg_bin->p_update_fn != NULL) + p_sar->p_sar_para->p_reg_bin->p_update_fn(p_sar); + + if (p_sar->driver_code_initover_flag) { + schedule_delayed_work(&p_sar->update_work, msecs_to_jiffies(0)); + } else { + INIT_DELAYED_WORK(&p_sar->update_work, aw_sar_update_work); + schedule_delayed_work(&p_sar->update_work, + msecs_to_jiffies(AW_POWER_ON_SYSFS_DELAY_MS)); + } +} + +static int32_t aw_sar_create_node(struct aw_sar *p_sar) +{ + int32_t ret; + + i2c_set_clientdata(p_sar->i2c, p_sar); + + ret = sysfs_create_group(&p_sar->i2c->dev.kobj, &aw_sar_attribute_group); + + if (p_sar->dts_info.update_fw_flag == true) + ret |= sysfs_create_group(&p_sar->i2c->dev.kobj, &aw_sar_update_attribute_group); + + //Special requirements of SAR chip + if (p_sar->p_sar_para->p_platform_config->p_add_node_create_fn != NULL) + ret |= p_sar->p_sar_para->p_platform_config->p_add_node_create_fn(p_sar); + + return ret; +} + +static void aw_sar_node_free(struct aw_sar *p_sar) +{ + sysfs_remove_group(&p_sar->i2c->dev.kobj, &aw_sar_attribute_group); + + if (p_sar->dts_info.update_fw_flag == true) + sysfs_remove_group(&p_sar->i2c->dev.kobj, &aw_sar_update_attribute_group); + + //Special requirements of SAR chip + if ((p_sar->p_sar_para->p_platform_config != NULL) && + (p_sar->p_sar_para->p_platform_config->p_add_node_free_fn != NULL)) + p_sar->p_sar_para->p_platform_config->p_add_node_free_fn(p_sar); +} + +//The interrupt pin is set to internal pull-up start +static void aw_sar_int_output(struct aw_sar *p_sar, int32_t level) +{ + if (level == 0) { + if (p_sar->pinctrl.pinctrl) + pinctrl_select_state(p_sar->pinctrl.pinctrl, p_sar->pinctrl.int_out_low); + else + dev_err(p_sar->dev, "Failed set int pin output low\n"); + } else if (level == 1) { + if (p_sar->pinctrl.pinctrl) + pinctrl_select_state(p_sar->pinctrl.pinctrl, p_sar->pinctrl.int_out_high); + else + dev_err(p_sar->dev, "Failed set int pin output high\n"); + } +} + +static int32_t aw_sar_pinctrl_init(struct aw_sar *p_sar) +{ + struct aw_sar_pinctrl *pinctrl = &p_sar->pinctrl; + uint8_t pin_default_name[50] = { 0 }; + uint8_t pin_output_low_name[50] = { 0 }; + uint8_t pin_output_high_name[50] = { 0 }; + + pinctrl->pinctrl = devm_pinctrl_get(p_sar->dev); + if (IS_ERR_OR_NULL(pinctrl->pinctrl)) { + dev_err(p_sar->dev, "No pinctrl found\n"); + pinctrl->pinctrl = NULL; + return -EINVAL; + } + + snprintf(pin_default_name, sizeof(pin_default_name), + "aw_default_sar%u", p_sar->dts_info.sar_num); + pinctrl->default_sta = pinctrl_lookup_state(pinctrl->pinctrl, pin_default_name); + if (IS_ERR_OR_NULL(pinctrl->default_sta)) { + dev_err(p_sar->dev, "Failed get pinctrl state:default state"); + goto exit_pinctrl_init; + } + + snprintf(pin_output_high_name, sizeof(pin_output_high_name), + "aw_int_output_high_sar%u", p_sar->dts_info.sar_num); + pinctrl->int_out_high = pinctrl_lookup_state(pinctrl->pinctrl, pin_output_high_name); + if (IS_ERR_OR_NULL(pinctrl->int_out_high)) { + dev_err(p_sar->dev, "Failed get pinctrl state:output_high"); + goto exit_pinctrl_init; + } + + snprintf(pin_output_low_name, sizeof(pin_output_low_name), + "aw_int_output_low_sar%u", p_sar->dts_info.sar_num); + pinctrl->int_out_low = pinctrl_lookup_state(pinctrl->pinctrl, pin_output_low_name); + if (IS_ERR_OR_NULL(pinctrl->int_out_low)) { + dev_err(p_sar->dev, "Failed get pinctrl state:output_low"); + goto exit_pinctrl_init; + } + + return 0; + +exit_pinctrl_init: + devm_pinctrl_put(pinctrl->pinctrl); + pinctrl->pinctrl = NULL; + + return -EINVAL; +} + +static void aw_sar_pinctrl_deinit(struct aw_sar *p_sar) +{ + if (p_sar->pinctrl.pinctrl) + devm_pinctrl_put(p_sar->pinctrl.pinctrl); +} +//The interrupt pin is set to internal pull-up end + +//AW_SAR_REGULATOR_POWER_ON start +static int32_t aw_sar_regulator_power_init(struct aw_sar *p_sar) +{ + uint8_t vcc_name[20] = { 0 }; + int32_t rc; + + snprintf(vcc_name, sizeof(vcc_name), "vcc%u", p_sar->dts_info.sar_num); + p_sar->vcc = regulator_get(p_sar->dev, vcc_name); + if (IS_ERR(p_sar->vcc)) { + rc = PTR_ERR(p_sar->vcc); + dev_err(p_sar->dev, "regulator get failed vcc rc = %d", rc); + return rc; + } + + if (regulator_count_voltages(p_sar->vcc) > 0) { + rc = regulator_set_voltage(p_sar->vcc, AW_SAR_VCC_MIN_UV, AW_SAR_VCC_MAX_UV); + if (rc) { + dev_err(p_sar->dev, "regulator set vol failed rc = %d", rc); + goto reg_vcc_put; + } + } + + return 0; + +reg_vcc_put: + regulator_put(p_sar->vcc); + return rc; +} + +static void aw_sar_power_deinit(struct aw_sar *p_sar) +{ + if (p_sar->power_enable) { + //Turn off the power output. However, + //it may not be turned off immediately + //There are scenes where power sharing can exist + regulator_disable(p_sar->vcc); + regulator_put(p_sar->vcc); + } +} + +static void aw_sar_power_enable(struct aw_sar *p_sar, bool on) +{ + int32_t rc; + + if (on) { + rc = regulator_enable(p_sar->vcc); + if (rc) { + dev_err(p_sar->dev, "regulator_enable vol failed rc = %d", rc); + } else { + p_sar->power_enable = AW_TRUE; + msleep(20); + } + } else { + rc = regulator_disable(p_sar->vcc); + if (rc) + dev_err(p_sar->dev, "regulator_disable vol failed rc = %d", rc); + else + p_sar->power_enable = AW_FALSE; + } +} + +static int32_t regulator_is_get_voltage(struct aw_sar *p_sar) +{ + uint32_t cnt = 10; + int32_t voltage_val; + + while (cnt--) { + voltage_val = regulator_get_voltage(p_sar->vcc); + if (voltage_val >= AW_SAR_VCC_MIN_UV) + return 0; + mdelay(1); + } + //Ensure that the chip initialization is completed + msleep(20); + + return -EINVAL; +} +//AW_SAR_REGULATOR_POWER_ON end + +static void aw_sar_init_lock(struct aw_sar *p_sar) +{ + //Initialize lock, To protect the thread safety of updating bin file + mutex_init(&aw_sar_lock); + //Required for mode setting + p_sar->last_mode = p_sar->p_sar_para->p_chip_mode->pre_init_mode; + p_sar->fw_fail_flag = AW_FALSE; + p_sar->ret_val = 0; +} + +// AW_SAR_USB_PLUG_CAIL start +static void aw_sar_ps_notify_callback_work(struct work_struct *work) +{ + struct aw_sar *p_sar = container_of(work, struct aw_sar, ps_notify_work); + + aw_sar_aot(p_sar); +} + +static int aw_sar_ps_get_state(struct aw_sar *p_sar, struct power_supply *psy, bool *present) +{ + union power_supply_propval pval = { 0 }; + int retval; + + retval = power_supply_get_property(psy, AW_USB_PROP_ONLINE, &pval); + if (retval) { + dev_err(p_sar->dev, "%s psy get property failed", psy->desc->name); + return retval; + } + *present = (pval.intval) ? true : false; + + return 0; +} + +static int aw_sar_ps_notify_callback(struct notifier_block *self, + unsigned long event, void *p) +{ + struct aw_sar *p_sar = container_of(self, struct aw_sar, ps_notif); + struct power_supply *psy = p; + bool present; + int retval; + + if (event == PSY_EVENT_PROP_CHANGED + && psy && psy->desc->get_property && psy->desc->name && + !strncmp(psy->desc->name, USB_POWER_SUPPLY_NAME, + sizeof(USB_POWER_SUPPLY_NAME))) { + retval = aw_sar_ps_get_state(p_sar, psy, &present); + if (retval) { + dev_err(p_sar->dev, "psy get property failed"); + return retval; + } + if (event == PSY_EVENT_PROP_CHANGED) { + if (p_sar->ps_is_present == present) + return 0; + } + p_sar->ps_is_present = present; + schedule_work(&p_sar->ps_notify_work); + } + return 0; +} + +static int aw_sar_ps_notify_init(struct aw_sar *p_sar) +{ + struct power_supply *psy; + int ret; + + INIT_WORK(&p_sar->ps_notify_work, aw_sar_ps_notify_callback_work); + p_sar->ps_notif.notifier_call = (notifier_fn_t)aw_sar_ps_notify_callback; + ret = power_supply_reg_notifier(&p_sar->ps_notif); + if (ret) { + dev_err(p_sar->dev, "Unable to register ps_notifier: %d", ret); + return ret; + } + psy = power_supply_get_by_name(USB_POWER_SUPPLY_NAME); + if (!psy) { + dev_err(p_sar->dev, "Unable to get power_supply: %s", USB_POWER_SUPPLY_NAME); + goto free_ps_notifier; + } + ret = aw_sar_ps_get_state(p_sar, psy, &p_sar->ps_is_present); + if (ret) { + dev_err(p_sar->dev, "psy get property failed rc=%d", ret); + goto free_ps_notifier; + } + return 0; + +free_ps_notifier: + power_supply_unreg_notifier(&p_sar->ps_notif); + + return -EINVAL; +} +// AW_SAR_USB_PLUG_CAIL end + +static int32_t aw_sar_platform_rsc_init(struct aw_sar *p_sar) +{ + int32_t ret; + + if (!p_sar->p_sar_para->p_platform_config) + return -EINVAL; + + //step 1.parsing dts data + ret = aw_sar_parse_dts(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "parse dts error!"); + return ret; + } + + //Initialization lock and some variables + aw_sar_init_lock(p_sar); + + //Configure whether to use USB plug-in calibration in DTS according to customer requirements + if (p_sar->dts_info.use_plug_cail_flag == true) { + ret = aw_sar_ps_notify_init(p_sar); + if (ret < 0) { + dev_err(p_sar->dev, "error creating power supply notify"); + goto err_ps_notify_init; + } + } + + //The interrupt pin is set to internal pull-up and configured by DTS + if (p_sar->dts_info.use_inter_pull_up == true) { + ret = aw_sar_pinctrl_init(p_sar); + if (ret < 0) { + /* if define pinctrl must define the following state + * to let int-pin work normally: default, int_output_high, + * int_output_low, int_input + */ + dev_err(p_sar->dev, "Failed get wanted pinctrl state"); + goto err_pinctrl_init; + } + aw_sar_int_output(p_sar, 1); + } + + //step 2.Create debug file node + ret = aw_sar_create_node(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "create node error!"); + goto err_sysfs_nodes; + } + + //step 3.Initialization interrupt + ret = aw_sar_irq_init(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "interrupt initialization error!"); + goto err_irq_init; + } + + //step 4.Initialization input Subsystem + ret = aw_sar_input_init(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "input_init error!"); + goto err_input_init; + } + + return 0; + +err_input_init: + aw_sar_input_free(p_sar); + aw_sar_irq_free(p_sar); +err_irq_init: + aw_sar_node_free(p_sar); +err_sysfs_nodes: + if (p_sar->dts_info.use_inter_pull_up == true) + aw_sar_pinctrl_deinit(p_sar); +err_pinctrl_init: + if (p_sar->dts_info.use_plug_cail_flag == true) + power_supply_unreg_notifier(&p_sar->ps_notif); +err_ps_notify_init: + mutex_destroy(&aw_sar_lock); + + return ret; +} + +/** + * @brief sar sensor initialization logic. + * + * @param p_sar data stored in type 'struct aw_sar *'. + * @return 0 if init succeeded. others if unpack error. + */ +static int32_t aw_sar_chip_init(struct aw_sar *p_sar) +{ + int32_t ret; + + //step 1.check chipid,Verify whether the chip communication is successful + ret = aw_sar_check_chipid(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "check_chipid error!"); + goto communication_fail; + } + + //step 2.Check chip initialization completed, + ret = aw_sar_soft_reset(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "soft_reset error!"); + goto communication_fail; + } + + ret = aw_sar_check_init_over_irq(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "check_init_over_irqt error!"); + goto communication_fail; + } + + //step 3.chip other operation + ret = aw_sar_chip_other_operation(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "chip_other_operation error!"); + goto free_other_opera; + } + + //step 4.Parse the bin file, upgrade the firmware, and load the register prize + aw_sar_update(p_sar); + + return 0; + +free_other_opera: + aw_sar_chip_other_operation_free(p_sar); +communication_fail: + + return ret; +} + +static int32_t aw_sar_init(struct aw_sar *p_sar) +{ + int32_t ret; + + //step 1: Platform resource initialization + ret = aw_sar_platform_rsc_init(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "platform_rsc_init error!"); + return ret; + } + + //step 2: Chip initialization + ret = aw_sar_chip_init(p_sar); + if (ret != 0) { + aw_sar_input_free(p_sar); + aw_sar_irq_free(p_sar); + aw_sar_node_free(p_sar); + if (p_sar->dts_info.use_inter_pull_up == true) + aw_sar_pinctrl_deinit(p_sar); + if (p_sar->dts_info.use_plug_cail_flag == true) + power_supply_unreg_notifier(&p_sar->ps_notif); + mutex_destroy(&aw_sar_lock); + return ret; + } + + return 0; +} + +static int32_t aw_sar_regulator_power(struct aw_sar *p_sar) +{ + struct aw_sar_dts_info *p_dts_info = &p_sar->dts_info; + int32_t ret = 0; + + p_dts_info->use_regulator_flag = + of_property_read_bool(p_sar->i2c->dev.of_node, "aw_sar,regulator-power-supply"); + + //Configure the use of regulator power supply in DTS + if (p_sar->dts_info.use_regulator_flag == true) { + ret = aw_sar_regulator_power_init(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "power init failed"); + return ret; + } + aw_sar_power_enable(p_sar, AW_TRUE); + ret = regulator_is_get_voltage(p_sar); + if (ret != 0) { + dev_err(p_sar->dev, "get_voltage failed"); + aw_sar_power_deinit(p_sar); + } + } + + return ret; +} + +/** + * @brief Distinguish different chips by chip name and obtain relevant chip information + * + * @param p_sar Structure to be filled + * @return 0 if init succeeded. + */ +static int32_t aw_sar_get_chip_info(struct aw_sar *p_sar) +{ + int32_t ret; + uint8_t i; + + for (i = 0; i < AW_SAR_DRIVER_MAX; i++) { + if (g_aw_sar_driver_list[i].p_who_am_i != NULL) { + ret = g_aw_sar_driver_list[i].p_who_am_i(p_sar); + if (ret == 0) { + p_sar->curr_use_driver_type = g_aw_sar_driver_list[i].driver_type; + if (!g_aw_sar_driver_list[i].p_chip_init) { + dev_err(p_sar->dev, + "drvier:%d p_chip_init is null error!", i); + continue; + } + g_aw_sar_driver_list[i].p_chip_init(p_sar); + dev_info(p_sar->dev, "current use drvier is :%d", + g_aw_sar_driver_list[i].driver_type); + return 0; + } + } + } + + return -EINVAL; +} + +static void aw_sar_monitor_work(struct work_struct *aw_work) +{ + struct aw_sar *p_sar = container_of(aw_work, struct aw_sar, monitor_work.work); + uint32_t data; + int32_t ret; + + ret = aw_sar_i2c_read(p_sar->i2c, 0x0000, &data); + if (ret != 0) { + dev_err(p_sar->dev, "read 0x0000 err: %d", ret); + return; + } + if (data == 0 && p_sar->driver_code_initover_flag) { + dev_err(p_sar->dev, "aw_chip may reset"); + aw_sar_disable_irq(p_sar); + ret = aw_sar_chip_init(p_sar); + if (ret != 0) + return; + } + queue_delayed_work(p_sar->monitor_wq, &p_sar->monitor_work, + msecs_to_jiffies(AW_SAR_MONITOR_ESD_DELAY_MS)); +} + +static int32_t aw_sar_monitor_esd_init(struct aw_sar *p_sar) +{ + p_sar->monitor_wq = create_singlethread_workqueue("aw_sar_workqueue"); + if (!p_sar->monitor_wq) { + dev_err(&p_sar->i2c->dev, "aw_sar_workqueue error"); + return -EINVAL; + } + INIT_DELAYED_WORK(&p_sar->monitor_work, aw_sar_monitor_work); + queue_delayed_work(p_sar->monitor_wq, &p_sar->monitor_work, + msecs_to_jiffies(AW_SAR_MONITOR_ESD_DELAY_MS)); + + return 0; +} + +static void aw_sar_sensor_free(struct aw_sar *p_sar) +{ + if (g_aw_sar_driver_list[p_sar->curr_use_driver_type].p_chip_deinit != NULL) + g_aw_sar_driver_list[p_sar->curr_use_driver_type].p_chip_deinit(p_sar); +} + + +/** + * @brief Drive logic entry + * + */ +static int32_t aw_sar_i2c_probe(struct i2c_client *i2c) +{ + struct aw_sar *p_sar; + int32_t ret; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) { + pr_err("check_functionality failed!\n"); + return -EIO; + } + + p_sar = devm_kzalloc(&i2c->dev, sizeof(struct aw_sar), GFP_KERNEL); + if (!p_sar) { + ret = -ENOMEM; + goto err_malloc; + } + + p_sar->dev = &i2c->dev; + p_sar->i2c = i2c; + i2c_set_clientdata(i2c, p_sar); + + //1.Judge whether to use regular power supply. If yes, supply power + ret = aw_sar_regulator_power(p_sar); + if (ret != 0) { + dev_err(&i2c->dev, "regulator_power error!"); + goto err_malloc; + } + + //2.Get chip initialization resources + ret = aw_sar_get_chip_info(p_sar); + if (ret != 0) { + dev_err(&i2c->dev, "chip_init error!"); + goto err_chip_init; + } + + //3.Chip initialization process + ret = aw_sar_init(p_sar); + if (ret != 0) { + dev_err(&i2c->dev, "sar_init error!"); + goto err_sar_init; + } + + if (p_sar->dts_info.monitor_esd_flag) { + ret = aw_sar_monitor_esd_init(p_sar); + if (ret != 0) { + dev_err(&i2c->dev, "monitor_esd_init error!"); + goto err_esd_init; + } + } + + dev_dbg(&i2c->dev, "probe success!"); + + return 0; + +err_esd_init: + aw_sar_input_free(p_sar); + aw_sar_irq_free(p_sar); + aw_sar_node_free(p_sar); + if (p_sar->dts_info.use_inter_pull_up == true) + aw_sar_pinctrl_deinit(p_sar); + if (p_sar->dts_info.use_plug_cail_flag == true) + power_supply_unreg_notifier(&p_sar->ps_notif); + mutex_destroy(&aw_sar_lock); +err_sar_init: + aw_sar_sensor_free(p_sar); +err_chip_init: +if (p_sar->dts_info.use_regulator_flag == true) + aw_sar_power_deinit(p_sar); +err_malloc: + return ret; +} + +static void aw_sar_i2c_remove(struct i2c_client *i2c) +{ + struct aw_sar *p_sar = i2c_get_clientdata(i2c); + + aw_sar_chip_other_operation_free(p_sar); + + aw_sar_node_free(p_sar); + + aw_sar_irq_free(p_sar); + + aw_sar_input_free(p_sar); + + if (p_sar->dts_info.use_inter_pull_up == true) + aw_sar_pinctrl_deinit(p_sar); + + if (p_sar->dts_info.use_regulator_flag == true) + aw_sar_power_deinit(p_sar); + + if (p_sar->dts_info.use_plug_cail_flag == true) + power_supply_unreg_notifier(&p_sar->ps_notif); + + aw_sar_sensor_free(p_sar); +} + +static int aw_sar_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct aw_sar *p_sar = i2c_get_clientdata(client); + + if (p_sar->dts_info.use_pm == true) { + if ((!p_sar->p_sar_para->p_platform_config) || + (!p_sar->p_sar_para->p_platform_config->p_pm_chip_mode)) + return 0; + if (p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_suspend_fn) { + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_suspend_fn(p_sar); + return 0; + } + aw_sar_mode_set(p_sar, + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->suspend_set_mode); + } + + if (p_sar->dts_info.monitor_esd_flag) + cancel_delayed_work_sync(&p_sar->monitor_work); + + return 0; +} + +static int aw_sar_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct aw_sar *p_sar = i2c_get_clientdata(client); + + if (p_sar->dts_info.use_pm == true) { + if ((!p_sar->p_sar_para->p_platform_config) || + (!p_sar->p_sar_para->p_platform_config->p_pm_chip_mode)) + return 0; + if (p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_resume_fn) { + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_resume_fn(p_sar); + return 0; + } + aw_sar_mode_set(p_sar, + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->resume_set_mode); + } + + if (p_sar->dts_info.monitor_esd_flag) + queue_delayed_work(p_sar->monitor_wq, &p_sar->monitor_work, + msecs_to_jiffies(AW_SAR_MONITOR_ESD_DELAY_MS)); + + return 0; +} + +static void aw_sar_i2c_shutdown(struct i2c_client *i2c) +{ + struct aw_sar *p_sar = i2c_get_clientdata(i2c); + + if ((!p_sar->p_sar_para->p_platform_config) || + (!p_sar->p_sar_para->p_platform_config->p_pm_chip_mode)) + return; + + if (p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_shutdown_fn) { + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->p_shutdown_fn(p_sar); + return; + } + + aw_sar_mode_set(p_sar, + p_sar->p_sar_para->p_platform_config->p_pm_chip_mode->shutdown_set_mode); +} + +static const struct dev_pm_ops aw_sar_pm_ops = { + .suspend = aw_sar_suspend, + .resume = aw_sar_resume, +}; + +static const struct of_device_id aw_sar_dt_match[] = { + { .compatible = "awinic,aw96103" }, + { .compatible = "awinic,aw96105" }, + { .compatible = "awinic,aw96303" }, + { .compatible = "awinic,aw96305" }, + { .compatible = "awinic,aw96308" }, +}; + +static const struct i2c_device_id aw_sar_i2c_id[] = { + { AW_SAR_I2C_NAME, 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, aw_sar_i2c_id); + +static struct i2c_driver aw_sar_i2c_driver = { + .driver = { + .name = AW_SAR_I2C_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(aw_sar_dt_match), + .pm = &aw_sar_pm_ops, + }, + .probe = aw_sar_i2c_probe, + .remove = aw_sar_i2c_remove, + .shutdown = aw_sar_i2c_shutdown, + .id_table = aw_sar_i2c_id, +}; + +static int32_t __init aw_sar_i2c_init(void) +{ + int32_t ret; + + ret = i2c_add_driver(&aw_sar_i2c_driver); + if (ret) { + pr_err("fail to add aw_sar device into i2c\n"); + return ret; + } + + return 0; +} + +module_init(aw_sar_i2c_init); +static void __exit aw_sar_i2c_exit(void) +{ + i2c_del_driver(&aw_sar_i2c_driver); +} +module_exit(aw_sar_i2c_exit); +MODULE_DESCRIPTION("AWINIC SAR Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/input/misc/aw_sar/aw_sar.h b/drivers/input/misc/aw_sar/aw_sar.h new file mode 100644 index 000000000000..7a139f56e9c3 --- /dev/null +++ b/drivers/input/misc/aw_sar/aw_sar.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef AW_SAR_H_ +#define AW_SAR_H_ + +void aw_sar_disable_irq(struct aw_sar *p_sar); +void aw_sar_enable_irq(struct aw_sar *p_sar); + +int32_t aw_sar_soft_reset(struct aw_sar *p_sar); +int32_t aw_sar_check_init_over_irq(struct aw_sar *p_sar); +int32_t aw_sar_update_fw(struct aw_sar *p_sar); +int32_t aw_sar_load_def_reg_bin(struct aw_sar *p_sar); +void aw_sar_mode_set(struct aw_sar *p_sar, uint8_t curr_mode); +int32_t aw_sar_update_reg_set_func(struct aw_sar *p_sar); + +#endif