diff mbox series

[3/4] usb: typec: mux: add typec orientation switch support via mux controller

Message ID 20220822153517.3747679-4-xu.yang_2@nxp.com
State Superseded
Headers show
Series typec orientation switch support via mux controller | expand

Commit Message

Xu Yang Aug. 22, 2022, 3:35 p.m. UTC
Some dedicated mux block can use existing mux controller as a mux
provider, typec port as a consumer to select channel for orientation
switch, this can be an alternate way to control typec orientation switch.
Also, one mux controller could cover highspeed, superspeed and sideband
use case one time in this implementation.

Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
---
 drivers/usb/typec/mux.c       | 74 +++++++++++++++++++++++++++++++++++
 include/linux/usb/typec_mux.h |  7 +---
 2 files changed, 76 insertions(+), 5 deletions(-)

Comments

kernel test robot Aug. 22, 2022, 3:46 p.m. UTC | #1
Hi Xu,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on shawnguo/for-next linus/master v6.0-rc2 next-20220822]
[cannot apply to robh/for-next]
[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/Xu-Yang/typec-orientation-switch-support-via-mux-controller/20220822-153600
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
config: i386-randconfig-a013-20220822 (https://download.01.org/0day-ci/archive/20220822/202208222312.IFf74Ze6-lkp@intel.com/config)
compiler: gcc-11 (Debian 11.3.0-5) 11.3.0
reproduce (this is a W=1 build):
        # https://github.com/intel-lab-lkp/linux/commit/703ba3cfec5b6f9422ac9a859bc6121f7c4a12fd
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Xu-Yang/typec-orientation-switch-support-via-mux-controller/20220822-153600
        git checkout 703ba3cfec5b6f9422ac9a859bc6121f7c4a12fd
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   ld: drivers/usb/typec/mux.o: in function `typec_switch_put':
>> mux.c:(.text+0x21d): undefined reference to `mux_control_put'
   ld: drivers/usb/typec/mux.o: in function `typec_switch_set':
>> mux.c:(.text+0x29a): undefined reference to `mux_control_deselect'
>> ld: mux.c:(.text+0x2ab): undefined reference to `mux_control_select_delay'
   ld: drivers/usb/typec/mux.o: in function `typec_switch_get':
>> mux.c:(.text+0x767): undefined reference to `mux_control_get'
Xu Yang Aug. 23, 2022, 5:13 a.m. UTC | #2
> -----Original Message-----
> From: kernel test robot <lkp@intel.com>
> Sent: Monday, August 22, 2022 11:47 PM
> To: Xu Yang <xu.yang_2@nxp.com>; heikki.krogerus@linux.intel.com;
> robh+dt@kernel.org; peda@axentia.se; shawnguo@kernel.org
> Cc: kbuild-all@lists.01.org; gregkh@linuxfoundation.org; linux@roeck-us.net;
> Jun Li <jun.li@nxp.com>; Xu Yang <xu.yang_2@nxp.com>; linux-
> usb@vger.kernel.org; dl-linux-imx <linux-imx@nxp.com>;
> devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org
> Subject: [EXT] Re: [PATCH 3/4] usb: typec: mux: add typec orientation switch
> support via mux controller
> 
> Caution: EXT Email
> 
> Hi Xu,
> 
> Thank you for the patch! Yet something to improve:

Thank you, test robot! I will fix it and submit a v2 for it.

Xu Yang

> 
> [auto build test ERROR on usb/usb-testing] [also build test ERROR on
> shawnguo/for-next linus/master v6.0-rc2 next-20220822] [cannot apply to
> robh/for-next] [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://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit-
> scm.com%2Fdocs%2Fgit-format-
> patch%23_base_tree_information&amp;data=05%7C01%7Cxu.yang_2%40nx
> p.com%7Cbfc9a4dc76fb43d05f7108da8455c2ab%7C686ea1d3bc2b4c6fa92cd9
> 9c5c301635%7C0%7C0%7C637967801123509493%7CUnknown%7CTWFpbGZs
> b3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn
> 0%3D%7C3000%7C%7C%7C&amp;sdata=1F2u5Ljc%2FxLAOzsnN9945e%2FeRl
> AVm5kMo1gLNbhUCjo%3D&amp;reserved=0]
> 
> url:
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithu
> b.com%2Fintel-lab-lkp%2Flinux%2Fcommits%2FXu-Yang%2Ftypec-
> orientation-switch-support-via-mux-controller%2F20220822-
> 153600&amp;data=05%7C01%7Cxu.yang_2%40nxp.com%7Cbfc9a4dc76fb43d
> 05f7108da8455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C6
> 37967801123509493%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMD
> AiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C
> &amp;sdata=f52r9hf0%2F5tfiSwZEjriijZ4da2XO7A8r8V9FjCRG%2BA%3D&amp
> ;reserved=0
> base:
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgit.ke
> rnel.org%2Fpub%2Fscm%2Flinux%2Fkernel%2Fgit%2Fgregkh%2Fusb.git&am
> p;data=05%7C01%7Cxu.yang_2%40nxp.com%7Cbfc9a4dc76fb43d05f7108da8
> 455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C63796780112
> 3509493%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV
> 2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata
> =MDXVH0E9FZ4zZBJkVeG5KuWoUqxl7lVDIbtdLcayD6Q%3D&amp;reserved=
> 0 usb-testing
> config: i386-randconfig-a013-20220822
> (https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fdow
> nload.01.org%2F0day-ci%2Farchive%2F20220822%2F202208222312.IFf74Ze6-
> lkp%40intel.com%2Fconfig&amp;data=05%7C01%7Cxu.yang_2%40nxp.com%
> 7Cbfc9a4dc76fb43d05f7108da8455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c3016
> 35%7C0%7C0%7C637967801123665718%7CUnknown%7CTWFpbGZsb3d8eyJ
> WIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%
> 7C3000%7C%7C%7C&amp;sdata=oZ%2FSbZ5Rp%2Bhj9l1x0fJPW1dIZ7p5ezqZ
> Y4ouw8EpmC4%3D&amp;reserved=0)
> compiler: gcc-11 (Debian 11.3.0-5) 11.3.0 reproduce (this is a W=1 build):
>         #
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithu
> b.com%2Fintel-lab-
> lkp%2Flinux%2Fcommit%2F703ba3cfec5b6f9422ac9a859bc6121f7c4a12fd&am
> p;data=05%7C01%7Cxu.yang_2%40nxp.com%7Cbfc9a4dc76fb43d05f7108da8
> 455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C63796780112
> 3665718%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV
> 2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&amp;sdata
> =6RJFht%2FkdfQ4domUP29WJC5m515k2RkAswDRQqwL85s%3D&amp;reserv
> ed=0
>         git remote add linux-review
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithu
> b.com%2Fintel-lab-
> lkp%2Flinux&amp;data=05%7C01%7Cxu.yang_2%40nxp.com%7Cbfc9a4dc76f
> b43d05f7108da8455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0
> %7C637967801123665718%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjA
> wMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C
> %7C&amp;sdata=wJeCdRdZ8UB0rHYQb1xEIlnOdqhJs53I%2BMM4%2FXvo8B
> w%3D&amp;reserved=0
>         git fetch --no-tags linux-review Xu-Yang/typec-orientation-switch-
> support-via-mux-controller/20220822-153600
>         git checkout 703ba3cfec5b6f9422ac9a859bc6121f7c4a12fd
>         # save the config file
>         mkdir build_dir && cp config build_dir/.config
>         make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash
> 
> If you fix the issue, kindly add following tag where applicable
> Reported-by: kernel test robot <lkp@intel.com>
> 
> All errors (new ones prefixed by >>):
> 
>    ld: drivers/usb/typec/mux.o: in function `typec_switch_put':
> >> mux.c:(.text+0x21d): undefined reference to `mux_control_put'
>    ld: drivers/usb/typec/mux.o: in function `typec_switch_set':
> >> mux.c:(.text+0x29a): undefined reference to `mux_control_deselect'
> >> ld: mux.c:(.text+0x2ab): undefined reference to
> `mux_control_select_delay'
>    ld: drivers/usb/typec/mux.o: in function `typec_switch_get':
> >> mux.c:(.text+0x767): undefined reference to `mux_control_get'
> 
> --
> 0-DAY CI Kernel Test Service
> https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2F01.or
> g%2Flkp&amp;data=05%7C01%7Cxu.yang_2%40nxp.com%7Cbfc9a4dc76fb43
> d05f7108da8455c2ab%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0%7C0%7C
> 637967801123665718%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwM
> DAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7
> C&amp;sdata=915lo2yL7e5Zk0SBUqNX1TRvqNvAx3A2wCMVgho%2Fblk%3D
> &amp;reserved=0
Peter Rosin Aug. 23, 2022, 6:13 a.m. UTC | #3
Hi!

2022-08-22 at 17:35, Xu Yang wrote:
> Some dedicated mux block can use existing mux controller as a mux
> provider, typec port as a consumer to select channel for orientation
> switch, this can be an alternate way to control typec orientation switch.
> Also, one mux controller could cover highspeed, superspeed and sideband
> use case one time in this implementation.
> 
> Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> ---
>  drivers/usb/typec/mux.c       | 74 +++++++++++++++++++++++++++++++++++
>  include/linux/usb/typec_mux.h |  7 +---
>  2 files changed, 76 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
> index 464330776cd6..5ee960fb668d 100644
> --- a/drivers/usb/typec/mux.c
> +++ b/drivers/usb/typec/mux.c
> @@ -13,6 +13,7 @@
>  #include <linux/mutex.h>
>  #include <linux/property.h>
>  #include <linux/slab.h>
> +#include <linux/mux/consumer.h>
>  
>  #include "class.h"
>  #include "mux.h"
> @@ -22,6 +23,11 @@
>  struct typec_switch {
>  	struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS];
>  	unsigned int num_sw_devs;
> +
> +	/* Could handle HighSpeed, SuperSpeed, Sideband switch one time */
> +	struct mux_control *mux_switch;
> +	/* 3 state correspond to NONE, NORMAL, REVERSE for all switches */
> +	int mux_states[3];
>  };
>  
>  static int switch_fwnode_match(struct device *dev, const void *fwnode)
> @@ -117,6 +123,58 @@ struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode)
>  }
>  EXPORT_SYMBOL_GPL(fwnode_typec_switch_get);
>  
> +static struct typec_switch *mux_control_typec_switch_get(struct device *dev)
> +{
> +	struct typec_switch *sw;
> +	struct mux_control *mux;
> +	int ret;
> +
> +	if (!device_property_present(dev, "mux-controls"))
> +		return NULL;
> +
> +	sw = kzalloc(sizeof(*sw), GFP_KERNEL);
> +	if (!sw)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mux = mux_control_get(dev, NULL);
> +	if (!IS_ERR(mux)) {
> +		sw->mux_switch = mux;
> +		ret = device_property_read_u32_array(dev,
> +			"typec-switch-states", sw->mux_states, 3);
> +		if (ret) {
> +			kfree(sw);
> +			return ERR_PTR(ret);
> +		}
> +	} else {
> +		kfree(sw);
> +		return ERR_CAST(mux);
> +	}
> +
> +	return sw;
> +}
> +
> +/**
> + * typec_switch_get - Find USB Type-C orientation switch
> + * @dev: The device using switch
> + *
> + * Finds a switch used by @dev. Returns a reference to the switch on
> + * success, NULL if no matching connection was found, or
> + * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch
> + * has not been enumerated yet, or ERR_PTR with a negative errno.
> + */
> +struct typec_switch *typec_switch_get(struct device *dev)
> +{
> +	struct typec_switch *sw;
> +
> +	sw = fwnode_typec_switch_get(dev_fwnode(dev));
> +	if (!sw)
> +		/* Try get switch based on mux control */
> +		sw = mux_control_typec_switch_get(dev);
> +
> +	return sw;
> +}
> +EXPORT_SYMBOL_GPL(typec_switch_get);
> +
>  /**
>   * typec_switch_put - Release USB Type-C orientation switch
>   * @sw: USB Type-C orientation switch
> @@ -137,6 +195,10 @@ void typec_switch_put(struct typec_switch *sw)
>  		module_put(sw_dev->dev.parent->driver->owner);
>  		put_device(&sw_dev->dev);
>  	}
> +
> +	if (sw->mux_switch)
> +		mux_control_put(sw->mux_switch);
> +
>  	kfree(sw);
>  }
>  EXPORT_SYMBOL_GPL(typec_switch_put);
> @@ -204,6 +266,7 @@ int typec_switch_set(struct typec_switch *sw,
>  		     enum typec_orientation orientation)
>  {
>  	struct typec_switch_dev *sw_dev;
> +	struct mux_control *mux;
>  	unsigned int i;
>  	int ret;
>  
> @@ -218,6 +281,17 @@ int typec_switch_set(struct typec_switch *sw,
>  			return ret;
>  	}
>  
> +	mux = sw->mux_switch;
> +	if (mux) {
> +		ret = mux_control_deselect(mux);

This is broken. Please read the documentation for mux_control_select and
mux_control_deselect. Every call to mux_control_deselect *must* be paired
with a *successful* call to mux_control_select. Here, mux_control_deselect
is called unconditionally (as long as a mux is configured).

Yes, agreed, that is indeed awkward (and fragile). But those are the rules.
(the mux interface was not designed for long-time selects like this)

Cheers,
Peter

> +		if (ret)
> +			return ret;
> +
> +		ret = mux_control_select(mux, sw->mux_states[orientation]);
> +		if (ret)
> +			return ret;
> +	}
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(typec_switch_set);
> diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h
> index 9292f0e07846..2287e5a5f591 100644
> --- a/include/linux/usb/typec_mux.h
> +++ b/include/linux/usb/typec_mux.h
> @@ -24,16 +24,13 @@ struct typec_switch_desc {
>  	void *drvdata;
>  };
>  
> +
> +struct typec_switch *typec_switch_get(struct device *dev);
>  struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode);
>  void typec_switch_put(struct typec_switch *sw);
>  int typec_switch_set(struct typec_switch *sw,
>  		     enum typec_orientation orientation);
>  
> -static inline struct typec_switch *typec_switch_get(struct device *dev)
> -{
> -	return fwnode_typec_switch_get(dev_fwnode(dev));
> -}
> -
>  struct typec_switch_dev *
>  typec_switch_register(struct device *parent,
>  		      const struct typec_switch_desc *desc);
Xu Yang Aug. 23, 2022, 8:46 a.m. UTC | #4
Hi Peter,

> -----Original Message-----
> From: Peter Rosin <peda@axentia.se>
> Sent: Tuesday, August 23, 2022 2:13 PM
> To: Xu Yang <xu.yang_2@nxp.com>; heikki.krogerus@linux.intel.com;
> robh+dt@kernel.org; shawnguo@kernel.org
> Cc: gregkh@linuxfoundation.org; linux@roeck-us.net; Jun Li
> <jun.li@nxp.com>; linux-usb@vger.kernel.org; dl-linux-imx <linux-
> imx@nxp.com>; devicetree@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: [EXT] Re: [PATCH 3/4] usb: typec: mux: add typec orientation switch
> support via mux controller
> 
> Caution: EXT Email
> 
> Hi!
> 
> 2022-08-22 at 17:35, Xu Yang wrote:
> > Some dedicated mux block can use existing mux controller as a mux
> > provider, typec port as a consumer to select channel for orientation
> > switch, this can be an alternate way to control typec orientation switch.
> > Also, one mux controller could cover highspeed, superspeed and sideband
> > use case one time in this implementation.
> >
> > Signed-off-by: Xu Yang <xu.yang_2@nxp.com>
> > ---
> >  drivers/usb/typec/mux.c       | 74
> +++++++++++++++++++++++++++++++++++
> >  include/linux/usb/typec_mux.h |  7 +---
> >  2 files changed, 76 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
> > index 464330776cd6..5ee960fb668d 100644
> > --- a/drivers/usb/typec/mux.c
> > +++ b/drivers/usb/typec/mux.c
> > @@ -13,6 +13,7 @@
> >  #include <linux/mutex.h>
> >  #include <linux/property.h>
> >  #include <linux/slab.h>
> > +#include <linux/mux/consumer.h>
> >
> >  #include "class.h"
> >  #include "mux.h"
> > @@ -22,6 +23,11 @@
> >  struct typec_switch {
> >       struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS];
> >       unsigned int num_sw_devs;
> > +
> > +     /* Could handle HighSpeed, SuperSpeed, Sideband switch one time */
> > +     struct mux_control *mux_switch;
> > +     /* 3 state correspond to NONE, NORMAL, REVERSE for all switches */
> > +     int mux_states[3];
> >  };
> >
> >  static int switch_fwnode_match(struct device *dev, const void *fwnode)
> > @@ -117,6 +123,58 @@ struct typec_switch
> *fwnode_typec_switch_get(struct fwnode_handle *fwnode)
> >  }
> >  EXPORT_SYMBOL_GPL(fwnode_typec_switch_get);
> >
> > +static struct typec_switch *mux_control_typec_switch_get(struct device
> *dev)
> > +{
> > +     struct typec_switch *sw;
> > +     struct mux_control *mux;
> > +     int ret;
> > +
> > +     if (!device_property_present(dev, "mux-controls"))
> > +             return NULL;
> > +
> > +     sw = kzalloc(sizeof(*sw), GFP_KERNEL);
> > +     if (!sw)
> > +             return ERR_PTR(-ENOMEM);
> > +
> > +     mux = mux_control_get(dev, NULL);
> > +     if (!IS_ERR(mux)) {
> > +             sw->mux_switch = mux;
> > +             ret = device_property_read_u32_array(dev,
> > +                     "typec-switch-states", sw->mux_states, 3);
> > +             if (ret) {
> > +                     kfree(sw);
> > +                     return ERR_PTR(ret);
> > +             }
> > +     } else {
> > +             kfree(sw);
> > +             return ERR_CAST(mux);
> > +     }
> > +
> > +     return sw;
> > +}
> > +
> > +/**
> > + * typec_switch_get - Find USB Type-C orientation switch
> > + * @dev: The device using switch
> > + *
> > + * Finds a switch used by @dev. Returns a reference to the switch on
> > + * success, NULL if no matching connection was found, or
> > + * ERR_PTR(-EPROBE_DEFER) when a connection was found but the
> switch
> > + * has not been enumerated yet, or ERR_PTR with a negative errno.
> > + */
> > +struct typec_switch *typec_switch_get(struct device *dev)
> > +{
> > +     struct typec_switch *sw;
> > +
> > +     sw = fwnode_typec_switch_get(dev_fwnode(dev));
> > +     if (!sw)
> > +             /* Try get switch based on mux control */
> > +             sw = mux_control_typec_switch_get(dev);
> > +
> > +     return sw;
> > +}
> > +EXPORT_SYMBOL_GPL(typec_switch_get);
> > +
> >  /**
> >   * typec_switch_put - Release USB Type-C orientation switch
> >   * @sw: USB Type-C orientation switch
> > @@ -137,6 +195,10 @@ void typec_switch_put(struct typec_switch *sw)
> >               module_put(sw_dev->dev.parent->driver->owner);
> >               put_device(&sw_dev->dev);
> >       }
> > +
> > +     if (sw->mux_switch)
> > +             mux_control_put(sw->mux_switch);
> > +
> >       kfree(sw);
> >  }
> >  EXPORT_SYMBOL_GPL(typec_switch_put);
> > @@ -204,6 +266,7 @@ int typec_switch_set(struct typec_switch *sw,
> >                    enum typec_orientation orientation)
> >  {
> >       struct typec_switch_dev *sw_dev;
> > +     struct mux_control *mux;
> >       unsigned int i;
> >       int ret;
> >
> > @@ -218,6 +281,17 @@ int typec_switch_set(struct typec_switch *sw,
> >                       return ret;
> >       }
> >
> > +     mux = sw->mux_switch;
> > +     if (mux) {
> > +             ret = mux_control_deselect(mux);
> 
> This is broken. Please read the documentation for mux_control_select and
> mux_control_deselect. Every call to mux_control_deselect *must* be paired
> with a *successful* call to mux_control_select. Here, mux_control_deselect
> is called unconditionally (as long as a mux is configured).

Okay, I will improve it in v2.

> 
> Yes, agreed, that is indeed awkward (and fragile). But those are the rules.
> (the mux interface was not designed for long-time selects like this)
> 

Understood. I'll follow the rules. 

Thanks,
Xu Yang

> Cheers,
> Peter
> 
> > +             if (ret)
> > +                     return ret;
> > +
> > +             ret = mux_control_select(mux, sw->mux_states[orientation]);
> > +             if (ret)
> > +                     return ret;
> > +     }
> > +
> >       return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(typec_switch_set);
> > diff --git a/include/linux/usb/typec_mux.h
> b/include/linux/usb/typec_mux.h
> > index 9292f0e07846..2287e5a5f591 100644
> > --- a/include/linux/usb/typec_mux.h
> > +++ b/include/linux/usb/typec_mux.h
> > @@ -24,16 +24,13 @@ struct typec_switch_desc {
> >       void *drvdata;
> >  };
> >
> > +
> > +struct typec_switch *typec_switch_get(struct device *dev);
> >  struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle
> *fwnode);
> >  void typec_switch_put(struct typec_switch *sw);
> >  int typec_switch_set(struct typec_switch *sw,
> >                    enum typec_orientation orientation);
> >
> > -static inline struct typec_switch *typec_switch_get(struct device *dev)
> > -{
> > -     return fwnode_typec_switch_get(dev_fwnode(dev));
> > -}
> > -
> >  struct typec_switch_dev *
> >  typec_switch_register(struct device *parent,
> >                     const struct typec_switch_desc *desc);
diff mbox series

Patch

diff --git a/drivers/usb/typec/mux.c b/drivers/usb/typec/mux.c
index 464330776cd6..5ee960fb668d 100644
--- a/drivers/usb/typec/mux.c
+++ b/drivers/usb/typec/mux.c
@@ -13,6 +13,7 @@ 
 #include <linux/mutex.h>
 #include <linux/property.h>
 #include <linux/slab.h>
+#include <linux/mux/consumer.h>
 
 #include "class.h"
 #include "mux.h"
@@ -22,6 +23,11 @@ 
 struct typec_switch {
 	struct typec_switch_dev *sw_devs[TYPEC_MUX_MAX_DEVS];
 	unsigned int num_sw_devs;
+
+	/* Could handle HighSpeed, SuperSpeed, Sideband switch one time */
+	struct mux_control *mux_switch;
+	/* 3 state correspond to NONE, NORMAL, REVERSE for all switches */
+	int mux_states[3];
 };
 
 static int switch_fwnode_match(struct device *dev, const void *fwnode)
