diff --git a/drivers/power/mmi_discrete_charger/Android.mk b/drivers/power/mmi_discrete_charger/Android.mk index 1cbfe7ee4526..243fe2ad22b9 100644 --- a/drivers/power/mmi_discrete_charger/Android.mk +++ b/drivers/power/mmi_discrete_charger/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE := mmi_discrete_charger.ko LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +LOCAL_ADDITIONAL_DEPENDENCIES := $(KERNEL_MODULES_OUT)/adapter_class.ko LOCAL_ADDITIONAL_DEPENDENCIES := $(KERNEL_MODULES_OUT)/mmi_charger.ko KBUILD_OPTIONS_GKI += GKI_OBJ_MODULE_DIR=gki include $(DLKM_DIR)/AndroidKernelModule.mk diff --git a/drivers/power/mmi_discrete_charger/Kbuild b/drivers/power/mmi_discrete_charger/Kbuild index 588c8a218dff..5801739c0586 100644 --- a/drivers/power/mmi_discrete_charger/Kbuild +++ b/drivers/power/mmi_discrete_charger/Kbuild @@ -10,6 +10,7 @@ mmi_discrete_charger-objs += mmi_discrete_charger_iio.o mmi_discrete_charger-objs += mmi_discrete_voter.o mmi_discrete_charger-objs += mmi_discrete_factory_tcmd.o +KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../../usb/typec/adapter_class/$(GKI_OBJ_MODULE_DIR)/Module.symvers KBUILD_EXTRA_SYMBOLS += $(CURDIR)/$(KBUILD_EXTMOD)/../mmi_charger/$(GKI_OBJ_MODULE_DIR)/Module.symvers diff --git a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.c b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.c index 312a09536981..cbdabd17a10a 100644 --- a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.c +++ b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.c @@ -51,16 +51,6 @@ static int mmi_discrete_parse_dts(struct mmi_discrete_charger *chip) int rc = 0, byte_len; struct device_node *node = chip->dev->of_node; -/* chip->pd_handle = devm_usbpd_get_by_phandle(chip->dev, - "mmi,usbpd-phandle"); - if (IS_ERR_OR_NULL(chip->pd_handle)) { - mmi_err(chip, "Error getting the pd phandle %ld\n", - PTR_ERR(chip->pd_handle)); - chip->pd_handle = NULL; - } else { - chip->pd_current_pdo = -1; - } -*/ rc = of_property_read_u32(node, "mmi,max-fv-mv", &chip->batt_profile_fv_uv); if (rc < 0) @@ -640,10 +630,7 @@ static int mmi_discrete_update_usb_type(struct mmi_discrete_charger *chip) return rc; } - /* if PD is active, APSD is disabled so won't have a valid result */ - if (chip->pd_active) { - chip->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; - } else if (chip->qc3p5_detected) { + if (chip->qc3p5_detected) { chip->real_charger_type = POWER_SUPPLY_TYPE_USB_HVDCP_3P5; } else { chip->real_charger_type = chg_type; @@ -742,13 +729,175 @@ static void mmi_discrete_check_otg_power(struct mmi_discrete_charger *chip) } } -/* -#define PD_POWER_MIN 15000 +static void mmi_set_pd20_cap(struct mmi_discrete_charger *chg, + int pdo, int mv, int ma) +{ + int ret; + + ret = adapter_dev_set_cap(chg->pd_adapter_dev, MMI_PD_FIXED, + pdo, mv, ma); + if (ret != MMI_ADAPTER_OK) + mmi_info(chg, "set pd20 cap fail ret=%d\n", ret); +} + +static void mmi_pd30_start(struct mmi_discrete_charger *chg, + int pdo, int mv, int ma) +{ + int ret; + + ret = adapter_dev_set_cap(chg->pd_adapter_dev, MMI_PD_APDO_START, + pdo, mv, ma); + if (ret != MMI_ADAPTER_OK) + mmi_info(chg, "set pd30 cap start fail ret=%d\n", ret); +} + +static void mmi_set_pd30_cap(struct mmi_discrete_charger *chg, + int pdo, int mv, int ma) +{ + int ret; + + ret = adapter_dev_set_cap(chg->pd_adapter_dev, MMI_PD_APDO, + pdo, mv, ma); + if (ret != MMI_ADAPTER_OK) + mmi_info(chg, "set pd30 cap fail ret=%d\n", ret); +} + + +#define CHARGER_POWER_18W 18000 +#define PD_POWER_MIN 15000 +#define PPS_VOLT_MV_MIN 5000 +#define PPS_CURR_MA_MIN 2000 +#define PD_CURR_MA_MAX 3000 +#define MICRO_MV_5V 5000 +#define MICRO_MV_9V 9000 +#define MICRO_MV_1V 1000 static void mmi_discrete_config_pd_charger(struct mmi_discrete_charger *chg) { - //config pd charger vbus and ibus + int rc = -EINVAL, i =0, req_pdo = -1, req_pd_volt = 0, req_pd_curr = 0; + int fixed_pd_volt = 0; + union power_supply_propval val = {0, }; + bool vbus_present = false, pps_active = false, fixed_active = false; + static bool pps_start = false, fixed_power_done = false; + struct adapter_power_cap cap; + int vbus_mv; + + rc = get_prop_usb_present(chg, &val); + if (rc < 0) { + mmi_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + vbus_present = val.intval; + if (chg->pd_active == MMI_POWER_SUPPLY_PD_INACTIVE + || !vbus_present) { + pps_start = false; + fixed_power_done = false; + return; + } + + if (!chg->pd_adapter_dev) { + chg->pd_adapter_dev = get_adapter_by_name("pd_adapter"); + if (!chg->pd_adapter_dev) { + mmi_err(chg, "Failed: pd_adapter has not registered yet\n"); + return; + } + } + + for (i = 0; i < ADAPTER_CAP_MAX_NR; i++) { + cap.max_mv[i] = 0; + cap.min_mv[i] = 0; + cap.ma[i] = 0; + cap.type[i] = 0; + cap.pwr_limit[i] = 0; + } + + rc = adapter_dev_get_cap(chg->pd_adapter_dev, MMI_PD_ALL, &cap); + if (MMI_ADAPTER_OK != rc) { + mmi_err(chg, "Couldn't get pdo rc = %d\n", rc); + return; + } + + rc = get_prop_usb_voltage_now(chg, &val); + if (rc < 0) { + mmi_err(chg, "Couldn't get usb vbus rc = %d\n", rc); + return; + } + vbus_mv = val.intval; + + for (i = 0; i < cap.nr; i++) { + if (cap.type[i] == MMI_PD_APDO + && cap.max_mv[i] >= PPS_VOLT_MV_MIN + && cap.ma[i] >= PPS_CURR_MA_MIN + && cap.max_mv[i] * cap.ma[i] / 1000 >= this_chip->constraint.pd_pmax) { + req_pdo = i; + req_pd_curr = cap.ma[i]; + req_pd_curr = min(req_pd_curr, PD_CURR_MA_MAX); + req_pd_volt = (this_chip->constraint.pd_pmax* 1000 / req_pd_curr) % 20; + req_pd_volt = (this_chip->constraint.pd_pmax * 1000 / req_pd_curr) - req_pd_volt; + req_pd_volt = max(req_pd_volt, PPS_VOLT_MV_MIN); + req_pd_volt = min(req_pd_volt, cap.max_mv[i]); + pps_active = true; + mmi_info(chg, "pps active: i=%d,pps_volt=%d, pps_curr=%d\n", + i, req_pd_volt, req_pd_curr); + break; + } + } + + if (!pps_active) { + pps_start = false; + + if (this_chip->constraint.pd_pmax < CHARGER_POWER_18W) + fixed_pd_volt = MICRO_MV_5V; + else + fixed_pd_volt = MICRO_MV_9V; + + for (i = 0; i < cap.nr; i++) { + if ((cap.type[i] == MMI_PD_FIXED) + && cap.max_mv[i] <= fixed_pd_volt + && cap.max_mv[i] >= MICRO_MV_5V) { + req_pdo = i; + req_pd_volt = cap.max_mv[i]; + req_pd_curr = this_chip->constraint.pd_pmax * 1000 / req_pd_volt; + req_pd_curr = min(req_pd_curr, cap.ma[i]); + req_pd_curr = min(req_pd_curr, PD_CURR_MA_MAX); + fixed_active = true; + mmi_info(chg, "fixed pdo active:i=%d,fixed_volt=%d, fixed_curr=%d\n", + i, req_pd_volt, req_pd_curr); + } + } + + if (fixed_active && vbus_mv < req_pd_volt - MICRO_MV_1V) + fixed_power_done = false; + } + + if (!pps_active && !fixed_active) + return; + + if (!fixed_power_done && fixed_active) { + mmi_set_pd20_cap(chg, req_pdo, req_pd_volt, req_pd_curr); + fixed_power_done = true; + mmi_info(chg, "Request fixed power , re-vote USB_ICL %dmA\n", req_pd_curr); + } else if (pps_active) { + if (!pps_start) { + mmi_pd30_start(chg, req_pdo, req_pd_volt, req_pd_curr); + pps_start = true; + } + mmi_set_pd30_cap(chg, req_pdo, req_pd_volt, req_pd_curr); + } + rc = vote(chg->usb_icl_votable, PD_VOTER, true, req_pd_curr * 1000); + if (rc < 0) + mmi_info(chg, "vote PD USB_ICL failed %duA\n", req_pd_curr); + + mmi_info(chg, + "Request PD power, fixed %d, pps %d, pdo %d, " + "req volt %dmV, req curr %dmA, vbus %dmV\n", + fixed_active, + pps_active, + req_pdo, + req_pd_volt, + req_pd_curr, + vbus_mv); + return; } -*/ #define HVDCP_POWER_MIN 15000 #define HVDCP_VOLTAGE_BASIC (this_chip->constraint.hvdcp_pmax / 3) @@ -884,18 +1033,16 @@ static void mmi_discrete_config_charger_input(struct mmi_discrete_charger *chip) vote(chip->usb_icl_votable, MMI_HB_VOTER, false, 0); } } -/* - if (chip->pd_handle && chip->usb_psy && - chip->constraint.pd_pmax >= PD_POWER_MIN && - chip->chg_info.chrg_type == POWER_SUPPLY_TYPE_USB_PD) + + if (chip->usb_psy && + chip->constraint.pd_pmax >= PD_POWER_MIN) mmi_discrete_config_pd_charger(chip); - else - chip->pd_current_pdo = -1; -*/ + if (chip->charger_psy && chip->usb_psy && chip->constraint.hvdcp_pmax >= HVDCP_POWER_MIN && chip->chg_info.chrg_mv > HVDCP_VOLTAGE_MIN && - chip->chg_info.chrg_type == POWER_SUPPLY_TYPE_USB_HVDCP_3) + chip->chg_info.chrg_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 && + chip->pd_active == MMI_POWER_SUPPLY_PD_INACTIVE) mmi_discrete_config_qc_charger(chip); if (chip->wls_psy && @@ -1733,6 +1880,31 @@ int mmi_discrete_config_typec_mode(struct mmi_discrete_charger *chip, int val) return 0; } +#define MMI_USBIN_500MA 500000 +int mmi_discrete_config_pd_active(struct mmi_discrete_charger *chip, int val) +{ + mmi_info(chip, "config pd active is %d old mode is %d\n", val, chip->pd_active); + + if (chip->pd_active && chip->pd_active == val) + return 0; + + chip->pd_active = val; + update_sw_icl_max(chip); + + if (chip->pd_active) { + vote(chip->usb_icl_votable, PD_VOTER, true, MMI_USBIN_500MA); + vote(chip->usb_icl_votable, USB_PSY_VOTER, false, 0); + vote(chip->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + } else { + vote(chip->usb_icl_votable, PD_VOTER, false, 0); + + } + + if (chip->usb_psy) + power_supply_changed(chip->usb_psy); + + return 0; +} static int mmi_discrete_usb_plugout(struct mmi_discrete_charger * chip) { chip->real_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; @@ -1741,6 +1913,7 @@ static int mmi_discrete_usb_plugout(struct mmi_discrete_charger * chip) mmi_notify_device_mode(chip, false); vote(chip->usb_icl_votable, SW_ICL_MAX_VOTER, true, SDP_100_MA); vote(chip->usb_icl_votable, USB_PSY_VOTER, false, 0); + vote(chip->usb_icl_votable, PD_VOTER, false, 0); vote(chip->chg_disable_votable, MMI_HB_VOTER, true, 0); power_supply_changed(chip->usb_psy); mmi_info(chip, "%s\n",__func__); @@ -1756,10 +1929,6 @@ static int usb_source_change_notify_handler(struct notifier_block *nb, unsigned union power_supply_propval pval; int rc = 0; - /* PD session is ongoing, ignore BC1.2 and QC detection */ - if (chip->pd_active) - return NOTIFY_DONE; - rc = get_prop_usb_present(chip, &pval); if (rc < 0) { mmi_err(chip, "Couldn't get usb present rc = %d\n", rc); @@ -1970,12 +2139,10 @@ static int mmi_discrete_config_charge(void *data, struct mmi_charger_cfg *config { struct mmi_discrete_chg_client *chg = data; - if (memcmp(config, &chg->chg_cfg, sizeof(struct mmi_charger_cfg))) { - memcpy(&chg->chg_cfg, config, sizeof(struct mmi_charger_cfg)); - cancel_delayed_work(&chg->chip->charger_work); - schedule_delayed_work(&chg->chip->charger_work, - msecs_to_jiffies(0)); - } + memcpy(&chg->chg_cfg, config, sizeof(struct mmi_charger_cfg)); + cancel_delayed_work(&chg->chip->charger_work); + schedule_delayed_work(&chg->chip->charger_work, + msecs_to_jiffies(0)); return 0; } diff --git a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.h b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.h index 9e80f76c3153..097e914d1211 100644 --- a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.h +++ b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_core.h @@ -18,6 +18,7 @@ #include #include "mmi_charger.h" #include +#include #define MMI_HB_VOTER "MMI_HB_VOTER" #define USER_VOTER "USER_VOTER" @@ -28,6 +29,7 @@ #define SW_ICL_MAX_VOTER "SW_ICL_MAX_VOTER" #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" #define DEFAULT_VOTER "DEFAULT_VOTER" +#define PD_VOTER "PD_VOTER" #define SDP_100_MA 100000 #define SDP_CURRENT_UA 500000 @@ -99,9 +101,8 @@ struct mmi_discrete_charger { struct iio_channel *int_iio_chans; /*PD*/ -/* struct usbpd *pd_handle; - int pd_current_pdo; -*/ int pd_active; + struct adapter_device *pd_adapter_dev; + int pd_active; bool pd_not_supported; int dc_cl_ma; @@ -127,5 +128,6 @@ struct mmi_discrete_charger { int mmi_discrete_otg_enable(struct mmi_discrete_charger *chip, bool en); int mmi_discrete_is_usb_suspended(struct mmi_discrete_charger *chip); int mmi_discrete_config_typec_mode(struct mmi_discrete_charger *chip, int val); +int mmi_discrete_config_pd_active(struct mmi_discrete_charger *chip, int val); #endif \ No newline at end of file diff --git a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.c b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.c index 4dd1629eaf2b..e369f70ee562 100644 --- a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.c +++ b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.c @@ -26,6 +26,9 @@ static int mmi_discrete_iio_write_raw(struct iio_dev *indio_dev, case PSY_IIO_TYPEC_MODE: rc = mmi_discrete_config_typec_mode(chip, val1); break; + case PSY_IIO_PD_ACTIVE: + rc = mmi_discrete_config_pd_active(chip, val1); + break; default: pr_err("Unsupported mmi_discrete IIO chan %d\n", chan->channel); rc = -EINVAL; diff --git a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.h b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.h index c3e77ad60221..0cc20ccd1627 100644 --- a/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.h +++ b/drivers/power/mmi_discrete_charger/mmi_discrete_charger_iio.h @@ -43,6 +43,7 @@ static const struct mmi_discrete_iio_channels mmi_discrete_iio_psy_channels[] = MMI_DISCRETE_CHAN_INDEX("usb_real_type", PSY_IIO_USB_REAL_TYPE) MMI_DISCRETE_CHAN_INDEX("otg_enable", PSY_IIO_MMI_OTG_ENABLE) MMI_DISCRETE_CHAN_INDEX("typec_mode", PSY_IIO_TYPEC_MODE) + MMI_DISCRETE_CHAN_INDEX("pd_active", PSY_IIO_PD_ACTIVE) }; int mmi_discrete_init_iio_psy(struct mmi_discrete_charger *chip, diff --git a/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c b/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c index 9234d687f93b..7e5c95e3a414 100644 --- a/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c +++ b/drivers/usb/typec/mmi_tcpc/rt_pd_manager.c @@ -76,11 +76,12 @@ enum iio_psy_property { POWER_SUPPLY_IIO_USB_REAL_TYPE = 0, POWER_SUPPLY_IIO_OTG_ENABLE, POWER_SUPPLY_IIO_TYPEC_MODE, + POWER_SUPPLY_IIO_PD_ACTIVE, POWER_SUPPLY_IIO_PROP_MAX, }; static const char * const iio_channel_map[] = { - "usb_real_type", "otg_enable", "typec_mode", + "usb_real_type", "otg_enable", "typec_mode", "pd_active", }; static int mmi_get_psy_iio_property(struct rt_pd_manager_data *rpmd, @@ -245,8 +246,7 @@ static void usb_dwork_handler(struct work_struct *work) break; } else if (val.intval != POWER_SUPPLY_TYPE_USB && val.intval != POWER_SUPPLY_TYPE_USB_CDP && - val.intval != POWER_SUPPLY_TYPE_USB_FLOAT && - val.intval != POWER_SUPPLY_TYPE_USB_PD) + val.intval != POWER_SUPPLY_TYPE_USB_FLOAT) break; case DR_HOST_TO_DEVICE: stop_usb_host(rpmd); @@ -580,6 +580,9 @@ static int pd_tcp_notifier_call(struct notifier_block *nb, __func__, noti->pd_state.connected); switch (noti->pd_state.connected) { case PD_CONNECT_NONE: + val.intval = MMI_POWER_SUPPLY_PD_INACTIVE; + mmi_set_psy_iio_property(rpmd, + POWER_SUPPLY_IIO_PD_ACTIVE, &val); break; case PD_CONNECT_HARD_RESET: break; @@ -588,6 +591,22 @@ static int pd_tcp_notifier_call(struct notifier_block *nb, case PD_CONNECT_PE_READY_SNK_APDO: case PD_CONNECT_PE_READY_SRC: case PD_CONNECT_PE_READY_SRC_PD30: + if ((noti->pd_state.connected == PD_CONNECT_PE_READY_SNK) + ||(noti->pd_state.connected == PD_CONNECT_PE_READY_SNK_PD30)) { + val.intval = MMI_POWER_SUPPLY_PD_ACTIVE; + mmi_set_psy_iio_property(rpmd, + POWER_SUPPLY_IIO_PD_ACTIVE, &val); + } else if (noti->pd_state.connected == PD_CONNECT_PE_READY_SNK_APDO) { + val.intval = MMI_POWER_SUPPLY_PD_PPS_ACTIVE; + mmi_set_psy_iio_property(rpmd, + POWER_SUPPLY_IIO_PD_ACTIVE, &val); + } else if ((noti->pd_state.connected == PD_CONNECT_PE_READY_SRC) + ||(noti->pd_state.connected == PD_CONNECT_PE_READY_SRC_PD30)) { + val.intval = MMI_POWER_SUPPLY_PD_INACTIVE; + mmi_set_psy_iio_property(rpmd, + POWER_SUPPLY_IIO_PD_ACTIVE, &val); + } + typec_set_pwr_opmode(rpmd->typec_port, TYPEC_PWR_MODE_PD); if (!rpmd->partner) diff --git a/include/linux/usb/mmi_discrete_typec.h b/include/linux/usb/mmi_discrete_typec.h index afad68afc2a2..f69332c5661a 100644 --- a/include/linux/usb/mmi_discrete_typec.h +++ b/include/linux/usb/mmi_discrete_typec.h @@ -31,4 +31,10 @@ enum mmi_power_supply_typec_mode { MMI_POWER_SUPPLY_TYPEC_NON_COMPLIANT, }; +enum { + MMI_POWER_SUPPLY_PD_INACTIVE = 0, + MMI_POWER_SUPPLY_PD_ACTIVE, + MMI_POWER_SUPPLY_PD_PPS_ACTIVE, +}; + #endif