Skip to content

Commit 8962771

Browse files
superna9999vinodkoul
authored andcommitted
phy: qcom: qmp-combo: register a typec mux to change the QMPPHY_MODE
Register a typec mux in order to change the PHY mode on the Type-C mux events depending on the mode and the svid when in Altmode setup. The DisplayPort phy should be left enabled if is still powered on by the DRM DisplayPort controller, so bail out until the DisplayPort PHY is not powered off. The Type-C Mode/SVID only changes on plug/unplug, and USB SAFE states will be set in between of USB-Only, Combo and DisplayPort Only so this will leave enough time to the DRM DisplayPort controller to turn of the DisplayPort PHY. Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org> [konrad: renaming, rewording, bug fixes] Signed-off-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com> Tested-by: Neil Armstrong <neil.armstrong@linaro.org> # on Lenovo Thinkpad T14S Link: https://lore.kernel.org/r/20250807-topic-4ln_dp_respin-v4-5-43272d6eca92@oss.qualcomm.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
1 parent dd33111 commit 8962771

File tree

1 file changed

+113
-5
lines changed

1 file changed

+113
-5
lines changed

drivers/phy/qualcomm/phy-qcom-qmp-combo.c

Lines changed: 113 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <linux/reset.h>
2020
#include <linux/slab.h>
2121
#include <linux/usb/typec.h>
22+
#include <linux/usb/typec_dp.h>
2223
#include <linux/usb/typec_mux.h>
2324

2425
#include <drm/bridge/aux-bridge.h>
@@ -1868,6 +1869,8 @@ struct qmp_combo {
18681869

18691870
struct typec_switch_dev *sw;
18701871
enum typec_orientation orientation;
1872+
1873+
struct typec_mux_dev *mux;
18711874
};
18721875

18731876
static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
@@ -3802,17 +3805,109 @@ static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
38023805
return 0;
38033806
}
38043807

