From c8afdd7c141fb4514633fc22f492e9f29215e5b3 Mon Sep 17 00:00:00 2001 From: chailu1 Date: Tue, 26 Oct 2021 18:29:18 +0800 Subject: [PATCH] sgm7220: Reorganize sgm7220 driver architecture sgm7220 is not typec TCPC architecture, so clear tcpc ops function. propagate from MTK kernel-4.14/drivers/misc/mediatek/typec/tcpc/ Change-Id: Icd59ec48c510306d7f8d46d7e9d0fdf7a39fb72b Reviewed-on: https://gerrit.mot.com/2100791 Reviewed-by: Huosheng Liao SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Submit-Approved: Jira Key --- drivers/usb/typec/mmi_tcpc/inc/sgm7220.h | 68 ++ drivers/usb/typec/mmi_tcpc/rt_pd_manager.c | 10 +- drivers/usb/typec/mmi_tcpc/tcpc_sgm7220.c | 1113 +++++++++----------- drivers/usb/typec/mmi_tcpc/tcpci.c | 1 + 4 files changed, 567 insertions(+), 625 deletions(-) create mode 100644 drivers/usb/typec/mmi_tcpc/inc/sgm7220.h diff --git a/drivers/usb/typec/mmi_tcpc/inc/sgm7220.h b/drivers/usb/typec/mmi_tcpc/inc/sgm7220.h new file mode 100644 index 000000000000..f804bd3e22ef --- /dev/null +++ b/drivers/usb/typec/mmi_tcpc/inc/sgm7220.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2021 MediaTek Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_SGM7220_H +#define __LINUX_SGM7220_H + +/****************************************************************************** +* Register addresses +******************************************************************************/ +#define REG_BASE 0x00 +/* 0x00 - 0x07 reserved for ID */ +#define REG_MOD 0x08 +#define REG_INT 0x09 +#define REG_SET 0x0A +#define REG_CTL 0X45 +#define REG_REVISION 0XA0 + +/****************************************************************************** +* Register bits +******************************************************************************/ +/* REG_ID (0x00) */ +#define ID_REG_LEN 0X08 + +/* REG_MOD (0x08) */ +#define MOD_ACTIVE_CABLE_DETECTION 0X01 /*RU*/ +#define MOD_ACCESSORY_CONNECTED_SHIFT 1 +#define MOD_ACCESSORY_CONNECTED (0x07 << MOD_ACCESSORY_CONNECTED_SHIFT) /*RU*/ +#define MOD_CURRENT_MODE_DETECT_SHIFT 4 +#define MOD_CURRENT_MODE_DETECT (0x03 << MOD_CURRENT_MODE_DETECT_SHIFT) /*RU*/ +#define MOD_CURRENT_MODE_ADVERTISE_SHIFT 6 +#define MOD_CURRENT_MODE_ADVERTISE (0x03 << MOD_CURRENT_MODE_ADVERTISE_SHIFT) /*RW*/ + +/* REG_INT (0x09) */ +#define INT_DRP_DUTY_CYCLE_SHIFT 1 +#define INT_DRP_DUTY_CYCLE (0x03 << INT_DRP_DUTY_CYCLE_SHIFT) /*RW*/ +#define INT_INTERRUPT_STATUS_SHIFT 4 +#define INT_INTERRUPT_STATUS (0x01 << INT_INTERRUPT_STATUS_SHIFT) /*RCU*/ +#define INT_CABLE_DIR_SHIFT 5 +#define INT_CABLE_DIR (0x01 << INT_CABLE_DIR_SHIFT) /*RU*/ +#define INT_ATTACHED_STATE_SHIFT 6 +#define INT_ATTACHED_STATE (0x03 << INT_ATTACHED_STATE_SHIFT) /*RU*/ + +/* REG_SET (0x0A) */ +#define SET_I2C_DISABLE_TERM 0x01 /*RW*/ +#define SET_I2C_SOURCE_PREF_SHIFT 1 +#define SET_I2C_SOURCE_PREF (0x03 << SET_I2C_SOURCE_PREF_SHIFT) /*RW*/ +#define SET_I2C_SOFT_RESET_SHIFT 3 +#define SET_I2C_SOFT_RESET (0x01 << SET_I2C_SOFT_RESET_SHIFT) /*RSU*/ +#define SET_MODE_SELECT_SHIFT 4 +#define SET_MODE_SELECT (0x03 << SET_MODE_SELECT_SHIFT) /*RW*/ +#define SET_DEBOUNCE_SHIFT 6 +#define SET_DEBOUNCE (0x03 << SET_DEBOUNCE_SHIFT) /*RW*/ + +/* REG_CTR (0x45) */ +#define CTR_DISABLE_RD_RP_SHIFT 2 +#define CTR_DISABLE_RD_RP (0x01 << CTR_DISABLE_RD_RP_SHIFT) /*RW*/ + +#endif /* #ifndef __LINUX_SGM7220_H */ diff --git a/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c b/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c index e7da66717ef1..c9e04e9bd831 100644 --- a/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c +++ b/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c @@ -318,8 +318,9 @@ static int pd_tcp_notifier_call(struct notifier_block *nb, new_state == TYPEC_ATTACHED_CUSTOM_SRC || new_state == TYPEC_ATTACHED_DBGACC_SNK)) { dev_info(rpmd->dev, - "%s Charger plug in, polarity = %d\n", - __func__, noti->typec_state.polarity); + "%s Charger plug in, polarity = %d, remote rp = %d\n", + __func__, noti->typec_state.polarity, + noti->typec_state.rp_level); /* * start charger type detection, * and enable device connection @@ -353,8 +354,9 @@ static int pd_tcp_notifier_call(struct notifier_block *nb, (new_state == TYPEC_ATTACHED_SRC || new_state == TYPEC_ATTACHED_DEBUG)) { dev_info(rpmd->dev, - "%s OTG plug in, polarity = %d\n", - __func__, noti->typec_state.polarity); + "%s OTG plug in, polarity = %d, local_rp = %d\n", + __func__, noti->typec_state.polarity, + noti->typec_state.local_rp_level); /* enable host connection */ cancel_delayed_work_sync(&rpmd->usb_dwork); rpmd->usb_dr = DR_HOST; diff --git a/drivers/usb/typec/mmi_tcpc/tcpc_sgm7220.c b/drivers/usb/typec/mmi_tcpc/tcpc_sgm7220.c index cf0698b5744a..eccfc5a01ff2 100644 --- a/drivers/usb/typec/mmi_tcpc/tcpc_sgm7220.c +++ b/drivers/usb/typec/mmi_tcpc/tcpc_sgm7220.c @@ -10,7 +10,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ - #include #include #include @@ -28,88 +27,17 @@ #include #include #include - #include "inc/tcpci.h" - +#include "inc/sgm7220.h" #include -#define SGM7220_DRV_VERSION "1.0" - -#define sgm7220_IRQ_WAKE_TIME (500) /* ms */ - -/****************************************************************************** -* Register addresses -******************************************************************************/ -#define REG_BASE 0x00 -/* 0x00 - 0x07 reserved for ID */ -#define REG_MOD 0x08 -#define REG_INT 0x09 -#define REG_SET 0x0A -#define REG_CTL 0X45 -#define REG_REVISION 0XA0 - -/****************************************************************************** -* Register bits -******************************************************************************/ -/* REG_ID (0x00) */ -#define ID_REG_LEN 0X08 - -/* REG_MOD (0x08) */ -#define MOD_ACTIVE_CABLE_DETECTION 0X01 /*RU*/ -#define MOD_ACCESSORY_CONNECTED_SHIFT 1 -#define MOD_ACCESSORY_CONNECTED (0x07 << MOD_ACCESSORY_CONNECTED_SHIFT) /*RU*/ -#define MOD_CURRENT_MODE_DETECT_SHIFT 4 -#define MOD_CURRENT_MODE_DETECT (0x03 << MOD_CURRENT_MODE_DETECT_SHIFT) /*RU*/ -#define MOD_CURRENT_MODE_ADVERTISE_SHIFT 6 -#define MOD_CURRENT_MODE_ADVERTISE (0x03 << MOD_CURRENT_MODE_ADVERTISE_SHIFT) /*RW*/ - -/* REG_INT (0x09) */ -#define INT_DRP_DUTY_CYCLE_SHIFT 1 -#define INT_DRP_DUTY_CYCLE (0x03 << INT_DRP_DUTY_CYCLE_SHIFT) /*RW*/ -#define INT_INTERRUPT_STATUS_SHIFT 4 -#define INT_INTERRUPT_STATUS (0x01 << INT_INTERRUPT_STATUS_SHIFT) /*RCU*/ -#define INT_CABLE_DIR_SHIFT 5 -#define INT_CABLE_DIR (0x01 << INT_CABLE_DIR_SHIFT) /*RU*/ -#define INT_ATTACHED_STATE_SHIFT 6 -#define INT_ATTACHED_STATE (0x03 << INT_ATTACHED_STATE_SHIFT) /*RU*/ - -/* REG_SET (0x0A) */ -#define SET_I2C_DISABLE_TERM 0x01 /*RW*/ -#define SET_I2C_SOURCE_PREF_SHIFT 1 -#define SET_I2C_SOURCE_PREF (0x03 << SET_I2C_SOURCE_PREF_SHIFT) /*RW*/ -#define SET_I2C_SOFT_RESET_SHIFT 3 -#define SET_I2C_SOFT_RESET (0x01 << SET_I2C_SOFT_RESET_SHIFT) /*RSU*/ -#define SET_MODE_SELECT_SHIFT 4 -#define SET_MODE_SELECT (0x03 << SET_MODE_SELECT_SHIFT) /*RW*/ -#define SET_DEBOUNCE_SHIFT 6 -#define SET_DEBOUNCE (0x03 << SET_DEBOUNCE_SHIFT) /*RW*/ - -/* REG_CTR (0x45) */ -#define CTR_DISABLE_RD_RP_SHIFT 2 -#define CTR_DISABLE_RD_RP (0x01 << CTR_DISABLE_RD_RP_SHIFT) /*RW*/ - -/****************************************************************************** - * Register values - ******************************************************************************/ -/* SET_MODE_SELECT */ -#define SET_MODE_SELECT_DEFAULT 0x00 -#define SET_MODE_SELECT_SNK 0x01 -#define SET_MODE_SELECT_SRC 0x02 -#define SET_MODE_SELECT_DRP 0x03 -/* MOD_CURRENT_MODE_ADVERTISE */ -#define MOD_CURRENT_MODE_ADVERTISE_DEFAULT 0x00 -#define MOD_CURRENT_MODE_ADVERTISE_MID 0x01 -#define MOD_CURRENT_MODE_ADVERTISE_HIGH 0x02 -/* MOD_CURRENT_MODE_DETECT */ -#define MOD_CURRENT_MODE_DETECT_DEFAULT 0x00 -#define MOD_CURRENT_MODE_DETECT_MID 0x01 -#define MOD_CURRENT_MODE_DETECT_ACCESSARY 0x02 -#define MOD_CURRENT_MODE_DETECT_HIGH 0x03 - +#define SGM7220_DRV_VERSION "1.0.0_SGM7220" +#define SGM7220_IRQ_WAKE_TIME (500) /* ms */ /****************************************************************************** * Constants ******************************************************************************/ + enum drp_toggle_type { TOGGLE_DFP_DRP_30 = 0, TOGGLE_DFP_DRP_40, @@ -150,8 +78,8 @@ enum cable_state_type { }; enum cable_dir_type { - ORIENT_CC2 = 0, - ORIENT_CC1 + ORIENT_CC1 = 0, + ORIENT_CC2 }; enum cc_modes_type { @@ -170,6 +98,13 @@ struct type_c_parameters { enum cable_dir_type cable_dir; /*cc1 or cc2*/ }; +struct state_disorder_monitor { + int count; + int err_detected; + enum cable_state_type former_state; + unsigned long time_before; +}; + struct sgm7220_chip { struct i2c_client *client; struct device *dev; @@ -182,251 +117,319 @@ struct sgm7220_chip { struct task_struct *irq_worker_task; struct wakeup_source *irq_wake_lock; struct wakeup_source *i2c_wake_lock; - struct mutex mutex; -#ifdef CONFIG_TCPC_SGM7220 + atomic_t poll_count; struct delayed_work poll_work; -#endif - struct type_c_parameters type_c_param; - struct type_c_parameters type_c_param_old; + struct delayed_work first_check_typec_work; + int irq_gpio; + uint8_t dev_id; + uint8_t dev_sub_id; int irq; int chip_id; + struct type_c_parameters type_c_param; + struct state_disorder_monitor monitor; }; -struct mutex mutex; -struct mutex mutex2; +static struct i2c_client *w_client; -/* i2c operate interfaces */ -static int sgm7220_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest) +static int sgm7220_read_device(void *client, u32 reg, int len, void *dst) { - int ret; - mutex_lock(&mutex); - ret = i2c_smbus_read_byte_data(i2c, reg); - mutex_unlock(&mutex); - if (ret < 0) { - pr_err("%s: (0x%x) error, ret(%d)\n", __func__, reg, ret); - return ret; + struct i2c_client *i2c = (struct i2c_client *)client; + struct sgm7220_chip *chip = i2c_get_clientdata(i2c); + int ret = 0, count = 5; + + __pm_stay_awake(chip->i2c_wake_lock); + down(&chip->suspend_lock); + while (count) { + if (len > 1) { + ret = i2c_smbus_read_i2c_block_data(i2c, reg, len, dst); + if (ret < 0) + count--; + else + goto out; + } else { + ret = i2c_smbus_read_byte_data(i2c, reg); + if (ret < 0) + count--; + else { + *(u8 *)dst = (u8)ret; + goto out; + } + } + udelay(100); } - - ret &= 0xff; - *dest = ret; - return 0; -} - -static int sgm7220_write_reg(struct i2c_client *i2c, u8 reg, u8 value) -{ - int ret; - mutex_lock(&mutex); - ret = i2c_smbus_write_byte_data(i2c, reg, value); - mutex_unlock(&mutex); - if (ret < 0) - pr_err("%s: (0x%x) error, ret(%d)\n", __func__, reg, ret); - +out: + up(&chip->suspend_lock); + __pm_relax(chip->i2c_wake_lock); return ret; } -static int sgm7220_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask) +static int sgm7220_write_device(void *client, u32 reg, int len, const void *src) { + const u8 *data; + struct i2c_client *i2c = (struct i2c_client *)client; + struct sgm7220_chip *chip = i2c_get_clientdata(i2c); + int ret = 0, count = 5; + + __pm_stay_awake(chip->i2c_wake_lock); + down(&chip->suspend_lock); + while (count) { + if (len > 1) { + ret = i2c_smbus_write_i2c_block_data(i2c, + reg, len, src); + if (ret < 0) + count--; + else + goto out; + } else { + data = src; + ret = i2c_smbus_write_byte_data(i2c, reg, *data); + if (ret < 0) + count--; + else + goto out; + } + udelay(100); + } +out: + up(&chip->suspend_lock); + __pm_relax(chip->i2c_wake_lock); + return ret; +} + +static int sgm7220_reg_write(struct i2c_client *i2c, u8 reg, const u8 data) +{ + struct sgm7220_chip *chip = i2c_get_clientdata(i2c); + int ret = 0; + + ret = sgm7220_write_device(chip->client, reg, 1, &data); + if (ret < 0) + dev_err(chip->dev, "sgm7220 reg write fail\n"); + return ret; +} + +static int sgm7220_reg_update(struct i2c_client *i2c, u8 reg, const u8 data, u8 mask) +{ + struct sgm7220_chip *chip = i2c_get_clientdata(i2c); int ret; u8 old_val, new_val; - mutex_lock(&mutex); - ret = i2c_smbus_read_byte_data(i2c, reg); + ret = sgm7220_read_device(chip->client, reg, 1, &old_val); + if (ret < 0) { + dev_err(chip->dev, "sgm7220 reg read fail\n"); + return ret; + } + if (ret >= 0) { old_val = ret & 0xff; - new_val = (val & mask) | (old_val & (~mask)); - ret = i2c_smbus_write_byte_data(i2c, reg, new_val); + new_val = (data & mask) | (old_val & (~mask)); + ret = sgm7220_write_device(chip->client, reg, 1, &new_val); + if (ret < 0) + dev_err(chip->dev, "sgm7220 reg write fail\n"); } - mutex_unlock(&mutex); return ret; } -static int sgm7220_init_alert_mask(struct tcpc_device *tcpc) +/* Detect non-DFP->DFP changes that happen more than 3 times within 10 Secs */ +static void sgm7220_state_disorder_detect(struct sgm7220_chip *chip) { - return 0; -} + unsigned long timeout; -static int sgm7220_init_power_status_mask(struct tcpc_device *tcpc) -{ - return 0; -} - -static int sgm7220_init_fault_mask(struct tcpc_device *tcpc) -{ - return 0; -} - -static int sgm7220_init_rt_mask(struct tcpc_device *tcpc) -{ - return 0; -} -#ifdef CONFIG_TCPC_SGM7220 -static inline void sgm7220_poll_ctrl(struct sgm7220_chip *chip) -{ - cancel_delayed_work_sync(&chip->poll_work); - - if (atomic_read(&chip->poll_count) == 0) { - atomic_inc(&chip->poll_count); - cpu_idle_poll_ctrl(true); + /* count the (non-DFP -> DFP) changes */ + if ((chip->monitor.former_state != chip->type_c_param.attach_state) + && (chip->type_c_param.attach_state == CABLE_STATE_AS_DFP)) { + if (!chip->monitor.count) { + chip->monitor.time_before = jiffies; + } + chip->monitor.count++; } - schedule_delayed_work( - &chip->poll_work, msecs_to_jiffies(40)); -} -#endif -/*********************************************************** - * read registers in irq process - ***********************************************************/ -static void process_mode_register(struct sgm7220_chip *info) -{ - u8 val, tmp, reg_val; - int ret; - ret = sgm7220_read_reg(info->client, REG_MOD, ®_val); - if (ret < 0) { - pr_err("%s err\n", __func__); - return; + /* store the state */ + chip->monitor.former_state = chip->type_c_param.attach_state; + + if (chip->monitor.count > 3) { + timeout = msecs_to_jiffies(10 * 1000); /* 10 Seconds */ + if (time_before(jiffies, chip->monitor.time_before + timeout)) { + chip->monitor.err_detected = 1; + /* disbale id irq before qpnp react to cc chip's id output */ + //interfere_id_irq_from_usb(0); + } + chip->monitor.count = 0; } - tmp = reg_val; + + if ((chip->type_c_param.attach_state == CABLE_STATE_NOT_ATTACHED) + && chip->monitor.err_detected) { + /* enable id irq */ + //interfere_id_irq_from_usb(1); + chip->monitor.err_detected = 0; + } +} + +static void sgm7220_process_mode_register(struct sgm7220_chip *chip, u8 status) +{ + u8 val; + u8 tmp = status; /* check current_detect */ val = ((tmp & MOD_CURRENT_MODE_DETECT) >> MOD_CURRENT_MODE_DETECT_SHIFT); - info->type_c_param.current_det = val; + chip->type_c_param.current_det = val; + /* check accessory attch */ - tmp = reg_val; + tmp = status; val = ((tmp & MOD_ACCESSORY_CONNECTED) >> MOD_ACCESSORY_CONNECTED_SHIFT); - info->type_c_param.accessory_attach = val; + chip->type_c_param.accessory_attach = val; /* check cable attach */ - tmp = reg_val; + tmp = status; val = (tmp & MOD_ACTIVE_CABLE_DETECTION); - info->type_c_param.active_cable_attach = val; + chip->type_c_param.active_cable_attach = val; - pr_info("sgm7220 %s , current_det = %d, accessory_attach = %d, active_cable_attach = %d\n", __func__, info->type_c_param.current_det, info->type_c_param.accessory_attach, info->type_c_param.active_cable_attach); + pr_info("sgm7220 %s , current_det = %d, accessory_attach = %d, active_cable_attach = %d\n", + __func__, + chip->type_c_param.current_det, + chip->type_c_param.accessory_attach, + chip->type_c_param.active_cable_attach); } -static void process_interrupt_register(struct sgm7220_chip *info) +static int sgm7220_remote_rp_level(struct sgm7220_chip *chip) { - u8 val, tmp, reg_val; - int ret; - ret = sgm7220_read_reg(info->client, REG_INT, ®_val); - if (ret < 0) { - pr_err("%s err\n", __func__); - return; - } - tmp = reg_val; + if (chip->type_c_param.current_det == DET_CUR_USB) + return TYPEC_CC_VOLT_SNK_DFT; + else if (chip->type_c_param.current_det == DET_CUR_1P5) + return TYPEC_CC_VOLT_SNK_1_5; + else if (chip->type_c_param.current_det == DET_CUR_3A) + return TYPEC_CC_VOLT_SNK_3_0; + else + return TYPEC_CC_VOLT_SNK_DFT; +} + +static int sgm7220_local_rp_level(struct sgm7220_chip *chip) +{ + return TYPEC_CC_RP_1_5; +} + +static void sgm7220_process_interrupt_register(struct sgm7220_chip *chip, u8 status) +{ + struct tcpc_device *tcpc; + u8 val; + u8 tmp = status; + + tcpc = chip->tcpc; /* check attach state */ val = ((tmp & INT_ATTACHED_STATE) >> INT_ATTACHED_STATE_SHIFT); - info->type_c_param.attach_state = val; + chip->type_c_param.attach_state = val; + /* update current adv when act as DFP */ - if (info->type_c_param.attach_state == CABLE_STATE_AS_DFP || - info->type_c_param.attach_state == CABLE_STATE_TO_ACCESSORY) { + if (chip->type_c_param.attach_state == CABLE_STATE_AS_DFP || + chip->type_c_param.attach_state == CABLE_STATE_TO_ACCESSORY) { val = (HOST_CUR_USB << MOD_CURRENT_MODE_ADVERTISE_SHIFT); - } else if (info->type_c_param.attach_state == CABLE_STATE_AS_UFP) { - val = (HOST_CUR_3A << MOD_CURRENT_MODE_ADVERTISE_SHIFT); } else { - val = (HOST_CUR_USB << MOD_CURRENT_MODE_ADVERTISE_SHIFT); + val = (HOST_CUR_1P5 << MOD_CURRENT_MODE_ADVERTISE_SHIFT); } - sgm7220_update_reg(info->client, REG_MOD, val, MOD_CURRENT_MODE_ADVERTISE); + sgm7220_reg_update(chip->client, REG_MOD, val, MOD_CURRENT_MODE_ADVERTISE); + + /* in case configured as DRP may detect some non-standard SDP */ + /* chargers as UFP, which may lead to a cyclic switching of DFP */ + /* and UFP on state detection result. */ + sgm7220_state_disorder_detect(chip); /* check cable dir */ - tmp = reg_val; + tmp = status; val = ((tmp & INT_CABLE_DIR) >> INT_CABLE_DIR_SHIFT); - info->type_c_param.cable_dir = val; + chip->type_c_param.cable_dir = val; + tcpc->typec_polarity = chip->type_c_param.cable_dir; + pr_info("%s type=%d,cc_stat(%d)\n", __func__, chip->type_c_param.attach_state, tcpc->typec_polarity); + pr_info("%s attach_new=%d,attach_old=%d\n", __func__, tcpc->typec_attach_new, tcpc->typec_attach_old); - pr_info("sgm7220 %s ,attach_state = %d, cable_dir = %d \n", __func__, info->type_c_param.attach_state, info->type_c_param.cable_dir); -} - -static void process_tcpci_attach_state(struct sgm7220_chip *chip) -{ - struct tcpc_device *tcpc_dev = chip->tcpc; - - if ((chip->type_c_param.attach_state == CABLE_STATE_NOT_ATTACHED) && - (chip->type_c_param_old.attach_state != CABLE_STATE_NOT_ATTACHED)) { - tcpc_dev->typec_attach_new = TYPEC_UNATTACHED; - if (chip->type_c_param_old.attach_state == CABLE_STATE_AS_UFP) { - tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SNK; - } else if (chip->type_c_param_old.attach_state == CABLE_STATE_AS_DFP) { - tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SRC; - } - tcpci_report_usb_port_changed(tcpc_dev); - if (chip->type_c_param_old.attach_state == CABLE_STATE_AS_DFP) { - tcpci_source_vbus(tcpc_dev, - TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_0V, 0); - } - tcpc_dev->typec_attach_old = TYPEC_UNATTACHED; - pr_info("sgm7220 %s , attach_state = DETACHED\n", __func__); - } - - if ((chip->type_c_param.attach_state == CABLE_STATE_AS_UFP) && - (chip->type_c_param_old.attach_state != CABLE_STATE_AS_UFP)) { - tcpc_dev->typec_attach_new = TYPEC_ATTACHED_SNK; - tcpci_report_usb_port_changed(tcpc_dev); - tcpci_source_vbus(tcpc_dev, - TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_0V, 0); - tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SNK; - pr_info("sgm7220 %s , attach_state = TYPEC_ATTACHED_SNK\n", __func__); - } - - if ((chip->type_c_param.attach_state == CABLE_STATE_AS_DFP) && - (chip->type_c_param_old.attach_state != CABLE_STATE_AS_DFP)) { - tcpc_dev->typec_attach_new = TYPEC_ATTACHED_SRC; - tcpci_report_usb_port_changed(tcpc_dev); - tcpci_source_vbus(tcpc_dev, - TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_5V, -1); - tcpc_dev->typec_attach_old = TYPEC_ATTACHED_SRC; - /* -1 means let tcpc decide current value */ - pr_info("sgm7220 %s , attach_state = TYPEC_ATTACHED_SRC\n", __func__); - } - chip->type_c_param_old.attach_state = chip->type_c_param.attach_state; - tcpc_dev->typec_polarity = chip->type_c_param.cable_dir; + switch (chip->type_c_param.attach_state) { + case CABLE_STATE_NOT_ATTACHED: + tcpc->typec_attach_new = TYPEC_UNATTACHED; + if (tcpc->typec_attach_old == TYPEC_ATTACHED_SRC) { + tcpci_source_vbus(tcpc, TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_0V, 0); + } + tcpci_notify_typec_state(tcpc); + tcpc->typec_attach_old = TYPEC_UNATTACHED; + break; + case CABLE_STATE_AS_DFP: + if (tcpc->typec_attach_new != TYPEC_ATTACHED_SRC) { + tcpc->typec_attach_new = TYPEC_ATTACHED_SRC; + tcpc->typec_local_rp_level = sgm7220_local_rp_level(chip); + tcpci_source_vbus(tcpc, TCP_VBUS_CTRL_TYPEC, TCPC_VBUS_SOURCE_5V, 0); + tcpci_notify_typec_state(tcpc); + tcpc->typec_attach_old = TYPEC_ATTACHED_SRC; + } + break; + case CABLE_STATE_AS_UFP: + if (tcpc->typec_attach_new != TYPEC_ATTACHED_SNK) { + tcpc->typec_attach_new = TYPEC_ATTACHED_SNK; + tcpc->typec_remote_rp_level = sgm7220_remote_rp_level(chip); + tcpci_notify_typec_state(tcpc); + tcpc->typec_attach_old = TYPEC_ATTACHED_SNK; + } + break; + case CABLE_STATE_TO_ACCESSORY: + if (chip->type_c_param.accessory_attach == ACCESSORY_AUDIO + && tcpc->typec_attach_new != TYPEC_ATTACHED_AUDIO) { + tcpc->typec_attach_new = TYPEC_ATTACHED_AUDIO; + tcpci_notify_typec_state(tcpc); + tcpc->typec_attach_old = TYPEC_ATTACHED_AUDIO; + } + break; + + default: + pr_err("%s: Unknwon type[0x%02x]\n", __func__, chip->type_c_param.attach_state); + break; + } } +static int first_check_flag = 0; static void sgm7220_irq_work_handler(struct kthread_work *work) { - struct sgm7220_chip *chip = - container_of(work, struct sgm7220_chip, irq_work); - int ret = 0; -#ifdef CONFIG_TCPC_SGM7220 - sgm7220_poll_ctrl(chip); -#endif - /* make sure I2C bus had resumed */ + struct sgm7220_chip *chip = container_of(work, struct sgm7220_chip, irq_work); + struct tcpc_device *tcpc; + u8 reg_val; + int ret; + + if (0 == first_check_flag) + return; + + tcpc = chip->tcpc; + tcpci_lock_typec(tcpc); - down(&chip->suspend_lock); - mutex_lock(&mutex2); pr_info("%s enter\n", __func__); - process_mode_register(chip); - process_interrupt_register(chip); - process_tcpci_attach_state(chip); - mutex_unlock(&mutex2); - up(&chip->suspend_lock); - ret = sgm7220_update_reg(chip->client, - REG_INT, (0x1 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); + ret = sgm7220_read_device(chip->client, REG_MOD, 1, ®_val); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + } + + pr_info("%s mode_register:0x%x\n", __func__, reg_val); + sgm7220_process_mode_register(chip, reg_val); + + ret = sgm7220_read_device(chip->client, REG_INT, 1, ®_val); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + } + + pr_info("%s interrupt_register:0x%x\n", __func__, reg_val); + sgm7220_process_interrupt_register(chip, reg_val); + + ret = sgm7220_reg_update(chip->client, REG_INT, (0x1 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); if (ret < 0) { pr_err("%s: update reg fail!\n", __func__); } - ret = sgm7220_update_reg(chip->client, - REG_INT, (0x0 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); - if (ret < 0) { - pr_err("%s: update reg fail!\n", __func__); - } -} -#ifdef CONFIG_TCPC_SGM7220 -static void sgm7220_poll_work(struct work_struct *work) -{ - struct sgm7220_chip *chip = container_of( - work, struct sgm7220_chip, poll_work.work); - if (atomic_dec_and_test(&chip->poll_count)) - cpu_idle_poll_ctrl(false); + tcpci_unlock_typec(tcpc); } -#endif + + static irqreturn_t sgm7220_intr_handler(int irq, void *data) { struct sgm7220_chip *chip = data; - __pm_wakeup_event(chip->irq_wake_lock, sgm7220_IRQ_WAKE_TIME); + + __pm_wakeup_event(chip->irq_wake_lock, SGM7220_IRQ_WAKE_TIME); kthread_queue_work(&chip->irq_worker, &chip->irq_work); return IRQ_HANDLED; @@ -445,13 +448,12 @@ static int sgm7220_init_alert(struct tcpc_device *tcpc) if (!name) return -ENOMEM; - snprintf(name, PAGE_SIZE, "%s-IRQ", chip->tcpc_desc->name); + snprintf (name, PAGE_SIZE, "%s-IRQ", chip->tcpc_desc->name); pr_info("%s name = %s, gpio = %d\n", __func__, chip->tcpc_desc->name, chip->irq_gpio); ret = devm_gpio_request(chip->dev, chip->irq_gpio, name); - if (ret < 0) { pr_err("Error: failed to request GPIO%d (ret = %d)\n", chip->irq_gpio, ret); @@ -476,7 +478,7 @@ static int sgm7220_init_alert(struct tcpc_device *tcpc) kthread_init_worker(&chip->irq_worker); chip->irq_worker_task = kthread_run(kthread_worker_fn, - &chip->irq_worker, "%s", chip->tcpc_desc->name); + &chip->irq_worker, "%s", "chip->tcpc_desc->name"); if (IS_ERR(chip->irq_worker_task)) { pr_err("Error: Could not create tcpc task\n"); goto init_alert_err; @@ -484,13 +486,9 @@ static int sgm7220_init_alert(struct tcpc_device *tcpc) sched_setscheduler(chip->irq_worker_task, SCHED_FIFO, ¶m); kthread_init_work(&chip->irq_work, sgm7220_irq_work_handler); - - pr_info("sgm7220 IRQF_NO_THREAD Test\r\n"); - ret = request_irq(chip->irq, sgm7220_intr_handler, IRQF_TRIGGER_FALLING | IRQF_NO_THREAD | IRQF_NO_SUSPEND, name, chip); - if (ret < 0) { pr_err("Error: failed to request irq%d (gpio = %d, ret = %d)\n", chip->irq, chip->irq_gpio, ret); @@ -501,378 +499,84 @@ static int sgm7220_init_alert(struct tcpc_device *tcpc) return 0; init_alert_err: return -EINVAL; - } int sgm7220_alert_status_clear(struct tcpc_device *tcpc, uint32_t mask) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int ret = 0; - - ret = sgm7220_update_reg(chip->client, - REG_INT, (0x1 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); - ret = sgm7220_update_reg(chip->client, - REG_SET, (0x3 << SET_MODE_SELECT_SHIFT), SET_MODE_SELECT); - if (ret < 0) { - pr_err("%s: update reg fail!\n", __func__); - } - - return 0; -} - -static int sgm7220_initialization(struct tcpc_device *tcpc) -{ - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int ret = 0; - u8 reg_val; - - /* do initialization here, before enable irq, - * clear irq, - * config DRP/UFP/DFP mode, - * and etc.. - */ - pr_debug("%s enter\n", __func__); - - /* 1 Disable term(default 0) [bit 0] - * 2 Source pref(DRP performs try.SNK 01) [bit 2:1] - * 3 Soft reset(default 0) [bit 3] - * 4 Mode slect(DRP start from Try.SNK 00) [bit 5:4] - * 5 Debounce time of voltage change on CC pin(default 0) [bit 7:6] - */ - reg_val = 0x02; - ret = sgm7220_write_reg(chip->client, REG_SET, reg_val); - if (ret < 0) { - pr_err("%s: init REG_SET fail!\n", __func__); - return ret; - } - - /* CURRENT MODE ADVERTISE 3A [bit 7:6] */ - reg_val = (HOST_CUR_3A << MOD_CURRENT_MODE_ADVERTISE_SHIFT); - ret = sgm7220_update_reg(chip->client, REG_MOD, reg_val, MOD_CURRENT_MODE_ADVERTISE); - if (ret < 0) { - pr_err("%s: init REG_MOD fail!\n", __func__); - return ret; - } - - return ret; -} - -static inline int sgm7220_software_reset(struct tcpc_device *tcpc) -{ - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - u8 reg_val; - int ret; - - reg_val = (0x01 << SET_I2C_SOFT_RESET_SHIFT); - ret = sgm7220_update_reg(chip->client, REG_SET, reg_val, SET_I2C_SOFT_RESET); - if (ret < 0) { - pr_err("%s: init REG_MOD fail!\n", __func__); - return ret; - } - return 0; -} - -static inline int sgm7220_i2c_reset(struct tcpc_device *tcpc) -{ + pr_info("%s enter \n", __func__); return 0; } static int sgm7220_tcpc_init(struct tcpc_device *tcpc, bool sw_reset) { - int ret; - - pr_info("%s\n", __func__); - - if (sw_reset) { - ret = sgm7220_software_reset(tcpc); - if (ret < 0) - return ret; - } - -#ifdef CONFIG_TCPC_I2CRST_EN - sgm7220_i2c_reset(tcpc); -#endif - - ret = sgm7220_initialization(tcpc); - if (ret < 0) { - pr_err("%s: fails to initialize %d\n", __func__, ret); - return ret; - } - - tcpci_alert_status_clear(tcpc, 0xffffffff); - - sgm7220_init_power_status_mask(tcpc); - sgm7220_init_alert_mask(tcpc); - sgm7220_init_fault_mask(tcpc); - sgm7220_init_rt_mask(tcpc); - + pr_info("%s enter \n", __func__); return 0; } int sgm7220_fault_status_clear(struct tcpc_device *tcpc, uint8_t status) { + pr_info("%s enter \n", __func__); return 0; } int sgm7220_get_alert_mask(struct tcpc_device *tcpc, uint32_t *mask) { - *mask = 0; - *mask |= (TCPC_REG_ALERT_CC_STATUS | - TCPC_REG_ALERT_POWER_STATUS | - TCPC_REG_ALERT_EXT_RA_DETACH); + pr_info("%s enter \n", __func__); return 0; } -/***************************************************************** - * sgm7220 does not have alert register, compare type_c_param_old - * with type_c_param for figuring out what has been changed. - ****************************************************************/ int sgm7220_get_alert_status(struct tcpc_device *tcpc, uint32_t *alert) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - *alert = 0; - - pr_err("%s enter\n", __func__); - - /* cc status change */ - if ((chip->type_c_param.current_det != chip->type_c_param_old.current_det) || - (chip->type_c_param.active_cable_attach != chip->type_c_param_old.active_cable_attach) || - (chip->type_c_param.attach_state != chip->type_c_param_old.attach_state) || - (chip->type_c_param.cable_dir != chip->type_c_param_old.cable_dir)) { - *alert |= TCPC_REG_ALERT_CC_STATUS; - } - - /* UFP <-> Non-UFP = Power present change */ - if (((chip->type_c_param.attach_state == CABLE_STATE_AS_UFP) && - (chip->type_c_param_old.attach_state != CABLE_STATE_AS_UFP)) || - ((chip->type_c_param.attach_state == CABLE_STATE_AS_DFP) && - (chip->type_c_param_old.attach_state != CABLE_STATE_AS_DFP))) { - *alert |= TCPC_REG_ALERT_POWER_STATUS; - } - - /* accessory attach change */ - if (chip->type_c_param.accessory_attach != chip->type_c_param_old.accessory_attach) { - *alert |= TCPC_REG_ALERT_EXT_RA_DETACH; - } - /* Add more alert bits here if need */ - - pr_err("%s, %d->%d, %d->%d, %d->%d, %d->%d, %d->%d\n", __func__, - chip->type_c_param_old.current_det, chip->type_c_param.current_det, - chip->type_c_param_old.active_cable_attach, chip->type_c_param.active_cable_attach, - chip->type_c_param_old.attach_state, chip->type_c_param.attach_state, - chip->type_c_param_old.cable_dir, chip->type_c_param.cable_dir, - chip->type_c_param_old.accessory_attach, chip->type_c_param.accessory_attach); - - /* sync status to type_c_param_old */ - chip->type_c_param_old.current_det = chip->type_c_param.current_det; - chip->type_c_param_old.active_cable_attach = chip->type_c_param.active_cable_attach; - chip->type_c_param_old.attach_state = chip->type_c_param.attach_state; - chip->type_c_param_old.cable_dir = chip->type_c_param.cable_dir; - chip->type_c_param_old.accessory_attach = chip->type_c_param.accessory_attach; - + pr_info("%s enter \n", __func__); return 0; } -static int sgm7220_get_power_status( - struct tcpc_device *tcpc, uint16_t *pwr_status) +static int sgm7220_get_power_status(struct tcpc_device *tcpc, uint16_t *pwr_status) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - u8 reg_val; - u8 val; - int ret; - - pr_err("%s enter\n", __func__); - ret = sgm7220_read_reg(chip->client, REG_INT, ®_val); - if (ret < 0) { - pr_err("%s err\n", __func__); - return ret; - } - - val = ((reg_val & INT_ATTACHED_STATE) >> INT_ATTACHED_STATE_SHIFT); + pr_info("%s enter \n", __func__); *pwr_status = 0; - - if (val & CABLE_STATE_AS_UFP) { - /* sgm7220 does not supprt vbus detection, - assume vbus is detected if act as UFP */ - *pwr_status |= TCPC_REG_POWER_STATUS_VBUS_PRES; - } - - if (val > 0) { - process_mode_register(chip); - process_interrupt_register(chip); - process_tcpci_attach_state(chip); - ret = sgm7220_update_reg(chip->client, - REG_INT, (0x1 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); - pr_err("%s sgm7220_update_reg create boot detect\n", __func__); - } - - /*if (val & CABLE_STATE_AS_DFP) { - if (*pwr_status & TCPC_REG_POWER_STATUS_EXT_VSAFE0V) { - *pwr_status |= TCPC_REG_ALERT_POWER_STATUS; - } else { - *pwr_status |= TCPC_REG_POWER_STATUS_EXT_VSAFE0V; - } - }*/ - return 0; } int sgm7220_get_fault_status(struct tcpc_device *tcpc, uint8_t *status) { + pr_info("%s enter \n", __func__); return 0; } -/******************************************************************* - * Translate sgm7220 cc register's value to tcpc_cc_voltage_status. - *******************************************************************/ static int sgm7220_get_cc(struct tcpc_device *tcpc, int *cc1, int *cc2) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int *active_cc, *secondary_cc; - bool act_as_sink; - - pr_info("%s enter\n", __func__); - - *cc1 = TYPEC_CC_VOLT_OPEN; - *cc2 = TYPEC_CC_VOLT_OPEN; - - if (chip->type_c_param.attach_state == CABLE_STATE_NOT_ATTACHED) { - pr_debug("cc not attached\n"); - return 0; - } - - active_cc = (chip->type_c_param.cable_dir) ? cc1 : cc2; - secondary_cc = (chip->type_c_param.cable_dir) ? cc2 : cc1; - - if (chip->type_c_param.attach_state == CABLE_STATE_AS_UFP) { - switch (chip->type_c_param.current_det) { - case 0: /* RP Default */ - *active_cc |= TYPEC_CC_VOLT_SNK_DFT; - break; - case 1: /* RP 1.5V */ - *active_cc |= TYPEC_CC_VOLT_SNK_1_5; - break; - case 3: /* RP 3.0V */ - *active_cc |= TYPEC_CC_VOLT_SNK_3_0; - break; - default: - *active_cc |= TYPEC_CC_VOLT_SNK_DFT; - break; - } - } else if (chip->type_c_param.attach_state == CABLE_STATE_TO_ACCESSORY) { - switch (chip->type_c_param.accessory_attach) { - case 4: /* audio accessory */ - *active_cc |= TYPEC_CC_VOLT_RA; - *secondary_cc |= TYPEC_CC_VOLT_RA; - break; - case 5: /* charged thru audio accessory */ - *active_cc |= TYPEC_CC_VOLT_RA; - *secondary_cc |= TYPEC_CC_VOLT_RA; - break; - case 6: /* DFP, debug accessory */ - *active_cc |= TYPEC_CC_VOLT_RD; - *secondary_cc |= TYPEC_CC_VOLT_RD; - break; - default: - break; - } - } else if (chip->type_c_param.attach_state == CABLE_STATE_AS_DFP) { - if (chip->type_c_param.active_cable_attach) { - *active_cc |= TYPEC_CC_VOLT_RA; - } else { - *active_cc |= TYPEC_CC_VOLT_RD; - } - } - - act_as_sink = (chip->type_c_param.attach_state == CABLE_STATE_AS_UFP) ? true : false; - - if (*cc1 != TYPEC_CC_VOLT_OPEN) - *cc1 |= (act_as_sink << 2); - - if (*cc2 != TYPEC_CC_VOLT_OPEN) - *cc2 |= (act_as_sink << 2); - + pr_info("%s enter \n", __func__); return 0; } static int sgm7220_set_cc(struct tcpc_device *tcpc, int pull) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int ret; - uint8_t value = 0; - - pr_info("%s enter ,pull = %d\n", __func__, pull); - - value = 0x01; - ret = sgm7220_update_reg(chip->client, REG_SET, value, SET_I2C_DISABLE_TERM);//Disable RD and RP - if (ret < 0) { - pr_err("%s: init REG_SET fail!\n", __func__); - return ret; - } -/* if (pull == TYPEC_CC_RP) - value = SET_MODE_SELECT_SRC; - else if (pull == TYPEC_CC_RD) - value = SET_MODE_SELECT_SNK; - else if (pull == TYPEC_CC_DRP) - value = SET_MODE_SELECT_DRP; - - value = value << SET_MODE_SELECT_SHIFT; - ret = sgm7220_update_reg(chip->client, REG_SET, value, SET_MODE_SELECT); - if (ret < 0) { - pr_err("%s: update reg fail!\n", __func__); - }*/ - value = 0x00; - ret = sgm7220_update_reg(chip->client, REG_SET, value, SET_I2C_DISABLE_TERM);//Enable RD and RP - if (ret < 0) { - pr_err("%s: init REG_SET fail!\n", __func__); - return ret; - } - - pr_info("%s end ,value = %x\n", __func__, value); + pr_info("%s enter \n", __func__); return 0; } static int sgm7220_set_polarity(struct tcpc_device *tcpc, int polarity) { - /* sgm7220 handles polarity automatcally */ + pr_info("%s enter \n", __func__); return 0; } static int sgm7220_set_low_rp_duty(struct tcpc_device *tcpc, bool low_rp) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int ret; - u8 val = low_rp ? 0x00 : 0x10; //sgm7220 lowest rp duty 30% - - ret = sgm7220_update_reg(chip->client, REG_INT, - val << INT_DRP_DUTY_CYCLE_SHIFT, INT_DRP_DUTY_CYCLE); - if (ret < 0) { - pr_err("%s: update reg fail!\n", __func__); - } - + pr_info("%s enter \n", __func__); return 0; } static int sgm7220_set_vconn(struct tcpc_device *tcpc, int enable) { - /* sgm7220 handles vconn automatically */ + pr_info("%s enter \n", __func__); return 0; } -static int sgm7220_tcpc_deinit(struct tcpc_device *tcpc) +static int sgm7220_tcpc_deinit(struct tcpc_device *tcpc_dev) { - struct sgm7220_chip *chip = tcpc_get_dev_data(tcpc); - int ret; - -#ifdef CONFIG_TCPC_SHUTDOWN_CC_DETACH - sgm7220_set_cc(tcpc, TYPEC_CC_DRP); - - ret = sgm7220_update_reg(chip->client, REG_CTL, 1 << CTR_DISABLE_RD_RP, CTR_DISABLE_RD_RP); - if (ret < 0) { - pr_err("%s: update reg fail!\n", __func__); - } -#endif - + pr_info("%s enter \n", __func__); return 0; } @@ -886,8 +590,7 @@ int sgm7220_set_watchdog(struct tcpc_device *tcpc, bool en) #ifdef CONFIG_TCPC_INTRST_EN int sgm7220_set_intrst(struct tcpc_device *tcpc, bool en) { - return rt1711_i2c_write8(tcpc, - RT1711H_REG_INTRST_CTRL, RT1711H_REG_INTRST_SET(en, 3)); + return 0; } #endif @@ -927,7 +630,6 @@ static int sgm7220_retransmit(struct tcpc_device *tcpc) return 0; } #endif - static int sgm7220_transmit(struct tcpc_device *tcpc, enum tcpm_transmit_type type, uint16_t header, const uint32_t *data) { @@ -954,7 +656,6 @@ static struct tcpc_ops sgm7220_tcpc_ops = { .set_low_rp_duty = sgm7220_set_low_rp_duty, .set_vconn = sgm7220_set_vconn, .deinit = sgm7220_tcpc_deinit, - #ifdef CONFIG_TCPC_WATCHDOG_EN .set_watchdog = sgm7220_set_watchdog, #endif /* CONFIG_TCPC_WATCHDOG_EN */ @@ -975,11 +676,10 @@ static struct tcpc_ops sgm7220_tcpc_ops = { #ifdef CONFIG_USB_PD_RETRY_CRC_DISCARD .retransmit = sgm7220_retransmit, #endif /* CONFIG_USB_PD_RETRY_CRC_DISCARD */ - - }; -static int sgm7220_parse_dt(struct sgm7220_chip *chip, struct device *dev) + +static int sgm_parse_dt(struct sgm7220_chip *chip, struct device *dev) { struct device_node *np = dev->of_node; int ret; @@ -992,25 +692,64 @@ static int sgm7220_parse_dt(struct sgm7220_chip *chip, struct device *dev) #if (!defined(CONFIG_MTK_GPIO) || defined(CONFIG_MTK_GPIOLIB_STAND)) ret = of_get_named_gpio(np, "sgm7220,intr_gpio", 0); if (ret < 0) { - pr_err("%s no sgm7220,intr_gpio info\n", __func__); + pr_err("%s no intr_gpio info\n", __func__); return ret; } chip->irq_gpio = ret; #else - ret = of_property_read_u32(np, - "sgm7220,intr_gpio_num", &chip->irq_gpio); + ret = of_property_read_u32( + np, "sgm7220,intr_gpio_num", &chip->irq_gpio); if (ret < 0) pr_err("%s no intr_gpio info\n", __func__); #endif return ret; } +static void sgm7220_first_check_typec_work(struct work_struct *work) +{ + struct sgm7220_chip *chip = container_of(work, struct sgm7220_chip, first_check_typec_work.work); + struct tcpc_device *tcpc; + u8 reg_val; + int ret; + + tcpc = chip->tcpc; + tcpci_lock_typec(tcpc); + + first_check_flag = 1; + + pr_info("%s enter\n", __func__); + + ret = sgm7220_read_device(chip->client, REG_MOD, 1, ®_val); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + } + + pr_info("%s mode_register:0x%x\n", __func__, reg_val); + sgm7220_process_mode_register(chip, reg_val); + + ret = sgm7220_read_device(chip->client, REG_INT, 1, ®_val); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + } + + pr_info("%s interrupt_register:0x%x\n", __func__, reg_val); + sgm7220_process_interrupt_register(chip, reg_val); + + ret = sgm7220_reg_update(chip->client, + REG_INT, (0x1 << INT_INTERRUPT_STATUS_SHIFT), INT_INTERRUPT_STATUS); + if (ret < 0) { + pr_err("%s: update reg fail!\n", __func__); + } + + tcpci_unlock_typec(tcpc); +} static int sgm7220_tcpcdev_init(struct sgm7220_chip *chip, struct device *dev) { struct tcpc_desc *desc; struct device_node *np = dev->of_node; u32 val, len; + const char *name = "default"; if (!np) return -EINVAL; @@ -1018,7 +757,6 @@ static int sgm7220_tcpcdev_init(struct sgm7220_chip *chip, struct device *dev) desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); if (!desc) return -ENOMEM; - if (of_property_read_u32(np, "sgm7220-tcpc,role_def", &val) >= 0) { if (val >= TYPEC_ROLE_NR) desc->role_def = TYPEC_ROLE_DRP; @@ -1057,43 +795,153 @@ static int sgm7220_tcpcdev_init(struct sgm7220_chip *chip, struct device *dev) #ifdef CONFIG_TCPC_VCONN_SUPPLY_MODE if (of_property_read_u32(np, "sgm7220-tcpc,vconn_supply", &val) >= 0) { if (val >= TCPC_VCONN_SUPPLY_NR) - desc->vconn_supply = TCPC_VCONN_SUPPLY_ALWAYS; + desc->vconn_supply = TCPC_VCONN_SUPPLY_NEVER; else desc->vconn_supply = val; } else { - dev_info(dev, "use default Vconn Supply\n"); - desc->vconn_supply = TCPC_VCONN_SUPPLY_ALWAYS; + dev_info(dev, "use never Vconn Supply\n"); + desc->vconn_supply = TCPC_VCONN_SUPPLY_NEVER; } #endif /* CONFIG_TCPC_VCONN_SUPPLY_MODE */ of_property_read_string(np, "sgm7220-tcpc,name", (char const **)&name); + len = strlen(name); desc->name = kzalloc(len+1, GFP_KERNEL); if (!desc->name) return -ENOMEM; + strncpy((char *)desc->name, name, strlen(name)+1); chip->tcpc_desc = desc; - chip->tcpc = tcpc_device_register(dev, desc, &sgm7220_tcpc_ops, chip); + chip->tcpc = tcpc_device_register(dev, + desc, &sgm7220_tcpc_ops, chip); if (IS_ERR(chip->tcpc)) return -EINVAL; - chip->tcpc->tcpc_flags = TCPC_FLAGS_LPM_WAKEUP_WATCHDOG; + schedule_delayed_work(&chip->first_check_typec_work, msecs_to_jiffies(3000)); + pr_info("%s end\n", __func__); return 0; } +static int sgm7220_initialization(struct sgm7220_chip *chip) +{ + int ret = 0; + u8 reg_val; + /* do initialization here, before enable irq, + * clear irq, + * config DRP/UFP/DFP mode, + * and etc.. + */ + pr_info("%s enter\n", __func__); + ret = sgm7220_read_device(chip->client, REG_REVISION, 1, ®_val); + if (ret < 0) { + return ret; + } + + /* 1 Disable term(default 0) [bit 0] + * 2 Source pref(DRP performs try.SNK 01) [bit 2:1] + * 3 Soft reset(default 0) [bit 3] + * 4 Mode slect(DRP start from Try.SNK 00) [bit 5:4] + * 5 Debounce time of voltage change on CC pin(default 0) [bit 7:6] + */ + reg_val = 0x32; + ret = sgm7220_reg_write(chip->client, REG_SET, reg_val); + if (ret < 0) { + pr_err("%s: init REG_SET fail!\n", __func__); + return ret; + } + + /* CURRENT MODE ADVERTISE 3A [bit 7:6] */ + reg_val = (HOST_CUR_1P5 << MOD_CURRENT_MODE_ADVERTISE_SHIFT); + ret = sgm7220_reg_update(chip->client, REG_MOD, reg_val, MOD_CURRENT_MODE_ADVERTISE); + if (ret < 0) { + pr_err("%s: init REG_MOD fail!\n", __func__); + return ret; + } + + return ret; +} + +/************************************************************************ + * + * chip_info_show + * + ************************************************************************/ +static ssize_t chip_info_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sgm7220_chip *chip = i2c_get_clientdata(client); + u8 reg_val; + char name[ID_REG_LEN + 1] = { 0 }; + u8 revision = 0; + int i, j, ret; + + for (i = 0, j = 0; i < ID_REG_LEN; i++) { + reg_val = 0; + ret = sgm7220_read_device(chip->client, (REG_BASE + (ID_REG_LEN - 1) - i), 1, ®_val); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + snprintf(name, ID_REG_LEN, "%s", "Error"); + break; + } + if (!reg_val) { + j++; + continue; + } + name[i - j] = (char)reg_val; + } + + ret = sgm7220_read_device(chip->client, REG_REVISION, 1, &revision); + if (ret < 0) { + pr_err("%s: read reg fail!\n", __func__); + return snprintf(buf, PAGE_SIZE, "USB TypeC chip info:\n" + " Manufacture: SGM\n" + " Chip Name : %s\n" + " Revision ID : Error\n", + name); + } else { + return snprintf(buf, PAGE_SIZE, "USB TypeC chip info:\n" + " Manufacture: SGM\n" + " Chip Name : %s\n" + " Revision ID : %d\n", + name, revision); + } +} +DEVICE_ATTR(chip_info, S_IRUGO, chip_info_show, NULL); + +/************************************************************************ + * + * cc_orientation_show + * + ************************************************************************/ +static ssize_t cc_orientation_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sgm7220_chip *chip = i2c_get_clientdata(client); + int ret; + + ret = snprintf (buf, PAGE_SIZE, "cc_sts (%d)\n", chip->type_c_param.cable_dir); + + return ret; +} +DEVICE_ATTR(cc_orientation, S_IRUGO, cc_orientation_show, NULL); + static int sgm7220_check_revision(struct i2c_client *client) { int ret; - u8 data; - ret = sgm7220_read_reg(client, 0x08, &data); + ret = i2c_smbus_read_byte_data(client, REG_REVISION); if (ret < 0) { dev_err(&client->dev, "read chip ID fail\n"); return -EIO; } - return data; + return ret; } static int sgm7220_pwr_on(struct device *dev) @@ -1133,32 +981,28 @@ static int sgm7220_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct sgm7220_chip *chip; - int ret = 0, chip_id; + int ret = 0, chip_id = 0; bool use_dt = client->dev.of_node; pr_info("%s\n", __func__); - if (i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BYTE_DATA)) { + I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_BYTE_DATA)) pr_info("I2C functionality : OK...\n"); - } else { + else pr_info("I2C functionality check : failuare...\n"); - } sgm7220_pwr_on(&client->dev); chip_id = sgm7220_check_revision(client); if (chip_id < 0) return chip_id; - mutex_init(&mutex); - mutex_init(&mutex2); - chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); + chip = devm_kzalloc(&client->dev, sizeof (*chip), GFP_KERNEL); if (!chip) return -ENOMEM; - if (use_dt) { - sgm7220_parse_dt(chip, &client->dev); - } else { + if (use_dt) + sgm_parse_dt(chip, &client->dev); + else { dev_err(&client->dev, "no dts node\n"); return -ENODEV; } @@ -1167,9 +1011,8 @@ static int sgm7220_i2c_probe(struct i2c_client *client, sema_init(&chip->io_lock, 1); sema_init(&chip->suspend_lock, 1); i2c_set_clientdata(client, chip); -#ifdef CONFIG_TCPC_SGM7220 - INIT_DELAYED_WORK(&chip->poll_work, sgm7220_poll_work); -#endif + w_client = chip->client; + INIT_DELAYED_WORK(&chip->first_check_typec_work, sgm7220_first_check_typec_work); chip->irq_wake_lock = wakeup_source_register(chip->dev, "sgm7220_irq_wakelock"); chip->i2c_wake_lock = @@ -1178,25 +1021,53 @@ static int sgm7220_i2c_probe(struct i2c_client *client, chip->chip_id = chip_id; pr_info("sgm7220_chipID = 0x%0x\n", chip_id); + /* try initialize device before request irq */ + ret = sgm7220_initialization(chip); + if (ret < 0) { + pr_err("%s: fails to do initialization %d\n", __func__, ret); + goto err_init_dev; + } + ret = sgm7220_tcpcdev_init(chip, &client->dev); if (ret < 0) { dev_err(&client->dev, "sgm7220 tcpc dev init fail\n"); - return -EINVAL; + goto err_tcpc_reg; } ret = sgm7220_init_alert(chip->tcpc); if (ret < 0) { - pr_err("sgm7110 init alert fail\n"); + pr_err("sgm7220 init alert fail\n"); goto err_irq_init; } - tcpc_schedule_init_work(chip->tcpc); + ret = device_create_file(&client->dev, &dev_attr_chip_info); + if (ret < 0) { + dev_err(&client->dev, "failed to create dev_attr_chip_info\n"); + ret = -ENODEV; + goto err_create_chip_info_file; + } + + ret = device_create_file(&client->dev, &dev_attr_cc_orientation); + if (ret < 0) { + dev_err(&client->dev, "failed to create dev_attr_cc_orientation\n"); + ret = -ENODEV; + goto err_create_cc_orientation_file; + } + pr_info("%s probe OK!\n", __func__); return 0; - +err_create_cc_orientation_file: + device_remove_file(&client->dev, &dev_attr_cc_orientation); +err_create_chip_info_file: + device_remove_file(&client->dev, &dev_attr_chip_info); err_irq_init: tcpc_device_unregister(chip->dev, chip->tcpc); - mutex_destroy(&chip->mutex); +err_tcpc_reg: + wakeup_source_unregister(chip->i2c_wake_lock); + wakeup_source_unregister(chip->irq_wake_lock); +err_init_dev: + i2c_set_clientdata(client, NULL); + return ret; } @@ -1205,12 +1076,12 @@ static int sgm7220_i2c_remove(struct i2c_client *client) struct sgm7220_chip *chip = i2c_get_clientdata(client); if (chip) { - #ifdef CONFIG_TCPC_SGM7220 - cancel_delayed_work_sync(&chip->poll_work); - #endif + cancel_delayed_work_sync(&chip->first_check_typec_work); tcpc_device_unregister(chip->dev, chip->tcpc); + device_remove_file(&client->dev, &dev_attr_cc_orientation); + device_remove_file(&client->dev, &dev_attr_chip_info); } - mutex_destroy(&chip->mutex); + return 0; } @@ -1219,6 +1090,7 @@ static int sgm7220_i2c_suspend(struct device *dev) { struct sgm7220_chip *chip; struct i2c_client *client = to_i2c_client(dev); + if (client) { chip = i2c_get_clientdata(client); if (chip) @@ -1232,6 +1104,7 @@ static int sgm7220_i2c_resume(struct device *dev) { struct sgm7220_chip *chip; struct i2c_client *client = to_i2c_client(dev); + if (client) { chip = i2c_get_clientdata(client); if (chip) @@ -1244,11 +1117,10 @@ static int sgm7220_i2c_resume(struct device *dev) static void sgm7220_shutdown(struct i2c_client *client) { struct sgm7220_chip *chip = i2c_get_clientdata(client); - /* Please reset IC here */ + if (chip != NULL) { if (chip->irq) disable_irq(chip->irq); - tcpm_shutdown(chip->tcpc); } } @@ -1264,7 +1136,8 @@ static int sgm7220_pm_resume_runtime(struct device *device) dev_dbg(device, "pm_runtime: resuming...\n"); return 0; } -#endif /* #ifdef CONFIG_PM_RUNTIME */ +#endif /* CONFIG_PM_RUNTIME */ + static const struct dev_pm_ops sgm7220_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS( @@ -1276,7 +1149,7 @@ static const struct dev_pm_ops sgm7220_pm_ops = { sgm7220_pm_resume_runtime, NULL ) -#endif +#endif /* CONFIG_PM_RUNTIME */ }; #define SGM7220_PM_OPS (&sgm7220_pm_ops) #else @@ -1310,7 +1183,5 @@ static struct i2c_driver sgm7220_driver = { module_i2c_driver(sgm7220_driver); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("NULL"); MODULE_DESCRIPTION("SGM7220 TCPC Driver"); MODULE_VERSION(SGM7220_DRV_VERSION); - diff --git a/drivers/usb/typec/mmi_tcpc/tcpci.c b/drivers/usb/typec/mmi_tcpc/tcpci.c index 47f98a793d32..e3ba53409493 100644 --- a/drivers/usb/typec/mmi_tcpc/tcpci.c +++ b/drivers/usb/typec/mmi_tcpc/tcpci.c @@ -487,6 +487,7 @@ int tcpci_notify_typec_state(struct tcpc_device *tcpc) TCP_NOTIFY_IDX_USB, TCP_NOTIFY_TYPEC_STATE); return ret; } +EXPORT_SYMBOL(tcpci_notify_typec_state); int tcpci_notify_role_swap( struct tcpc_device *tcpc, uint8_t event, uint8_t role)