@@ -117,6 +123,58 @@  struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode)
 }
 EXPORT_SYMBOL_GPL(fwnode_typec_switch_get);
 
+static struct typec_switch *mux_control_typec_switch_get(struct device *dev)
+{
+	struct typec_switch *sw;
+	struct mux_control *mux;
+	int ret;
+
+	if (!device_property_present(dev, "mux-controls"))
+		return NULL;
+
+	sw = kzalloc(sizeof(*sw), GFP_KERNEL);
+	if (!sw)
+		return ERR_PTR(-ENOMEM);
+
+	mux = mux_control_get(dev, NULL);
+	if (!IS_ERR(mux)) {
+		sw->mux_switch = mux;
+		ret = device_property_read_u32_array(dev,
+			"typec-switch-states", sw->mux_states, 3);
+		if (ret) {
+			kfree(sw);
+			return ERR_PTR(ret);
+		}
+	} else {
+		kfree(sw);
+		return ERR_CAST(mux);
+	}
+
+	return sw;
+}
+
+/**
+ * typec_switch_get - Find USB Type-C orientation switch
+ * @dev: The device using switch
+ *
+ * Finds a switch used by @dev. Returns a reference to the switch on
+ * success, NULL if no matching connection was found, or
+ * ERR_PTR(-EPROBE_DEFER) when a connection was found but the switch
+ * has not been enumerated yet, or ERR_PTR with a negative errno.
+ */
+struct typec_switch *typec_switch_get(struct device *dev)
+{
+	struct typec_switch *sw;
+
+	sw = fwnode_typec_switch_get(dev_fwnode(dev));
+	if (!sw)
+		/* Try get switch based on mux control */
+		sw = mux_control_typec_switch_get(dev);
+
+	return sw;
+}
+EXPORT_SYMBOL_GPL(typec_switch_get);
+
 /**
  * typec_switch_put - Release USB Type-C orientation switch
  * @sw: USB Type-C orientation switch
@@ -137,6 +195,10 @@  void typec_switch_put(struct typec_switch *sw)
 		module_put(sw_dev->dev.parent->driver->owner);
 		put_device(&sw_dev->dev);
 	}
+
+	if (sw->mux_switch)
+		mux_control_put(sw->mux_switch);
+
 	kfree(sw);
 }
 EXPORT_SYMBOL_GPL(typec_switch_put);
@@ -204,6 +266,7 @@  int typec_switch_set(struct typec_switch *sw,
 		     enum typec_orientation orientation)
 {
 	struct typec_switch_dev *sw_dev;
+	struct mux_control *mux;
 	unsigned int i;
 	int ret;
 
@@ -218,6 +281,17 @@  int typec_switch_set(struct typec_switch *sw,
 			return ret;
 	}
 
+	mux = sw->mux_switch;
+	if (mux) {
+		ret = mux_control_deselect(mux);
+		if (ret)
+			return ret;
+
+		ret = mux_control_select(mux, sw->mux_states[orientation]);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(typec_switch_set);
diff --git a/include/linux/usb/typec_mux.h b/include/linux/usb/typec_mux.h
index 9292f0e07846..2287e5a5f591 100644
--- a/include/linux/usb/typec_mux.h
+++ b/include/linux/usb/typec_mux.h
@@ -24,16 +24,13 @@  struct typec_switch_desc {
 	void *drvdata;
 };
 
+
+struct typec_switch *typec_switch_get(struct device *dev);
 struct typec_switch *fwnode_typec_switch_get(struct fwnode_handle *fwnode);
 void typec_switch_put(struct typec_switch *sw);
 int typec_switch_set(struct typec_switch *sw,
 		     enum typec_orientation orientation);
 
-static inline struct typec_switch *typec_switch_get(struct device *dev)
-{
-	return fwnode_typec_switch_get(dev_fwnode(dev));
-}
-
 struct typec_switch_dev *
 typec_switch_register(struct device *parent,
 		      const struct typec_switch_desc *desc);