3805-
static void qmp_combo_typec_unregister(void *data)
3808+
static int qmp_combo_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state)
3809+
{
3810+
struct qmp_combo *qmp = typec_mux_get_drvdata(mux);
3811+
const struct qmp_phy_cfg *cfg = qmp->cfg;
3812+
enum qmpphy_mode new_mode;
3813+
unsigned int svid;
3814+
3815+
guard(mutex)(&qmp->phy_mutex);
3816+
3817+
if (state->alt)
3818+
svid = state->alt->svid;
3819+
else
3820+
svid = 0;
3821+
3822+
if (svid == USB_TYPEC_DP_SID) {
3823+
switch (state->mode) {
3824+
/* DP Only */
3825+
case TYPEC_DP_STATE_C:
3826+
case TYPEC_DP_STATE_E:
3827+
new_mode = QMPPHY_MODE_DP_ONLY;
3828+
break;
3829+
3830+
/* DP + USB */
3831+
case TYPEC_DP_STATE_D:
3832+
case TYPEC_DP_STATE_F:
3833+
3834+
/* Safe fallback...*/
3835+
default:
3836+
new_mode = QMPPHY_MODE_USB3DP;
3837+
break;
3838+
}
3839+
} else {
3840+
/* No DP SVID => don't care, assume it's just USB3 */
3841+
new_mode = QMPPHY_MODE_USB3_ONLY;
3842+
}
3843+
3844+
if (new_mode == qmp->qmpphy_mode) {
3845+
dev_dbg(qmp->dev, "typec_mux_set: same qmpphy mode, bail out\n");
3846+
return 0;
3847+
}
3848+
3849+
if (qmp->qmpphy_mode != QMPPHY_MODE_USB3_ONLY && qmp->dp_powered_on) {
3850+
dev_dbg(qmp->dev, "typec_mux_set: DP PHY is still in use, delaying switch\n");
3851+
return 0;
3852+
}
3853+
3854+
dev_dbg(qmp->dev, "typec_mux_set: switching from qmpphy mode %d to %d\n",
3855+
qmp->qmpphy_mode, new_mode);
3856+
3857+
qmp->qmpphy_mode = new_mode;
3858+
3859+
if (qmp->init_count) {
3860+
if (qmp->usb_init_count)
3861+
qmp_combo_usb_power_off(qmp->usb_phy);
3862+
3863+
if (qmp->dp_init_count)
3864+
writel(DP_PHY_PD_CTL_PSR_PWRDN, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
3865+
3866+
qmp_combo_com_exit(qmp, true);
3867+
3868+
/* Now everything's powered down, power up the right PHYs */
3869+
qmp_combo_com_init(qmp, true);
3870+
3871+
if (new_mode == QMPPHY_MODE_DP_ONLY) {
3872+
if (qmp->usb_init_count)
3873+
qmp->usb_init_count--;
3874+
}
3875+
3876+
if (new_mode == QMPPHY_MODE_USB3DP || new_mode == QMPPHY_MODE_USB3_ONLY) {
3877+
qmp_combo_usb_power_on(qmp->usb_phy);
3878+
if (!qmp->usb_init_count)
3879+
qmp->usb_init_count++;
3880+
}
3881+
3882+
if (new_mode == QMPPHY_MODE_DP_ONLY || new_mode == QMPPHY_MODE_USB3DP) {
3883+
if (qmp->dp_init_count)
3884+
cfg->dp_aux_init(qmp);
3885+
}
3886+
}
3887+
3888+
return 0;
3889+
}
3890+
3891+
static void qmp_combo_typec_switch_unregister(void *data)
38063892
{
38073893
struct qmp_combo *qmp = data;
38083894

38093895
typec_switch_unregister(qmp->sw);
38103896
}
38113897

3812-
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
3898+
static void qmp_combo_typec_mux_unregister(void *data)
3899+
{
3900+
struct qmp_combo *qmp = data;
3901+
3902+
typec_mux_unregister(qmp->mux);
3903+
}
3904+
3905+
static int qmp_combo_typec_register(struct qmp_combo *qmp)
38133906
{
38143907
struct typec_switch_desc sw_desc = {};
3908+
struct typec_mux_desc mux_desc = { };
38153909
struct device *dev = qmp->dev;
3910+
int ret;
38163911

38173912
sw_desc.drvdata = qmp;
38183913
sw_desc.fwnode = dev->fwnode;
@@ -3823,10 +3918,23 @@ static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
38233918
return PTR_ERR(qmp->sw);
38243919
}
38253920

3826-
return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp);
3921+
ret = devm_add_action_or_reset(dev, qmp_combo_typec_switch_unregister, qmp);
3922+
if (ret)
3923+
return ret;
3924+
3925+
mux_desc.drvdata = qmp;
3926+
mux_desc.fwnode = dev->fwnode;
3927+
mux_desc.set = qmp_combo_typec_mux_set;
3928+
qmp->mux = typec_mux_register(dev, &mux_desc);
3929+
if (IS_ERR(qmp->mux)) {
3930+
dev_err(dev, "Unable to register typec mux: %pe\n", qmp->mux);
3931+
return PTR_ERR(qmp->mux);
3932+
}
3933+
3934+
return devm_add_action_or_reset(dev, qmp_combo_typec_mux_unregister, qmp);
38273935
}
38283936
#else
3829-
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
3937+
static int qmp_combo_typec_register(struct qmp_combo *qmp)
38303938
{
38313939
return 0;
38323940
}
@@ -4059,7 +4167,7 @@ static int qmp_combo_probe(struct platform_device *pdev)
40594167
if (ret)
40604168
goto err_node_put;
40614169

4062-
ret = qmp_combo_typec_switch_register(qmp);
4170+
ret = qmp_combo_typec_register(qmp);
40634171
if (ret)
40644172
goto err_node_put;
40654173

0 commit comments

Comments
 (0)