Skip to content

Commit 2851117

Browse files
quic-bjorandevinodkoul
authored andcommitted
phy: qcom-qmp-combo: Introduce orientation switching
The data lanes of the QMP PHY is swapped in order to handle changing orientation of the USB Type-C cable. Register a typec_switch device to allow a TCPM to configure the orientation. The newly introduced orientation variable is adjusted based on the request, and the initialized components are brought down and up again. To keep track of what parts needs to be cycled new variables to keep track of the individual init_count is introduced. Both the USB and the DisplayPort altmode signals are properly switched. For DisplayPort the controller will after the TCPM having established orientation power on the PHY, so this is not done implicitly, but for USB the PHY typically is kept initialized across the switch, and must therefore then be reinitialized. This is based on initial work by Wesley Cheng. Link: https://lore.kernel.org/r/[email protected]/ Reviewed-by: Johan Hovold <[email protected]> Reviewed-by: Neil Armstrong <[email protected]> Tested-by: Abel Vesa <[email protected]> Tested-by: Steev Klimaszewski <[email protected]> Tested-by: Neil Armstrong <[email protected]> # on HDK8450 Tested-by: Johan Hovold <[email protected]> # X13s Signed-off-by: Bjorn Andersson <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 815891e commit 2851117

File tree

2 files changed

+85
-9
lines changed

2 files changed

+85
-9
lines changed

drivers/phy/qualcomm/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ if PHY_QCOM_QMP
5959
config PHY_QCOM_QMP_COMBO
6060
tristate "Qualcomm QMP Combo PHY Driver"
6161
default PHY_QCOM_QMP
62+
depends on TYPEC || TYPEC=n
6263
select GENERIC_PHY
6364
select MFD_SYSCON
6465
help

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

Lines changed: 84 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/reset.h>
2121
#include <linux/slab.h>
2222
#include <linux/usb/typec.h>
23+
#include <linux/usb/typec_mux.h>
2324

2425
#include <dt-bindings/phy/phy-qcom-qmp.h>
2526

@@ -1320,15 +1321,18 @@ struct qmp_combo {
13201321

13211322
struct phy *usb_phy;
13221323
enum phy_mode mode;
1324+
unsigned int usb_init_count;
13231325

13241326
struct phy *dp_phy;
13251327
unsigned int dp_aux_cfg;
13261328
struct phy_configure_opts_dp dp_opts;
1329+
unsigned int dp_init_count;
13271330

13281331
struct clk_fixed_rate pipe_clk_fixed;
13291332
struct clk_hw dp_link_hw;
13301333
struct clk_hw dp_pixel_hw;
13311334

1335+
struct typec_switch_dev *sw;
13321336
enum typec_orientation orientation;
13331337
};
13341338

@@ -2467,14 +2471,14 @@ static int qmp_combo_dp_calibrate(struct phy *phy)
24672471
return ret;
24682472
}
24692473

2470-
static int qmp_combo_com_init(struct qmp_combo *qmp)
2474+
static int qmp_combo_com_init(struct qmp_combo *qmp, bool force)
24712475
{
24722476
const struct qmp_phy_cfg *cfg = qmp->cfg;
24732477
void __iomem *com = qmp->com;
24742478
int ret;
24752479
u32 val;
24762480

2477-
if (qmp->init_count++)
2481+
if (!force && qmp->init_count++)
24782482
return 0;
24792483

24802484
ret = regulator_bulk_enable(cfg->num_vregs, qmp->vregs);
@@ -2536,11 +2540,11 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
25362540
return ret;
25372541
}
25382542

