diff mbox series

[v4,13/18] phy: qcom-qmp: Register as a typec switch for orientation detection

Message ID 20230318121828.739424-14-bryan.odonoghue@linaro.org (mailing list archive)
State Superseded
Headers show
Series Add Qualcomm PMIC TPCM support | expand

Commit Message

Bryan O'Donoghue March 18, 2023, 12:18 p.m. UTC
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>

The lane select switch for USB typec orientation is within the USB QMP PHY.
the current device.  It could be connected through an endpoint, to an
independent device handling the typec detection, ie the QCOM SPMI typec
driver.

bod: Fixed the logic qcom_qmp_phy_typec_switch_set() to disable phy
 on disconnect if and only if we have initialized the PHY.
 Retained CC orientation logic in qcom_qmp_phy_com_init() to simplify
 patch.

bod: Ported from earlier version of driver to phy-qcom-qmp-combo.c

Co-developed-by: Wesley Cheng <wcheng@codeaurora.org>
Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
Co-developed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/phy/qualcomm/Kconfig              |  8 +++
 drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 80 +++++++++++++++++++++--
 2 files changed, 84 insertions(+), 4 deletions(-)

Comments

kernel test robot March 18, 2023, 4:42 p.m. UTC | #1
Hi Bryan,

I love your patch! Perhaps something to improve:

[auto build test WARNING on usb/usb-testing]
[also build test WARNING on usb/usb-next usb/usb-linus robh/for-next broonie-regulator/for-next lee-mfd/for-mfd-next linus/master v6.3-rc2 next-20230317]
[cannot apply to lee-mfd/for-mfd-fixes]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bryan-O-Donoghue/dt-bindings-regulator-qcom-usb-vbus-regulator-Mark-reg-as-required/20230318-202034
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link:    https://lore.kernel.org/r/20230318121828.739424-14-bryan.odonoghue%40linaro.org
patch subject: [PATCH v4 13/18] phy: qcom-qmp: Register as a typec switch for orientation detection
config: m68k-allyesconfig (https://download.01.org/0day-ci/archive/20230319/202303190010.w3QR1CU6-lkp@intel.com/config)
compiler: m68k-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/intel-lab-lkp/linux/commit/76d1e355779b094d3ddb20776b0835215dc3646c
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Bryan-O-Donoghue/dt-bindings-regulator-qcom-usb-vbus-regulator-Mark-reg-as-required/20230318-202034
        git checkout 76d1e355779b094d3ddb20776b0835215dc3646c
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k olddefconfig
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=m68k SHELL=/bin/bash drivers/phy/qualcomm/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>
| Link: https://lore.kernel.org/oe-kbuild-all/202303190010.w3QR1CU6-lkp@intel.com/

All warnings (new ones prefixed by >>):

   drivers/phy/qualcomm/phy-qcom-qmp-combo.c: In function 'qmp_combo_typec_switch_set':
>> drivers/phy/qualcomm/phy-qcom-qmp-combo.c:3383:13: warning: variable 'ret' set but not used [-Wunused-but-set-variable]
    3383 |         int ret = 0;
         |             ^~~


vim +/ret +3383 drivers/phy/qualcomm/phy-qcom-qmp-combo.c

  3376	
  3377	#if IS_ENABLED(CONFIG_PHY_QCOM_QMP_TYPEC)
  3378	static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
  3379					      enum typec_orientation orientation)
  3380	{
  3381		struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
  3382		struct phy *dp_phy = qmp->dp_phy;
> 3383		int ret = 0;
  3384	
  3385		dev_dbg(qmp->dev, "Toggling orientation current %d requested %d\n",
  3386			qmp->orientation, orientation);
  3387	
  3388		qmp->orientation = orientation;
  3389	
  3390		if (orientation == TYPEC_ORIENTATION_NONE) {
  3391			if (qmp->init_count)
  3392				ret = qmp_combo_dp_power_off(dp_phy);
  3393		} else {
  3394			if (!qmp->init_count)
  3395				ret = qmp_combo_dp_power_on(dp_phy);
  3396		}
  3397	
  3398		return 0;
  3399	}
  3400
Neil Armstrong March 20, 2023, 11:15 a.m. UTC | #2
Hi,