2539-
static int qmp_combo_com_exit(struct qmp_combo *qmp)
2543+
static int qmp_combo_com_exit(struct qmp_combo *qmp, bool force)
25402544
{
25412545
const struct qmp_phy_cfg *cfg = qmp->cfg;
25422546

2543-
if (--qmp->init_count)
2547+
if (!force && --qmp->init_count)
25442548
return 0;
25452549

25462550
reset_control_bulk_assert(cfg->num_resets, qmp->resets);
@@ -2560,12 +2564,14 @@ static int qmp_combo_dp_init(struct phy *phy)
25602564

25612565
mutex_lock(&qmp->phy_mutex);
25622566

2563-
ret = qmp_combo_com_init(qmp);
2567+
ret = qmp_combo_com_init(qmp, false);
25642568
if (ret)
25652569
goto out_unlock;
25662570

25672571
cfg->dp_aux_init(qmp);
25682572

2573+
qmp->dp_init_count++;
2574+
25692575
out_unlock:
25702576
mutex_unlock(&qmp->phy_mutex);
25712577
return ret;
@@ -2577,7 +2583,9 @@ static int qmp_combo_dp_exit(struct phy *phy)
25772583

25782584
mutex_lock(&qmp->phy_mutex);
25792585

2580-
qmp_combo_com_exit(qmp);
2586+
qmp_combo_com_exit(qmp, false);
2587+
2588+
qmp->dp_init_count--;
25812589

25822590
mutex_unlock(&qmp->phy_mutex);
25832591

@@ -2706,16 +2714,18 @@ static int qmp_combo_usb_init(struct phy *phy)
27062714
int ret;
27072715

27082716
mutex_lock(&qmp->phy_mutex);
2709-
ret = qmp_combo_com_init(qmp);
2717+
ret = qmp_combo_com_init(qmp, false);
27102718
if (ret)
27112719
goto out_unlock;
27122720

27132721
ret = qmp_combo_usb_power_on(phy);
27142722
if (ret) {
2715-
qmp_combo_com_exit(qmp);
2723+
qmp_combo_com_exit(qmp, false);
27162724
goto out_unlock;
27172725
}
27182726

2727+
qmp->usb_init_count++;
2728+
27192729
out_unlock:
27202730
mutex_unlock(&qmp->phy_mutex);
27212731
return ret;
@@ -2731,10 +2741,12 @@ static int qmp_combo_usb_exit(struct phy *phy)
27312741
if (ret)
27322742
goto out_unlock;
27332743

2734-
ret = qmp_combo_com_exit(qmp);
2744+
ret = qmp_combo_com_exit(qmp, false);
27352745
if (ret)
27362746
goto out_unlock;
27372747

2748+
qmp->usb_init_count--;
2749+
27382750
out_unlock:
27392751
mutex_unlock(&qmp->phy_mutex);
27402752
return ret;
@@ -3203,6 +3215,65 @@ static int qmp_combo_register_clocks(struct qmp_combo *qmp, struct device_node *
32033215
return devm_add_action_or_reset(qmp->dev, phy_clk_release_provider, dp_np);
32043216
}
32053217

3218+
#if IS_ENABLED(CONFIG_TYPEC)
3219+
static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
3220+
enum typec_orientation orientation)
3221+
{
3222+
struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
3223+
const struct qmp_phy_cfg *cfg = qmp->cfg;
3224+
3225+
if (orientation == qmp->orientation || orientation == TYPEC_ORIENTATION_NONE)
3226+
return 0;
3227+
3228+
mutex_lock(&qmp->phy_mutex);
3229+
qmp->orientation = orientation;
3230+
3231+
if (qmp->init_count) {
3232+
if (qmp->usb_init_count)
3233+
qmp_combo_usb_power_off(qmp->usb_phy);
3234+
qmp_combo_com_exit(qmp, true);
3235+
3236+
qmp_combo_com_init(qmp, true);
3237+
if (qmp->usb_init_count)
3238+
qmp_combo_usb_power_on(qmp->usb_phy);
3239+
if (qmp->dp_init_count)
3240+
cfg->dp_aux_init(qmp);
3241+
}
3242+
mutex_unlock(&qmp->phy_mutex);
3243+
3244+
return 0;
3245+
}
3246+
3247+
static void qmp_combo_typec_unregister(void *data)
3248+
{
3249+
struct qmp_combo *qmp = data;
3250+
3251+
typec_switch_unregister(qmp->sw);
3252+
}
3253+
3254+
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
3255+
{
3256+
struct typec_switch_desc sw_desc = {};
3257+
struct device *dev = qmp->dev;
3258+
3259+
sw_desc.drvdata = qmp;
3260+
sw_desc.fwnode = dev->fwnode;
3261+
sw_desc.set = qmp_combo_typec_switch_set;
3262+
qmp->sw = typec_switch_register(dev, &sw_desc);
3263+
if (IS_ERR(qmp->sw)) {
3264+
dev_err(dev, "Unable to register typec switch: %pe\n", qmp->sw);
3265+
return PTR_ERR(qmp->sw);
3266+
}
3267+
3268+
return devm_add_action_or_reset(dev, qmp_combo_typec_unregister, qmp);
3269+
}
3270+
#else
3271+
static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
3272+
{
3273+
return 0;
3274+
}
3275+
#endif
3276+
32063277
static int qmp_combo_parse_dt_lecacy_dp(struct qmp_combo *qmp, struct device_node *np)
32073278
{
32083279
struct device *dev = qmp->dev;
@@ -3403,6 +3474,10 @@ static int qmp_combo_probe(struct platform_device *pdev)
34033474
if (ret)
34043475
return ret;
34053476

3477+
ret = qmp_combo_typec_switch_register(qmp);
3478+
if (ret)
3479+
return ret;
3480+
34063481
/* Check for legacy binding with child nodes. */
34073482
usb_np = of_get_child_by_name(dev->of_node, "usb3-phy");
34083483
if (usb_np) {

0 commit comments

Comments
 (0)