On 18/03/2023 13:18, Bryan O'Donoghue wrote:
> From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> 
> The lane select switch for USB typec orientation is within the USB QMP PHY.
> the current device.  It could be connected through an endpoint, to an
> independent device handling the typec detection, ie the QCOM SPMI typec
> driver.
> 
> bod: Fixed the logic qcom_qmp_phy_typec_switch_set() to disable phy
>   on disconnect if and only if we have initialized the PHY.
>   Retained CC orientation logic in qcom_qmp_phy_com_init() to simplify
>   patch.
> 
> bod: Ported from earlier version of driver to phy-qcom-qmp-combo.c
> 
> Co-developed-by: Wesley Cheng <wcheng@codeaurora.org>
> Signed-off-by: Wesley Cheng <wcheng@codeaurora.org>
> Co-developed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> ---
>   drivers/phy/qualcomm/Kconfig              |  8 +++
>   drivers/phy/qualcomm/phy-qcom-qmp-combo.c | 80 +++++++++++++++++++++--
>   2 files changed, 84 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
> index 4850d48f31fa1..8240fffdbed4e 100644
> --- a/drivers/phy/qualcomm/Kconfig
> +++ b/drivers/phy/qualcomm/Kconfig
> @@ -101,6 +101,14 @@ config PHY_QCOM_QMP_USB
>   
>   endif # PHY_QCOM_QMP
>   
> +config PHY_QCOM_QMP_TYPEC
> +	def_bool PHY_QCOM_QMP=y && TYPEC=y || PHY_QCOM_QMP=m && TYPEC
> +	help
> +	  Register a type C switch from the QMP PHY driver for type C
> +	  orientation support.  This has dependencies with if the type C kernel
> +	  configuration is enabled or not.  This support will not be present if
> +	  USB type C is disabled.

Is there a reason to only enable the TypeC logic with a config ?

If unlinked from DT it won't be used, so no need to add a new config for that.

Neil

> +
>   config PHY_QCOM_QUSB2
>   	tristate "Qualcomm QUSB2 PHY Driver"
>   	depends on OF && (ARCH_QCOM || COMPILE_TEST)
> diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> index c1483e157af4a..afe708c63557d 100644
> --- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> +++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
> @@ -19,6 +19,7 @@
>   #include <linux/regulator/consumer.h>
>   #include <linux/reset.h>
>   #include <linux/slab.h>
> +#include <linux/usb/typec_mux.h>
>   
>   #include <dt-bindings/phy/phy-qcom-qmp.h>
>   
> @@ -63,6 +64,10 @@
>   /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
>   #define CLAMP_EN				BIT(0) /* enables i/o clamp_n */
>   
> +/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
> +#define SW_PORTSELECT_VAL			BIT(0)
> +#define SW_PORTSELECT_MUX			BIT(1)
> +
>   #define PHY_INIT_COMPLETE_TIMEOUT		10000
>   
>   struct qmp_phy_init_tbl {
> @@ -1323,6 +1328,9 @@ struct qmp_combo {
>   	struct clk_fixed_rate pipe_clk_fixed;
>   	struct clk_hw dp_link_hw;
>   	struct clk_hw dp_pixel_hw;
> +
> +	struct typec_switch_dev *sw;
> +	enum typec_orientation orientation;
>   };
>   
>   static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
> @@ -1970,7 +1978,8 @@ static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp)
>   static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
>   {
>   	u32 val;
> -	bool reverse = false;
> +	bool reverse = qmp->orientation == TYPEC_ORIENTATION_REVERSE;
> +	const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
>   
>   	val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
>   	      DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN;
> @@ -1989,10 +1998,18 @@ static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
>   	 * if (orientation == ORIENTATION_CC2)
>   	 *	writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
>   	 */
> +	if (dp_opts->lanes == 4 || reverse)
> +		val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
> +	if (dp_opts->lanes == 4 || !reverse)
> +		val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
> +
>   	val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
>   	writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
>   
> -	writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
> +	if (reverse)
> +		writel(0x4c, qmp->pcs + QSERDES_DP_PHY_MODE);
> +	else
> +		writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE);
>   
>   	return reverse;
>   }
> @@ -2476,6 +2493,7 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
>   {
>   	const struct qmp_phy_cfg *cfg = qmp->cfg;
>   	void __iomem *com = qmp->com;
> +	u32 val;
>   	int ret;
>   
>   	mutex_lock(&qmp->phy_mutex);
> @@ -2513,8 +2531,11 @@ static int qmp_combo_com_init(struct qmp_combo *qmp)
>   			SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
>   			SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
>   
> -	/* Default type-c orientation, i.e CC1 */
> -	qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
> +	/* Latch CC orientation based on reported state by TCPM */
> +	val = SW_PORTSELECT_MUX;
> +	if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
> +		val |= SW_PORTSELECT_VAL;
> +	qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, val);
>   
>   	qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
>   
> @@ -3353,6 +3374,53 @@ static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_arg
>   	return ERR_PTR(-EINVAL);
>   }
>   
> +#if IS_ENABLED(CONFIG_PHY_QCOM_QMP_TYPEC)
> +static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
> +				      enum typec_orientation orientation)
> +{
> +	struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
> +	struct phy *dp_phy = qmp->dp_phy;
> +	int ret = 0;
> +
> +	dev_dbg(qmp->dev, "Toggling orientation current %d requested %d\n",
> +		qmp->orientation, orientation);
> +
> +	qmp->orientation = orientation;
> +
> +	if (orientation == TYPEC_ORIENTATION_NONE) {
> +		if (qmp->init_count)
> +			ret = qmp_combo_dp_power_off(dp_phy);
> +	} else {
> +		if (!qmp->init_count)
> +			ret = qmp_combo_dp_power_on(dp_phy);
> +	}
> +
> +	return 0;
> +}
> +
> +static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
> +{
> +	struct typec_switch_desc sw_desc;
> +	struct device *dev = qmp->dev;
> +
> +	sw_desc.drvdata = qmp;
> +	sw_desc.fwnode = dev->fwnode;
> +	sw_desc.set = qmp_combo_typec_switch_set;
> +	qmp->sw = typec_switch_register(dev, &sw_desc);
> +	if (IS_ERR(qmp->sw)) {
> +		dev_err(dev, "Error registering typec switch: %ld\n",
> +			PTR_ERR(qmp->sw));
> +	}
> +
> +	return 0;
> +}
> +#else
> +static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
> +{
> +	return 0;
> +}
> +#endif
> +
>   static int qmp_combo_probe(struct platform_device *pdev)
>   {
>   	struct qmp_combo *qmp;
> @@ -3443,6 +3511,10 @@ static int qmp_combo_probe(struct platform_device *pdev)
>   	else
>   		phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>   
> +	ret = qmp_combo_typec_switch_register(qmp);
> +	if (ret)
> +		goto err_node_put;
> +
>   	of_node_put(usb_np);
>   	of_node_put(dp_np);
>
Bryan O'Donoghue March 20, 2023, 11:19 a.m. UTC | #3
On 20/03/2023 11:15, Neil Armstrong wrote:
>> +    def_bool PHY_QCOM_QMP=y && TYPEC=y || PHY_QCOM_QMP=m && TYPEC
>> +    help
>> +      Register a type C switch from the QMP PHY driver for type C
>> +      orientation support.  This has dependencies with if the type C 
>> kernel
>> +      configuration is enabled or not.  This support will not be 
>> present if
>> +      USB type C is disabled.
> 
> Is there a reason to only enable the TypeC logic with a config ?
> 
> If unlinked from DT it won't be used, so no need to add a new config for 
> that.
> 
> Neil

ack, np
diff mbox series

Patch

diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig
index 4850d48f31fa1..8240fffdbed4e 100644
--- a/drivers/phy/qualcomm/Kconfig
+++ b/drivers/phy/qualcomm/Kconfig
@@ -101,6 +101,14 @@  config PHY_QCOM_QMP_USB
 
 endif # PHY_QCOM_QMP
 
+config PHY_QCOM_QMP_TYPEC
+	def_bool PHY_QCOM_QMP=y && TYPEC=y || PHY_QCOM_QMP=m && TYPEC
+	help
+	  Register a type C switch from the QMP PHY driver for type C
+	  orientation support.  This has dependencies with if the type C kernel
+	  configuration is enabled or not.  This support will not be present if
+	  USB type C is disabled.
+
 config PHY_QCOM_QUSB2
 	tristate "Qualcomm QUSB2 PHY Driver"
 	depends on OF && (ARCH_QCOM || COMPILE_TEST)
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
index c1483e157af4a..afe708c63557d 100644
--- a/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-combo.c
@@ -19,6 +19,7 @@ 
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/slab.h>
+#include <linux/usb/typec_mux.h>
 
 #include <dt-bindings/phy/phy-qcom-qmp.h>
 
@@ -63,6 +64,10 @@ 
 /* QPHY_V3_PCS_MISC_CLAMP_ENABLE register bits */
 #define CLAMP_EN				BIT(0) /* enables i/o clamp_n */
 
+/* QPHY_V3_DP_COM_TYPEC_CTRL register bits */
+#define SW_PORTSELECT_VAL			BIT(0)
+#define SW_PORTSELECT_MUX			BIT(1)
+
 #define PHY_INIT_COMPLETE_TIMEOUT		10000
 
 struct qmp_phy_init_tbl {
@@ -1323,6 +1328,9 @@  struct qmp_combo {
 	struct clk_fixed_rate pipe_clk_fixed;
 	struct clk_hw dp_link_hw;
 	struct clk_hw dp_pixel_hw;
+
+	struct typec_switch_dev *sw;
+	enum typec_orientation orientation;
 };
 
 static void qmp_v3_dp_aux_init(struct qmp_combo *qmp);
@@ -1970,7 +1978,8 @@  static void qmp_v3_configure_dp_tx(struct qmp_combo *qmp)
 static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
 {
 	u32 val;
-	bool reverse = false;
+	bool reverse = qmp->orientation == TYPEC_ORIENTATION_REVERSE;
+	const struct phy_configure_opts_dp *dp_opts = &qmp->dp_opts;
 
 	val = DP_PHY_PD_CTL_PWRDN | DP_PHY_PD_CTL_AUX_PWRDN |
 	      DP_PHY_PD_CTL_PLL_PWRDN | DP_PHY_PD_CTL_DP_CLAMP_EN;
@@ -1989,10 +1998,18 @@  static bool qmp_combo_configure_dp_mode(struct qmp_combo *qmp)
 	 * if (orientation == ORIENTATION_CC2)
 	 *	writel(0x4c, qmp->dp_dp_phy + QSERDES_V3_DP_PHY_MODE);
 	 */
+	if (dp_opts->lanes == 4 || reverse)
+		val |= DP_PHY_PD_CTL_LANE_0_1_PWRDN;
+	if (dp_opts->lanes == 4 || !reverse)
+		val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
+
 	val |= DP_PHY_PD_CTL_LANE_2_3_PWRDN;
 	writel(val, qmp->dp_dp_phy + QSERDES_DP_PHY_PD_CTL);
 
-	writel(0x5c, qmp->dp_dp_phy + QSERDES_DP_PHY_MODE);
+	if (reverse)
+		writel(0x4c, qmp->pcs + QSERDES_DP_PHY_MODE);
+	else
+		writel(0x5c, qmp->pcs + QSERDES_DP_PHY_MODE);
 
 	return reverse;
 }
@@ -2476,6 +2493,7 @@  static int qmp_combo_com_init(struct qmp_combo *qmp)
 {
 	const struct qmp_phy_cfg *cfg = qmp->cfg;
 	void __iomem *com = qmp->com;
+	u32 val;
 	int ret;
 
 	mutex_lock(&qmp->phy_mutex);
@@ -2513,8 +2531,11 @@  static int qmp_combo_com_init(struct qmp_combo *qmp)
 			SW_DPPHY_RESET_MUX | SW_DPPHY_RESET |
 			SW_USB3PHY_RESET_MUX | SW_USB3PHY_RESET);
 
-	/* Default type-c orientation, i.e CC1 */
-	qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, 0x02);
+	/* Latch CC orientation based on reported state by TCPM */
+	val = SW_PORTSELECT_MUX;
+	if (qmp->orientation == TYPEC_ORIENTATION_REVERSE)
+		val |= SW_PORTSELECT_VAL;
+	qphy_setbits(com, QPHY_V3_DP_COM_TYPEC_CTRL, val);
 
 	qphy_setbits(com, QPHY_V3_DP_COM_PHY_MODE_CTRL, USB3_MODE | DP_MODE);
 
@@ -3353,6 +3374,53 @@  static struct phy *qmp_combo_phy_xlate(struct device *dev, struct of_phandle_arg
 	return ERR_PTR(-EINVAL);
 }
 
+#if IS_ENABLED(CONFIG_PHY_QCOM_QMP_TYPEC)
+static int qmp_combo_typec_switch_set(struct typec_switch_dev *sw,
+				      enum typec_orientation orientation)
+{
+	struct qmp_combo *qmp = typec_switch_get_drvdata(sw);
+	struct phy *dp_phy = qmp->dp_phy;
+	int ret = 0;
+
+	dev_dbg(qmp->dev, "Toggling orientation current %d requested %d\n",
+		qmp->orientation, orientation);
+
+	qmp->orientation = orientation;
+
+	if (orientation == TYPEC_ORIENTATION_NONE) {
+		if (qmp->init_count)
+			ret = qmp_combo_dp_power_off(dp_phy);
+	} else {
+		if (!qmp->init_count)
+			ret = qmp_combo_dp_power_on(dp_phy);
+	}
+
+	return 0;
+}
+
+static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
+{
+	struct typec_switch_desc sw_desc;
+	struct device *dev = qmp->dev;
+
+	sw_desc.drvdata = qmp;
+	sw_desc.fwnode = dev->fwnode;
+	sw_desc.set = qmp_combo_typec_switch_set;
+	qmp->sw = typec_switch_register(dev, &sw_desc);
+	if (IS_ERR(qmp->sw)) {
+		dev_err(dev, "Error registering typec switch: %ld\n",
+			PTR_ERR(qmp->sw));
+	}
+
+	return 0;
+}
+#else
+static int qmp_combo_typec_switch_register(struct qmp_combo *qmp)
+{
+	return 0;
+}
+#endif
+
 static int qmp_combo_probe(struct platform_device *pdev)
 {
 	struct qmp_combo *qmp;
@@ -3443,6 +3511,10 @@  static int qmp_combo_probe(struct platform_device *pdev)
 	else
 		phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
 
+	ret = qmp_combo_typec_switch_register(qmp);
+	if (ret)
+		goto err_node_put;
+
 	of_node_put(usb_np);
 	of_node_put(dp_np);