[PATCH 2/3] usb: typec: tcpm: Add support for configuring DP altmode through device-properties

2019-10-18 Thread Hans de Goede
Add support for configuring display-port altmode through device-properties.

We could try to add a generic mechanism for describing altmodes in
device-properties, but various altmodes will likely need altmode specific
configuration. E.g. the display-port altmode needs some way to describe
which set of DP pins on the GPU is connected to the USB Type-C connector.

As such it is better to have a separate set of altmode specific properties
per altmode and this commit adds a property for basic display-port altmode
support.

Signed-off-by: Hans de Goede 
---
 .../bindings/connector/usb-connector.txt  |  3 ++
 drivers/usb/typec/tcpm/tcpm.c | 33 +++
 2 files changed, 36 insertions(+)

diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt 
b/Documentation/devicetree/bindings/connector/usb-connector.txt
index d357987181ee..7bae3cc9c76a 100644
--- a/Documentation/devicetree/bindings/connector/usb-connector.txt
+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt
@@ -38,6 +38,9 @@ Optional properties for usb-c-connector:
   or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC.
 - data-role: should be one of "host", "device", "dual"(DRD) if typec
   connector supports USB data.
+- displayport-vdo: The presenence of this property indicates that the
+  usb-connector supports displayport-altmode (svid 0xff01), the value of
+  this property is an u32 with the vdo value for the displayport-altmode,
 
 Required properties for usb-c-connector with power delivery support:
 - source-pdos: An array of u32 with each entry providing supported power
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index c5fa18759f8e..2e3096657e96 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #define FOREACH_STATE(S)   \
@@ -281,6 +282,7 @@ struct tcpm_port {
unsigned int nr_snk_pdo;
u32 snk_vdo[VDO_MAX_OBJECTS];
unsigned int nr_snk_vdo;
+   u32 displayport_vdo;
 
unsigned int operating_snk_mw;
bool update_sink_caps;
@@ -4433,6 +4435,9 @@ static int tcpm_fw_get_caps(struct tcpm_port *port,
port->nr_snk_pdo))
return -EINVAL;
 
+   fwnode_property_read_u32(fwnode, "displayport-vdo",
+&port->displayport_vdo);
+
if (fwnode_property_read_u32(fwnode, "op-sink-microwatt", &mw) < 0)
return -EINVAL;
port->operating_snk_mw = mw / 1000;
@@ -4667,6 +4672,28 @@ static int devm_tcpm_psy_register(struct tcpm_port *port)
return PTR_ERR_OR_ZERO(port->psy);
 }
 
+static int tcpm_register_port_altmodes(struct tcpm_port *port)
+{
+   struct typec_altmode_desc desc;
+   struct typec_altmode *alt;
+   int index = 0;
+
+   if (port->displayport_vdo) {
+   desc.svid = USB_TYPEC_DP_SID;
+   desc.mode = USB_TYPEC_DP_MODE;
+   desc.vdo  = port->displayport_vdo;
+   alt = typec_port_register_altmode(port->typec_port, &desc);
+   if (IS_ERR(alt))
+   return PTR_ERR(alt);
+   typec_altmode_set_drvdata(alt, port);
+   alt->ops = &tcpm_altmode_ops;
+   port->port_altmode[index] = alt;
+   index++;
+   }
+   /* Future support for further altmodes goes here */
+   return 0;
+}
+
 struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
 {
struct tcpm_port *port;
@@ -4736,6 +4763,10 @@ struct tcpm_port *tcpm_register_port(struct device *dev, 
struct tcpc_dev *tcpc)
goto out_role_sw_put;
}
 
+   err = tcpm_register_port_altmodes(port);
+   if (err)
+   goto out_unregister_port;
+
mutex_lock(&port->lock);
tcpm_init(port);
mutex_unlock(&port->lock);
@@ -4743,6 +4774,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, 
struct tcpc_dev *tcpc)
tcpm_log(port, "%s: registered", dev_name(dev));
return port;
 
+out_unregister_port:
+   typec_unregister_port(port->typec_port);
 out_role_sw_put:
usb_role_switch_put(port->role_sw);
 out_destroy_wq:
-- 
2.23.0



[PATCH 3/3] platform/x86/intel_cht_int33fe: Add displayport-vdo property to the connector node

2019-10-18 Thread Hans de Goede
Add a displayport-vdo property to the usb-connector fwnode, devices
which use this driver support display-port altmode through the
PI3USB30532 USB switch, this enabled support for this.

Signed-off-by: Hans de Goede 
---
 drivers/platform/x86/intel_cht_int33fe.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/platform/x86/intel_cht_int33fe.c 
b/drivers/platform/x86/intel_cht_int33fe.c
index 1d5d877b9582..61f10b633678 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -129,6 +129,7 @@ static const struct property_entry usb_connector_props[] = {
PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
PROPERTY_ENTRY_U32("op-sink-microwatt", 250),
+   PROPERTY_ENTRY_U32("displayport-vdo", 0x0c0086),
{ }
 };
 
-- 
2.23.0



[PATCH 1/3] usb: typec: tcpm: Remove tcpc_config configuration mechanism

2019-10-18 Thread Hans de Goede
All configuration can and should be done through fwnodes instead of
through the tcpc_config struct and there are no existing users left of
struct tcpc_config, so lets remove it.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/tcpm.c | 90 ++-
 include/linux/usb/tcpm.h  | 41 
 2 files changed, 3 insertions(+), 128 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 5f61d9977a15..c5fa18759f8e 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -380,9 +380,6 @@ static enum tcpm_state tcpm_default_state(struct tcpm_port 
*port)
return SNK_UNATTACHED;
else if (port->try_role == TYPEC_SOURCE)
return SRC_UNATTACHED;
-   else if (port->tcpc->config &&
-port->tcpc->config->default_role == TYPEC_SINK)
-   return SNK_UNATTACHED;
/* Fall through to return SRC_UNATTACHED */
} else if (port->port_type == TYPEC_PORT_SNK) {
return SNK_UNATTACHED;
@@ -4131,7 +4128,7 @@ static int tcpm_try_role(const struct typec_capability 
*cap, int role)
mutex_lock(&port->lock);
if (tcpc->try_role)
ret = tcpc->try_role(tcpc, role);
-   if (!ret && (!tcpc->config || !tcpc->config->try_role_hw))
+   if (!ret)
port->try_role = role;
port->try_src_count = 0;
port->try_snk_count = 0;
@@ -4368,34 +4365,6 @@ void tcpm_tcpc_reset(struct tcpm_port *port)
 }
 EXPORT_SYMBOL_GPL(tcpm_tcpc_reset);
 
-static int tcpm_copy_pdos(u32 *dest_pdo, const u32 *src_pdo,
- unsigned int nr_pdo)
-{
-   unsigned int i;
-
-   if (nr_pdo > PDO_MAX_OBJECTS)
-   nr_pdo = PDO_MAX_OBJECTS;
-
-   for (i = 0; i < nr_pdo; i++)
-   dest_pdo[i] = src_pdo[i];
-
-   return nr_pdo;
-}
-
-static int tcpm_copy_vdos(u32 *dest_vdo, const u32 *src_vdo,
- unsigned int nr_vdo)
-{
-   unsigned int i;
-
-   if (nr_vdo > VDO_MAX_OBJECTS)
-   nr_vdo = VDO_MAX_OBJECTS;
-
-   for (i = 0; i < nr_vdo; i++)
-   dest_vdo[i] = src_vdo[i];
-
-   return nr_vdo;
-}
-
 static int tcpm_fw_get_caps(struct tcpm_port *port,
struct fwnode_handle *fwnode)
 {
@@ -4698,35 +4667,10 @@ static int devm_tcpm_psy_register(struct tcpm_port 
*port)
return PTR_ERR_OR_ZERO(port->psy);
 }
 
-static int tcpm_copy_caps(struct tcpm_port *port,
- const struct tcpc_config *tcfg)
-{
-   if (tcpm_validate_caps(port, tcfg->src_pdo, tcfg->nr_src_pdo) ||
-   tcpm_validate_caps(port, tcfg->snk_pdo, tcfg->nr_snk_pdo))
-   return -EINVAL;
-
-   port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcfg->src_pdo,
- tcfg->nr_src_pdo);
-   port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcfg->snk_pdo,
- tcfg->nr_snk_pdo);
-
-   port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcfg->snk_vdo,
- tcfg->nr_snk_vdo);
-
-   port->operating_snk_mw = tcfg->operating_snk_mw;
-
-   port->typec_caps.prefer_role = tcfg->default_role;
-   port->typec_caps.type = tcfg->type;
-   port->typec_caps.data = tcfg->data;
-   port->self_powered = tcfg->self_powered;
-
-   return 0;
-}
-
 struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
 {
struct tcpm_port *port;
-   int i, err;
+   int err;
 
if (!dev || !tcpc ||
!tcpc->get_vbus || !tcpc->set_cc || !tcpc->get_cc ||
@@ -4759,15 +4703,10 @@ struct tcpm_port *tcpm_register_port(struct device 
*dev, struct tcpc_dev *tcpc)
tcpm_debugfs_init(port);
 
err = tcpm_fw_get_caps(port, tcpc->fwnode);
-   if ((err < 0) && tcpc->config)
-   err = tcpm_copy_caps(port, tcpc->config);
if (err < 0)
goto out_destroy_wq;
 
-   if (!tcpc->config || !tcpc->config->try_role_hw)
-   port->try_role = port->typec_caps.prefer_role;
-   else
-   port->try_role = TYPEC_NO_PREFERRED_ROLE;
+   port->try_role = port->typec_caps.prefer_role;
 
port->typec_caps.fwnode = tcpc->fwnode;
port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */
@@ -4797,29 +4736,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, 
struct tcpc_dev *tcpc)
goto out_role_sw_put;
}
 
-   if (tcpc->config && tcpc->config->alt_modes) {
-   const struc

Re: [PATCH v4 2/2] usb: roles: intel: Enable static DRD mode for role switch

2019-08-29 Thread Hans de Goede

Hi Saranya,

On 29-08-19 12:42, Saranya Gopal wrote:

Enable static DRD mode in Intel platforms which guarantees
successful role switch all the time. This fixes issues like
software role switch failure after cold boot and issue with
role switch when USB 3.0 cable is used. But, do not enable
static DRD mode for Cherrytrail devices which rely on firmware
for role switch.

Signed-off-by: Saranya Gopal 
Signed-off-by: Balaji Manoharan 


Unfortunately this patch conflicts with a patch to
drivers/usb/roles/intel-xhci-usb-role-switch.c from Heikki
which is already in -next, see:

https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git/log/?h=devprop

And specifically this commit:

https://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git/commit/?h=devprop&id=d2a90ebb65536a6deeb9daf5aa8e0700e8cbb43a

So you need to rebase on op of that branch and then the subsys
maintainers need to figure out how to merge this, I guess
the usb-next tree can merge Rafael's devprop branch for this?

I've manually resolved the conflict locally and  given this new version
a test-run on a Cherry Trail device and things still work as they should
there, so with the conflict fixed this series is:

Tested-by: Hans de Goede 
Reviewed-by: Hans de Goede 

Regards,

Hans



---
  changes since v3: Initialized drd_config variable to fix warning
  changes since v2: Revised SoB tags
  changes since v1: Added drd_config to avoid multiple if checks
Other minor changes suggested by Hans

  drivers/usb/roles/intel-xhci-usb-role-switch.c | 27 --

  1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c 
b/drivers/usb/roles/intel-xhci-usb-role-switch.c
index 277de96..88d0416 100644
--- a/drivers/usb/roles/intel-xhci-usb-role-switch.c
+++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c
@@ -19,6 +19,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  
  /* register definition */

@@ -26,6 +27,12 @@
  #define SW_VBUS_VALID BIT(24)
  #define SW_IDPIN_EN   BIT(21)
  #define SW_IDPIN  BIT(20)
+#define SW_SWITCH_EN   BIT(16)
+
+#define DRD_CONFIG_DYNAMIC 0
+#define DRD_CONFIG_STATIC_HOST 1
+#define DRD_CONFIG_STATIC_DEVICE   2
+#define DRD_CONFIG_MASK3
  
  #define DUAL_ROLE_CFG1			0x6c

  #define HOST_MODE BIT(29)
@@ -37,6 +44,7 @@
  struct intel_xhci_usb_data {
struct usb_role_switch *role_sw;
void __iomem *base;
+   bool enable_sw_switch;
  };
  
  static int intel_xhci_usb_set_role(struct device *dev, enum usb_role role)

@@ -45,6 +53,7 @@ static int intel_xhci_usb_set_role(struct device *dev, enum 
usb_role role)
unsigned long timeout;
acpi_status status;
u32 glk, val;
+   u32 drd_config = DRD_CONFIG_DYNAMIC;
  
  	/*

 * On many CHT devices ACPI event (_AEI) handlers read / modify /
@@ -59,24 +68,35 @@ static int intel_xhci_usb_set_role(struct device *dev, enum 
usb_role role)
  
  	pm_runtime_get_sync(dev);
  
-	/* Set idpin value as requested */

+   /*
+* Set idpin value as requested.
+* Since some devices rely on firmware setting DRD_CONFIG and
+* SW_SWITCH_EN bits to be zero for role switch,
+* do not set these bits for those devices.
+*/
val = readl(data->base + DUAL_ROLE_CFG0);
switch (role) {
case USB_ROLE_NONE:
val |= SW_IDPIN;
val &= ~SW_VBUS_VALID;
+   drd_config = DRD_CONFIG_DYNAMIC;
break;
case USB_ROLE_HOST:
val &= ~SW_IDPIN;
val &= ~SW_VBUS_VALID;
+   drd_config = DRD_CONFIG_STATIC_HOST;
break;
case USB_ROLE_DEVICE:
val |= SW_IDPIN;
val |= SW_VBUS_VALID;
+   drd_config = DRD_CONFIG_STATIC_DEVICE;
break;
}
val |= SW_IDPIN_EN;
-
+   if (data->enable_sw_switch) {
+   val &= ~DRD_CONFIG_MASK;
+   val |= SW_SWITCH_EN | drd_config;
+   }
writel(val, data->base + DUAL_ROLE_CFG0);
  
  	acpi_release_global_lock(glk);

@@ -147,6 +167,9 @@ static int intel_xhci_usb_probe(struct platform_device 
*pdev)
  
  	platform_set_drvdata(pdev, data);
  
+	data->enable_sw_switch = !device_property_read_bool(dev,

+   "sw_switch_disable");
+
data->role_sw = usb_role_switch_register(dev, &sw_desc);
if (IS_ERR(data->role_sw))
return PTR_ERR(data->role_sw);



Re: [PATCH 2/2] usb: roles: intel: Enable static DRD mode for role switch

2019-08-27 Thread Hans de Goede

Hi,

On 26-08-19 16:32, Heikki Krogerus wrote:

From: Saranya Gopal 

Enable static DRD mode in Intel platforms which guarantees
successful role switch all the time. This fixes issues like
software role switch failure after cold boot and issue with
role switch when USB 3.0 cable is used. But, do not enable
static DRD mode for Cherrytrail devices which rely on firmware
for role switch.

Signed-off-by: Saranya Gopal 
Signed-off-by: Balaji Manoharan 
Signed-off-by: Heikki Krogerus 
---
  .../usb/roles/intel-xhci-usb-role-switch.c| 26 ++-
  1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/roles/intel-xhci-usb-role-switch.c 
b/drivers/usb/roles/intel-xhci-usb-role-switch.c
index 7325a84dd1c8..9101ff94c8d2 100644
--- a/drivers/usb/roles/intel-xhci-usb-role-switch.c
+++ b/drivers/usb/roles/intel-xhci-usb-role-switch.c
@@ -19,6 +19,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  
  /* register definition */

@@ -26,6 +27,9 @@
  #define SW_VBUS_VALID BIT(24)
  #define SW_IDPIN_EN   BIT(21)
  #define SW_IDPIN  BIT(20)
+#define SW_SWITCH_EN_CFG0  BIT(16)


Nitpick: Please drop the _CFG0 postfix, if anything this
should be a prefix applied to *all* defines for the bits
in this register


+#define SW_DRD_STATIC_HOST_CFG01
+#define SW_DRD_STATIC_DEV_CFG0 2


So bits 0-1 together define the drd-mode. The datasheet
calls the combination DRD_CONFIG, without a SW_ prefix,
with the following values being defined:

00: Dynamic role-switch
01: Static Host mode
10: Static device mode
11: Reserved

Notice this is an enum, so the use of bit-ops to clear the
other state below is wrong. It happens to work, but this is
not how a multi-bit setting should be modified.

I suggest using the following defines instead:

#define DRD_CONFIG_DYNAMIC  0
#define DRD_CONFIG_STATIC_HOST  1
#define DRD_CONFIG_STATIC_DEVICE2
#define DRD_CONFIG_MASK 3


  #define DUAL_ROLE_CFG10x6c
  #define HOST_MODE BIT(29)
@@ -37,6 +41,7 @@
  struct intel_xhci_usb_data {
struct usb_role_switch *role_sw;
void __iomem *base;
+   bool disable_sw_switch;


I would prefer for this to be enable_sw_switch and the negation
when reading the property.


  };
  
  static const struct software_node intel_xhci_usb_node = {

@@ -63,23 +68,39 @@ static int intel_xhci_usb_set_role(struct device *dev, enum 
usb_role role)
  
  	pm_runtime_get_sync(dev);
  
-	/* Set idpin value as requested */

+   /*
+* Set idpin value as requested.
+* Since some devices rely on firmware setting DRD_CONFIG and
+* SW_SWITCH_EN_CFG0 bits to be zero for role switch,
+* do not set these bits for those devices.
+*/
val = readl(data->base + DUAL_ROLE_CFG0);
switch (role) {
case USB_ROLE_NONE:
val |= SW_IDPIN;
val &= ~SW_VBUS_VALID;
+   val &= ~(SW_DRD_STATIC_DEV_CFG0 | SW_DRD_STATIC_HOST_CFG0);
break;


Right, so this should be:

val &= ~DRD_CONFIG_MASK;

Also ideally this should also have a if (!data->disable_sw_switch)
for consistency.


case USB_ROLE_HOST:
val &= ~SW_IDPIN;
val &= ~SW_VBUS_VALID;
+   if (!data->disable_sw_switch) {
+   val &= ~SW_DRD_STATIC_DEV_CFG0;


So this clearing is wrong, it happens to work, but is not
how modifying a "bit-set" / enum should be done, this should be:

val &= ~DRD_CONFIG_MASK;


+   val |= SW_DRD_STATIC_HOST_CFG0;
+   }
break;
case USB_ROLE_DEVICE:
val |= SW_IDPIN;
val |= SW_VBUS_VALID;
+   if (!data->disable_sw_switch) {
+   val &= ~SW_DRD_STATIC_HOST_CFG0;
+   val |= SW_DRD_STATIC_DEV_CFG0;
+   }


Idem.



break;
}
val |= SW_IDPIN_EN;
+   if (!data->disable_sw_switch)
+   val |= SW_SWITCH_EN_CFG0;


So we now have a lot of "if (!data->disable_sw_switch)" checks,

IMHO it would be better / cleaner to do this:

u32 glk, val, drd_config;

...

val = readl(data->base + DUAL_ROLE_CFG0);
switch (role) {
case USB_ROLE_NONE:
val |= SW_IDPIN;
val &= ~SW_VBUS_VALID;
drd_config = DRD_CONFIG_DYNAMIC;
break;
case USB_ROLE_HOST:
val &= ~SW_IDPIN;
val &= ~SW_VBUS_VALID;
drd_config = DRD_CONFIG_STATIC_HOST;
break;
case USB_ROLE_DEVICE:
val |= SW_IDPIN;
val |= SW_VBUS_VALID;
drd_config = DRD_CONFIG_STATIC_DEVICE;
break;
}
val |=

Re: [PATCH 0/2] usb: roles: intel: Use static mode by default

2019-08-27 Thread Hans de Goede

Hi Heikki,

On 26-08-19 16:32, Heikki Krogerus wrote:

Hi Hans,

These have been in my queue for a while now. For some reason I've been
under the impression that there was still an issue with them, but that
was a misunderstanding. Saranya and Balaji, I'm really sorry about
that.

Hans, I don't know if you remember these, but they address an issue
where the device mode does not work (I think on APL). I believe static
mode is used always except on Cherrytrail. You had reported that using the
static mode creates a conflict on some CHT boards that have ACPI tables that
also write to the mux registers. To prevent the use of the static mode on
Cherrytrail the property is used.


I've given this a test-run on a Cherry Trail device which used ACPI
_AEI handlers to do the mux switching as well as on 2 models (1 with
micro-usb id-pin, one with a Type-C fusb302 controller) where the
kernel does the switching.

I can confirm that with these patches applied things still work fine
on all 3 models.

With that said I do have some review remarks on the second patch
I will reply to that patch with my remarks.

Regards,

Hans




Saranya Gopal (2):
   usb: xhci: ext-caps: Add property to disable Intel SW switch
   usb: roles: intel: Enable static DRD mode for role switch

  drivers/usb/host/xhci-ext-caps.c  | 18 +
  .../usb/roles/intel-xhci-usb-role-switch.c| 26 ++-
  2 files changed, 43 insertions(+), 1 deletion(-)



Re: AW: [Resend] [PATCH v3] usb: xhci-pci: reorder removal to avoid use-after-free

2019-08-22 Thread Hans de Goede

Hi,

On 22-08-19 17:48, Schmid, Carsten wrote:

On 22-08-19 17:23, Mathias Nyman wrote:

On 16.8.2019 12.03, Schmid, Carsten wrote:

On driver removal, the platform_device_unregister call
attached through devm_add_action_or_reset was executed
after usb_hcd_pci_remove.
This lead to a use-after-free for the iomem resource of
the xhci-ext-caps driver in the platform removal
because the parent of the resource was freed earlier.

Fix this by reordering of the removal sequence.



Could all this be avoided if usb_hcd_pci_probe()
used managed device resources as well?
(using devm_request_mem_region(), and devm_ioremap_nocache())

This way the iomem resource would be added to the same devres list
as the platform_unregister_call, and the iomem resource should be
released after the platform_device_unregister as devres_release_all()
releases the resources in reverse order.


Yes I believe that that would work.


I don't think so, because xhci_create_intel_xhci_sw_pdev registers it's
resource through platform_device_add_resources which does not use devm_.

The only thing what is done through devm in xhci_create_intel_xhci_sw_pdev is
ret = devm_add_action_or_reset(...)


Right, so if I understand correctly the problem with the current code (before 
your patch)
is:

Probe:
1. usb_hcd_pci_probe() uses request_mem_region()
2. xhci_create_intel_xhci_sw_pde uses platform_device_add_resources() which are 
a child of the previous region

Remove:
3. usb_hcd_pci_remove does release_region() while the child region is still in 
use
4. At end of remove() devm code calls xhci_intel_unregister_pdev

And the problem is we want to swap 3 and 4.

Now if we make usb_hcd_pci_probe() use devm_request_mem_region and drop the 
cleanup from usb_hcd_pci_remove

Probe:
1. usb_hcd_pci_probe() uses devm_request_mem_region(), this registers a 
release_region() with devm as cleanup
2. xhci_create_intel_xhci_sw_pde uses platform_device_add_resources() which are 
a child of the previous region and calls
   devm_add_action_or_reset() to add xhci_intel_unregister_pdev as cleanup

Remove:
3. usb_hcd_pci_remove does nothing of relevance
4. At end of remove() devm code runs and calls the cleanups in reverse order of 
registration! so it calls:
   xhci_intel_unregister_pdev()
   release_region()

Note the trick here is that the devm framework calls devm registered cleanup 
functions in reverse order of their registration, putting things in the right 
order.

Regards,

Hans


Re: [Resend] [PATCH v3] usb: xhci-pci: reorder removal to avoid use-after-free

2019-08-22 Thread Hans de Goede

Hi,

On 22-08-19 17:23, Mathias Nyman wrote:

On 16.8.2019 12.03, Schmid, Carsten wrote:

On driver removal, the platform_device_unregister call
attached through devm_add_action_or_reset was executed
after usb_hcd_pci_remove.
This lead to a use-after-free for the iomem resource of
the xhci-ext-caps driver in the platform removal
because the parent of the resource was freed earlier.

Fix this by reordering of the removal sequence.



Could all this be avoided if usb_hcd_pci_probe()
used managed device resources as well?
(using devm_request_mem_region(), and devm_ioremap_nocache())

This way the iomem resource would be added to the same devres list
as the platform_unregister_call, and the iomem resource should be
released after the platform_device_unregister as devres_release_all()
releases the resources in reverse order.


Yes I believe that that would work.

Regards,

Hans



[PATCH v2 2/3] usb: typec: fusb302: Use usb_debug_root as root for our debugfs entry

2019-08-17 Thread Hans de Goede
Use usb_debug_root as root for our debugfs entry instead of creating our
own subdirectory under the debugfs root.

Reviewed-by: Guenter Roeck 
Reviewed-by: Heikki Krogerus 
Signed-off-by: Hans de Goede 
---
Changes in v2:
- Prefix debugfs entry filename with "fusb302-"
---
 drivers/usb/typec/tcpm/fusb302.c | 13 +
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 93244d6c4bff..603ab87b466e 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -206,23 +207,19 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
 
-static struct dentry *rootdir;
-
 static void fusb302_debugfs_init(struct fusb302_chip *chip)
 {
-   mutex_init(&chip->logbuffer_lock);
-   if (!rootdir)
-   rootdir = debugfs_create_dir("fusb302", NULL);
+   char name[NAME_MAX];
 
-   chip->dentry = debugfs_create_file(dev_name(chip->dev),
-  S_IFREG | 0444, rootdir,
+   mutex_init(&chip->logbuffer_lock);
+   snprintf(name, NAME_MAX, "fusb302-%s", dev_name(chip->dev));
+   chip->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root,
   chip, &fusb302_debug_fops);
 }
 
 static void fusb302_debugfs_exit(struct fusb302_chip *chip)
 {
debugfs_remove(chip->dentry);
-   debugfs_remove(rootdir);
 }
 
 #else
-- 
2.23.0.rc2



[PATCH v2 1/3] usb: typec: tcpm: Use usb_debug_root as root for our debugfs entry

2019-08-17 Thread Hans de Goede
Use usb_debug_root as root for our debugfs entry instead of creating our
own subdirectory under the debugfs root.

Another patch in this series will make the same change to the fusb302
driver, which also uses dev_name() (on the same device) for the debugfs
entry name. So we also prefix dev_name() with "tcpm-" here to avoid a
name conflict.

Reviewed-by: Guenter Roeck 
Reviewed-by: Heikki Krogerus 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/tcpm.c | 17 +
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 15abe1d9958f..5241d17c3399 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -571,17 +572,13 @@ static int tcpm_debug_show(struct seq_file *s, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(tcpm_debug);
 
-static struct dentry *rootdir;
-
 static void tcpm_debugfs_init(struct tcpm_port *port)
 {
-   mutex_init(&port->logbuffer_lock);
-   /* /sys/kernel/debug/tcpm/usbcX */
-   if (!rootdir)
-   rootdir = debugfs_create_dir("tcpm", NULL);
+   char name[NAME_MAX];
 
-   port->dentry = debugfs_create_file(dev_name(port->dev),
-  S_IFREG | 0444, rootdir,
+   mutex_init(&port->logbuffer_lock);
+   snprintf(name, NAME_MAX, "tcpm-%s", dev_name(port->dev));
+   port->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root,
   port, &tcpm_debug_fops);
 }
 
@@ -597,10 +594,6 @@ static void tcpm_debugfs_exit(struct tcpm_port *port)
mutex_unlock(&port->logbuffer_lock);
 
debugfs_remove(port->dentry);
-   if (list_empty(&rootdir->d_subdirs)) {
-   debugfs_remove(rootdir);
-   rootdir = NULL;
-   }
 }
 
 #else
-- 
2.23.0.rc2



[PATCH v2 3/3] usb: typec: fusb302: Call fusb302_debugfs_init earlier

2019-08-17 Thread Hans de Goede
tcpm_register_port() will call some of the fusb302 code's callbacks
wich in turn will call fusb302_log(). So we need to call
fusb302_debugfs_init() before we call tcpm_register_port().

This fixes the following warning, which was caused by the logbuffer_lock
not yet being initialized (which is done by fusb302_debugfs_init):

 DEBUG_LOCKS_WARN_ON(lock->magic != lock)
 WARNING: CPU: 0 PID: 1306 at kernel/locking/mutex.c:912 
__mutex_lock+0x978/0x9a0
 Modules linked in: fusb302(+) tcpm pi3usb30532 typec bq24190_charger 
snd_soc_sst_cht_bsw_rt5645 mei_hdcp dwc3 intel_rapl_msr udc_core ulpi gpio_keys 
intel_powerclamp coretemp kvm_intel brcmfmac kvm brcmutil joydev cfg80211 
wdat_wdt irqbypass pcspkr intel_cstate extcon_intel_cht_wc i2c_cht_wc(E) 
snd_intel_sst_acpi snd_intel_sst_core snd_soc_rt5645 
snd_soc_sst_atom_hifi2_platform snd_soc_acpi_intel_match snd_soc_rl6231 
snd_soc_acpi intel_xhci_usb_role_switch roles hci_uart snd_soc_core btqca 
mei_txe btrtl processor_thermal_device mei snd_hdmi_lpe_audio lpc_ich 
snd_compress btbcm intel_rapl_common ac97_bus dwc3_pci snd_pcm_dmaengine 
intel_soc_dts_iosf btintel snd_seq bluetooth snd_seq_device snd_pcm 
intel_cht_int33fe_musb snd_timer intel_cht_int33fe_typec intel_hid 
intel_cht_int33fe_common sparse_keymap snd ecdh_generic goodix rfkill soundcore 
ecc spi_pxa2xx_platform max17042_battery dw_dmac int3406_thermal dptf_power 
acpi_pad soc_button_array int3400_thermal int3403_thermal
  gpd_pocket_fan intel_int0002_vgpio int340x_thermal_zone acpi_thermal_rel 
dm_crypt mmc_block i915 crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel i2c_algo_bit drm_kms_helper drm video sdhci_acpi sdhci 
mmc_core pwm_lpss_platform pwm_lpss i2c_dev
 CPU: 0 PID: 1306 Comm: systemd-udevd Tainted: GE 5.3.0-rc4+ #83
 Hardware name: Default string Default string/Default string, BIOS 5.11 
06/28/2017
 RIP: 0010:__mutex_lock+0x978/0x9a0
 Code: c0 0f 84 26 f7 ff ff 44 8b 05 24 25 c8 00 45 85 c0 0f 85 16 f7 ff ff 48 
c7 c6 da 55 2f ae 48 c7 c7 98 8c 2d ae e8 a0 f9 5c ff <0f> 0b e9 fc f6 ff ff 4c 
89 f0 4d 89 fe 49 89 c7 e9 cf fa ff ff e8
 RSP: 0018:b7a8c0523800 EFLAGS: 00010286
 RAX:  RBX:  RCX: 
 RDX: 0002 RSI: 0001 RDI: 0246
 RBP: b7a8c05238c0 R08:  R09: 
 R10: b7a8c0523648 R11: 0030 R12: 
 R13: b7a8c0523990 R14: 9bf22f70c028 R15: 9bf22f70c360
 FS:  7f39ca234940() GS:9bf23740() knlGS:
 CS:  0010 DS:  ES:  CR0: 80050033
 CR2: 7f1f108481a0 CR3: 000271f28000 CR4: 001006f0
 Call Trace:
  ? find_held_lock+0x39/0x90
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  ? vsnprintf+0x3aa/0x4f0
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  _fusb302_log+0x81/0x1d0 [fusb302]
 ...

Reviewed-by: Guenter Roeck 
Reviewed-by: Heikki Krogerus 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 603ab87b466e..ed8655c6af8c 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1728,6 +1728,7 @@ static int fusb302_probe(struct i2c_client *client,
INIT_WORK(&chip->irq_work, fusb302_irq_work);
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
+   fusb302_debugfs_init(chip);
 
if (client->irq) {
chip->gpio_int_n_irq = client->irq;
@@ -1760,7 +1761,6 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
-   fusb302_debugfs_init(chip);
i2c_set_clientdata(client, chip);
 
return ret;
@@ -1769,6 +1769,7 @@ static int fusb302_probe(struct i2c_client *client,
tcpm_unregister_port(chip->tcpm_port);
fwnode_handle_put(chip->tcpc_dev.fwnode);
 destroy_workqueue:
+   fusb302_debugfs_exit(chip);
destroy_workqueue(chip->wq);
 
return ret;
-- 
2.23.0.rc2



Re: [PATCH 2/3] usb: typec: fusb: Use usb_debug_root as root for our debugfs entry

2019-08-17 Thread Hans de Goede

Hi,

On 16-08-19 09:51, Heikki Krogerus wrote:

On Thu, Aug 15, 2019 at 09:18:14PM +0200, Hans de Goede wrote:

Use usb_debug_root as root for our debugfs entry instead of creating our
own subdirectory under the debugfs root.

Signed-off-by: Hans de Goede 


I have one question below. Otherwise:

Reviewed-by: Heikki Krogerus 


---
  drivers/usb/typec/tcpm/fusb302.c | 9 ++---
  1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 93244d6c4bff..69a2afaf8f68 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -26,6 +26,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -206,23 +207,17 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
  }
  DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
  
-static struct dentry *rootdir;

-
  static void fusb302_debugfs_init(struct fusb302_chip *chip)
  {
mutex_init(&chip->logbuffer_lock);
-   if (!rootdir)
-   rootdir = debugfs_create_dir("fusb302", NULL);
-
chip->dentry = debugfs_create_file(dev_name(chip->dev),
-  S_IFREG | 0444, rootdir,
+  S_IFREG | 0444, usb_debug_root,
   chip, &fusb302_debug_fops);


In tcpm.c you named the entries "tcpm-%s", dev_name(...

Shouldn't we do something similar with these as well? I mean,
even though this is just debugfs, shouldn't we give some hint for the
user how to identify these entries?


Well on my test-machinw te dev_name is i2c-fusb302, but I realize the
dev_name is not always going to be so descriptive, so I will send
out a v2 adding a "fusb302-" prefix, like how we are doing for the
tcpm.c debug entry already.


How about if we still continue grouping the entries under the
"fusb302" directory, but just place that under usb_debug_root?


I would rather go with a prefix, the whole purpose of dropping the
subdir is so that we do not have a resource (the dir) shared between
multiple instances of the driver.

Regards,

Hans



[PATCH 3/3] usb: typec: fusb302: Call fusb302_debugfs_init earlier

2019-08-15 Thread Hans de Goede
tcpm_register_port() will call some of the fusb302 code's callbacks
wich in turn will call fusb302_log(). So we need to call
fusb302_debugfs_init() before we call tcpm_register_port().

This fixes the following warning, which was caused by the logbuffer_lock
not yet being initialized (which is done by fusb302_debugfs_init):

 DEBUG_LOCKS_WARN_ON(lock->magic != lock)
 WARNING: CPU: 0 PID: 1306 at kernel/locking/mutex.c:912 
__mutex_lock+0x978/0x9a0
 Modules linked in: fusb302(+) tcpm pi3usb30532 typec bq24190_charger 
snd_soc_sst_cht_bsw_rt5645 mei_hdcp dwc3 intel_rapl_msr udc_core ulpi gpio_keys 
intel_powerclamp coretemp kvm_intel brcmfmac kvm brcmutil joydev cfg80211 
wdat_wdt irqbypass pcspkr intel_cstate extcon_intel_cht_wc i2c_cht_wc(E) 
snd_intel_sst_acpi snd_intel_sst_core snd_soc_rt5645 
snd_soc_sst_atom_hifi2_platform snd_soc_acpi_intel_match snd_soc_rl6231 
snd_soc_acpi intel_xhci_usb_role_switch roles hci_uart snd_soc_core btqca 
mei_txe btrtl processor_thermal_device mei snd_hdmi_lpe_audio lpc_ich 
snd_compress btbcm intel_rapl_common ac97_bus dwc3_pci snd_pcm_dmaengine 
intel_soc_dts_iosf btintel snd_seq bluetooth snd_seq_device snd_pcm 
intel_cht_int33fe_musb snd_timer intel_cht_int33fe_typec intel_hid 
intel_cht_int33fe_common sparse_keymap snd ecdh_generic goodix rfkill soundcore 
ecc spi_pxa2xx_platform max17042_battery dw_dmac int3406_thermal dptf_power 
acpi_pad soc_button_array int3400_thermal int3403_thermal
  gpd_pocket_fan intel_int0002_vgpio int340x_thermal_zone acpi_thermal_rel 
dm_crypt mmc_block i915 crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel i2c_algo_bit drm_kms_helper drm video sdhci_acpi sdhci 
mmc_core pwm_lpss_platform pwm_lpss i2c_dev
 CPU: 0 PID: 1306 Comm: systemd-udevd Tainted: GE 5.3.0-rc4+ #83
 Hardware name: Default string Default string/Default string, BIOS 5.11 
06/28/2017
 RIP: 0010:__mutex_lock+0x978/0x9a0
 Code: c0 0f 84 26 f7 ff ff 44 8b 05 24 25 c8 00 45 85 c0 0f 85 16 f7 ff ff 48 
c7 c6 da 55 2f ae 48 c7 c7 98 8c 2d ae e8 a0 f9 5c ff <0f> 0b e9 fc f6 ff ff 4c 
89 f0 4d 89 fe 49 89 c7 e9 cf fa ff ff e8
 RSP: 0018:b7a8c0523800 EFLAGS: 00010286
 RAX:  RBX:  RCX: 
 RDX: 0002 RSI: 0001 RDI: 0246
 RBP: b7a8c05238c0 R08:  R09: 
 R10: b7a8c0523648 R11: 0030 R12: 
 R13: b7a8c0523990 R14: 9bf22f70c028 R15: 9bf22f70c360
 FS:  7f39ca234940() GS:9bf23740() knlGS:
 CS:  0010 DS:  ES:  CR0: 80050033
 CR2: 7f1f108481a0 CR3: 000271f28000 CR4: 001006f0
 Call Trace:
  ? find_held_lock+0x39/0x90
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  ? vsnprintf+0x3aa/0x4f0
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  _fusb302_log+0x81/0x1d0 [fusb302]
 ...

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 69a2afaf8f68..c7769fa73148 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1726,6 +1726,7 @@ static int fusb302_probe(struct i2c_client *client,
INIT_WORK(&chip->irq_work, fusb302_irq_work);
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
+   fusb302_debugfs_init(chip);
 
if (client->irq) {
chip->gpio_int_n_irq = client->irq;
@@ -1758,7 +1759,6 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
-   fusb302_debugfs_init(chip);
i2c_set_clientdata(client, chip);
 
return ret;
@@ -1767,6 +1767,7 @@ static int fusb302_probe(struct i2c_client *client,
tcpm_unregister_port(chip->tcpm_port);
fwnode_handle_put(chip->tcpc_dev.fwnode);
 destroy_workqueue:
+   fusb302_debugfs_exit(chip);
destroy_workqueue(chip->wq);
 
return ret;
-- 
2.23.0.rc2



[PATCH 1/3] usb: typec: tcpm: Use usb_debug_root as root for our debugfs entry

2019-08-15 Thread Hans de Goede
Use usb_debug_root as root for our debugfs entry instead of creating our
own subdirectory under the debugfs root.

Another patch in this series will make the same change to the fusb302
driver, which also uses dev_name() (on the same device) for the debugfs
entry name. So we also prefix dev_name() with "tcpm-" here to avoid a
name conflict.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/tcpm.c | 17 +
 1 file changed, 5 insertions(+), 12 deletions(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 15abe1d9958f..5241d17c3399 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -571,17 +572,13 @@ static int tcpm_debug_show(struct seq_file *s, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(tcpm_debug);
 
-static struct dentry *rootdir;
-
 static void tcpm_debugfs_init(struct tcpm_port *port)
 {
-   mutex_init(&port->logbuffer_lock);
-   /* /sys/kernel/debug/tcpm/usbcX */
-   if (!rootdir)
-   rootdir = debugfs_create_dir("tcpm", NULL);
+   char name[NAME_MAX];
 
-   port->dentry = debugfs_create_file(dev_name(port->dev),
-  S_IFREG | 0444, rootdir,
+   mutex_init(&port->logbuffer_lock);
+   snprintf(name, NAME_MAX, "tcpm-%s", dev_name(port->dev));
+   port->dentry = debugfs_create_file(name, S_IFREG | 0444, usb_debug_root,
   port, &tcpm_debug_fops);
 }
 
@@ -597,10 +594,6 @@ static void tcpm_debugfs_exit(struct tcpm_port *port)
mutex_unlock(&port->logbuffer_lock);
 
debugfs_remove(port->dentry);
-   if (list_empty(&rootdir->d_subdirs)) {
-   debugfs_remove(rootdir);
-   rootdir = NULL;
-   }
 }
 
 #else
-- 
2.23.0.rc2



[PATCH 2/3] usb: typec: fusb: Use usb_debug_root as root for our debugfs entry

2019-08-15 Thread Hans de Goede
Use usb_debug_root as root for our debugfs entry instead of creating our
own subdirectory under the debugfs root.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 9 ++---
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 93244d6c4bff..69a2afaf8f68 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -26,6 +26,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -206,23 +207,17 @@ static int fusb302_debug_show(struct seq_file *s, void *v)
 }
 DEFINE_SHOW_ATTRIBUTE(fusb302_debug);
 
-static struct dentry *rootdir;
-
 static void fusb302_debugfs_init(struct fusb302_chip *chip)
 {
mutex_init(&chip->logbuffer_lock);
-   if (!rootdir)
-   rootdir = debugfs_create_dir("fusb302", NULL);
-
chip->dentry = debugfs_create_file(dev_name(chip->dev),
-  S_IFREG | 0444, rootdir,
+  S_IFREG | 0444, usb_debug_root,
   chip, &fusb302_debug_fops);
 }
 
 static void fusb302_debugfs_exit(struct fusb302_chip *chip)
 {
debugfs_remove(chip->dentry);
-   debugfs_remove(rootdir);
 }
 
 #else
-- 
2.23.0.rc2



Re: [PATCH 0/3] usb: typec: fusb302: Small changes

2019-08-15 Thread Hans de Goede

Hi,

On 14-08-19 15:24, Heikki Krogerus wrote:

Hi,

This series removes the deprecated fusb302 specific properties, and
stops using struct tcpc_config in the driver.

thanks,

Heikki Krogerus (3):
   usb: typec: fusb302: Remove unused properties
   dt-bindings: usb: fusb302: Remove deprecated properties
   usb: typec: fusb302: Always provide fwnode for the port


I know this series is already in usb-testing, still I thought
it would be a good idea to test it on my CHT hw with a fusb302
TypeC controller. So I've just completed testing this and it
works as advertised:

So FWIW:

Tested-by: Hans de Goede 

Regards,

Hans



Re: [PATCH v2] usb: xhci-pci: reorder removal to avoid use-after-free

2019-08-15 Thread Hans de Goede

Hi,

On 14-08-19 16:32, Schmid, Carsten wrote:

On driver removal, the platform_device_unregister call
attached through devm_add_action_or_reset was executed
after usb_hcd_pci_remove.
This lead to a use-after-free for the iomem resorce of
the xhci-ext-caps driver in the platform removal
because the parent of the resource was freed earlier.

Fix this by reordering of the removal sequence.

Signed-off-by: Carsten Schmid 


Patch looks good to me:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
v2:
   - more speaking name for private data element
   - consider failure in driver init sequence
   - fix minor issues found by checkpatch.pl
---
  drivers/usb/host/xhci-ext-caps.c | 25 +++--
  drivers/usb/host/xhci-pci.c  |  8 +++-
  drivers/usb/host/xhci-pci.h  | 20 
  drivers/usb/host/xhci.h  |  1 +
  4 files changed, 43 insertions(+), 11 deletions(-)
  create mode 100644 drivers/usb/host/xhci-pci.h

diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
index 399113f9fc5c..28a7d53ecf2c 100644
--- a/drivers/usb/host/xhci-ext-caps.c
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -7,21 +7,19 @@
  
  #include 

  #include "xhci.h"
+#include "xhci-pci.h"
  
  #define USB_SW_DRV_NAME		"intel_xhci_usb_sw"

  #define USB_SW_RESOURCE_SIZE  0x400
  
-static void xhci_intel_unregister_pdev(void *arg)

-{
-   platform_device_unregister(arg);
-}
-
  static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 
cap_offset)
  {
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct device *dev = hcd->self.controller;
struct platform_device *pdev;
struct resource res = { 0, };
+   struct xhci_pci_priv *priv = (struct xhci_pci_priv *)xhci->priv;
+
int ret;
  
  	pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE);

@@ -52,11 +50,7 @@ static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd 
*xhci, u32 cap_offset)
return ret;
}
  
-	ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);

-   if (ret) {
-   dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw 
pdev\n");
-   return ret;
-   }
+   priv->role_switch_pdev = pdev;
  
  	return 0;

  }
@@ -88,3 +82,14 @@ int xhci_ext_cap_init(struct xhci_hcd *xhci)
return 0;
  }
  EXPORT_SYMBOL_GPL(xhci_ext_cap_init);
+
+void xhci_ext_cap_remove(struct xhci_hcd *xhci)
+{
+   struct xhci_pci_priv *priv = (struct xhci_pci_priv *)xhci->priv;
+
+   if (priv->role_switch_pdev) {
+   platform_device_unregister(priv->role_switch_pdev);
+   priv->role_switch_pdev = NULL;
+   }
+}
+EXPORT_SYMBOL_GPL(xhci_ext_cap_remove);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index c2fe218e051f..f2201f380c17 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -14,6 +14,7 @@
  #include 
  
  #include "xhci.h"

+#include "xhci-pci.h"
  #include "xhci-trace.h"
  
  #define SSIC_PORT_NUM		2

@@ -62,6 +63,7 @@ static struct hc_driver __read_mostly xhci_pci_hc_driver;
  static int xhci_pci_setup(struct usb_hcd *hcd);
  
  static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {

+   .extra_priv_size = sizeof(struct xhci_pci_priv),
.reset = xhci_pci_setup,
  };
  
@@ -350,7 +352,7 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)

retval = usb_add_hcd(xhci->shared_hcd, dev->irq,
IRQF_SHARED);
if (retval)
-   goto put_usb3_hcd;
+   goto remove_ext_cap;
/* Roothub already marked as USB 3.0 speed */
  
  	if (!(xhci->quirks & XHCI_BROKEN_STREAMS) &&

@@ -368,6 +370,8 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct 
pci_device_id *id)
  
  	return 0;
  
+remove_ext_cap:

+   xhci_ext_cap_remove(xhci);
  put_usb3_hcd:
usb_put_hcd(xhci->shared_hcd);
  dealloc_usb2_hcd:
@@ -393,6 +397,8 @@ static void xhci_pci_remove(struct pci_dev *dev)
xhci->shared_hcd = NULL;
}
  
+	xhci_ext_cap_remove(xhci);

+
/* Workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
pci_set_power_state(dev, PCI_D3hot);
diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h
new file mode 100644
index ..fc0cde231679
--- /dev/null
+++ b/drivers/usb/host/xhci-pci.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * xhci-pci.h - xHCI extended capability handling platform Glue.
+ *
+ * Copyright (C) 2019 Mentor Graphics (Deutschland) GmbH
+ * Derived from xhci-plat.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Pub

Re: [PATCH] usb: typec: fusb302: Call fusb302_debugfs_init earlier

2019-08-15 Thread Hans de Goede

Hi,

On 15-08-19 17:20, Guenter Roeck wrote:

On Thu, Aug 15, 2019 at 04:31:59PM +0300, Heikki Krogerus wrote:


As Guenter points out, don't check this, just call it anb move on.

But are you _SURE_ you want this to be the name, at the root of debugfs?
Why not put it under the usb debugfs directory?


That's a good point. Let's move it there while at it.


Maybe we should move the tcpm root as well ?


Ack, I'm preparing a patch series that does both.

Regards,

Hans



Re: [PATCH 0/3] usb: typec: fusb302: Small changes

2019-08-15 Thread Hans de Goede

Hi,

On 15-08-19 14:55, Greg Kroah-Hartman wrote:

On Wed, Aug 14, 2019 at 03:42:46PM +0200, Hans de Goede wrote:

Hi,

On 14-08-19 15:24, Heikki Krogerus wrote:

Hi,

This series removes the deprecated fusb302 specific properties, and
stops using struct tcpc_config in the driver.


Series looks good to me:

Reviewed-by: Hans de Goede 

This has a small conflict with my
"[PATCH] usb: typec: fusb302: Call fusb302_debugfs_init earlier"
patch.

Since we've agreed to do the rootdir leak fix as a separate patch
(which I will write when I find some time probably tomorrow), I
was wondering if we can merge my patch first. I would like to see
a "Cc: sta...@vger.kernel.org" added to my patch and then it would
be good to have it merged first.

Regardless we should probable prepare one series with all patches
for Greg to make this easy to merge for him.


I'll take this series now, and you can redo your patch based on my
usb-next branch with them in it.


Ok.

Regards,

Hans


Re: [PATCH 0/3] usb: typec: fusb302: Small changes

2019-08-14 Thread Hans de Goede

Hi,

On 14-08-19 15:24, Heikki Krogerus wrote:

Hi,

This series removes the deprecated fusb302 specific properties, and
stops using struct tcpc_config in the driver.


Series looks good to me:

Reviewed-by: Hans de Goede 

This has a small conflict with my
"[PATCH] usb: typec: fusb302: Call fusb302_debugfs_init earlier"
patch.

Since we've agreed to do the rootdir leak fix as a separate patch
(which I will write when I find some time probably tomorrow), I
was wondering if we can merge my patch first. I would like to see
a "Cc: sta...@vger.kernel.org" added to my patch and then it would
be good to have it merged first.

Regardless we should probable prepare one series with all patches
for Greg to make this easy to merge for him.

Shall I combine this series + my fix + my to be written fix into
1 series, test that on actual hardware and then post that?

Regards,

Hans


Re: AW: [PATCH] usb: xhci-pci: reorder removal to avoid use-after-free

2019-08-14 Thread Hans de Goede

Hi,

On 14-08-19 15:32, Schmid, Carsten wrote:

On driver removal, the platform_device_unregister call
attached through devm_add_action_or_reset was executed
after usb_hcd_pci_remove.
This lead to a use-after-free for the iomem resorce of
the xhci-ext-caps driver in the platform removal
because the parent of the resource was freed earlier.

Fix this by reordering of the removal sequence.

Signed-off-by: Carsten Schmid 


Assuming this has been tested, overal this looks good to me.


Tested on 4.14.129, ported to v5.2.7, compiled there.



But there are 2 things to fix:

1) Maybe pick a more descriptive struct member name then pdev.
 pdev with pci-devices often points to a pci_device ...
 How about: role_switch_pdev ?


Ok, good point. Had platform dev pdev in mind ...



2) xhci_ext_cap_init() is not the last call which can fail in
 xhci_pci_probe(), since you now no longer use
devm_add_action_or_reset
 for auto-cleanup, you must now manually cleanup by calling
 xhci_ext_cap_remove() when later steps of xhci_pci_probe() fail.
 it looks like you will need a new ext_cap_remove error-exit label
 for this put above the put_usb3_hcd label and goto this new label
 instead of to put_usb3_hcd in all error paths after a successful call
 to xhci_ext_cap_init()


Right. Will review this path and correct accordingly.

Maybe an additional label isn't required because pdev is only set when
xhci_ext_cap_init created the platform device, and xhci_ext_cap_remove
checks for pdev being set.
So a call to xhci_ext_cap_remove doesn't harm if pdev is not set up yet.
But for readability it might be better to create a label.


Right, when taking a quick look myself I realized that an extra label would
not be necessary, but not having the extra label will confuse the reader
of the code, since now we are undoing something which we did not do,
so I would prefer if you use the extra label.

Regards,

Hans



Re: [PATCH] usb: xhci-pci: reorder removal to avoid use-after-free

2019-08-14 Thread Hans de Goede

Hi,

On 14-08-19 13:39, Schmid, Carsten wrote:

On driver removal, the platform_device_unregister call
attached through devm_add_action_or_reset was executed
after usb_hcd_pci_remove.
This lead to a use-after-free for the iomem resorce of
the xhci-ext-caps driver in the platform removal
because the parent of the resource was freed earlier.

Fix this by reordering of the removal sequence.

Signed-off-by: Carsten Schmid 


Assuming this has been tested, overal this looks good to me.

But there are 2 things to fix:

1) Maybe pick a more descriptive struct member name then pdev.
   pdev with pci-devices often points to a pci_device ...
   How about: role_switch_pdev ?

2) xhci_ext_cap_init() is not the last call which can fail in
   xhci_pci_probe(), since you now no longer use devm_add_action_or_reset
   for auto-cleanup, you must now manually cleanup by calling
   xhci_ext_cap_remove() when later steps of xhci_pci_probe() fail.
   it looks like you will need a new ext_cap_remove error-exit label
   for this put above the put_usb3_hcd label and goto this new label
   instead of to put_usb3_hcd in all error paths after a successful call
   to xhci_ext_cap_init()

Regards,

Hans



---
  drivers/usb/host/xhci-ext-caps.c | 22 --
  drivers/usb/host/xhci-pci.c  |  4 
  drivers/usb/host/xhci-pci.h  | 19 +++
  drivers/usb/host/xhci.h  |  1 +
  4 files changed, 36 insertions(+), 10 deletions(-)
  create mode 100644 drivers/usb/host/xhci-pci.h

diff --git a/drivers/usb/host/xhci-ext-caps.c b/drivers/usb/host/xhci-ext-caps.c
index 399113f9fc5c..d2ab1e2a39c0 100644
--- a/drivers/usb/host/xhci-ext-caps.c
+++ b/drivers/usb/host/xhci-ext-caps.c
@@ -7,21 +7,19 @@
  
  #include 

  #include "xhci.h"
+#include "xhci-pci.h"
  
  #define USB_SW_DRV_NAME		"intel_xhci_usb_sw"

  #define USB_SW_RESOURCE_SIZE  0x400
  
-static void xhci_intel_unregister_pdev(void *arg)

-{
-   platform_device_unregister(arg);
-}
-
  static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd *xhci, u32 
cap_offset)
  {
struct usb_hcd *hcd = xhci_to_hcd(xhci);
struct device *dev = hcd->self.controller;
struct platform_device *pdev;
struct resource res = { 0, };
+   struct xhci_pci_priv *priv = (struct xhci_pci_priv *)xhci->priv;
+
int ret;
  
  	pdev = platform_device_alloc(USB_SW_DRV_NAME, PLATFORM_DEVID_NONE);

@@ -52,11 +50,7 @@ static int xhci_create_intel_xhci_sw_pdev(struct xhci_hcd 
*xhci, u32 cap_offset)
return ret;
}
  
-	ret = devm_add_action_or_reset(dev, xhci_intel_unregister_pdev, pdev);

-   if (ret) {
-   dev_err(dev, "couldn't add unregister action for intel_xhci_usb_sw 
pdev\n");
-   return ret;
-   }
+   priv->pdev = pdev;
  
  	return 0;

  }
@@ -88,3 +82,11 @@ int xhci_ext_cap_init(struct xhci_hcd *xhci)
return 0;
  }
  EXPORT_SYMBOL_GPL(xhci_ext_cap_init);
+
+void xhci_ext_cap_remove(struct xhci_hcd *xhci)
+{
+   struct xhci_pci_priv *priv = (struct xhci_pci_priv *)xhci->priv;
+   if (priv->pdev)
+   platform_device_unregister(priv->pdev);
+}
+EXPORT_SYMBOL_GPL(xhci_ext_cap_remove);
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index c2fe218e051f..a4d094df56f7 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -14,6 +14,7 @@
  #include 
  
  #include "xhci.h"

+#include "xhci-pci.h"
  #include "xhci-trace.h"
  
  #define SSIC_PORT_NUM		2

@@ -62,6 +63,7 @@ static struct hc_driver __read_mostly xhci_pci_hc_driver;
  static int xhci_pci_setup(struct usb_hcd *hcd);
  
  static const struct xhci_driver_overrides xhci_pci_overrides __initconst = {

+   .extra_priv_size = sizeof(struct xhci_pci_priv),
.reset = xhci_pci_setup,
  };
  
@@ -393,6 +395,8 @@ static void xhci_pci_remove(struct pci_dev *dev)

xhci->shared_hcd = NULL;
}
  
+	xhci_ext_cap_remove(xhci);

+
/* Workaround for spurious wakeups at shutdown with HSW */
if (xhci->quirks & XHCI_SPURIOUS_WAKEUP)
pci_set_power_state(dev, PCI_D3hot);
diff --git a/drivers/usb/host/xhci-pci.h b/drivers/usb/host/xhci-pci.h
new file mode 100644
index ..ead9618d7368
--- /dev/null
+++ b/drivers/usb/host/xhci-pci.h
@@ -0,0 +1,19 @@
+/*
+ * xhci-pci.h - xHCI extended capability handling platform Glue.
+ *
+ * Copyright (C) 2019 Mentor Graphics (Deutschland) GmbH
+ * Derived from xhci-plat.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _XHCI_PCI_H
+#define _XHCI_PCI_H
+
+struct xhci_pci_priv {
+   struct platform_device *pdev;
+};
+
+#endif /* _XHCI_PCI_H */
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index fabbce1c542a..847d2021fc2c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xh

Re: [PATCH] usb: typec: fusb302: Call fusb302_debugfs_init earlier

2019-08-13 Thread Hans de Goede

Hi Heikki,

On 13-08-19 12:52, Heikki Krogerus wrote:

Hi Hans,

On Tue, Aug 13, 2019 at 12:15:24PM +0200, Hans de Goede wrote:

tcpm_register_port() will call some of the fusb302 code's callbacks
wich in turn will call fusb302_log(). So we need to call
fusb302_debugfs_init() before we call tcpm_register_port().

This fixes the following warning, which was caused by the logbuffer_lock
not yet being initialized (which is done by fusb302_debugfs_init):

  DEBUG_LOCKS_WARN_ON(lock->magic != lock)
  WARNING: CPU: 0 PID: 1306 at kernel/locking/mutex.c:912 
__mutex_lock+0x978/0x9a0
  Modules linked in: fusb302(+) tcpm pi3usb30532 typec bq24190_charger 
snd_soc_sst_cht_bsw_rt5645 mei_hdcp dwc3 intel_rapl_msr udc_core ulpi gpio_keys 
intel_powerclamp coretemp kvm_intel brcmfmac kvm brcmutil joydev cfg80211 
wdat_wdt irqbypass pcspkr intel_cstate extcon_intel_cht_wc i2c_cht_wc(E) 
snd_intel_sst_acpi snd_intel_sst_core snd_soc_rt5645 
snd_soc_sst_atom_hifi2_platform snd_soc_acpi_intel_match snd_soc_rl6231 
snd_soc_acpi intel_xhci_usb_role_switch roles hci_uart snd_soc_core btqca 
mei_txe btrtl processor_thermal_device mei snd_hdmi_lpe_audio lpc_ich 
snd_compress btbcm intel_rapl_common ac97_bus dwc3_pci snd_pcm_dmaengine 
intel_soc_dts_iosf btintel snd_seq bluetooth snd_seq_device snd_pcm 
intel_cht_int33fe_musb snd_timer intel_cht_int33fe_typec intel_hid 
intel_cht_int33fe_common sparse_keymap snd ecdh_generic goodix rfkill soundcore 
ecc spi_pxa2xx_platform max17042_battery dw_dmac int3406_thermal dptf_power 
acpi_pad soc_button_array int3400_thermal int3403_thermal
   gpd_pocket_fan intel_int0002_vgpio int340x_thermal_zone acpi_thermal_rel 
dm_crypt mmc_block i915 crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel i2c_algo_bit drm_kms_helper drm video sdhci_acpi sdhci 
mmc_core pwm_lpss_platform pwm_lpss i2c_dev
  CPU: 0 PID: 1306 Comm: systemd-udevd Tainted: GE 5.3.0-rc4+ 
#83
  Hardware name: Default string Default string/Default string, BIOS 5.11 
06/28/2017
  RIP: 0010:__mutex_lock+0x978/0x9a0
  Code: c0 0f 84 26 f7 ff ff 44 8b 05 24 25 c8 00 45 85 c0 0f 85 16 f7 ff ff 48 c7 c6 
da 55 2f ae 48 c7 c7 98 8c 2d ae e8 a0 f9 5c ff <0f> 0b e9 fc f6 ff ff 4c 89 f0 
4d 89 fe 49 89 c7 e9 cf fa ff ff e8
  RSP: 0018:b7a8c0523800 EFLAGS: 00010286
  RAX:  RBX:  RCX: 
  RDX: 0002 RSI: 0001 RDI: 0246
  RBP: b7a8c05238c0 R08:  R09: 
  R10: b7a8c0523648 R11: 0030 R12: 
  R13: b7a8c0523990 R14: 9bf22f70c028 R15: 9bf22f70c360
  FS:  7f39ca234940() GS:9bf23740() knlGS:
  CS:  0010 DS:  ES:  CR0: 80050033
  CR2: 7f1f108481a0 CR3: 000271f28000 CR4: 001006f0
  Call Trace:
   ? find_held_lock+0x39/0x90
   ? _fusb302_log+0x81/0x1d0 [fusb302]
   ? vsnprintf+0x3aa/0x4f0
   ? _fusb302_log+0x81/0x1d0 [fusb302]
   _fusb302_log+0x81/0x1d0 [fusb302]
  ...

Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/fusb302.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index ccfc7e91e7a3..04c76b9d0065 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1759,6 +1759,7 @@ static int fusb302_probe(struct i2c_client *client,
INIT_WORK(&chip->irq_work, fusb302_irq_work);
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
+   fusb302_debugfs_init(chip);
  
  	if (client->irq) {

chip->gpio_int_n_irq = client->irq;
@@ -1784,7 +1785,6 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
-   fusb302_debugfs_init(chip);
i2c_set_clientdata(client, chip);


That leaves the rootdir variable pointing to something again for
example if a failure happens (like -EPROBE_AGAIN) during probe (the
"fusb302" directory is removed, but the rootdir static variable still
points to something).

Let's just create that rootdir directory during driver init. I don't
really understand why should we only create it when/if the first
instance of fusb302 is registered. I think something like this would
work:

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index c524088246ee..7a950a6e5f0d 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -212,9 +212,6 @@ static struct dentry *rootdir;
  static void fusb302_debugfs_init(struct fusb302_chip *chip)
  {
 mutex_init(&chip->logbuffer_lock);
-   if (!rootdir)
-   rootdir = debugfs_create_dir("fusb302", NULL);
-
 chip->dentry = debugfs_create_file(d

[PATCH] usb: typec: fusb302: Call fusb302_debugfs_init earlier

2019-08-13 Thread Hans de Goede
tcpm_register_port() will call some of the fusb302 code's callbacks
wich in turn will call fusb302_log(). So we need to call
fusb302_debugfs_init() before we call tcpm_register_port().

This fixes the following warning, which was caused by the logbuffer_lock
not yet being initialized (which is done by fusb302_debugfs_init):

 DEBUG_LOCKS_WARN_ON(lock->magic != lock)
 WARNING: CPU: 0 PID: 1306 at kernel/locking/mutex.c:912 
__mutex_lock+0x978/0x9a0
 Modules linked in: fusb302(+) tcpm pi3usb30532 typec bq24190_charger 
snd_soc_sst_cht_bsw_rt5645 mei_hdcp dwc3 intel_rapl_msr udc_core ulpi gpio_keys 
intel_powerclamp coretemp kvm_intel brcmfmac kvm brcmutil joydev cfg80211 
wdat_wdt irqbypass pcspkr intel_cstate extcon_intel_cht_wc i2c_cht_wc(E) 
snd_intel_sst_acpi snd_intel_sst_core snd_soc_rt5645 
snd_soc_sst_atom_hifi2_platform snd_soc_acpi_intel_match snd_soc_rl6231 
snd_soc_acpi intel_xhci_usb_role_switch roles hci_uart snd_soc_core btqca 
mei_txe btrtl processor_thermal_device mei snd_hdmi_lpe_audio lpc_ich 
snd_compress btbcm intel_rapl_common ac97_bus dwc3_pci snd_pcm_dmaengine 
intel_soc_dts_iosf btintel snd_seq bluetooth snd_seq_device snd_pcm 
intel_cht_int33fe_musb snd_timer intel_cht_int33fe_typec intel_hid 
intel_cht_int33fe_common sparse_keymap snd ecdh_generic goodix rfkill soundcore 
ecc spi_pxa2xx_platform max17042_battery dw_dmac int3406_thermal dptf_power 
acpi_pad soc_button_array int3400_thermal int3403_thermal
  gpd_pocket_fan intel_int0002_vgpio int340x_thermal_zone acpi_thermal_rel 
dm_crypt mmc_block i915 crct10dif_pclmul crc32_pclmul crc32c_intel 
ghash_clmulni_intel i2c_algo_bit drm_kms_helper drm video sdhci_acpi sdhci 
mmc_core pwm_lpss_platform pwm_lpss i2c_dev
 CPU: 0 PID: 1306 Comm: systemd-udevd Tainted: GE 5.3.0-rc4+ #83
 Hardware name: Default string Default string/Default string, BIOS 5.11 
06/28/2017
 RIP: 0010:__mutex_lock+0x978/0x9a0
 Code: c0 0f 84 26 f7 ff ff 44 8b 05 24 25 c8 00 45 85 c0 0f 85 16 f7 ff ff 48 
c7 c6 da 55 2f ae 48 c7 c7 98 8c 2d ae e8 a0 f9 5c ff <0f> 0b e9 fc f6 ff ff 4c 
89 f0 4d 89 fe 49 89 c7 e9 cf fa ff ff e8
 RSP: 0018:b7a8c0523800 EFLAGS: 00010286
 RAX:  RBX:  RCX: 
 RDX: 0002 RSI: 0001 RDI: 0246
 RBP: b7a8c05238c0 R08:  R09: 
 R10: b7a8c0523648 R11: 0030 R12: 
 R13: b7a8c0523990 R14: 9bf22f70c028 R15: 9bf22f70c360
 FS:  7f39ca234940() GS:9bf23740() knlGS:
 CS:  0010 DS:  ES:  CR0: 80050033
 CR2: 7f1f108481a0 CR3: 000271f28000 CR4: 001006f0
 Call Trace:
  ? find_held_lock+0x39/0x90
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  ? vsnprintf+0x3aa/0x4f0
  ? _fusb302_log+0x81/0x1d0 [fusb302]
  _fusb302_log+0x81/0x1d0 [fusb302]
 ...

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index ccfc7e91e7a3..04c76b9d0065 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1759,6 +1759,7 @@ static int fusb302_probe(struct i2c_client *client,
INIT_WORK(&chip->irq_work, fusb302_irq_work);
INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
init_tcpc_dev(&chip->tcpc_dev);
+   fusb302_debugfs_init(chip);
 
if (client->irq) {
chip->gpio_int_n_irq = client->irq;
@@ -1784,7 +1785,6 @@ static int fusb302_probe(struct i2c_client *client,
goto tcpm_unregister_port;
}
enable_irq_wake(chip->gpio_int_n_irq);
-   fusb302_debugfs_init(chip);
i2c_set_clientdata(client, chip);
 
return ret;
@@ -1792,6 +1792,7 @@ static int fusb302_probe(struct i2c_client *client,
 tcpm_unregister_port:
tcpm_unregister_port(chip->tcpm_port);
 destroy_workqueue:
+   fusb302_debugfs_exit(chip);
destroy_workqueue(chip->wq);
 
return ret;
-- 
2.23.0.rc1



Re: AW: AW: AW: KASAN: use-after-free Read in usbhid_power

2019-08-10 Thread Hans de Goede

Hi,

On 09-08-19 14:38, Schmid, Carsten wrote:

Hi again,



Hey, i did not want to trigger an eartquake in the basement of the kernel ;-)
My intention was to prevent some crashes, and help developers to find their 
bugs.
I think my patch exactly does this.


Hehe, actually drivers not being able to block unbind has been bugging me
for
a while now, because there are cases where this would be really helpful.

1) make resources refcounted, have child resources take a ref on the parent
2) Disallow unbind on devices with bound child-devices?


Exactly what i was thinking of in first attempts.
But i fear that would break even more use cases.

Hans, directly regarding the driver:
The problem i see is that the xhci_intel_unregister_pdev which is added
as an action with devm_add_action_or_reset() is called late by the framework,
later than the usb_hcd_pci_remove() in xhci_pci_remove.
Is there any chance to trigger this before?
This is what Greg meant with "right order".


Ah, I missed that part, sure that should be easy, just stop using
devm_add_action_or_reset() and do the xhci_intel_unregister_pdev()
manually at the right time. The downside of this is that you also
need to make sure it happens at the right time from probe error-paths
but given the bug you are hitting, I guess that is probably
already a problem.


@Hans:
Sure, will have a look at this. I think i have found where to do that,
but need to check how to get the pdev pointer there 


You probably need to store the pdev pointer in one of the xhci driver's
private data structs.

Regards,

Hans


Re: AW: AW: KASAN: use-after-free Read in usbhid_power

2019-08-09 Thread Hans de Goede

Hi,

On 8/9/19 12:47 PM, Schmid, Carsten wrote:


We are talking memory-mapped io here, so it cannot just be "re-used", it
is wat it is. I guess the PCI BAR could be released and then the physical
address the resource was at could be re-used for another piece of MMIo,
but AFAIK outside of PI=CI hotplug we never release BARs.

Maybe we need to ref-count resources and have the aprent free only be
a deref and not release the resource until the child resource also
is free-ed doing another deref?

I must say that to me it sometimes just seems like always allowing unbind
is a bad idea. Another example of this is things like virtio, where
we can have a filesystem based on virtio-block, but the virtio interface
between the hypervisor and the guest-kernel is a PCI-device and in theory
the user could unbind the virtio driver from that PCI-device, after which
the whole house comes crashing down.

I also know that the extcon framework in its current incarnaton
does not deal with unbind properly...

Maybe it is time that we allow drivers to block unbind instead of
trying to support unbind in really complex situations where normal
use-cases will never need it ?

I do realize unbind is very useful for driver developent without
rebooting.



Hey, i did not want to trigger an eartquake in the basement of the kernel ;-)
My intention was to prevent some crashes, and help developers to find their 
bugs.
I think my patch exactly does this.


Hehe, actually drivers not being able to block unbind has been bugging me for
a while now, because there are cases where this would be really helpful.

1) make resources refcounted, have child resources take a ref on the parent
2) Disallow unbind on devices with bound child-devices?



Exactly what i was thinking of in first attempts.
But i fear that would break even more use cases.

Hans, directly regarding the driver:
The problem i see is that the xhci_intel_unregister_pdev which is added
as an action with devm_add_action_or_reset() is called late by the framework,
later than the usb_hcd_pci_remove() in xhci_pci_remove.
Is there any chance to trigger this before?
This is what Greg meant with "right order".


Ah, I missed that part, sure that should be easy, just stop using
devm_add_action_or_reset() and do the xhci_intel_unregister_pdev()
manually at the right time. The downside of this is that you also
need to make sure it happens at the right time from probe error-paths
but given the bug you are hitting, I guess that is probably
already a problem.

Regards,

Hans



Re: AW: KASAN: use-after-free Read in usbhid_power

2019-08-09 Thread Hans de Goede

Hi,

On 8/9/19 11:34 AM, Schmid, Carsten wrote:

-Ursprüngliche Nachricht-
Von: Greg KH [mailto:gre...@linuxfoundation.org]
Gesendet: Freitag, 9. August 2019 09:56
An: Schmid, Carsten 
Cc: Alan Stern ; Andrey Konovalov
; Oliver Neukum ;
syzkaller-bugs ; syzbot
; USB list
; Hillf Danton 
Betreff: Re: KASAN: use-after-free Read in usbhid_power

On Fri, Aug 09, 2019 at 07:35:32AM +, Schmid, Carsten wrote:

Hi all having use-after-free issues in USB shutdowns:
I hunted for a similar case in the intel_xhci_usb_sw driver.
What i have found and proposed is (from yesterday):
---
[PATCH] kernel/resource.c: invalidate parent when freed resource has

childs


When a resource is freed and has children, the childrens are
left without any hint that their parent is no more valid.
This caused at least one use-after-free in the xhci-hcd using
ext-caps driver when platform code released platform devices.

Fix this by setting child's parent to zero and warn.

Signed-off-by: Carsten Schmid 
---
Rationale:
When hunting for the root cause of a crash on a 4.14.86 kernel, i
have found the root cause and checked it being still present
upstream. Our case:
Having xhci-hcd and intel_xhci_usb_sw active we can see in
/proc/meminfo: (exceirpt)
   b3c0-b3c0 : :00:15.0
 b3c0-b3c0 : xhci-hcd
   b3c08070-b3c0846f : intel_xhci_usb_sw
intel_xhci_usb_sw being a child of xhci-hcd.

Doing an unbind command
echo :00:15.0 > /sys/bus/pci/drivers/xhci_hcd/unbind
leads to xhci-hcd being freed in __release_region.
The intel_xhci_usb_sw resource is accessed in platform code
in platform_device_del with
 for (i = 0; i < pdev->num_resources; i++) {
 struct resource *r = &pdev->resource[i];
 if (r->parent)
 release_resource(r);
 }
as the resource's parent has not been updated, the release_resource
uses the parent:
 p = &old->parent->child;
which is now invalid.
Fix this by marking the parent invalid in the child and give a warning
in dmesg.
---
  kernel/resource.c | 9 +
  1 file changed, 9 insertions(+)

diff --git a/kernel/resource.c b/kernel/resource.c
index 158f04ec1d4f..95340cb0b1c2 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -1200,6 +1200,15 @@ void __release_region(struct resource *parent,

resource_size_t start,

 write_unlock(&resource_lock);
 if (res->flags & IORESOURCE_MUXED)
 wake_up(&muxed_resource_wait);
+
+   write_lock(&resource_lock);


Nit, should't this be written so that you only drop/get the lock if the
above if statement is true?


What if some other async part invalidates the child while accessing it?
I wanted to make sure that the res->child is valid through the time it is 
accessed.


+   if (res->child) {
+   printk(KERN_WARNING "__release_region: %s has 
child

%s,"

+   "invalidating childs parent\n",
+   res->name, res->child->name);


What can userspace/anyone do about this if it triggers?


At least a platform driver developer can see he did something wrong.
I had a look at the code of Hans and did not see anything weird.
(platform driver is in drivers/usb/host/xhci-ext-caps.c)
The issue is very racy - what happens when the platform code accesses the
resource mainly depends on if the freed resource memory already has been
reused by someone.


We are talking memory-mapped io here, so it cannot just be "re-used", it
is wat it is. I guess the PCI BAR could be released and then the physical
address the resource was at could be re-used for another piece of MMIo,
but AFAIK outside of PI=CI hotplug we never release BARs.

Maybe we need to ref-count resources and have the aprent free only be
a deref and not release the resource until the child resource also
is free-ed doing another deref?

I must say that to me it sometimes just seems like always allowing unbind
is a bad idea. Another example of this is things like virtio, where
we can have a filesystem based on virtio-block, but the virtio interface
between the hypervisor and the guest-kernel is a PCI-device and in theory
the user could unbind the virtio driver from that PCI-device, after which
the whole house comes crashing down.

I also know that the extcon framework in its current incarnaton
does not deal with unbind properly...

Maybe it is time that we allow drivers to block unbind instead of
trying to support unbind in really complex situations where normal
use-cases will never need it ?

I do realize unbind is very useful for driver developent without
rebooting.


It was hard to find that, and only a single core dump enabled me to find it.
A first attempt was to set resource count to 0 in Hans' driver in the unregister
pdev before calling platform_device_unregis

[PATCH v2 3/3] usb: typec: fusb302: Revert "Resolve fixed power role contract setup"

2019-04-16 Thread Hans de Goede
Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. But for single-role ports we've so far been
falling back to just calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

Commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup") fixed SRPs not working because of this by making the
fusb302 driver start connection detection on every tcpm_set_cc() call.
It turns out this breaks src->snk power-role swapping because during the
swap we first set the Cc pins to Rp, calling set_cc, and then send a PS_RDY
message. But the fusb302 cannot send PD messages while its toggling engine
is active, so sending the PS_RDY message fails.

Struct tcpc_dev now has a new start_srp_connection_detect callback and
fusb302.c now implements this. This callback gets called when we the
fusb302 needs to start connection detection, fixing fusb302 SRPs not
seeing connected devices.

This allows us to revert the changes to fusb302's set_cc implementation,
making it once again purely setup the Cc-s and matching disconnect
detection, fixing src->snk power-role swapping no longer working.

Note that since the code was refactored in between, codewise this is not a
straight forward revert. Functionality wise this is a straight revert and
the original functionality is fully restored.

Fixes: ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
Changes in v2:
-No changes
---
 drivers/usb/typec/tcpm/fusb302.c | 55 ++--
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index ba030b03d156..4328a6cbfb69 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -606,19 +606,16 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
FUSB_REG_SWITCHES0_CC2_PU_EN |
FUSB_REG_SWITCHES0_CC1_PD_EN |
FUSB_REG_SWITCHES0_CC2_PD_EN;
-   u8 switches0_data = 0x00;
+   u8 rd_mda, switches0_data = 0x00;
int ret = 0;
-   enum toggling_mode mode;
 
mutex_lock(&chip->lock);
switch (cc) {
case TYPEC_CC_OPEN:
-   mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
  FUSB_REG_SWITCHES0_CC2_PD_EN;
-   mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
@@ -626,7 +623,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
  FUSB_REG_SWITCHES0_CC1_PU_EN :
  FUSB_REG_SWITCHES0_CC2_PU_EN;
-   mode = TOGGLING_MODE_SRC;
break;
default:
fusb302_log(chip, "unsupported cc value %s",
@@ -637,6 +633,12 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
 
+   ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
+   if (ret < 0) {
+   fusb302_log(chip, "cannot set toggling mode, ret=%d", ret);
+   goto done;
+   }
+
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
 switches0_mask, switches0_data);
if (ret < 0) {
@@ -655,10 +657,45 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
goto done;
}
 
-   ret = fusb302_set_toggling(chip, mode);
-   if (ret < 0)
-   fusb302_log(chip, "cannot set toggling mode, ret=%d", ret);
-
+   /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
+   switch (cc) {
+   case TYPEC_CC_RP_DEF:
+   case TYPEC_CC_RP_1_5:
+   case TYPEC_CC_RP_3_0:
+   rd_mda = rd_mda_value[cc_src_current[cc]];
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0) {
+   fusb302_log(chip,
+   "cannot set SRC measure value, ret=%d",
+   ret);
+   goto done;
+   }
+   ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
+   

[PATCH v2 1/3] usb: typec: tcpm: Notify the tcpc to start connection-detection for SRPs

2019-04-16 Thread Hans de Goede
Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. Sofar we lack a similar callback to the tcpc
for single-role ports. With some tcpc-s such as the fusb302 this means
no TCPM_CC_EVENTs will be generated when the port is configured as a
single-role port.

This commit renames start_drp_toggling to start_toggling and since the
device-properties are parsed by the tcpm-core, adds a port_type parameter
to the start_toggling callback so that the tcpc_dev driver knows the
port-type and can act accordingly when it starts toggling.

The new start_toggling callback now always gets called if defined, instead
of only being called for DRP ports.

To avoid this causing undesirable functional changes all existing
start_drp_toggling implementations are not only renamed to start_toggling,
but also get a port_type check added and return -EOPNOTSUPP when port_type
is not DRP.

Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
Changes in v2:
-Rename start_drp_toggling to start_toggling and make it multi-purpose,
 rather then adding a new start_srp_connection_detect callback
---
 drivers/usb/typec/tcpm/fusb302.c | 10 +++---
 drivers/usb/typec/tcpm/tcpci.c   | 10 +++---
 drivers/usb/typec/tcpm/tcpm.c| 32 ++--
 drivers/usb/typec/tcpm/wcove.c   | 10 +++---
 include/linux/usb/tcpm.h | 13 +++--
 5 files changed, 42 insertions(+), 33 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 6ea6199caafa..6d83891cc895 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -876,13 +876,17 @@ static int tcpm_set_roles(struct tcpc_dev *dev, bool 
attached,
return ret;
 }
 
-static int tcpm_start_drp_toggling(struct tcpc_dev *dev,
-  enum typec_cc_status cc)
+static int tcpm_start_toggling(struct tcpc_dev *dev,
+  enum typec_port_type port_type,
+  enum typec_cc_status cc)
 {
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
 tcpc_dev);
int ret = 0;
 
+   if (port_type != TYPEC_PORT_DRP)
+   return -EOPNOTSUPP;
+
mutex_lock(&chip->lock);
ret = fusb302_set_src_current(chip, cc_src_current[cc]);
if (ret < 0) {
@@ -1094,7 +1098,7 @@ static void init_tcpc_dev(struct tcpc_dev 
*fusb302_tcpc_dev)
fusb302_tcpc_dev->set_vbus = tcpm_set_vbus;
fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx;
fusb302_tcpc_dev->set_roles = tcpm_set_roles;
-   fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
+   fusb302_tcpc_dev->start_toggling = tcpm_start_toggling;
fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
 }
 
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c
index ac6b418b15f1..c1f7073a56de 100644
--- a/drivers/usb/typec/tcpm/tcpci.c
+++ b/drivers/usb/typec/tcpm/tcpci.c
@@ -100,13 +100,17 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum 
typec_cc_status cc)
return 0;
 }
 
-static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
-   enum typec_cc_status cc)
+static int tcpci_start_toggling(struct tcpc_dev *tcpc,
+   enum typec_port_type port_type,
+   enum typec_cc_status cc)
 {
int ret;
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
unsigned int reg = TCPC_ROLE_CTRL_DRP;
 
+   if (port_type != TYPEC_PORT_DRP)
+   return -EOPNOTSUPP;
+
/* Handle vendor drp toggling */
if (tcpci->data->start_drp_toggling) {
ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc);
@@ -511,7 +515,7 @@ struct tcpci *tcpci_register_port(struct device *dev, 
struct tcpci_data *data)
tcpci->tcpc.get_cc = tcpci_get_cc;
tcpci->tcpc.set_polarity = tcpci_set_polarity;
tcpci->tcpc.set_vconn = tcpci_set_vconn;
-   tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling;
+   tcpci->tcpc.start_toggling = tcpci_start_toggling;
 
tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
tcpci->tcpc.set_roles = tcpci_set_roles;
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a2233d72ae7c..fba32d84e578 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -31,7 +31,7 @@
 
 #define FOREACH_STATE(S)   \
S(INVALID_STATE),   \
-   S(DRP_TOGGLING),   

[PATCH v2 2/3] usb: typec: fusb302: Implement start_toggling for all port-types

2019-04-16 Thread Hans de Goede
When in single-role port mode, we must start single-role toggling to
get an interrupt when a device / cable gets plugged into the port.

This commit modifies the fusb302 start_toggling implementation to
start toggling for all port-types, so that connection-detection works
on single-role ports too.

Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
Changes in v2:
-Adjust for the tcpm core renaming start_drp_toggling to start_toggling,
 instead of adding a new start_srp_connection_detect callback
---
 drivers/usb/typec/tcpm/fusb302.c | 16 +---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 6d83891cc895..ba030b03d156 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -882,10 +882,20 @@ static int tcpm_start_toggling(struct tcpc_dev *dev,
 {
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
 tcpc_dev);
+   enum toggling_mode mode = TOGGLING_MODE_OFF;
int ret = 0;
 
-   if (port_type != TYPEC_PORT_DRP)
-   return -EOPNOTSUPP;
+   switch (port_type) {
+   case TYPEC_PORT_SRC:
+   mode = TOGGLING_MODE_SRC;
+   break;
+   case TYPEC_PORT_SNK:
+   mode = TOGGLING_MODE_SNK;
+   break;
+   case TYPEC_PORT_DRP:
+   mode = TOGGLING_MODE_DRP;
+   break;
+   }
 
mutex_lock(&chip->lock);
ret = fusb302_set_src_current(chip, cc_src_current[cc]);
@@ -894,7 +904,7 @@ static int tcpm_start_toggling(struct tcpc_dev *dev,
typec_cc_status_name[cc], ret);
goto done;
}
-   ret = fusb302_set_toggling(chip, TOGGLING_MODE_DRP);
+   ret = fusb302_set_toggling(chip, mode);
if (ret < 0) {
fusb302_log(chip,
"unable to start drp toggling, ret=%d", ret);
-- 
2.21.0



Re: [PATCH 1/3] usb: typec: tcpm: Add start_srp_connection_detect callback

2019-04-16 Thread Hans de Goede

Hi,

On 15-04-19 20:38, Guenter Roeck wrote:

On Mon, Apr 15, 2019 at 07:53:58PM +0200, Hans de Goede wrote:

Hi Guenter,

On 15-04-19 17:51, Guenter Roeck wrote:

On Sat, Apr 13, 2019 at 10:39:53PM +0200, Hans de Goede wrote:

Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. But for single-role ports we've so far been
falling back to just calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

This commit adds a new start_srp_connection_detect callback to tcpc_dev
and when this is implemented calls this in place of start_drp_toggling
for SRP devices.



Do we indeed need an additional callback for this purpose, or would a single
"start_connection_detect" call to replace start_drp_toggling be sufficient ?
If necessary, we could add the port type as argument (if the low level driver
doesn't already know that).


A single "start_connection_detect" call to replace start_drp_toggling will be
sufficient AFAICT.

If you prefer that option, I can rework the patch-set accordingly.



Yes, I do. I find it quite pointless to have two callbacks if exactly one
is ever called.


Ok, I've refactored this as requested for v2.

Regards,

Hans



Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/tcpm.c | 8 
  include/linux/usb/tcpm.h  | 6 ++
  2 files changed, 14 insertions(+)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a2233d72ae7c..1af54af90b50 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2553,6 +2553,14 @@ static bool tcpm_start_drp_toggling(struct tcpm_port 
*port,
return true;
}
+   if (port->tcpc->start_srp_connection_detect &&
+   port->port_type != TYPEC_PORT_DRP) {
+   tcpm_log_force(port, "Start SRP connection detection");
+   ret = port->tcpc->start_srp_connection_detect(port->tcpc, cc);
+   if (!ret)
+   return true;
+   }
+
return false;
  }
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index 0c532ca3f079..bf2bbbf2e2b2 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -125,6 +125,10 @@ struct tcpc_config {
   *Optional; if supported by hardware, called to start DRP
   *toggling. DRP toggling is stopped automatically if
   *a connection is established.
+ * @start_srp_connection_detect:
+ * Optional; if supported by hardware, called to start connection
+ * detection for single role ports. Connection detection is stopped
+ * automatically if a connection is established.
   * @try_role: Optional; called to set a preferred role
   * @pd_transmit:Called to transmit PD message
   * @mux:  Pointer to multiplexer data
@@ -149,6 +153,8 @@ struct tcpc_dev {
 enum typec_role role, enum typec_data_role data);
int (*start_drp_toggling)(struct tcpc_dev *dev,
  enum typec_cc_status cc);
+   int (*start_srp_connection_detect)(struct tcpc_dev *dev,
+  enum typec_cc_status cc);
int (*try_role)(struct tcpc_dev *dev, int role);
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
   const struct pd_message *msg);
--
2.21.0



Re: [PATCH 2/3] usb: typec: fusb302: Implement start_srp_connection_detect

2019-04-16 Thread Hans de Goede

Hi,

Thank you for the review.

On 14-04-19 09:40, Sergei Shtylyov wrote:

Hello!

On 13.04.2019 23:39, Hans de Goede wrote:


When in single role port mode, we most start single-role toggling to


    Must, perhaps?


Right, fixed for the upcoming v2 of the patch-set.


get an interrupt when a device / cable gets plugged into the port.

This commit implements the tcpc_dev start_srp_connection_detect callback
for this.

Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/fusb302.c | 30 ++
  1 file changed, 30 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 6ea6199caafa..30413a45104f 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -876,6 +876,34 @@ static int tcpm_set_roles(struct tcpc_dev *dev, bool 
attached,
  return ret;
  }
+static int tcpm_start_srp_connection_detect(struct tcpc_dev *dev,
+    enum typec_cc_status cc)
+{
+    struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
+ tcpc_dev);
+    int ret = 0;


    This initializer is useless.


Ack, this part is gone for v2 of the patch though.

Regards,

Hans






+
+    mutex_lock(&chip->lock);
+    ret = fusb302_set_src_current(chip, cc_src_current[cc]);
+    if (ret < 0) {
+    fusb302_log(chip, "unable to set src current %s, ret=%d",
+    typec_cc_status_name[cc], ret);
+    goto done;
+    }
+    ret = fusb302_set_toggling(chip, (cc == TYPEC_CC_RD) ?
+ TOGGLING_MODE_SNK : TOGGLING_MODE_SRC);
+    if (ret < 0) {
+    fusb302_log(chip,
+    "unable to start srp toggling, ret=%d", ret);
+    goto done;
+    }
+    fusb302_log(chip, "start srp toggling");
+done:
+    mutex_unlock(&chip->lock);
+
+    return ret;
+}
+
  static int tcpm_start_drp_toggling(struct tcpc_dev *dev,
 enum typec_cc_status cc)
  {

[...]

MBR, Sergei


Re: [PATCH 1/3] usb: typec: tcpm: Add start_srp_connection_detect callback

2019-04-15 Thread Hans de Goede

Hi Guenter,

On 15-04-19 17:51, Guenter Roeck wrote:

On Sat, Apr 13, 2019 at 10:39:53PM +0200, Hans de Goede wrote:

Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. But for single-role ports we've so far been
falling back to just calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

This commit adds a new start_srp_connection_detect callback to tcpc_dev
and when this is implemented calls this in place of start_drp_toggling
for SRP devices.



Do we indeed need an additional callback for this purpose, or would a single
"start_connection_detect" call to replace start_drp_toggling be sufficient ?
If necessary, we could add the port type as argument (if the low level driver
doesn't already know that).


A single "start_connection_detect" call to replace start_drp_toggling will be
sufficient AFAICT.

If you prefer that option, I can rework the patch-set accordingly.

Regards,

Hans




Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/tcpm.c | 8 
  include/linux/usb/tcpm.h  | 6 ++
  2 files changed, 14 insertions(+)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a2233d72ae7c..1af54af90b50 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2553,6 +2553,14 @@ static bool tcpm_start_drp_toggling(struct tcpm_port 
*port,
return true;
}
  
+	if (port->tcpc->start_srp_connection_detect &&

+   port->port_type != TYPEC_PORT_DRP) {
+   tcpm_log_force(port, "Start SRP connection detection");
+   ret = port->tcpc->start_srp_connection_detect(port->tcpc, cc);
+   if (!ret)
+   return true;
+   }
+
return false;
  }
  
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h

index 0c532ca3f079..bf2bbbf2e2b2 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -125,6 +125,10 @@ struct tcpc_config {
   *Optional; if supported by hardware, called to start DRP
   *toggling. DRP toggling is stopped automatically if
   *a connection is established.
+ * @start_srp_connection_detect:
+ * Optional; if supported by hardware, called to start connection
+ * detection for single role ports. Connection detection is stopped
+ * automatically if a connection is established.
   * @try_role: Optional; called to set a preferred role
   * @pd_transmit:Called to transmit PD message
   * @mux:  Pointer to multiplexer data
@@ -149,6 +153,8 @@ struct tcpc_dev {
 enum typec_role role, enum typec_data_role data);
int (*start_drp_toggling)(struct tcpc_dev *dev,
  enum typec_cc_status cc);
+   int (*start_srp_connection_detect)(struct tcpc_dev *dev,
+  enum typec_cc_status cc);
int (*try_role)(struct tcpc_dev *dev, int role);
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
   const struct pd_message *msg);
--
2.21.0



Re: [PATCH 1/3] usb: typec: tcpm: Add start_srp_connection_detect callback

2019-04-15 Thread Hans de Goede

Hi,

On 15-04-19 12:31, Adam Thomson wrote:

On 13 April 2019 21:40, Hans de Goede wrote:


Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to watch 
for
connection events. But for single-role ports we've so far been falling back to 
just
calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

This commit adds a new start_srp_connection_detect callback to tcpc_dev and
when this is implemented calls this in place of start_drp_toggling for SRP 
devices.

Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/tcpm.c | 8 
  include/linux/usb/tcpm.h  | 6 ++
  2 files changed, 14 insertions(+)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a2233d72ae7c..1af54af90b50 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2553,6 +2553,14 @@ static bool tcpm_start_drp_toggling(struct tcpm_port
*port,
return true;
}

+   if (port->tcpc->start_srp_connection_detect &&
+   port->port_type != TYPEC_PORT_DRP) {
+   tcpm_log_force(port, "Start SRP connection detection");
+   ret = port->tcpc->start_srp_connection_detect(port->tcpc, cc);
+   if (!ret)
+   return true;
+   }
+


Is it a little misleading when reading the state machine code that we're calling
tcpm_start_drp_toggling() to actually start SRP detection? Maybe we could rename
this function and the associated state to cover both SRP and DRP, or
alternatively add a new state for SRP_DETECTION, just to keep logging and code
readability clear and then move the above code to a different function just for
SRP?


I'm not in fan of adding a separate state for this. Even though connection
detection is not really toggling, I've considered changing
tcpm_start_drp_toggling to tcpm_start_toggling and rename the state to match.
I think that if we want to drop drp/DRP from the names, that using
tcpm_start_toggling / TOGGLING is the best solution.

Also note that on the fusb302, which is the tcpc which needs SRP connection
detection, this is done using the toggling engine. So just changing the
names from drp-toggling to toggling seems best.

Regards,

Hans





Functionally though, the change makes sense to me.


return false;
  }

diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index
0c532ca3f079..bf2bbbf2e2b2 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -125,6 +125,10 @@ struct tcpc_config {
   *Optional; if supported by hardware, called to start DRP
   *toggling. DRP toggling is stopped automatically if
   *a connection is established.
+ * @start_srp_connection_detect:
+ * Optional; if supported by hardware, called to start connection
+ * detection for single role ports. Connection detection is stopped
+ * automatically if a connection is established.
   * @try_role: Optional; called to set a preferred role
   * @pd_transmit:Called to transmit PD message
   * @mux:  Pointer to multiplexer data
@@ -149,6 +153,8 @@ struct tcpc_dev {
 enum typec_role role, enum typec_data_role data);
int (*start_drp_toggling)(struct tcpc_dev *dev,
  enum typec_cc_status cc);
+   int (*start_srp_connection_detect)(struct tcpc_dev *dev,
+  enum typec_cc_status cc);
int (*try_role)(struct tcpc_dev *dev, int role);
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type
type,
   const struct pd_message *msg);
--
2.21.0


[PATCH 2/3] usb: typec: fusb302: Implement start_srp_connection_detect

2019-04-13 Thread Hans de Goede
When in single role port mode, we most start single-role toggling to
get an interrupt when a device / cable gets plugged into the port.

This commit implements the tcpc_dev start_srp_connection_detect callback
for this.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 30 ++
 1 file changed, 30 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 6ea6199caafa..30413a45104f 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -876,6 +876,34 @@ static int tcpm_set_roles(struct tcpc_dev *dev, bool 
attached,
return ret;
 }
 
+static int tcpm_start_srp_connection_detect(struct tcpc_dev *dev,
+   enum typec_cc_status cc)
+{
+   struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
+tcpc_dev);
+   int ret = 0;
+
+   mutex_lock(&chip->lock);
+   ret = fusb302_set_src_current(chip, cc_src_current[cc]);
+   if (ret < 0) {
+   fusb302_log(chip, "unable to set src current %s, ret=%d",
+   typec_cc_status_name[cc], ret);
+   goto done;
+   }
+   ret = fusb302_set_toggling(chip, (cc == TYPEC_CC_RD) ?
+TOGGLING_MODE_SNK : TOGGLING_MODE_SRC);
+   if (ret < 0) {
+   fusb302_log(chip,
+   "unable to start srp toggling, ret=%d", ret);
+   goto done;
+   }
+   fusb302_log(chip, "start srp toggling");
+done:
+   mutex_unlock(&chip->lock);
+
+   return ret;
+}
+
 static int tcpm_start_drp_toggling(struct tcpc_dev *dev,
   enum typec_cc_status cc)
 {
@@ -1095,6 +1123,8 @@ static void init_tcpc_dev(struct tcpc_dev 
*fusb302_tcpc_dev)
fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx;
fusb302_tcpc_dev->set_roles = tcpm_set_roles;
fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
+   fusb302_tcpc_dev->start_srp_connection_detect =
+   tcpm_start_srp_connection_detect;
fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit;
 }
 
-- 
2.21.0



[PATCH 1/3] usb: typec: tcpm: Add start_srp_connection_detect callback

2019-04-13 Thread Hans de Goede
Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. But for single-role ports we've so far been
falling back to just calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

This commit adds a new start_srp_connection_detect callback to tcpc_dev
and when this is implemented calls this in place of start_drp_toggling
for SRP devices.

Fixes: ea3b4d5523bc("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/tcpm.c | 8 
 include/linux/usb/tcpm.h  | 6 ++
 2 files changed, 14 insertions(+)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index a2233d72ae7c..1af54af90b50 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -2553,6 +2553,14 @@ static bool tcpm_start_drp_toggling(struct tcpm_port 
*port,
return true;
}
 
+   if (port->tcpc->start_srp_connection_detect &&
+   port->port_type != TYPEC_PORT_DRP) {
+   tcpm_log_force(port, "Start SRP connection detection");
+   ret = port->tcpc->start_srp_connection_detect(port->tcpc, cc);
+   if (!ret)
+   return true;
+   }
+
return false;
 }
 
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h
index 0c532ca3f079..bf2bbbf2e2b2 100644
--- a/include/linux/usb/tcpm.h
+++ b/include/linux/usb/tcpm.h
@@ -125,6 +125,10 @@ struct tcpc_config {
  * Optional; if supported by hardware, called to start DRP
  * toggling. DRP toggling is stopped automatically if
  * a connection is established.
+ * @start_srp_connection_detect:
+ * Optional; if supported by hardware, called to start connection
+ * detection for single role ports. Connection detection is stopped
+ * automatically if a connection is established.
  * @try_role:  Optional; called to set a preferred role
  * @pd_transmit:Called to transmit PD message
  * @mux:   Pointer to multiplexer data
@@ -149,6 +153,8 @@ struct tcpc_dev {
 enum typec_role role, enum typec_data_role data);
int (*start_drp_toggling)(struct tcpc_dev *dev,
  enum typec_cc_status cc);
+   int (*start_srp_connection_detect)(struct tcpc_dev *dev,
+  enum typec_cc_status cc);
int (*try_role)(struct tcpc_dev *dev, int role);
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
   const struct pd_message *msg);
-- 
2.21.0



[PATCH 3/3] usb: typec: fusb302: Revert "Resolve fixed power role contract setup"

2019-04-13 Thread Hans de Goede
Some tcpc device-drivers need to explicitly be told to watch for connection
events, otherwise the tcpc will not generate any TCPM_CC_EVENTs and devices
being plugged into the Type-C port will not be noticed.

For dual-role ports tcpm_start_drp_toggling() is used to tell the tcpc to
watch for connection events. But for single-role ports we've so far been
falling back to just calling tcpm_set_cc(). For some tcpc-s such as the
fusb302 this is not enough and no TCPM_CC_EVENT will be generated.

Commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup") fixed SRPs not working because of this by making the
fusb302 driver start connection detection on every tcpm_set_cc() call.
It turns out this breaks src->snk power-role swapping because during the
swap we first set the Cc pins to Rp, calling set_cc, and then send a PS_RDY
message. But the fusb302 cannot send PD messages while its toggling engine
is active, so sending the PS_RDY message fails.

Struct tcpc_dev now has a new start_srp_connection_detect callback and
fusb302.c now implements this. This callback gets called when we the
fusb302 needs to start connection detection, fixing fusb302 SRPs not
seeing connected devices.

This allows us to revert the changes to fusb302's set_cc implementation,
making it once again purely setup the Cc-s and matching disconnect
detection, fixing src->snk power-role swapping no longer working.

Note that since the code was refactored in between, codewise this is not a
straight forward revert. Functionality wise this is a straight revert and
the original functionality is fully restored.

Fixes: ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role ...")
Cc: Adam Thomson 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 55 ++--
 1 file changed, 46 insertions(+), 9 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 30413a45104f..96da41f82834 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -606,19 +606,16 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
FUSB_REG_SWITCHES0_CC2_PU_EN |
FUSB_REG_SWITCHES0_CC1_PD_EN |
FUSB_REG_SWITCHES0_CC2_PD_EN;
-   u8 switches0_data = 0x00;
+   u8 rd_mda, switches0_data = 0x00;
int ret = 0;
-   enum toggling_mode mode;
 
mutex_lock(&chip->lock);
switch (cc) {
case TYPEC_CC_OPEN:
-   mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
  FUSB_REG_SWITCHES0_CC2_PD_EN;
-   mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
@@ -626,7 +623,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
  FUSB_REG_SWITCHES0_CC1_PU_EN :
  FUSB_REG_SWITCHES0_CC2_PU_EN;
-   mode = TOGGLING_MODE_SRC;
break;
default:
fusb302_log(chip, "unsupported cc value %s",
@@ -637,6 +633,12 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
 
+   ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
+   if (ret < 0) {
+   fusb302_log(chip, "cannot set toggling mode, ret=%d", ret);
+   goto done;
+   }
+
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
 switches0_mask, switches0_data);
if (ret < 0) {
@@ -655,10 +657,45 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
goto done;
}
 
-   ret = fusb302_set_toggling(chip, mode);
-   if (ret < 0)
-   fusb302_log(chip, "cannot set toggling mode, ret=%d", ret);
-
+   /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
+   switch (cc) {
+   case TYPEC_CC_RP_DEF:
+   case TYPEC_CC_RP_1_5:
+   case TYPEC_CC_RP_3_0:
+   rd_mda = rd_mda_value[cc_src_current[cc]];
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0) {
+   fusb302_log(chip,
+   "cannot set SRC measure value, ret=%d",
+   ret);
+   goto done;
+   }
+   ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
+FUSB_REG_MASK_BC_LVL |
+FUSB_REG_MASK_C

Re: Question about regulators

2019-04-09 Thread Hans de Goede

Hi,

On 09-04-19 09:26, Miquel Raynal wrote:

Hello,

Adding Greg & Hans just in case they have an idea, or someone else to
ping in mind.

Miquel Raynal  wrote on Wed, 3 Apr 2019
10:13:43 +0200:


Hello,

I am reading the document named "xHCI interoperability testing v0.94"
available on usb.org. There is this paragraph:

 Devices operating at Enhanced SuperSpeed GenX are allowed to
 draw a maximum configured current of 900mA and unconfigured
 current of 150mA. Devices operating at High-Speed or below may
 draw a maximum configured current of 500mA and unconfigured
 current of 100mA*. Devices must report their maximum configured
 current draw and their power configuration as self or bus
 powered to the host and must operate within the regions
 reported. Additionally any device that is in the suspended
 state may draw no more than 2.5 mA.

My understanding is that the current limitation on Vbus should be tuned
dynamically between 100, 150, 500 and 900mA depending on the type of
device and if has been configured or not.

Despite some researches in the USB core I can't find any mechanism
handling this in Linux implementation.

Behind this remark, I actually have boards (Armada 7040/8040 DB) with a
regulator on Vbus to limit the current to either 500 or 900mA. I
checked the xhci-platform driver which is used with these SoCs and I
don't find any mean to tweak this value depending on the inserted
device.

Should I actually care? Is it enough to limit to 900mA whenever the
xHCI driver is probed?


To be clear you are talking about a regulator producing Vbus for device
plugged into the system, right ?

In that case just configuring th current-limit at 900mA is fine, it really
is up to the device to not consume more then it may and even if it does since
the port is capable of delivering 900mA anyways that is not a problem.

There is code in various places in the kernel for Linux devices to not
consume too much energy (mostly in charger ic drivers) when the Linux
device itself is an USB device drawing power.

Regards,

Hans



Re: [PATCH] usb: typec: Registering real device entries for the muxes

2019-04-01 Thread Hans de Goede

HI,

On 01-04-19 14:40, Heikki Krogerus wrote:

On Mon, Apr 01, 2019 at 12:34:29PM +0200, Greg KH wrote:

On Mon, Apr 01, 2019 at 01:15:53PM +0300, Heikki Krogerus wrote:

Registering real device entries (struct device) for the mode
muxes as well as for the orientation switches.

The Type-C mux code was deliberately attempting to avoid
creation of separate device entries for the orientation
switch and the mode switch (alternate modes) because they
are not physical devices. They are functions of a single
physical multiplexer/demultiplexer switch device.

Unfortunately because of the dependency we still have on the
underlying mux device driver, we had to put in hacks like
the one in the commit 3e3b81965cbf ("usb: typec: mux: Take
care of driver module reference counting") to make sure the
driver does not disappear from underneath us. Even with
those hacks we were still left with a potential NUll pointer
dereference scenario, so just creating the device entries,
and letting the core take care of the dependencies. No more
hacks needed.

Fixes: 3e3b81965cbf ("usb: typec: mux: Take care of driver module reference 
counting")
Cc: v4.19.x  # v4.19.x+
Signed-off-by: Heikki Krogerus 


This looks good to me, nice work!

But, it would be nice if someone who has this hardware can test it to
verify it does actually work :)


This alone does not work on Intel Cherrytrail platforms. I need to make
the Intel Cherrytrail MFD driver (intel_cht_int33fe.c) to use the new
device names that we now have for the muxes. Sorry for the mistake.

I'll resend this and include the needed modifications to
intel_cht_int33fe.c. Hans should be able to test this once I do that. I
hope he has time.


Yes I need to get back to the CherryTrail Type-C stuff we discussed a while
back anyways. On which tree/branch should I test v2 of this patch(series) ?

Regards,

Hans


[PATCH v2] usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps

2019-03-16 Thread Hans de Goede
PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
simply ignore any src PDOs which the sink does not understand such as PPS
but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
causing contract negotiation to fail.

This commit fixes such sinks not working by re-trying the contract
negotiation with PD-2.0 source-caps messages if we don't have a contract
after PD_N_HARD_RESET_COUNT hard-reset attempts.

The problem fixed by this commit was noticed with a Type-C to VGA dongle.

Signed-off-by: Hans de Goede 
---
The Type-C to VGA dongle on which this encountered looks like this one:
https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
---
Changes in v2:
-Refactor the patch to avoid a check vs use race wrt negotiated_rev
---
 drivers/usb/typec/tcpm/tcpm.c | 27 ++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index f1c39a3c7534..d34e945e5d09 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -37,6 +37,7 @@
S(SRC_ATTACHED),\
S(SRC_STARTUP), \
S(SRC_SEND_CAPABILITIES),   \
+   S(SRC_SEND_CAPABILITIES_TIMEOUT),   \
S(SRC_NEGOTIATE_CAPABILITIES),  \
S(SRC_TRANSITION_SUPPLY),   \
S(SRC_READY),   \
@@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcpm_port *port)
/* port->hard_reset_count = 0; */
port->caps_count = 0;
port->pd_capable = true;
-   tcpm_set_state_cond(port, hard_reset_state(port),
+   tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT,
PD_T_SEND_SOURCE_CAP);
}
break;
+   case SRC_SEND_CAPABILITIES_TIMEOUT:
+   /*
+* Error recovery for a PD_DATA_SOURCE_CAP reply timeout.
+*
+* PD 2.0 sinks are supposed to accept src-capabilities with a
+* 3.0 header and simply ignore any src PDOs which the sink does
+* not understand such as PPS but some 2.0 sinks instead ignore
+* the entire PD_DATA_SOURCE_CAP message, causing contract
+* negotiation to fail.
+*
+* After PD_N_HARD_RESET_COUNT hard-reset attempts, we try
+* sending src-capabilities with a lower PD revision to
+* make these broken sinks work.
+*/
+   if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) {
+   tcpm_set_state(port, HARD_RESET_SEND, 0);
+   } else if (port->negotiated_rev > PD_REV20) {
+   port->negotiated_rev--;
+   port->hard_reset_count = 0;
+   tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+   } else {
+   tcpm_set_state(port, hard_reset_state(port), 0);
+   }
+   break;
case SRC_NEGOTIATE_CAPABILITIES:
ret = tcpm_pd_check_request(port);
if (ret < 0) {
-- 
2.20.1



Re: [PATCH] usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps

2019-03-16 Thread Hans de Goede

Hi,

On 15-03-19 17:53, Guenter Roeck wrote:

On Fri, Mar 15, 2019 at 05:43:05PM +0100, Hans de Goede wrote:

Hi,

On 3/15/19 3:57 PM, Guenter Roeck wrote:

On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:

PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
simply ignore any src PDOs which the sink does not understand such as PPS
but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
causing contract negotiation to fail.

This commit fixes such sinks not working by re-trying the contract
negotiation with PD-2.0 source-caps messages if we don't have a contract
after PD_N_HARD_RESET_COUNT hard-reset attempts.

The problem fixed by this commit was noticed with a Type-C to VGA dongle.

Signed-off-by: Hans de Goede 
---
The Type-C to VGA dongle on which this encountered looks like this one:
https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
---
  drivers/usb/typec/tcpm/tcpm.c | 34 +-
  1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index f1c39a3c7534..3f8df845d1a5 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -37,6 +37,7 @@
S(SRC_ATTACHED),\
S(SRC_STARTUP), \
S(SRC_SEND_CAPABILITIES),   \
+   S(SRC_SEND_CAP_LOWER_PD_REVISION),  \
S(SRC_NEGOTIATE_CAPABILITIES),  \
S(SRC_TRANSITION_SUPPLY),   \
S(SRC_READY),   \
@@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct 
tcpm_port *port)
return SNK_UNATTACHED;
  }
+/*
+ * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
+ * simply ignore any src PDOs which the sink does not understand such as PPS
+ * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
+ * causing contract negotiation to fail.
+ *
+ * This function is used by the SRC_SEND_CAPABILITIES state in
+ * run_state_machine() to work around this.
+ *
+ * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
+ * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
+ * this state will fallback to a lower PD revision and then try sending the
+ * src-capabilities again.
+ */
+static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port 
*port)
+{
+   if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
+   return HARD_RESET_SEND;
+   if (port->negotiated_rev > PD_REV20)
+   return SRC_SEND_CAP_LOWER_PD_REVISION;
+   return hard_reset_state(port);
+}
+
  static inline enum tcpm_state unattached_state(struct tcpm_port *port)
  {
if (port->port_type == TYPEC_PORT_DRP) {
@@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
/* port->hard_reset_count = 0; */
port->caps_count = 0;
port->pd_capable = true;
-   tcpm_set_state_cond(port, hard_reset_state(port),
+   tcpm_set_state_cond(port,
+   src_send_cap_timeout_state(port),
PD_T_SEND_SOURCE_CAP);
}
break;
+   case SRC_SEND_CAP_LOWER_PD_REVISION:
+   if (WARN_ON(port->negotiated_rev <= PD_REV20))
+   break;


I really dislike the WARN_ON here. A bad remote can potentially trigger
this, which on systems with crash on warning enabled can result in a
reboot. Just revert to the original behavior here, and maybe add
a tcpm log message.


How would a bad remote trigger this?

We only ever call set_state with SRC_SEND_CAP_LOWER_PD_REVISION in the new
src_send_cap_timeout_state which has:

if (port->negotiated_rev > PD_REV20)
return SRC_SEND_CAP_LOWER_PD_REVISION;

So we really should never hit the WARN_ON, of we do hit the WARN_ON
something is seriously wrong.



If that situation can't happen, the check should not be there in the first
place. Otherwise you could litter the implementation with WARN_ON all over
the place, and make it all but unreadable. I am not in favor of code like
that.


So thinking more about this, the WARN_ON can actually trigger if we
receive a pd packet with a lower revision during the timeout window and
this does not cause the state to change.

This is an obvious time of check vs time of use problem and the fix is
to check if we should try to fallback / check the negotiated_rev after
the timeout, rather then when determining the next state to use after
the timeout, so that both the check and the decrement of negotiated_rev
are done in one go while holding the lock. I will rework the patch
accordi

Re: [PATCH] usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps

2019-03-15 Thread Hans de Goede

Hi,

On 3/15/19 3:57 PM, Guenter Roeck wrote:

On Fri, Mar 15, 2019 at 03:42:19PM +0100, Hans de Goede wrote:

PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
simply ignore any src PDOs which the sink does not understand such as PPS
but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
causing contract negotiation to fail.

This commit fixes such sinks not working by re-trying the contract
negotiation with PD-2.0 source-caps messages if we don't have a contract
after PD_N_HARD_RESET_COUNT hard-reset attempts.

The problem fixed by this commit was noticed with a Type-C to VGA dongle.

Signed-off-by: Hans de Goede 
---
The Type-C to VGA dongle on which this encountered looks like this one:
https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
---
  drivers/usb/typec/tcpm/tcpm.c | 34 +-
  1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index f1c39a3c7534..3f8df845d1a5 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -37,6 +37,7 @@
S(SRC_ATTACHED),\
S(SRC_STARTUP), \
S(SRC_SEND_CAPABILITIES),   \
+   S(SRC_SEND_CAP_LOWER_PD_REVISION),  \
S(SRC_NEGOTIATE_CAPABILITIES),  \
S(SRC_TRANSITION_SUPPLY),   \
S(SRC_READY),   \
@@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct 
tcpm_port *port)
return SNK_UNATTACHED;
  }
  
+/*

+ * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
+ * simply ignore any src PDOs which the sink does not understand such as PPS
+ * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
+ * causing contract negotiation to fail.
+ *
+ * This function is used by the SRC_SEND_CAPABILITIES state in
+ * run_state_machine() to work around this.
+ *
+ * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
+ * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
+ * this state will fallback to a lower PD revision and then try sending the
+ * src-capabilities again.
+ */
+static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port 
*port)
+{
+   if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
+   return HARD_RESET_SEND;
+   if (port->negotiated_rev > PD_REV20)
+   return SRC_SEND_CAP_LOWER_PD_REVISION;
+   return hard_reset_state(port);
+}
+
  static inline enum tcpm_state unattached_state(struct tcpm_port *port)
  {
if (port->port_type == TYPEC_PORT_DRP) {
@@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
/* port->hard_reset_count = 0; */
port->caps_count = 0;
port->pd_capable = true;
-   tcpm_set_state_cond(port, hard_reset_state(port),
+   tcpm_set_state_cond(port,
+   src_send_cap_timeout_state(port),
PD_T_SEND_SOURCE_CAP);
}
break;
+   case SRC_SEND_CAP_LOWER_PD_REVISION:
+   if (WARN_ON(port->negotiated_rev <= PD_REV20))
+   break;


I really dislike the WARN_ON here. A bad remote can potentially trigger
this, which on systems with crash on warning enabled can result in a
reboot. Just revert to the original behavior here, and maybe add
a tcpm log message.


How would a bad remote trigger this?

We only ever call set_state with SRC_SEND_CAP_LOWER_PD_REVISION in the new
src_send_cap_timeout_state which has:

if (port->negotiated_rev > PD_REV20)
return SRC_SEND_CAP_LOWER_PD_REVISION;

So we really should never hit the WARN_ON, of we do hit the WARN_ON
something is seriously wrong.

Regards,

Hans





Guenter


+   port->negotiated_rev--;
+   port->hard_reset_count = 0;
+   tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+   break;
case SRC_NEGOTIATE_CAPABILITIES:
ret = tcpm_pd_check_request(port);
if (ret < 0) {
--
2.20.1



[PATCH] usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps

2019-03-15 Thread Hans de Goede
PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
simply ignore any src PDOs which the sink does not understand such as PPS
but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
causing contract negotiation to fail.

This commit fixes such sinks not working by re-trying the contract
negotiation with PD-2.0 source-caps messages if we don't have a contract
after PD_N_HARD_RESET_COUNT hard-reset attempts.

The problem fixed by this commit was noticed with a Type-C to VGA dongle.

Signed-off-by: Hans de Goede 
---
The Type-C to VGA dongle on which this encountered looks like this one:
https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html
---
 drivers/usb/typec/tcpm/tcpm.c | 34 +-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index f1c39a3c7534..3f8df845d1a5 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -37,6 +37,7 @@
S(SRC_ATTACHED),\
S(SRC_STARTUP), \
S(SRC_SEND_CAPABILITIES),   \
+   S(SRC_SEND_CAP_LOWER_PD_REVISION),  \
S(SRC_NEGOTIATE_CAPABILITIES),  \
S(SRC_TRANSITION_SUPPLY),   \
S(SRC_READY),   \
@@ -2792,6 +2793,29 @@ static inline enum tcpm_state hard_reset_state(struct 
tcpm_port *port)
return SNK_UNATTACHED;
 }
 
+/*
+ * PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and
+ * simply ignore any src PDOs which the sink does not understand such as PPS
+ * but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message,
+ * causing contract negotiation to fail.
+ *
+ * This function is used by the SRC_SEND_CAPABILITIES state in
+ * run_state_machine() to work around this.
+ *
+ * After PD_N_HARD_RESET_COUNT hard-reset attempts this function selects
+ * SRC_SEND_CAP_LOWER_PD_REVISION as state to set after the next timeout,
+ * this state will fallback to a lower PD revision and then try sending the
+ * src-capabilities again.
+ */
+static inline enum tcpm_state src_send_cap_timeout_state(struct tcpm_port 
*port)
+{
+   if (port->hard_reset_count < PD_N_HARD_RESET_COUNT)
+   return HARD_RESET_SEND;
+   if (port->negotiated_rev > PD_REV20)
+   return SRC_SEND_CAP_LOWER_PD_REVISION;
+   return hard_reset_state(port);
+}
+
 static inline enum tcpm_state unattached_state(struct tcpm_port *port)
 {
if (port->port_type == TYPEC_PORT_DRP) {
@@ -2966,10 +2990,18 @@ static void run_state_machine(struct tcpm_port *port)
/* port->hard_reset_count = 0; */
port->caps_count = 0;
port->pd_capable = true;
-   tcpm_set_state_cond(port, hard_reset_state(port),
+   tcpm_set_state_cond(port,
+   src_send_cap_timeout_state(port),
PD_T_SEND_SOURCE_CAP);
}
break;
+   case SRC_SEND_CAP_LOWER_PD_REVISION:
+   if (WARN_ON(port->negotiated_rev <= PD_REV20))
+   break;
+   port->negotiated_rev--;
+   port->hard_reset_count = 0;
+   tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0);
+   break;
case SRC_NEGOTIATE_CAPABILITIES:
ret = tcpm_pd_check_request(port);
if (ret < 0) {
-- 
2.20.1



Re: [PATCH v3 1/2] dt-bindings: usb: add documentation for typec switch via GPIO

2019-03-12 Thread Hans de Goede

Hi,

On 12-03-19 11:45, Heikki Krogerus wrote:

Hi,

On Tue, Mar 12, 2019 at 10:32:00AM +, Jun Li wrote:

Hi Hans

-Original Message-
From: Hans de Goede 
Sent: 2019年3月11日 19:03
To: Jun Li ; robh...@kernel.org; heikki.kroge...@linux.intel.com
Cc: gre...@linuxfoundation.org; andy.shevche...@gmail.com;
linux-usb@vger.kernel.org; devicet...@vger.kernel.org; dl-linux-imx

Subject: Re: [PATCH v3 1/2] dt-bindings: usb: add documentation for typec switch
via GPIO

Hi,

On 11-03-19 11:40, Jun Li wrote:

Some typec super speed active channel switch can be controlled via a
GPIO, this binding can be used to specify the switch node by a GPIO
and the remote endpoint of its consumer.

Signed-off-by: Li Jun 
---
   .../devicetree/bindings/usb/typec-switch-gpio.txt  | 30

++

   1 file changed, 30 insertions(+)

diff --git
a/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
new file mode 100644
index 000..4ef76cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
@@ -0,0 +1,30 @@
+Typec orientation switch via a GPIO
+---
+
+Required properties:
+- compatible: should be set one of following:
+   - "nxp,ptn36043" for NXP Type-C SuperSpeed active switch.
+
+- gpios: the GPIO used to switch the super speed active channel,
+   GPIO_ACTIVE_HIGH: GPIO state high for cc1;
+   GPIO_ACTIVE_LOW:  GPIO state low for cc1.
+- orientation-switch: must be present.


Shouldn't this have usb-c in the propery name, e.g.:
usb-c-orientation-switch  ?


This is decided by drivers/usb/typec/mux.c:36
/*
  * With OF graph the mux node must have a boolean device property named
  * "orientation-switch".
  */


Yes, but it's still OK to change it. It's not documented anywhere yet.


+
+Required sub-node:
+- port: specify the remote endpoint of typec switch consumer.
+
+Example:
+
+ptn36043 {
+   compatible = "nxp,ptn36043";
+   pinctrl-names = "default";
+   pinctrl-0 = <&pinctrl_ss_sel>;
+   gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+   orientation-switch;
+
+   port {
+   usb3_data_ss: endpoint {
+   remote-endpoint = <&typec_con_ss>;



Isn't this the wrong way around, shouldn't the "usb-c-connector"
compatible port be pointing to the orientation switch, rather then the other way
around?


Hans, in OF graph both endpoints will have a remote-endpoint pointing
to each other..


I am not sure I am getting your point, "usb-c-connector" is the user of typec 
switch,
yes, it is pointing to the orientation switch provider(i.e, this example node).


Both will work in the end. but to me it feels more natural to group all the
info about the type-c connector together in the "usb-c-connector" compatible 
port



 ptn36043 {
 compatible = "nxp,ptn36043";
 pinctrl-names = "default";
 pinctrl-0 = <&pinctrl_ss_sel>;
 gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
 orientation-switch;

 port {
 usb3_data_ss: endpoint {
 remote-endpoint = <&typec_con_ss>;
 };
 };
 };

usb_con: connector {
compatible = "usb-c-connector";
...
ports {
#address-cells = <1>;
#size-cells = <0>;

port@1 {
reg = <1>;
typec_con_ss: endpoint {
remote-endpoint = <&usb3_data_ss>;
};
};
};
};


So like that.


Ah I see, thank you for clarifying that.

Regards,

Hans


Re: [PATCH v3 1/2] dt-bindings: usb: add documentation for typec switch via GPIO

2019-03-11 Thread Hans de Goede

Hi,

On 11-03-19 12:02, Hans de Goede wrote:

Hi,

On 11-03-19 11:40, Jun Li wrote:

Some typec super speed active channel switch can be controlled via
a GPIO, this binding can be used to specify the switch node by
a GPIO and the remote endpoint of its consumer.

Signed-off-by: Li Jun 
---
  .../devicetree/bindings/usb/typec-switch-gpio.txt  | 30 ++
  1 file changed, 30 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt 
b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
new file mode 100644
index 000..4ef76cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
@@ -0,0 +1,30 @@
+Typec orientation switch via a GPIO
+---
+
+Required properties:
+- compatible: should be set one of following:
+    - "nxp,ptn36043" for NXP Type-C SuperSpeed active switch.


Hmm, it seems that this binding should work fine with
other orientation-switches as well, so I think this needs
a generic compatible string.


+
+- gpios: the GPIO used to switch the super speed active channel,
+    GPIO_ACTIVE_HIGH: GPIO state high for cc1;
+    GPIO_ACTIVE_LOW:  GPIO state low for cc1.
+- orientation-switch: must be present.


Shouldn't this have usb-c in the propery name, e.g.:
usb-c-orientation-switch  ?


Also perhaps it would be better to use an additional compatible
string for this, rather then a boolean property, because what you
are trying to say is that this device is compatible with some
(to be written) generic usb-c-orientation-switch binding.

So I think you may want to use an extra compatible for this
and describe the port/graph usage linking the usb-c-connector port
and the port on the orientation-switch together in a new
usb-c-orientation-switch binding document.

This new binding will then document the port usage which is
mostly undocumented in your typec-switch-gpio.txt binding and
this port usage documentation can then be re-used for other
orientation-switch bindings.

Regards,

Hans





+
+Required sub-node:
+- port: specify the remote endpoint of typec switch consumer.
+
+Example:
+
+ptn36043 {
+    compatible = "nxp,ptn36043";
+    pinctrl-names = "default";
+    pinctrl-0 = <&pinctrl_ss_sel>;
+    gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+    orientation-switch;
+
+    port {
+    usb3_data_ss: endpoint {
+    remote-endpoint = <&typec_con_ss>;



Isn't this the wrong way around, shouldn't the "usb-c-connector"
compatible port be pointing to the orientation switch, rather then
the other way around?  Both will work in the end. but to me it
feels more natural to group all the info about the type-c connector
together in the "usb-c-connector" compatible port

Regards,

Hans



Re: [PATCH v3 1/2] dt-bindings: usb: add documentation for typec switch via GPIO

2019-03-11 Thread Hans de Goede

Hi,

On 11-03-19 11:40, Jun Li wrote:

Some typec super speed active channel switch can be controlled via
a GPIO, this binding can be used to specify the switch node by
a GPIO and the remote endpoint of its consumer.

Signed-off-by: Li Jun 
---
  .../devicetree/bindings/usb/typec-switch-gpio.txt  | 30 ++
  1 file changed, 30 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt 
b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
new file mode 100644
index 000..4ef76cf
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/typec-switch-gpio.txt
@@ -0,0 +1,30 @@
+Typec orientation switch via a GPIO
+---
+
+Required properties:
+- compatible: should be set one of following:
+   - "nxp,ptn36043" for NXP Type-C SuperSpeed active switch.
+
+- gpios: the GPIO used to switch the super speed active channel,
+   GPIO_ACTIVE_HIGH: GPIO state high for cc1;
+   GPIO_ACTIVE_LOW:  GPIO state low for cc1.
+- orientation-switch: must be present.


Shouldn't this have usb-c in the propery name, e.g.:
usb-c-orientation-switch  ?


+
+Required sub-node:
+- port: specify the remote endpoint of typec switch consumer.
+
+Example:
+
+ptn36043 {
+   compatible = "nxp,ptn36043";
+   pinctrl-names = "default";
+   pinctrl-0 = <&pinctrl_ss_sel>;
+   gpios = <&gpio3 15 GPIO_ACTIVE_HIGH>;
+   orientation-switch;
+
+   port {
+   usb3_data_ss: endpoint {
+   remote-endpoint = <&typec_con_ss>;



Isn't this the wrong way around, shouldn't the "usb-c-connector"
compatible port be pointing to the orientation switch, rather then
the other way around?  Both will work in the end. but to me it
feels more natural to group all the info about the type-c connector
together in the "usb-c-connector" compatible port

Regards,

Hans



[PATCH v3 7/8] usb: typec: fusb302: Improve suspend/resume handling

2019-03-11 Thread Hans de Goede
Remove the code which avoids doing i2c-transfers while our parent
i2c-adapter may be suspended by busy-waiting for our resume handler
to be called.

Instead move the interrupt handling from a threaded interrupt handler
to a work-queue and install a non-threaded interrupt handler which
normally queues the new interrupt handling work directly.

When our suspend handler gets called we set a flag which makes the new
non-threaded interrupt handler skip queueing the work before our parent
i2c-adapter is ready, instead the new non-threaded handler will record an
interrupt has happened during suspend and then our resume handler will
queue the work (at which point our parent will be ready).

Note normally i2c drivers solve the problem of not being able to access
the i2c bus until the i2c-controller is resumed by simply disabling their
irq from the suspend handler and re-enabling it on resume.

That is not possible with the fusb302 since the irq is a wakeup source
(it must be a wakeup source so that we can do PD negotiation when a
charger gets plugged in while suspended).

Besides avoiding the ugly busy-wait, this also fixes the following errors
which were logged by the busy-wait code when woken from suspend by plugging
in a Type-C device:

fusb302: i2c: pm suspend, retry 1 / 10
fusb302: i2c: pm suspend, retry 2 / 10
etc.

This commit also changes the devm_request_irq to a regular request_irq
+ free_irq, so that the work can be properly stopped. While at it also
properly disable the wake setting on the irq and also properly stop the
delayed work for bcl handling.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
Changes in v3:
-Change devm_request_irq to a regular request_irq free_irq, so that the work
 can be properly stopped

Changes in v2:
-Use a work_queue item which gets delayed during suspend, rather then
 disabling the interrupts entirely during suspend
---
 drivers/usb/typec/tcpm/fusb302.c | 112 +--
 1 file changed, 48 insertions(+), 64 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 4bb10564082a..f3b66dc71c33 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -78,6 +79,10 @@ struct fusb302_chip {
 
struct regulator *vbus;
 
+   spinlock_t irq_lock;
+   struct work_struct irq_work;
+   bool irq_suspended;
+   bool irq_while_suspended;
int gpio_int_n;
int gpio_int_n_irq;
struct extcon_dev *extcon;
@@ -85,9 +90,6 @@ struct fusb302_chip {
struct workqueue_struct *wq;
struct delayed_work bc_lvl_handler;
 
-   atomic_t pm_suspend;
-   atomic_t i2c_busy;
-
/* lock for sharing chip states */
struct mutex lock;
 
@@ -233,43 +235,15 @@ static void fusb302_debugfs_exit(const struct 
fusb302_chip *chip) { }
 
 #endif
 
-#define FUSB302_RESUME_RETRY 10
-#define FUSB302_RESUME_RETRY_SLEEP 50
-
-static bool fusb302_is_suspended(struct fusb302_chip *chip)
-{
-   int retry_cnt;
-
-   for (retry_cnt = 0; retry_cnt < FUSB302_RESUME_RETRY; retry_cnt++) {
-   if (atomic_read(&chip->pm_suspend)) {
-   dev_err(chip->dev, "i2c: pm suspend, retry %d/%d\n",
-   retry_cnt + 1, FUSB302_RESUME_RETRY);
-   msleep(FUSB302_RESUME_RETRY_SLEEP);
-   } else {
-   return false;
-   }
-   }
-
-   return true;
-}
-
 static int fusb302_i2c_write(struct fusb302_chip *chip,
 u8 address, u8 data)
 {
int ret = 0;
 
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
-
ret = i2c_smbus_write_byte_data(chip->i2c_client, address, data);
if (ret < 0)
fusb302_log(chip, "cannot write 0x%02x to 0x%02x, ret=%d",
data, address, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -281,19 +255,12 @@ static int fusb302_i2c_block_write(struct fusb302_chip 
*chip, u8 address,
 
if (length <= 0)
return ret;
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
 
ret = i2c_smbus_write_i2c_block_data(chip->i2c_client, address,
 length, data);
if (ret < 0)
fusb302_log(chip, "cannot block write 0x%02x, len=%d, ret=%d",
address, length, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -303,18 +270,10 @@ stati

[PATCH v3 1/8] usb: typec: fusb302: Make fusb302_set_cc_polarity also set pull ups / downs

2019-03-11 Thread Hans de Goede
The 2 callers of fusb302_set_cc_polarity both call fusb302_set_cc_pull
directly before calling fusb302_set_cc_polarity, this is not ideal for
2 reasons:

1) fusb302_set_cc_pull uses the cached polarity when applying the pull-ups,
which maybe changed immediately afterwards, to fix this set_cc_polarity
already does the pull-up setting.

2) Both touch the SWITCHES0 register in a r-w-modify cycle, this leads to
read reg, write reg, read reg, write reg. If we fold the setting of
the pull-downs into fusb302_set_cc_polarity then not only can we avoid
doing the reads / writes twice, at this point we set all bits, so we
can skip the read, turning 4 (slowish) i2c-transfers into 1.

Doing this also avoids the need to cache the pull_up state in
struct fusb302_chip.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 48 +++-
 1 file changed, 16 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 45b8b75080cf..50ba978a46e4 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -99,7 +99,6 @@ struct fusb302_chip {
bool intr_comp_chng;
 
/* port status */
-   bool pull_up;
bool vconn_on;
bool vbus_on;
bool charge_on;
@@ -540,7 +539,6 @@ static int fusb302_set_cc_pull(struct fusb302_chip *chip,
 mask, data);
if (ret < 0)
return ret;
-   chip->pull_up = pull_up;
 
return ret;
 }
@@ -1232,38 +1230,36 @@ static const char * const cc_polarity_name[] = {
[TYPEC_POLARITY_CC2]= "Polarity_CC2",
 };
 
-static int fusb302_set_cc_polarity(struct fusb302_chip *chip,
-  enum typec_cc_polarity cc_polarity)
+static int fusb302_set_cc_polarity_and_pull(struct fusb302_chip *chip,
+   enum typec_cc_polarity cc_polarity,
+   bool pull_up, bool pull_down)
 {
int ret = 0;
-   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
-   FUSB_REG_SWITCHES0_CC2_PU_EN |
-   FUSB_REG_SWITCHES0_VCONN_CC1 |
-   FUSB_REG_SWITCHES0_VCONN_CC2 |
-   FUSB_REG_SWITCHES0_MEAS_CC1 |
-   FUSB_REG_SWITCHES0_MEAS_CC2;
u8 switches0_data = 0x00;
u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN |
FUSB_REG_SWITCHES1_TXCC2_EN;
u8 switches1_data = 0x00;
 
+   if (pull_down)
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
+
if (cc_polarity == TYPEC_POLARITY_CC1) {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC1;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC1;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN;
} else {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC2;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC2;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN;
}
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-switches0_mask, switches0_data);
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
if (ret < 0)
return ret;
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES1,
@@ -1284,16 +1280,10 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
enum typec_cc_polarity cc_polarity;
enum typec_cc_status cc_status_active, cc1, cc2;
 
-   /* set pull_up, pull_down */
-   ret = fusb302_set_cc_pull(chip, false, true);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set cc to pull down, ret=%d", ret);
-   return ret;
-   }
-   /* set polarity */
+   /* set polarity and pull_up, pull_down */
cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ?
  TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2;
-   ret = fusb302_set_cc_polarity(chip, cc_polarity);
+   ret = fusb302_set_cc_polarity_and_pull(chip, cc_polarity, false, true);
if (ret < 0) {
fusb302_log(chip, "cannot set cc polarity %s, ret=%d",
cc_polarit

[PATCH v3 8/8] usb: typec: fusb302: Add __printf attribute to fusb302_log function

2019-03-11 Thread Hans de Goede
Add __printf attribute to fusb302_log function, so that we get
compiler warnings when specifying wrong vararg parameters.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index f3b66dc71c33..6ea6199caafa 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -125,13 +125,13 @@ struct fusb302_chip {
  */
 
 #ifdef CONFIG_DEBUG_FS
-
 static bool fusb302_log_full(struct fusb302_chip *chip)
 {
return chip->logbuffer_tail ==
(chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
 }
 
+__printf(2, 0)
 static void _fusb302_log(struct fusb302_chip *chip, const char *fmt,
 va_list args)
 {
-- 
2.20.1



[PATCH v3 3/8] usb: typec: fusb302: Fold fusb302_set_cc_pull into tcpm_set_cc

2019-03-11 Thread Hans de Goede
After the recent cleanups, tcpm_set_cc is the only caller of
fusb302_set_cc_pull, fold fusb302_set_cc_pull directly into
tcpm_set_cc for a nice cleanup.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 51 
 1 file changed, 13 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 605fbbb92e39..c947d18cdc0f 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -518,31 +518,6 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
return current_limit;
 }
 
-static int fusb302_set_cc_pull(struct fusb302_chip *chip,
-  bool pull_up, bool pull_down)
-{
-   int ret = 0;
-   u8 data = 0x00;
-   u8 mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
- FUSB_REG_SWITCHES0_CC2_PU_EN |
- FUSB_REG_SWITCHES0_CC1_PD_EN |
- FUSB_REG_SWITCHES0_CC2_PD_EN;
-
-   if (pull_up)
-   data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
-   FUSB_REG_SWITCHES0_CC1_PU_EN :
-   FUSB_REG_SWITCHES0_CC2_PU_EN;
-   if (pull_down)
-   data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
-   FUSB_REG_SWITCHES0_CC2_PD_EN;
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-mask, data);
-   if (ret < 0)
-   return ret;
-
-   return ret;
-}
-
 static int fusb302_set_src_current(struct fusb302_chip *chip,
   enum src_current_status status)
 {
@@ -674,27 +649,30 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 {
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
 tcpc_dev);
+   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
+   FUSB_REG_SWITCHES0_CC2_PU_EN |
+   FUSB_REG_SWITCHES0_CC1_PD_EN |
+   FUSB_REG_SWITCHES0_CC2_PD_EN;
+   u8 switches0_data = 0x00;
int ret = 0;
-   bool pull_up, pull_down;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
switch (cc) {
case TYPEC_CC_OPEN:
-   pull_up = false;
-   pull_down = false;
mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
-   pull_up = false;
-   pull_down = true;
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
-   pull_up = true;
-   pull_down = false;
+   switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
+ FUSB_REG_SWITCHES0_CC1_PU_EN :
+ FUSB_REG_SWITCHES0_CC2_PU_EN;
mode = TOGGLING_MODE_SRC;
break;
default:
@@ -706,13 +684,10 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
 
-   ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
+   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
+switches0_mask, switches0_data);
if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set cc pulling up %s, down %s, ret = %d",
-   pull_up ? "True" : "False",
-   pull_down ? "True" : "False",
-   ret);
+   fusb302_log(chip, "cannot set pull-up/-down, ret = %d", ret);
goto done;
}
/* reset the cc status */
-- 
2.20.1



[PATCH v3 0/8] usb: typec: fusb302: Various fixes

2019-03-11 Thread Hans de Goede
Hi All,

Here is v3 of my fusb302 bug-fix series, the main fix in this series
makes active adapters like Type-C to HDMI (often HDMI + USB-3-A) adapters
work when they are to be powered by the Type-C port and thus present both
an Ra and a Rd resistor on their Cc pins (patch 5).

Changes in v3:

[PATCH v3 4/8] usb: typec: fusb302: Check vconn is off when we start
-Use WARN with a message describing the problem, instead of WARN_ON

[PATCH v3 5/8] usb: typec: fusb302: Fix fusb302_handle_togdone_src Ra
-Keep the delays for measuring Rd / Ra the same as before instead of
 multiplying them by a factor 100

[PATCH v3 7/8] usb: typec: fusb302: Improve suspend/resume handling
-Change devm_request_irq to a regular request_irq free_irq, so that the work
 can be properly stopped on remove

Regards,

Hans



[PATCH v3 4/8] usb: typec: fusb302: Check vconn is off when we start toggling

2019-03-11 Thread Hans de Goede
The datasheet says the vconn MUST be off when we start toggling. The
tcpm.c state-machine is responsible to make sure vconn is off, but lets
add a WARN to catch any cases where vconn is not off for some reason.

Signed-off-by: Hans de Goede 
---
Changes in v3:
-Use WARN with a message describing the problem, instead of WARN_ON
---
 drivers/usb/typec/tcpm/fusb302.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index c947d18cdc0f..a1256855eaa0 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -607,6 +607,8 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
return ret;
chip->intr_togdone = false;
} else {
+   /* Datasheet says vconn MUST be off when toggling */
+   WARN(chip->vconn_on, "Vconn is on during toggle start");
/* unmask TOGDONE interrupt */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
 FUSB_REG_MASKA_TOGDONE);
-- 
2.20.1



[PATCH v3 2/8] usb: typec: fusb302: Refactor / simplify tcpm_set_cc()

2019-03-11 Thread Hans de Goede
After commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup"), tcpm_set_cc always calls fusb302_set_toggling.

Before this refactor tcpm_set_cc does the following:

1) fusb302_set_toggling(TOGGLING_MODE_OFF),
   this sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG.
2) fusb302_set_cc_pull(...).
3) "reset cc status".
4) if pull-up fusb302_set_src_current(...).
5) if pull-up or pull-down enable bc-lvl resp comp-chng irq.
6) fusb302_set_toggling(new-toggling-mode), which again
   sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG disabling
   the just enabled irq. fusb302_set_toggling is skipped when the new
   toggling mode is TOGGLING_MODE_OFF because this is already done in 1,
   note in this case 5) is a no-op.

When we are toggling the bits set by fusb302_set_cc_pull will be ignored
until we turn toggling off, so we can safely move the fusb302_set_cc_pull
call to before setting TOGGLING_MODE_OFF.

Either we are not toggling yet, or the src-current has already been set,
so we can also safely set the src-current earlier, allowing us to do the
fusb302_set_toggling(TOGGLING_MODE_OFF) call at the same time as we
set the other toggling modes. Also setting the src-current is a no-op
when not enabling pull-ups, so we can drop the if.

And since the second fusb302_set_toggling undoes the effects of step 5,
we can skip step 5, the bc-lvl resp comp-chng irq wil be enabled by
fusb302_handle_togdone_snk resp. fusb302_handle_togdone_src when toggling
is done.

Together this allows us to simplify things to:

1) fusb302_set_cc_pull(...)
2) "reset cc status"
3) fusb302_set_src_current(...)
4) fusb302_set_toggling(new-toggling-mode)

This commit does this, leading to a nice cleanup.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 85 ++--
 1 file changed, 15 insertions(+), 70 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 50ba978a46e4..605fbbb92e39 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -676,7 +676,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 tcpc_dev);
int ret = 0;
bool pull_up, pull_down;
-   u8 rd_mda;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
@@ -684,16 +683,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
case TYPEC_CC_OPEN:
pull_up = false;
pull_down = false;
+   mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
pull_up = false;
pull_down = true;
+   mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
pull_up = true;
pull_down = false;
+   mode = TOGGLING_MODE_SRC;
break;
default:
fusb302_log(chip, "unsupported cc value %s",
@@ -701,11 +703,9 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
ret = -EINVAL;
goto done;
}
-   ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot stop toggling, ret=%d", ret);
-   goto done;
-   }
+
+   fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
+
ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
if (ret < 0) {
fusb302_log(chip,
@@ -718,74 +718,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
/* reset the cc status */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
+
/* adjust current for SRC */
-   if (pull_up) {
-   ret = fusb302_set_src_current(chip, cc_src_current[cc]);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set src current %s, ret=%d",
-   typec_cc_status_name[cc], ret);
-   goto done;
-   }
-   }
-   /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
-   if (pull_up) {
-   rd_mda = rd_mda_value[cc_src_current[cc]];
-   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
-   if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set SRC measure value, ret=%d",
-   ret);
-   goto done;
-   }
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
-FUSB_REG_MASK_BC_LVL |
-

[PATCH v3 5/8] usb: typec: fusb302: Fix fusb302_handle_togdone_src Ra handling

2019-03-11 Thread Hans de Goede
The FUSB302 will stop toggling with a FUSB_REG_STATUS1A_TOGSS_SRC? status,
as soon as it sees either Ra or Rd on a CC pin.

Before this commit fusb302_handle_togdone_src would assume that the toggle-
engine always stopped at the CC pin indicating the polarity, IOW it assumed
that it stopped at the pin connected to Rd. It did check the CC-status of
that pin, but it did not expect to get a CC-status of Ra and therefore
treated this as CC-open. This lead to the following 2 problems:

1) If a powered cable/adapter gets plugged in with Ra on CC1 and Rd on CC2
then 4 of 5 times when plugged in toggling will stop with a togdone_result
of FUSB_REG_STATUS1A_TOGSS_SRC1.  3/5th of the time the toggle-engine is
testing for being connected as a sink and after that it tests 1/5th of the
time for connected as a src through CC1 before finally testing the last
1/5th of the time for being a src connected through CC2.

This was a problem because we would only check the CC pin status for the
pin on which the toggling stopped which in this polarity 4 out of 5
times would be the Ra pin. The code before this commit would treat Ra as
CC-open and then restart toggling. Once toggling is restarted we are
guaranteed to end with FUSB_REG_STATUS1A_TOGSS_SRC1 as CC1 is tested first,
leading to a CC-status of Ra again and an infinite restart toggling loop.
So 4 out of 5 times when plugged in in this polarity a powered adapter
will not work.

2) Even if we happen to have the right polarity or 1/5th of the time in
the polarity with problem 1), we would report the non Rd pin as CC-open
rather then as Ra, resulting in the tcpm.c code not enabling Vconn which
is a problem for some adapters.

This commit fixes this by getting the CC-status of *both* pins and then
determining the polarity based on that, rather then on where the toggling
stopped.

Signed-off-by: Hans de Goede 
---
Changes in v3
-Keep the delays for measuring Rd / Ra the same as before instead of
 multiplying them by a factor 100
---
 drivers/usb/typec/tcpm/fusb302.c | 149 ---
 1 file changed, 97 insertions(+), 52 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index a1256855eaa0..a4387ce5ac85 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1255,6 +1255,62 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
return ret;
 }
 
+/* On error returns < 0, otherwise a typec_cc_status value */
+static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
+enum typec_cc_polarity cc_polarity,
+enum typec_cc_status *cc)
+{
+   u8 ra_mda = ra_mda_value[chip->src_current_status];
+   u8 rd_mda = rd_mda_value[chip->src_current_status];
+   u8 switches0_data, status0;
+   int ret;
+
+   /* Step 1: Set switches so that we measure the right CC pin */
+   switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ?
+   FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 :
+   FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2;
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
+   if (ret < 0)
+   return ret;
+
+   fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
+   fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
+
+   /* Step 2: Set compararator volt to differentiate between Open and Rd */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(50, 100);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP) {
+   *cc = TYPEC_CC_OPEN;
+   return 0;
+   }
+
+   /* Step 3: Set compararator input to differentiate between Rd and Ra. */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, ra_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(50, 100);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP)
+   *cc = TYPEC_CC_RD;
+   else
+   *cc = TYPEC_CC_RA;
+
+   return 0;
+}
+
 static int fusb302_handle_togdone_src(struct fusb302_chip *chip,
  u8 togdone_result)
 {
@@ -1265,71 +1321,62 @@ static int fusb302_handle_togdone_src(struct 
fusb302_chip *chip,
 * - set I_COMP interrupt on
 */
int ret = 0;
-   u8 status0;
-   u8 ra_mda = ra_mda_value[chip->src_current_status];
   

[PATCH v3 6/8] usb: typec: fusb302: 2 small misc. fixes

2019-03-11 Thread Hans de Goede
Fix a copy and paste error in an error message and a spelling error
in a comment.

Reviewed-by: Guenter Roeck 
Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index a4387ce5ac85..4bb10564082a 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1386,7 +1386,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip 
*chip,
 FUSB_REG_MASK_COMP_CHNG);
if (ret < 0) {
fusb302_log(chip,
-   "cannot unmask bc_lcl interrupt, ret=%d", ret);
+   "cannot unmask comp_chng interrupt, ret=%d", ret);
return ret;
}
chip->intr_comp_chng = true;
@@ -1561,7 +1561,7 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s",
comp_result ? "true" : "false");
if (comp_result) {
-   /* cc level > Rd_threashold, detach */
+   /* cc level > Rd_threshold, detach */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
tcpm_cc_change(chip->tcpm_port);
-- 
2.20.1



Re: [PATCH v2 4/8] usb: typec: fusb302: Check vconn is off when we start toggling

2019-03-08 Thread Hans de Goede

Hi,

On 07-03-19 19:11, Guenter Roeck wrote:

On Thu, Mar 07, 2019 at 05:36:03PM +0100, Hans de Goede wrote:

The datasheet says the vconn MUST be off when we start toggling. The
tcpm.c state-machine is responsible to make sure vconn is off, but
lets add a WARN_ON check to catch any cases where vconn is not off
for some reason.



Curious - have you seen this happening ?


No, just something which I noticed in the datasheet and it seems
like a good idea to add a check for this.


Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/fusb302.c | 2 ++
  1 file changed, 2 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index cb6637e82f32..f43fe34b7a73 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -607,6 +607,8 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
return ret;
chip->intr_togdone = false;
} else {
+   /* Datasheet says vconn MUST be off when toggling */
+   WARN_ON(chip->vconn_on);


Personally I am not a friend of WARN_ON. I prefer WARN statements
telling me what is wrong.


Ok, I will switch to WARN() for v3 of the series.

Regards,

Hans



/* unmask TOGDONE interrupt */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
 FUSB_REG_MASKA_TOGDONE);
--
2.20.1



Re: [PATCH 1/5] dt-bindings: connector: add optional properties for Type-B

2019-03-08 Thread Hans de Goede

Hi,

On 08-03-19 07:13, Chunfeng Yun wrote:

Add id-gpios, vbus-gpios, vbus-supply and pinctrl properties for
usb-b-connector

Signed-off-by: Chunfeng Yun 
---
  .../devicetree/bindings/connector/usb-connector.txt| 10 ++
  1 file changed, 10 insertions(+)

diff --git a/Documentation/devicetree/bindings/connector/usb-connector.txt 
b/Documentation/devicetree/bindings/connector/usb-connector.txt
index a9a2f2fc44f2..7a07b0f4f973 100644
--- a/Documentation/devicetree/bindings/connector/usb-connector.txt
+++ b/Documentation/devicetree/bindings/connector/usb-connector.txt
@@ -17,6 +17,16 @@ Optional properties:
  - self-powered: Set this property if the usb device that has its own power
source.
  
+Optional properties for usb-b-connector:

+- id-gpios: gpio for USB ID pin.


What about boards where the ID pin is *not* connected to a GPIO,
but e.g. to a special pin on the PMIC which can also detect
an ACA adapter ? Currently this case is handled by extcon
drivers, but we have no way to set e.g. vbus-supply for the
connector. Maybe in this case the usb-connector node should
be a child of the PMIC node ?

And in many cases there also is a mux to switch the datalines
between the host and device(gadget) controllers, how should
that be described in this model?  See the new usb-role-switch
code under drivers/usb/roles

In some cases the mux is controlled through a gpio, so we
may want to add a "mux-gpios" here in which case we also
need to define what 0/1 means.


+- vbus-gpios: gpio for USB VBUS pin.
+  see gpio/gpio.txt.
+- vbus-supply: reference to the VBUS regulator, needed when supports
+  dual-role mode.


I think this needs some text that there can be either a vbus-gpio or
a vbus-supply. Oh wait reading:

https://patchwork.kernel.org/patch/10819377/

I see that this GPIO is for detecting vbus presence, not for driving/enabling
5v to Vbus from the board, that needs to be described more clearly.


+- pinctrl-names : a pinctrl state named "default" is optional
+- pinctrl-0 : pin control group
+  see pinctrl/pinctrl-bindings.txt
+
  Optional properties for usb-c-connector:
  - power-role: should be one of "source", "sink" or "dual"(DRP) if typec
connector has power support.




Regards,

Hans


Re: [PATCH v2 5/8] usb: typec: fusb302: Fix fusb302_handle_togdone_src Ra handling

2019-03-08 Thread Hans de Goede

Hi,

On 07-03-19 19:19, Guenter Roeck wrote:

On Thu, Mar 07, 2019 at 05:36:04PM +0100, Hans de Goede wrote:

The FUSB302 will stop toggling with a FUSB_REG_STATUS1A_TOGSS_SRC? status,
as soon as it sees either Ra or Rd on a CC pin.

Before this commit fusb302_handle_togdone_src would assume that the toggle-
engine always stopped at the CC pin indicating the polarity, IOW it assumed
that it stopped at the pin connected to Rd. It did check the CC-status of
that pin, but it did not expect to get a CC-status of Ra and therefore
treated this as CC-open. This lead to the following 2 problems:

1) If a powered cable/adapter gets plugged in with Ra on CC1 and Rd on CC2
then 4 of 5 times when plugged in toggling will stop with a togdone_result
of FUSB_REG_STATUS1A_TOGSS_SRC1.  3/5th of the time the toggle-engine is
testing for being connected as a sink and after that it tests 1/5th of the
time for connected as a src through CC1 before finally testing the last
1/5th of the time for being a src connected through CC2.

This was a problem because we would only check the CC pin status for the
pin on which the toggling stopped which in this polarity 4 out of 5
times would be the Ra pin. The code before this commit would treat Ra as
CC-open and then restart toggling. Once toggling is restarted we are
guaranteed to end with FUSB_REG_STATUS1A_TOGSS_SRC1 as CC1 is tested first,
leading to a CC-status of Ra again and an infinite restart toggling loop.
So 4 out of 5 times when plugged in in this polarity a powered adapter
will not work.

2) Even if we happen to have the right polarity or 1/5th of the time in
the polarity with problem 1), we would report the non Rd pin as CC-open
rather then as Ra, resulting in the tcpm.c code not enabling Vconn which
is a problem for some adapters.

This commit fixes this by getting the CC-status of *both* pins and then
determining the polarity based on that, rather then on where the toggling
stopped.

Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/tcpm/fusb302.c | 149 ---
  1 file changed, 97 insertions(+), 52 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index f43fe34b7a73..b74c6ff67aae 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1249,6 +1249,62 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
return ret;
  }
  
+/* On error returns < 0, otherwise a typec_cc_status value */

+static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
+enum typec_cc_polarity cc_polarity,
+enum typec_cc_status *cc)
+{
+   u8 ra_mda = ra_mda_value[chip->src_current_status];
+   u8 rd_mda = rd_mda_value[chip->src_current_status];
+   u8 switches0_data, status0;
+   int ret;
+
+   /* Step 1: Set switches so that we measure the right CC pin */
+   switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ?
+   FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 :
+   FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2;
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
+   if (ret < 0)
+   return ret;
+
+   fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
+   fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
+
+   /* Step 2: Set compararator volt to differentiate between Open and Rd */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(5000, 1);


This and the second sleep below results in significant delays of up to
20 ms. This is significantly more than before. Are you sure this doesn't
result in some timing violations ?


Ugh, that line should be:

usleep_range(50, 100);

(and again below).

I added the 2 extra zeroes while debugging this code, but the actual bug
I had then in the code was different. I actually remember removing the zeroes
again, but clearly they somehow got back; or I remember wrongly.

Anyways I will do a v3 with this fixed, hopefully later today, but I
need to re-run all my tests, so this may take a while.

> And is that really the only possible
> solution to address the problem you observed ?

I have been unable to come up with another way to deal with the toggle
engine stopping on the first Cc pin with a pull-down attached, be it the
Rd or Ra one.

But I should be able to get the delay down to twice the old delay,
instead of the up to 20 ms.

Regards,

Hans

p.s.

Thank you for the review!


+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP) {
+   *cc = TYPEC_CC_OPEN;

Re: [PATCH v2 2/8] usb: typec: fusb302: Refactor / simplify tcpm_set_cc()

2019-03-08 Thread Hans de Goede

Hi,

On 08-03-19 08:33, Heikki Krogerus wrote:

On Thu, Mar 07, 2019 at 10:12:59AM -0800, Guenter Roeck wrote:

On Thu, Mar 07, 2019 at 05:36:01PM +0100, Hans de Goede wrote:

After commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup"), tcpm_set_cc always calls fusb302_set_toggling.

Before this refactor tcpm_set_cc does the following:

1) fusb302_set_toggling(TOGGLING_MODE_OFF),
this sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG.
2) fusb302_set_cc_pull(...).
3) "reset cc status".
4) if pull-up fusb302_set_src_current(...).
5) if pull-up or pull-down enable bc-lvl resp comp-chng irq.
6) fusb302_set_toggling(new-toggling-mode), which again
sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG disabling
the just enabled irq. fusb302_set_toggling is skipped when the new
toggling mode is TOGGLING_MODE_OFF because this is already done in 1,
note in this case 5) is a no-op.

When we are toggling the bits set by fusb302_set_cc_pull will be ignored
until we turn toggling off, so we can safely move the fusb302_set_cc_pull
call to before setting TOGGLING_MODE_OFF.

Either we are not toggling yet, or the src-current has already been set,
so we can also safely set the src-current earlier, allowing us to do the
fusb302_set_toggling(TOGGLING_MODE_OFF) call at the same time as we
set the other toggling modes. Also setting the src-current is a no-op
when not enabling pull-ups, so we can drop the if.

And since the second fusb302_set_toggling undoes the effects of step 5,
we can skip step 5, the bc-lvl resp comp-chng irq wil be enabled by
fusb302_handle_togdone_snk resp. fusb302_handle_togdone_src when toggling
is done.

Together this allows us to simplify things to:

1) fusb302_set_cc_pull(...)
2) "reset cc status"
3) fusb302_set_src_current(...)
4) fusb302_set_toggling(new-toggling-mode)

This commit does this, leading to a nice cleanup.

Signed-off-by: Hans de Goede 


I think I understand the logic, but I think it would be really beneficial
if this (and the rest of the series) can be tested independently (ie
by someone with hardware).

Reviewed-by: Guenter Roeck 


I'll test this series with my GPD win board today.


Note I've already tested this series on both a GPD win and a GPD pocket.

Also Guenter's reviewed has shown that a small error has crept up
in patch 5, patch 5 adds 2:

usleep_range(5000, 1);

lines which should be:

usleep_range(50, 100);

So if you test please make that change, or wait for v3 of the series.

Regards,

Hans



[PATCH v2 7/8] usb: typec: fusb302: Improve suspend/resume handling

2019-03-07 Thread Hans de Goede
Remove the code which avoids doing i2c-transfers while our parent
i2c-adapter may be suspended by busy-waiting for our resume handler
to be called.

Instead move the interrupt handling from a threaded interrupt handler
to a work-queue and install a non-threaded interrupt handler which
normally queues the new interrupt handling work directly.

When our suspend handler gets called we set a flag which makes the new
non-threaded interrupt handler skip queueing the work before our parent
i2c-adapter is ready, instead the new non-threaded handler will record an
interrupt has happened during suspend and then our resume handler will
queue the work (at which point our parent will be ready).

Note normally i2c drivers solve the problem of not being able to access
the i2c bus until the i2c-controller is resumed by simply disabling their
irq from the suspend handler and re-enable it on resume.

That is not possible with the fusb302 since the irq is a wakeup source
(it must be a wakeup source so that we can do PD negotiation when a
charger gets plugged in while suspended).

Besides avoiding the ugly busy-wait, this also fixes the following errors
which were logged by the busy-wait code when woken from suspend by plugging
in a Type-C device:

fusb302: i2c: pm suspend, retry 1 / 10
fusb302: i2c: pm suspend, retry 2 / 10
etc.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 109 +--
 1 file changed, 45 insertions(+), 64 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 23f773d07514..6cdc38b8da74 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -23,6 +23,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -78,6 +79,10 @@ struct fusb302_chip {
 
struct regulator *vbus;
 
+   spinlock_t irq_lock;
+   struct work_struct irq_work;
+   bool irq_suspended;
+   bool irq_while_suspended;
int gpio_int_n;
int gpio_int_n_irq;
struct extcon_dev *extcon;
@@ -85,9 +90,6 @@ struct fusb302_chip {
struct workqueue_struct *wq;
struct delayed_work bc_lvl_handler;
 
-   atomic_t pm_suspend;
-   atomic_t i2c_busy;
-
/* lock for sharing chip states */
struct mutex lock;
 
@@ -233,43 +235,15 @@ static void fusb302_debugfs_exit(const struct 
fusb302_chip *chip) { }
 
 #endif
 
-#define FUSB302_RESUME_RETRY 10
-#define FUSB302_RESUME_RETRY_SLEEP 50
-
-static bool fusb302_is_suspended(struct fusb302_chip *chip)
-{
-   int retry_cnt;
-
-   for (retry_cnt = 0; retry_cnt < FUSB302_RESUME_RETRY; retry_cnt++) {
-   if (atomic_read(&chip->pm_suspend)) {
-   dev_err(chip->dev, "i2c: pm suspend, retry %d/%d\n",
-   retry_cnt + 1, FUSB302_RESUME_RETRY);
-   msleep(FUSB302_RESUME_RETRY_SLEEP);
-   } else {
-   return false;
-   }
-   }
-
-   return true;
-}
-
 static int fusb302_i2c_write(struct fusb302_chip *chip,
 u8 address, u8 data)
 {
int ret = 0;
 
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
-
ret = i2c_smbus_write_byte_data(chip->i2c_client, address, data);
if (ret < 0)
fusb302_log(chip, "cannot write 0x%02x to 0x%02x, ret=%d",
data, address, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -281,19 +255,12 @@ static int fusb302_i2c_block_write(struct fusb302_chip 
*chip, u8 address,
 
if (length <= 0)
return ret;
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
 
ret = i2c_smbus_write_i2c_block_data(chip->i2c_client, address,
 length, data);
if (ret < 0)
fusb302_log(chip, "cannot block write 0x%02x, len=%d, ret=%d",
address, length, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -303,18 +270,10 @@ static int fusb302_i2c_read(struct fusb302_chip *chip,
 {
int ret = 0;
 
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
-
ret = i2c_smbus_read_byte_data(chip->i2c_client, address);
*data = (u8)ret;
if (ret < 0)
fusb302_log(chip, "cannot read %02x, ret=%d", address, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
  

[PATCH v2 8/8] usb: typec: fusb302: Add __printf attribute to fusb302_log function

2019-03-07 Thread Hans de Goede
Add __printf attribute to fusb302_log function, so that we get
compiler warnings when specifying wrong vararg parameters.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 6cdc38b8da74..ad1538c31dc8 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -125,13 +125,13 @@ struct fusb302_chip {
  */
 
 #ifdef CONFIG_DEBUG_FS
-
 static bool fusb302_log_full(struct fusb302_chip *chip)
 {
return chip->logbuffer_tail ==
(chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
 }
 
+__printf(2, 0)
 static void _fusb302_log(struct fusb302_chip *chip, const char *fmt,
 va_list args)
 {
-- 
2.20.1



[PATCH v2 6/8] usb: typec: fusb302: 2 small misc. fixes

2019-03-07 Thread Hans de Goede
Fix a copy and paste error in an error message and a spelling error
in a comment.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index b74c6ff67aae..23f773d07514 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1380,7 +1380,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip 
*chip,
 FUSB_REG_MASK_COMP_CHNG);
if (ret < 0) {
fusb302_log(chip,
-   "cannot unmask bc_lcl interrupt, ret=%d", ret);
+   "cannot unmask comp_chng interrupt, ret=%d", ret);
return ret;
}
chip->intr_comp_chng = true;
@@ -1555,7 +1555,7 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s",
comp_result ? "true" : "false");
if (comp_result) {
-   /* cc level > Rd_threashold, detach */
+   /* cc level > Rd_threshold, detach */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
tcpm_cc_change(chip->tcpm_port);
-- 
2.20.1



[PATCH v2 5/8] usb: typec: fusb302: Fix fusb302_handle_togdone_src Ra handling

2019-03-07 Thread Hans de Goede
The FUSB302 will stop toggling with a FUSB_REG_STATUS1A_TOGSS_SRC? status,
as soon as it sees either Ra or Rd on a CC pin.

Before this commit fusb302_handle_togdone_src would assume that the toggle-
engine always stopped at the CC pin indicating the polarity, IOW it assumed
that it stopped at the pin connected to Rd. It did check the CC-status of
that pin, but it did not expect to get a CC-status of Ra and therefore
treated this as CC-open. This lead to the following 2 problems:

1) If a powered cable/adapter gets plugged in with Ra on CC1 and Rd on CC2
then 4 of 5 times when plugged in toggling will stop with a togdone_result
of FUSB_REG_STATUS1A_TOGSS_SRC1.  3/5th of the time the toggle-engine is
testing for being connected as a sink and after that it tests 1/5th of the
time for connected as a src through CC1 before finally testing the last
1/5th of the time for being a src connected through CC2.

This was a problem because we would only check the CC pin status for the
pin on which the toggling stopped which in this polarity 4 out of 5
times would be the Ra pin. The code before this commit would treat Ra as
CC-open and then restart toggling. Once toggling is restarted we are
guaranteed to end with FUSB_REG_STATUS1A_TOGSS_SRC1 as CC1 is tested first,
leading to a CC-status of Ra again and an infinite restart toggling loop.
So 4 out of 5 times when plugged in in this polarity a powered adapter
will not work.

2) Even if we happen to have the right polarity or 1/5th of the time in
the polarity with problem 1), we would report the non Rd pin as CC-open
rather then as Ra, resulting in the tcpm.c code not enabling Vconn which
is a problem for some adapters.

This commit fixes this by getting the CC-status of *both* pins and then
determining the polarity based on that, rather then on where the toggling
stopped.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 149 ---
 1 file changed, 97 insertions(+), 52 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index f43fe34b7a73..b74c6ff67aae 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1249,6 +1249,62 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
return ret;
 }
 
+/* On error returns < 0, otherwise a typec_cc_status value */
+static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
+enum typec_cc_polarity cc_polarity,
+enum typec_cc_status *cc)
+{
+   u8 ra_mda = ra_mda_value[chip->src_current_status];
+   u8 rd_mda = rd_mda_value[chip->src_current_status];
+   u8 switches0_data, status0;
+   int ret;
+
+   /* Step 1: Set switches so that we measure the right CC pin */
+   switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ?
+   FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 :
+   FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2;
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
+   if (ret < 0)
+   return ret;
+
+   fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
+   fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
+
+   /* Step 2: Set compararator volt to differentiate between Open and Rd */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(5000, 1);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP) {
+   *cc = TYPEC_CC_OPEN;
+   return 0;
+   }
+
+   /* Step 3: Set compararator input to differentiate between Rd and Ra. */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, ra_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(5000, 1);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP)
+   *cc = TYPEC_CC_RD;
+   else
+   *cc = TYPEC_CC_RA;
+
+   return 0;
+}
+
 static int fusb302_handle_togdone_src(struct fusb302_chip *chip,
  u8 togdone_result)
 {
@@ -1259,71 +1315,62 @@ static int fusb302_handle_togdone_src(struct 
fusb302_chip *chip,
 * - set I_COMP interrupt on
 */
int ret = 0;
-   u8 status0;
-   u8 ra_mda = ra_mda_value[chip->src_current_status];
u8 rd_mda = rd_mda_value[chip->src_current_status];
-   bool ra_comp, rd_comp;
+   enum toggling_mode

[PATCH v2 1/8] usb: typec: fusb302: Make fusb302_set_cc_polarity also set pull ups / downs

2019-03-07 Thread Hans de Goede
The 2 callers of fusb302_set_cc_polarity both call fusb302_set_cc_pull
directly before calling fusb302_set_cc_polarity, this is not ideal for
2 reasons:

1) fusb302_set_cc_pull uses the cached polarity when applying pull-ups,
which maybe changed immediately afterwards, to fix this set_cc_polarity
already does the pull-up setting.

2) Both touch the SWITCHES0 register in a r-w-modify cycle, this leads to
read reg, write reg, read reg, write reg. If we fold the setting of
the pull-downs into fusb302_set_cc_polarity then not only can we avoid
doing the reads / writes twice, at this point we set all bits, so we
can skip the read, turning 4 (slowish) i2c-transfers into 1.

Doing this also avoids the need to cache the pull_up state in
struct fusb302_chip.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 48 +++-
 1 file changed, 16 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index e9344997329c..d2cce67289d4 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -99,7 +99,6 @@ struct fusb302_chip {
bool intr_comp_chng;
 
/* port status */
-   bool pull_up;
bool vconn_on;
bool vbus_on;
bool charge_on;
@@ -540,7 +539,6 @@ static int fusb302_set_cc_pull(struct fusb302_chip *chip,
 mask, data);
if (ret < 0)
return ret;
-   chip->pull_up = pull_up;
 
return ret;
 }
@@ -1226,38 +1224,36 @@ static const char * const cc_polarity_name[] = {
[TYPEC_POLARITY_CC2]= "Polarity_CC2",
 };
 
-static int fusb302_set_cc_polarity(struct fusb302_chip *chip,
-  enum typec_cc_polarity cc_polarity)
+static int fusb302_set_cc_polarity_and_pull(struct fusb302_chip *chip,
+   enum typec_cc_polarity cc_polarity,
+   bool pull_up, bool pull_down)
 {
int ret = 0;
-   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
-   FUSB_REG_SWITCHES0_CC2_PU_EN |
-   FUSB_REG_SWITCHES0_VCONN_CC1 |
-   FUSB_REG_SWITCHES0_VCONN_CC2 |
-   FUSB_REG_SWITCHES0_MEAS_CC1 |
-   FUSB_REG_SWITCHES0_MEAS_CC2;
u8 switches0_data = 0x00;
u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN |
FUSB_REG_SWITCHES1_TXCC2_EN;
u8 switches1_data = 0x00;
 
+   if (pull_down)
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
+
if (cc_polarity == TYPEC_POLARITY_CC1) {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC1;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC1;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN;
} else {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC2;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC2;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN;
}
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-switches0_mask, switches0_data);
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
if (ret < 0)
return ret;
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES1,
@@ -1278,16 +1274,10 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
enum typec_cc_polarity cc_polarity;
enum typec_cc_status cc_status_active, cc1, cc2;
 
-   /* set pull_up, pull_down */
-   ret = fusb302_set_cc_pull(chip, false, true);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set cc to pull down, ret=%d", ret);
-   return ret;
-   }
-   /* set polarity */
+   /* set polarity and pull_up, pull_down */
cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ?
  TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2;
-   ret = fusb302_set_cc_polarity(chip, cc_polarity);
+   ret = fusb302_set_cc_polarity_and_pull(chip, cc_polarity, false, true);
if (ret < 0) {
fusb302_log(chip, "cannot set cc polarity %s, ret=%d",
cc_polarity_name[cc_polarity], ret);
@@ -

[PATCH v2 2/8] usb: typec: fusb302: Refactor / simplify tcpm_set_cc()

2019-03-07 Thread Hans de Goede
After commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup"), tcpm_set_cc always calls fusb302_set_toggling.

Before this refactor tcpm_set_cc does the following:

1) fusb302_set_toggling(TOGGLING_MODE_OFF),
   this sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG.
2) fusb302_set_cc_pull(...).
3) "reset cc status".
4) if pull-up fusb302_set_src_current(...).
5) if pull-up or pull-down enable bc-lvl resp comp-chng irq.
6) fusb302_set_toggling(new-toggling-mode), which again
   sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG disabling
   the just enabled irq. fusb302_set_toggling is skipped when the new
   toggling mode is TOGGLING_MODE_OFF because this is already done in 1,
   note in this case 5) is a no-op.

When we are toggling the bits set by fusb302_set_cc_pull will be ignored
until we turn toggling off, so we can safely move the fusb302_set_cc_pull
call to before setting TOGGLING_MODE_OFF.

Either we are not toggling yet, or the src-current has already been set,
so we can also safely set the src-current earlier, allowing us to do the
fusb302_set_toggling(TOGGLING_MODE_OFF) call at the same time as we
set the other toggling modes. Also setting the src-current is a no-op
when not enabling pull-ups, so we can drop the if.

And since the second fusb302_set_toggling undoes the effects of step 5,
we can skip step 5, the bc-lvl resp comp-chng irq wil be enabled by
fusb302_handle_togdone_snk resp. fusb302_handle_togdone_src when toggling
is done.

Together this allows us to simplify things to:

1) fusb302_set_cc_pull(...)
2) "reset cc status"
3) fusb302_set_src_current(...)
4) fusb302_set_toggling(new-toggling-mode)

This commit does this, leading to a nice cleanup.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 85 ++--
 1 file changed, 15 insertions(+), 70 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index d2cce67289d4..bcb38e397712 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -676,7 +676,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 tcpc_dev);
int ret = 0;
bool pull_up, pull_down;
-   u8 rd_mda;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
@@ -684,16 +683,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
case TYPEC_CC_OPEN:
pull_up = false;
pull_down = false;
+   mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
pull_up = false;
pull_down = true;
+   mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
pull_up = true;
pull_down = false;
+   mode = TOGGLING_MODE_SRC;
break;
default:
fusb302_log(chip, "unsupported cc value %s",
@@ -701,11 +703,9 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
ret = -EINVAL;
goto done;
}
-   ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot stop toggling, ret=%d", ret);
-   goto done;
-   }
+
+   fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
+
ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
if (ret < 0) {
fusb302_log(chip,
@@ -718,74 +718,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
/* reset the cc status */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
+
/* adjust current for SRC */
-   if (pull_up) {
-   ret = fusb302_set_src_current(chip, cc_src_current[cc]);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set src current %s, ret=%d",
-   typec_cc_status_name[cc], ret);
-   goto done;
-   }
-   }
-   /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
-   if (pull_up) {
-   rd_mda = rd_mda_value[cc_src_current[cc]];
-   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
-   if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set SRC measure value, ret=%d",
-   ret);
-   goto done;
-   }
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
-FUSB_REG_MASK_BC_LVL |
-FUSB_REG_MASK_COMP

[PATCH v2 3/8] usb: typec: fusb302: Fold fusb302_set_cc_pull into tcpm_set_cc

2019-03-07 Thread Hans de Goede
After the recent cleanups, tcpm_set_cc is the only caller of
fusb302_set_cc_pull, fold fusb302_set_cc_pull directly into
tcpm_set_cc for a nice cleanup.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 51 
 1 file changed, 13 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index bcb38e397712..cb6637e82f32 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -518,31 +518,6 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
return current_limit;
 }
 
-static int fusb302_set_cc_pull(struct fusb302_chip *chip,
-  bool pull_up, bool pull_down)
-{
-   int ret = 0;
-   u8 data = 0x00;
-   u8 mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
- FUSB_REG_SWITCHES0_CC2_PU_EN |
- FUSB_REG_SWITCHES0_CC1_PD_EN |
- FUSB_REG_SWITCHES0_CC2_PD_EN;
-
-   if (pull_up)
-   data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
-   FUSB_REG_SWITCHES0_CC1_PU_EN :
-   FUSB_REG_SWITCHES0_CC2_PU_EN;
-   if (pull_down)
-   data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
-   FUSB_REG_SWITCHES0_CC2_PD_EN;
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-mask, data);
-   if (ret < 0)
-   return ret;
-
-   return ret;
-}
-
 static int fusb302_set_src_current(struct fusb302_chip *chip,
   enum src_current_status status)
 {
@@ -674,27 +649,30 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 {
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
 tcpc_dev);
+   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
+   FUSB_REG_SWITCHES0_CC2_PU_EN |
+   FUSB_REG_SWITCHES0_CC1_PD_EN |
+   FUSB_REG_SWITCHES0_CC2_PD_EN;
+   u8 switches0_data = 0x00;
int ret = 0;
-   bool pull_up, pull_down;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
switch (cc) {
case TYPEC_CC_OPEN:
-   pull_up = false;
-   pull_down = false;
mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
-   pull_up = false;
-   pull_down = true;
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
-   pull_up = true;
-   pull_down = false;
+   switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
+ FUSB_REG_SWITCHES0_CC1_PU_EN :
+ FUSB_REG_SWITCHES0_CC2_PU_EN;
mode = TOGGLING_MODE_SRC;
break;
default:
@@ -706,13 +684,10 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
 
-   ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
+   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
+switches0_mask, switches0_data);
if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set cc pulling up %s, down %s, ret = %d",
-   pull_up ? "True" : "False",
-   pull_down ? "True" : "False",
-   ret);
+   fusb302_log(chip, "cannot set pull-up/-down, ret = %d", ret);
goto done;
}
/* reset the cc status */
-- 
2.20.1



[PATCH v2 4/8] usb: typec: fusb302: Check vconn is off when we start toggling

2019-03-07 Thread Hans de Goede
The datasheet says the vconn MUST be off when we start toggling. The
tcpm.c state-machine is responsible to make sure vconn is off, but
lets add a WARN_ON check to catch any cases where vconn is not off
for some reason.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index cb6637e82f32..f43fe34b7a73 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -607,6 +607,8 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
return ret;
chip->intr_togdone = false;
} else {
+   /* Datasheet says vconn MUST be off when toggling */
+   WARN_ON(chip->vconn_on);
/* unmask TOGDONE interrupt */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
 FUSB_REG_MASKA_TOGDONE);
-- 
2.20.1



[PATCH v2 0/8] usb: typec: fusb302: Various fixes

2019-03-07 Thread Hans de Goede
Hi All,

Here is v2 of my fusb302 bug-fix series, the main fix in this series
makes active adapters like Type-C to HDMI (often HDMI + USB-3-A) adapters
work when they are to be powered by the Type-C port and thus present both
an Ra and a Rd resistor on their Cc pins (patch 5).

Without this fix these adapters only work 1 out of every times when
plugged in with Ra on Cc1. Version 1 of this series did not see much
review, please review.

New in v2 is patch 7 which in v1 was "fusb302: Simplify suspend/resume
handling" being replaced with "fusb302: Improve suspend/resume handling"
in v1 I went for the simply fix of disabling the irq during suspend, but
that breaks it being a wakeup source.

Regards,

Hans



Re: [PATCH 0/3] Propagate DP-over-Type-C hotplug events from Type-C subsys to drm-drivers

2019-03-04 Thread Hans de Goede

Hi,

On 04-03-19 16:17, Heikki Krogerus wrote:

Hi Hans,

On Thu, Feb 28, 2019 at 05:54:21PM +0100, Hans de Goede wrote:

Hi Heikki,

On 28-02-19 15:47, Heikki Krogerus wrote:

Hi Hans,

On Thu, Feb 28, 2019 at 12:24:25PM +0100, Hans de Goede wrote:

Hi,

On 28-02-19 10:15, Heikki Krogerus wrote:





I've been thinking about this... Do we actually need to link the
correct drm_connector to the Type-C connector? Perhaps we can make
this work by just linking the GFX device to the Type-C connector.


What use is it to the kms driver if it gets an event there is a DP
hotplug with x lanes and orientation foo, if we are not telling it
on which DP port it is ? kms devices already have multiple DP ports
and more then one could be hooked-up to type-c connectors.


I was looking at this series. You walk trough every DP port in the
system when the DP alt mode driver broadcasts the event, but maybe
that's different. Never mind.


Right, my "simple / naive" solution simply tells the kms driver to
check all DP ports for connection state changes, similar to how
running "xrandr" under Xorg causes the kms driver to re-check the
connection status of all ports. Actually running xrandr under Xorg
after plugging in the cable, is how I did my initial DP over Type-C
testing on the GPD win.

But once we start passing extra-info, I believe the kms driver needs
to know to which connector that info belongs.




Well, I don't think we can deny the GPU driver (in this case) the
information that we have and that is relevant to it, just because it
seems difficult to deliver that information to the right location.


Right, but this does not require a tight-coupling. My original
proposal can do this if we pass a data struct with an identifier
for the DP port for which the event is to the notifier. I suggest using
a string for identifier, something like: ":00:02.0/DP-1" this
event struct could then also contain all the info we want to pass.


I do agree that we should not tie the objects (device entries)
representing these components in kernel together, but I assume that we
agree now that the connection between the two - the USB Type-C
connector and the DisplayPort - must be described somewhere, either in
firmware or build-in? So I guess we are talking implementation details
here, right?


Right.


If that is the case...

That string identifier you proposed would basically provide the
details about the connection, so if we know those details, we might as
well use "normal" ways to describe the connection and just extract
them in runtime in the function that our DP alt mode driver calls. I
think the connection has to be defined in i915 on CHT in any case.


Interesting, I think the connection should be described in the fwnode
for the fusb302 device for the CHT/GPD win case. Specifically I think
this fits well as a property of the dp altmode.


OK, you are correct. I was stupidly still thinking about the driver
loading order, but the order does not matter.


The DP alt mode driver should definitely not need to pass anything
else to the notifier other than handle to itself (actually, handle
straight to the port device would be better) as an identifier. The
notifier function needs to be the one that determines the actual
connection using that handle. Even if the target DP is described using
a string like you propose, then that string has to come from
somewhere, most likely from a device property. The notifier function
can just as well extract it, we don't need to pass it separately.

Here's my suggestion for function prototype:

int drm_typec_dp_notification(struct device *typec_port_dev,
struct typec_displayport_data *data);


How about instead of the port_dev we pass in the altmode object and
we have a method to get the fwnode for the altmode? Then the
drm_typec_dp_notification() function can get info from that fwnode
to implement the connection finding you describe below:


We can pass the altmode object, np, but let's not decide which fwnode
we'll ultimately use. I'm still leaning towards the connector node.


So that function finds the connection between typec_port_dev and the
correct DP in runtime, possibly by letting i915 (or what ever GPU
driver) to do that. Once the function is done, it decrements any ref
counts that it incremented before returning.

That struct typec_displayport_data has all the information we have -
the current pin assignment from the Configure VDO, HPD IRQ from the
last Status Update, etc. - so it needs to be passed as payload to the
notifier.


Ack.

So I believe that this discussion ties into the discussion from the:
"[PATCH 0/2] platform/x86: intel_cht_int33fe: Start using software nodes"

Mail thread. As discussed there I agree that adding a usb_connector
child fwnode to the fwnode for the fusb302 to describe things like
sink- and source-pdos is a good idea.

Our last few mails were d

Re: [PATCH 0/3] Propagate DP-over-Type-C hotplug events from Type-C subsys to drm-drivers

2019-02-28 Thread Hans de Goede

Hi Heikki,

On 28-02-19 15:47, Heikki Krogerus wrote:

Hi Hans,

On Thu, Feb 28, 2019 at 12:24:25PM +0100, Hans de Goede wrote:

Hi,

On 28-02-19 10:15, Heikki Krogerus wrote:





I've been thinking about this... Do we actually need to link the
correct drm_connector to the Type-C connector? Perhaps we can make
this work by just linking the GFX device to the Type-C connector.


What use is it to the kms driver if it gets an event there is a DP
hotplug with x lanes and orientation foo, if we are not telling it
on which DP port it is ? kms devices already have multiple DP ports
and more then one could be hooked-up to type-c connectors.


I was looking at this series. You walk trough every DP port in the
system when the DP alt mode driver broadcasts the event, but maybe
that's different. Never mind.


Right, my "simple / naive" solution simply tells the kms driver to
check all DP ports for connection state changes, similar to how
running "xrandr" under Xorg causes the kms driver to re-check the
connection status of all ports. Actually running xrandr under Xorg
after plugging in the cable, is how I did my initial DP over Type-C
testing on the GPD win.

But once we start passing extra-info, I believe the kms driver needs
to know to which connector that info belongs.




Well, I don't think we can deny the GPU driver (in this case) the
information that we have and that is relevant to it, just because it
seems difficult to deliver that information to the right location.


Right, but this does not require a tight-coupling. My original
proposal can do this if we pass a data struct with an identifier
for the DP port for which the event is to the notifier. I suggest using
a string for identifier, something like: ":00:02.0/DP-1" this
event struct could then also contain all the info we want to pass.


I do agree that we should not tie the objects (device entries)
representing these components in kernel together, but I assume that we
agree now that the connection between the two - the USB Type-C
connector and the DisplayPort - must be described somewhere, either in
firmware or build-in? So I guess we are talking implementation details
here, right?


Right.


If that is the case...

That string identifier you proposed would basically provide the
details about the connection, so if we know those details, we might as
well use "normal" ways to describe the connection and just extract
them in runtime in the function that our DP alt mode driver calls. I
think the connection has to be defined in i915 on CHT in any case.


Interesting, I think the connection should be described in the fwnode
for the fusb302 device for the CHT/GPD win case. Specifically I think
this fits well as a property of the dp altmode.


The DP alt mode driver should definitely not need to pass anything
else to the notifier other than handle to itself (actually, handle
straight to the port device would be better) as an identifier. The
notifier function needs to be the one that determines the actual
connection using that handle. Even if the target DP is described using
a string like you propose, then that string has to come from
somewhere, most likely from a device property. The notifier function
can just as well extract it, we don't need to pass it separately.

Here's my suggestion for function prototype:

int drm_typec_dp_notification(struct device *typec_port_dev,
   struct typec_displayport_data *data);


How about instead of the port_dev we pass in the altmode object and
we have a method to get the fwnode for the altmode? Then the
drm_typec_dp_notification() function can get info from that fwnode
to implement the connection finding you describe below:


So that function finds the connection between typec_port_dev and the
correct DP in runtime, possibly by letting i915 (or what ever GPU
driver) to do that. Once the function is done, it decrements any ref
counts that it incremented before returning.

That struct typec_displayport_data has all the information we have -
the current pin assignment from the Configure VDO, HPD IRQ from the
last Status Update, etc. - so it needs to be passed as payload to the
notifier.


Ack.

So I believe that this discussion ties into the discussion from the:
"[PATCH 0/2] platform/x86: intel_cht_int33fe: Start using software nodes"

Mail thread. As discussed there I agree that adding a usb_connector
child fwnode to the fwnode for the fusb302 to describe things like
sink- and source-pdos is a good idea.

Our last few mails were discussing describing supported alt-modes on
the connector by adding altmode child-nodes to the usb_connector node.

I think it is best to continue that discussion here, as the 2 discussions
tie into one another.

So my last proposal in that thread was adding the following to:

Documentation/devicetree/bindings/connector/usb-connector.txt:

"""
Optionally an "usb-c-

Re: [PATCH 0/3] Propagate DP-over-Type-C hotplug events from Type-C subsys to drm-drivers

2019-02-28 Thread Hans de Goede

Hi,

On 28-02-19 10:15, Heikki Krogerus wrote:

On Wed, Feb 27, 2019 at 04:45:32PM +0100, Hans de Goede wrote:

Hi,

On 27-02-19 12:16, Jani Nikula wrote:

On Wed, 27 Feb 2019, Heikki Krogerus  wrote:

One thing that this series does not consider is the DP lane count
problem. The GPU drivers (i915 in this case) does not know is four,
two or one DP lanes in use.


Also, orientation.


The orientation should simply be correct with Type-C over DP. The mux /
orientation-switch used will take care of (physically) swapping the
lanes if the connector is inserted upside-down.


I guess that is not a critical issue since there is a workaround (I
think) where the driver basically does trial and error, but ideally we
should be able to tell i915 also the pin assignment that was
negotiated with the partner device so it knows the DP lane count.


Yeah, if the information is there, we'd like to know.


So far machines actually using a setup where the kernel does the
USB-PD / Type-C negotiation rather then this being handled in firmware
in say the Alpine Ridge controller, are very rare.

AFAIK in the Alpine Ridge controller case, there is no communication
with the i915 driver, the only thing the Alpine Ridge controller does
which the everything done in the kernel approach does not, is that
it actually has a pin connected to the HDP pin of the displayport in
question.  But that just lets the i915 driver know about hotplug-events,
not how many lanes are used.

Currently I'm aware of only 2 x86 models which actually need the
hotplug event propagation from the Type-C subsystem to the i915 driver.
Do we really want to come up with a much more complex solution to
optimize for this corner case, while the much more common case
(Alpine Ridge controller) does not provide this info to the i915 driver?


The HPD signal is often handled with a GPIO on Intel Platforms. Either
the PD controller or EC controller, after receiving the Attention
message, triggers the GPIO. On some systems though that GPIO method
could not be used, so instead a side channel communication is used:
the GFX device (so i915 driver) receives a specific custom interrupt.

Unfortunately it now appears that there may be products coming where
using the GPIO is not going to be possible, and also side channel
communication is going to be out of the question. I've started an
internal discussion inside Intel about the possibility to extend the
UCSI specification to be able to support that kind of products.

Alpine Ridge uses TI's Power Delivery controllers. The platforms that
have Alpine Ridge TBT controller(s) often expose the USB Type-C
connectors on them to the OS via UCSI, however, it appears the Alpine
Ridge actually allows direct access to the PD controllers from the OS.
That would mean we can supply the same information to the GPU drivers
that we will deliver on CHT also on every platform that uses Alpine
Ridge.


Ok.


To give some idea of the complexity, first of all we need some
mechanism to let the kernel know which drm_connector is connected
to which Type-C port. For the 2 models I know if which need this, this
info is not available and we would need to hardcode it in the kernel
based on e.g. DMI matching.


I've been thinking about this... Do we actually need to link the
correct drm_connector to the Type-C connector? Perhaps we can make
this work by just linking the GFX device to the Type-C connector.


What use is it to the kms driver if it gets an event there is a DP
hotplug with x lanes and orientation foo, if we are not telling it
on which DP port it is ? kms devices already have multiple DP ports
and more then one could be hooked-up to type-c connectors.


Then once we have this link, we need to start thinking about probe
ordering. Likely we need the typec framework to find the drm_connector,
since the typec-partner device is only created when there actually is
a DP capable "dongle" connected, making doing it the other way around
tricky. Then the typec-partner device needs to get a reference or some
such to make sure the drm_connector does not fgo away during the lifetime
of the typec-partner device.


No! We must not link the partner device with anything other than the
Type-C connector. We link the USB Type-C connector to the DisplayPort,
and we link the USB Type-C connector to the partner. The Type-C
connector is the proxy here.


Maybe, but even then we still need one side of the link to have a
reference on the other, having a proxy in between does not change
anything.


I would really like to avoid this, so if we want to send more info to
the i915 driver, I suggest we create some event struct for this which
gets passed to the notifier, this could include a string to
describe the DP connector which the Type-C connector is connected to
when the mux is set to DP mode, e.g. "i915/DP-1" should be unique
or probably better, use the PCI device name, so: ":00:02.0/DP-1"

Then we still have a loose

Re: [PATCH 3/3] usb: typec: altmodes/displayport: Notify drm subsys of hotplug events

2019-02-27 Thread Hans de Goede

Hi,

On 27-02-19 10:44, Heikki Krogerus wrote:

On Mon, Feb 25, 2019 at 02:20:37PM +0100, Hans de Goede wrote:

Use the new drm_kms_call_oob_hotplug_notifier_chain() function to load
drm/kms drivers know about DisplayPort over Type-C hotplug events.

Signed-off-by: Hans de Goede 


I'm OK with this. I'll wait for the v2 and see if I can test these.


The only change I've queued for v2 is adding a "depends on DRM" to
the TYPEC_DP_ALTMODE Kconfig.

And given the discussion about passing lane-info, it might be a while
before we get a v2, so if you want to give this a test run, it is
probably best to just test v1 for now (if you've time).

Note to test this on the GPD win (which you have AFAIK) you will also
need the fusb302 + pi3usb30532 patches I've send out recently, as well as:

https://github.com/jwrdegoede/linux-sunxi/commit/945c6fe0a18957357b42e04ed34bf33667003030

I've one Type-C to VGA dongle (without any other functions) where the Type-C
mode negotiation fails. This one does work on a XPS 15 so I need to borrow
some hardware from a friend so that I can capture the USB-PD signals and
see what the Alpine Ridge controller does different compared to the in kernel
stack and fix this. My other 4 dongles work fine, including this "standard" 
model:
http://media.redgamingtech.com/rgt-website/2015/03/Apple-HDMI-Usb-Type-C-dongle.jpg

Regards,

Hans


Re: [PATCH 0/3] Propagate DP-over-Type-C hotplug events from Type-C subsys to drm-drivers

2019-02-27 Thread Hans de Goede

Hi,

On 27-02-19 12:16, Jani Nikula wrote:

On Wed, 27 Feb 2019, Heikki Krogerus  wrote:

One thing that this series does not consider is the DP lane count
problem. The GPU drivers (i915 in this case) does not know is four,
two or one DP lanes in use.


Also, orientation.


The orientation should simply be correct with Type-C over DP. The mux /
orientation-switch used will take care of (physically) swapping the
lanes if the connector is inserted upside-down.


I guess that is not a critical issue since there is a workaround (I
think) where the driver basically does trial and error, but ideally we
should be able to tell i915 also the pin assignment that was
negotiated with the partner device so it knows the DP lane count.


Yeah, if the information is there, we'd like to know.


So far machines actually using a setup where the kernel does the
USB-PD / Type-C negotiation rather then this being handled in firmware
in say the Alpine Ridge controller, are very rare.

AFAIK in the Alpine Ridge controller case, there is no communication
with the i915 driver, the only thing the Alpine Ridge controller does
which the everything done in the kernel approach does not, is that
it actually has a pin connected to the HDP pin of the displayport in
question.  But that just lets the i915 driver know about hotplug-events,
not how many lanes are used.

Currently I'm aware of only 2 x86 models which actually need the
hotplug event propagation from the Type-C subsystem to the i915 driver.
Do we really want to come up with a much more complex solution to
optimize for this corner case, while the much more common case
(Alpine Ridge controller) does not provide this info to the i915 driver?

To give some idea of the complexity, first of all we need some
mechanism to let the kernel know which drm_connector is connected
to which Type-C port. For the 2 models I know if which need this, this
info is not available and we would need to hardcode it in the kernel
based on e.g. DMI matching.

Then once we have this link, we need to start thinking about probe
ordering. Likely we need the typec framework to find the drm_connector,
since the typec-partner device is only created when there actually is
a DP capable "dongle" connected, making doing it the other way around
tricky. Then the typec-partner device needs to get a reference or some
such to make sure the drm_connector does not fgo away during the lifetime
of the typec-partner device.

I would really like to avoid this, so if we want to send more info to
the i915 driver, I suggest we create some event struct for this which
gets passed to the notifier, this could include a string to
describe the DP connector which the Type-C connector is connected to
when the mux is set to DP mode, e.g. "i915/DP-1" should be unique
or probably better, use the PCI device name, so: ":00:02.0/DP-1"

Then we still have a loose coupling avoiding lifetime issues, while
the receiving drm driver can check which connector the event is for
and we can then also include other info such as lane-count and orientation
in the event struct.


With the orientation


As said, the orientation *should* be corrected by the mux switch,
it is corrected by the mux switch on the hardware I know about and
actually getting it wrong breaks the display output (we had a bug there),
so I guess that getting it wrong leads to the lines being swizzled in a way
which the i915 driver does not check for ...

Regards,

Hans


Re: [PATCH] usb: typec: pi3usb30532: Keep orientation when setting mux to safe mode

2019-02-25 Thread Hans de Goede

Hi,

On 25-02-19 16:50, Heikki Krogerus wrote:

On Fri, Feb 22, 2019 at 08:22:39PM +0100, Hans de Goede wrote:

Keep the orientation value when setting the mux to safe mode, this
fixes the orientation getting reset when switching alt-modes.

Signed-off-by: Hans de Goede 


Should this be also a fix?


This only comes into play when switching alt-modes, so more
or less the same as with the displayport altmode fix:

"There are no users if this yet, until we've agreement
on the DT bindings and code merged for adding alt-modes
to an usb-connector node, nothing will be using this code,
so I see little use in adding a Cc: stable or some such."

Regards,

Hans







---
  drivers/usb/typec/mux/pi3usb30532.c | 3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/mux/pi3usb30532.c 
b/drivers/usb/typec/mux/pi3usb30532.c
index 64eb5983e17a..9294e85fd34b 100644
--- a/drivers/usb/typec/mux/pi3usb30532.c
+++ b/drivers/usb/typec/mux/pi3usb30532.c
@@ -84,7 +84,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int 
state)
  
  	switch (state) {

case TYPEC_STATE_SAFE:
-   new_conf = PI3USB30532_CONF_OPEN;
+   new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
+  PI3USB30532_CONF_OPEN;
break;
case TYPEC_STATE_USB:
new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
--
2.20.1


thanks,



Re: [PATCH] usb: typec: altmodes/displayport: Fall back to multi-func pins

2019-02-25 Thread Hans de Goede

Hi Heikki,

On 25-02-19 16:49, Heikki Krogerus wrote:

On Mon, Feb 25, 2019 at 01:56:37PM +0100, Hans de Goede wrote:

If our port-partner supports both DP-only operation (pin-assignment C)
and multi-func operation (pin-assignment D) and we only support
pin-assignment D and the port-partner prefers DP-only mode, then
before this commit we would and up masking out pin-assignment D from
the available pin-assignments and fail to pick a pin-assignment.

Instead only mask out the multi-func pin-assignments if we support
dp-only pin-assignments, so that we correctly fall-back to a multi-func
pin-assignment in this case (by picking pin-assignment D).

Signed-off-by: Hans de Goede 


Should this be handled as a fix?


AFAIK they are no users if this yet, until we've agreement
on the DT bindings and code merged for adding alt-modes
to an usb-connector node, nothing will be using this code,
so I see little use in adding a Cc: stable or some such.

Regards,

Hans





---
  drivers/usb/typec/altmodes/displayport.c | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/typec/altmodes/displayport.c 
b/drivers/usb/typec/altmodes/displayport.c
index 3f06e94771a7..35161594e368 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -104,7 +104,7 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 
con)
if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC &&
pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK)
pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK;
-   else
+   else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK)
pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK;
  
  		if (!pin_assign)

--
2.20.1


thanks,



Re: [PATCH 3/3] usb: typec: altmodes/displayport: Notify drm subsys of hotplug events

2019-02-25 Thread Hans de Goede

Hi,

On 25-02-19 15:06, Greg Kroah-Hartman wrote:

On Mon, Feb 25, 2019 at 02:20:37PM +0100, Hans de Goede wrote:

Use the new drm_kms_call_oob_hotplug_notifier_chain() function to load


s/load/let/ fixed in my tree.


drm/kms drivers know about DisplayPort over Type-C hotplug events.

Signed-off-by: Hans de Goede 
---
  drivers/usb/typec/altmodes/displayport.c | 34 
  1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/typec/altmodes/displayport.c 
b/drivers/usb/typec/altmodes/displayport.c
index 35161594e368..87760ea252d6 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -13,6 +13,7 @@
  #include 
  #include 
  #include 
+#include 
  
  #define DP_HEADER(cmd)			(VDO(USB_TYPEC_DP_SID, 1, cmd) | \

 VDO_OPOS(USB_TYPEC_DP_MODE))
@@ -67,12 +68,23 @@ struct dp_altmode {
const struct typec_altmode *port;
  };
  
-static int dp_altmode_notify(struct dp_altmode *dp)

+static int dp_altmode_notify(struct dp_altmode *dp, unsigned long conf)
+{
+   int ret;
+
+   ret = typec_altmode_notify(dp->alt, conf, &dp->data);
+   if (ret)
+   return ret;
+
+   drm_kms_call_oob_hotplug_notifier_chain(DRM_OOB_HOTPLUG_TYPE_C_DP);


Is this causing a build/run-time dependancy of the USB code on DRM now?
What about typec systems without DRM, is that a thing?


Good point, yes this adds a build/run-time dependancy on the drm-core
to the Type-C DisplayPort altmode driver (typec_displayport.ko). But
only to that driver, which can be enabled / disabled separately through
CONFIG_TYPEC_DP_ALTMODE and that specific Type-C altmode makes little
sense without having drm/kms support.

Your remark does make me realize that I have forgotten to add a Kconfig
dependency for this to the TYPEC_DP_ALTMODE Kconfig symbol, I will fix
this for v2.

Regards,

Hans


[PATCH 3/3] usb: typec: altmodes/displayport: Notify drm subsys of hotplug events

2019-02-25 Thread Hans de Goede
Use the new drm_kms_call_oob_hotplug_notifier_chain() function to load
drm/kms drivers know about DisplayPort over Type-C hotplug events.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/altmodes/displayport.c | 34 
 1 file changed, 23 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/typec/altmodes/displayport.c 
b/drivers/usb/typec/altmodes/displayport.c
index 35161594e368..87760ea252d6 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DP_HEADER(cmd) (VDO(USB_TYPEC_DP_SID, 1, cmd) | \
 VDO_OPOS(USB_TYPEC_DP_MODE))
@@ -67,12 +68,23 @@ struct dp_altmode {
const struct typec_altmode *port;
 };
 
-static int dp_altmode_notify(struct dp_altmode *dp)
+static int dp_altmode_notify(struct dp_altmode *dp, unsigned long conf)
+{
+   int ret;
+
+   ret = typec_altmode_notify(dp->alt, conf, &dp->data);
+   if (ret)
+   return ret;
+
+   drm_kms_call_oob_hotplug_notifier_chain(DRM_OOB_HOTPLUG_TYPE_C_DP);
+   return 0;
+}
+
+static int dp_altmode_notify_dp(struct dp_altmode *dp)
 {
u8 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
 
-   return typec_altmode_notify(dp->alt, TYPEC_MODAL_STATE(state),
-  &dp->data);
+   return dp_altmode_notify(dp, TYPEC_MODAL_STATE(state));
 }
 
 static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
@@ -145,10 +157,9 @@ static int dp_altmode_configured(struct dp_altmode *dp)
sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
 
if (!dp->data.conf)
-   return typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-   &dp->data);
+   return dp_altmode_notify(dp, TYPEC_STATE_USB);
 
-   ret = dp_altmode_notify(dp);
+   ret = dp_altmode_notify_dp(dp);
if (ret)
return ret;
 
@@ -162,7 +173,7 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, 
u32 conf)
u32 header = DP_HEADER(DP_CMD_CONFIGURE);
int ret;
 
-   ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
+   ret = dp_altmode_notify(dp, TYPEC_STATE_SAFE);
if (ret) {
dev_err(&dp->alt->dev,
"unable to put to connector to safe mode\n");
@@ -172,10 +183,9 @@ static int dp_altmode_configure_vdm(struct dp_altmode *dp, 
u32 conf)
ret = typec_altmode_vdm(dp->alt, header, &conf, 2);
if (ret) {
if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf))
-   dp_altmode_notify(dp);
+   dp_altmode_notify_dp(dp);
else
-   typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
-&dp->data);
+   dp_altmode_notify(dp, TYPEC_STATE_USB);
}
 
return ret;
@@ -241,7 +251,7 @@ static void dp_altmode_attention(struct typec_altmode *alt, 
const u32 vdo)
if (dp_altmode_status_update(dp))
dev_warn(&alt->dev, "%s: status update failed\n", __func__);
 
-   if (dp_altmode_notify(dp))
+   if (dp_altmode_notify_dp(dp))
dev_err(&alt->dev, "%s: notification failed\n", __func__);
 
if (old_state == DP_STATE_IDLE && dp->state != DP_STATE_IDLE)
@@ -556,6 +566,8 @@ static void dp_altmode_remove(struct typec_altmode *alt)
 
sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
cancel_work_sync(&dp->work);
+
+   drm_kms_call_oob_hotplug_notifier_chain(DRM_OOB_HOTPLUG_TYPE_C_DP);
 }
 
 static const struct typec_device_id dp_typec_id[] = {
-- 
2.20.1



[PATCH 2/3] i915: Add support for out-of-bound hotplug events

2019-02-25 Thread Hans de Goede
On some Cherry Trail devices, DisplayPort over Type-C is supported through
a USB-PD microcontroller (e.g. a fusb302) + a mux to switch the superspeed
datalines between USB-3 and DP (e.g. a pi3usb30532). The kernel in this
case does the PD/alt-mode negotiation itself, rather then everything being
handled in firmware.

So the kernel itself picks an alt-mode, tells the Type-C "dongle" to switch
to DP mode and sets the mux accordingly. In this setup the HPD pin is not
connected, so the i915 driver needs to respond to a software event and scan
the DP port for changes manually.

This commit adds support for this. Together with the recent addition of
DP alt-mode support to the Type-C subsystem this makes DP over Type-C
work on these devices.

Signed-off-by: Hans de Goede 
---
 drivers/gpu/drm/i915/i915_drv.h  |  2 ++
 drivers/gpu/drm/i915/i915_irq.c  |  2 ++
 drivers/gpu/drm/i915/intel_hotplug.c | 38 
 3 files changed, 42 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b1c31967194b..5d8c585ddbf7 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -153,6 +153,7 @@ enum hpd_pin {
 
 struct i915_hotplug {
struct work_struct hotplug_work;
+   struct notifier_block oob_notifier;
 
struct {
unsigned long last_jiffies;
@@ -2632,6 +2633,7 @@ void intel_hpd_irq_handler(struct drm_i915_private 
*dev_priv,
   u32 pin_mask, u32 long_mask);
 void intel_hpd_init(struct drm_i915_private *dev_priv);
 void intel_hpd_init_work(struct drm_i915_private *dev_priv);
+void intel_hpd_fini_work(struct drm_i915_private *dev_priv);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
 enum hpd_pin intel_hpd_pin_default(struct drm_i915_private *dev_priv,
   enum port port);
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 8211045a981b..14f3323b721b 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -4965,6 +4965,8 @@ void intel_irq_fini(struct drm_i915_private *i915)
 
for (i = 0; i < MAX_L3_SLICES; ++i)
kfree(i915->l3_parity.remap_info[i]);
+
+   intel_hpd_fini_work(i915);
 }
 
 /**
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c 
b/drivers/gpu/drm/i915/intel_hotplug.c
index e24174d08fed..221878fa26af 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -518,6 +518,36 @@ void intel_hpd_irq_handler(struct drm_i915_private 
*dev_priv,
schedule_work(&dev_priv->hotplug.hotplug_work);
 }
 
+static int intel_hpd_oob_notifier(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+   struct drm_i915_private *dev_priv =
+   container_of(nb, struct drm_i915_private, hotplug.oob_notifier);
+   struct intel_encoder *encoder;
+   u32 bits = 0;
+
+   /* We only support DP over Type-C notifications */
+   if (event != DRM_OOB_HOTPLUG_TYPE_C_DP)
+   return NOTIFY_DONE;
+
+   /* Schedule a hotplug check for each DP encoder, except for EDP ones */
+   for_each_intel_dp(&dev_priv->drm, encoder) {
+   if (encoder->type == INTEL_OUTPUT_EDP)
+   continue;
+
+   bits |= BIT(encoder->hpd_pin);
+   }
+
+   if (bits) {
+   spin_lock_irq(&dev_priv->irq_lock);
+   dev_priv->hotplug.event_bits |= bits;
+   spin_unlock_irq(&dev_priv->irq_lock);
+   schedule_work(&dev_priv->hotplug.hotplug_work);
+   }
+
+   return NOTIFY_DONE;
+}
+
 /**
  * intel_hpd_init - initializes and enables hpd support
  * @dev_priv: i915 device instance
@@ -640,6 +670,14 @@ void intel_hpd_init_work(struct drm_i915_private *dev_priv)
INIT_WORK(&dev_priv->hotplug.poll_init_work, i915_hpd_poll_init_work);
INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work,
  intel_hpd_irq_storm_reenable_work);
+   dev_priv->hotplug.oob_notifier.notifier_call = intel_hpd_oob_notifier;
+   drm_kms_register_oob_hotplug_notifier(&dev_priv->hotplug.oob_notifier);
+}
+
+void intel_hpd_fini_work(struct drm_i915_private *dev_priv)
+{
+   drm_kms_unregister_oob_hotplug_notifier(
+   &dev_priv->hotplug.oob_notifier);
 }
 
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv)
-- 
2.20.1



[PATCH 0/3] Propagate DP-over-Type-C hotplug events from Type-C subsys to drm-drivers

2019-02-25 Thread Hans de Goede
Hi All,

On some Cherry Trail devices, DisplayPort over Type-C is supported through
a USB-PD microcontroller (e.g. a fusb302) + a mux to switch the superspeed
datalines between USB-3 and DP (e.g. a pi3usb30532). The kernel in this
case does the PD/alt-mode negotiation itself, rather then everything being
handled in firmware.

So the kernel itself picks an alt-mode, tells the Type-C "dongle" to switch
to DP mode and sets the mux accordingly. In this setup the HPD pin is not
connected, so the i915 driver needs to respond to a software event and scan
the DP port for changes manually.

Thanks to Heikki's great work on the DisplayPort altmode support in the
typec subsys, we now correctly tell the dongle to switch to DP altmode
and we correctly set the mux and orientation switches to connect the
DP lines to the Type-C connector.

This just leaves sending an out-of-band hotplug event from the Type-C
subsystem to the i915 driver and then we've fully working DP over Type-C
on these devices.

This series implements this. The first patch adds a generic mechanism
for oob hotplug events to be send to the drm subsys, the second patch
adds support for this mechanism to the i915 driver and the third patch
makes the typec displayport_altmode driver send these events.

The commit message of the first patch explains why I've chosen to things
the way these patches do them.

Regards,

Hans



[PATCH 1/3] drm: Add support for out-of-band hotplug notification

2019-02-25 Thread Hans de Goede
On some hardware a hotplug event notification may come from outside the
display driver / device.

One example of this is laptops with hybrid graphics where one or more
outputs are connected to the discrete GPU only. In this case if the
discrete GPU is fully powered down to save power, a hotplug to one of
these outputs will not be noticed through normal means. These laptops
have another mechanism to detect the hotplug which will typically raise
an event on the ACPI video bus.

Another example of this is some USB Type-C setups where the hardware
muxes the DisplayPort data and aux-lines but does not pass the altmode
HPD status bit to the GPUs DP HPD pin.

This commit adds a loose coupling to the drm subsys allowing event-sources
to notify drm-drivers of such events without needing a reference to a
drm-device or a drm-connector.

This loose coupling is implemented through a blocking notifier. drm-drivers
interested in oob hotplug events can register themselves to receive
notifations and event-sources call drm_kms_call_oob_hotplug_notifier_chain
to let any listeners know about events.

An earlier attempt has been done to implement this functionality with a
tight coupling, where the event-source would somehow figure out the right
drm-connector to deliver the event to and then send it directly to that
drm-connector. Such a tight coupling approach has several issues with
lifetime management of the coupled objects as well as introducing several
probe-ordering issues. Therefor the tight coupling approach has been
abandoned.

Note for now drm_kms_call_oob_hotplug_notifier_chain's event parameter can
only have 1 value: DRM_OOB_HOTPLUG_TYPE_C_DP.  The ACPI videobus hotplug
event case is currently already supported in the nouveau driver by
registering a generic acpi event notifier.

Signed-off-by: Hans de Goede 
---
 Documentation/gpu/drm-kms-helpers.rst |  1 +
 drivers/gpu/drm/drm_probe_helper.c| 67 +++
 include/drm/drm_probe_helper.h| 12 +
 3 files changed, 80 insertions(+)

diff --git a/Documentation/gpu/drm-kms-helpers.rst 
b/Documentation/gpu/drm-kms-helpers.rst
index b422eb8edf16..f144d68f8e7a 100644
--- a/Documentation/gpu/drm-kms-helpers.rst
+++ b/Documentation/gpu/drm-kms-helpers.rst
@@ -249,6 +249,7 @@ Output Probing Helper Functions Reference
 
 .. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
:doc: output probing helper overview
+   :doc: out-of-band hotplug event helper overview
 
 .. kernel-doc:: drivers/gpu/drm/drm_probe_helper.c
:export:
diff --git a/drivers/gpu/drm/drm_probe_helper.c 
b/drivers/gpu/drm/drm_probe_helper.c
index 6fd08e04b323..4f0b421514ef 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -31,6 +31,7 @@
 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -792,3 +793,69 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
return changed;
 }
 EXPORT_SYMBOL(drm_helper_hpd_irq_event);
+
+/**
+ * DOC: out-of-band hotplug event helper overview
+ *
+ * On some hardware a hotplug event notification may come from outside
+ * the display driver / device.
+ *
+ * One example of this is laptops with hybrid graphics where one or more
+ * outputs are connected to the discrete GPU only. In this case if the discrete
+ * GPU is fully powered down to save power, a hotplug to one of these outputs
+ * will not be noticed through normal means. These laptops have another
+ * mechanism to detect the hotplug which will typically raise an event on the
+ * ACPI video bus.
+ *
+ * Another example of this is some USB Type-C setups where the hardware
+ * muxes the DisplayPort data and aux-lines but does not pass the altmode
+ * HPD status bit to the GPUs DP HPD pin.
+ *
+ * The oob hotplug helper functions allow a drm display driver to listen
+ * for such oob events and allow other subsystems to notify listeners of
+ * these events.
+ */
+
+static BLOCKING_NOTIFIER_HEAD(drm_kms_oob_hotplug_notifier_head);
+
+/**
+ * drm_kms_register_oob_hotplug_notifier - register an oob hotplug notifier
+ * @nb: notifier_block to register
+ *
+ * Drivers can use this helper function to register a notifier for
+ * out-of-band hotplug events.
+ */
+int drm_kms_register_oob_hotplug_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_register(
+   &drm_kms_oob_hotplug_notifier_head, nb);
+}
+EXPORT_SYMBOL(drm_kms_register_oob_hotplug_notifier);
+
+/**
+ * drm_kms_unregister_oob_hotplug_notifier - unregister an oob hotplug notifier
+ * @nb: notifier_block to register
+ *
+ * Drivers can use this helper function to unregister a notifier for
+ * out-of-band hotplug events.
+ */
+int drm_kms_unregister_oob_hotplug_notifier(struct notifier_block *nb)
+{
+   return blocking_notifier_chain_unregister(
+   &drm_kms_oob_hotplug_notifier_head, nb);
+}
+EXPORT_SYMBOL(drm_kms_unregister_oob_hot

[PATCH] usb: typec: altmodes/displayport: Fall back to multi-func pins

2019-02-25 Thread Hans de Goede
If our port-partner supports both DP-only operation (pin-assignment C)
and multi-func operation (pin-assignment D) and we only support
pin-assignment D and the port-partner prefers DP-only mode, then
before this commit we would and up masking out pin-assignment D from
the available pin-assignments and fail to pick a pin-assignment.

Instead only mask out the multi-func pin-assignments if we support
dp-only pin-assignments, so that we correctly fall-back to a multi-func
pin-assignment in this case (by picking pin-assignment D).

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/altmodes/displayport.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/typec/altmodes/displayport.c 
b/drivers/usb/typec/altmodes/displayport.c
index 3f06e94771a7..35161594e368 100644
--- a/drivers/usb/typec/altmodes/displayport.c
+++ b/drivers/usb/typec/altmodes/displayport.c
@@ -104,7 +104,7 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 
con)
if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC &&
pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK)
pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK;
-   else
+   else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK)
pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK;
 
if (!pin_assign)
-- 
2.20.1



[PATCH] usb: typec: pi3usb30532: Keep orientation when setting mux to safe mode

2019-02-22 Thread Hans de Goede
Keep the orientation value when setting the mux to safe mode, this
fixes the orientation getting reset when switching alt-modes.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/mux/pi3usb30532.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/typec/mux/pi3usb30532.c 
b/drivers/usb/typec/mux/pi3usb30532.c
index 64eb5983e17a..9294e85fd34b 100644
--- a/drivers/usb/typec/mux/pi3usb30532.c
+++ b/drivers/usb/typec/mux/pi3usb30532.c
@@ -84,7 +84,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int 
state)
 
switch (state) {
case TYPEC_STATE_SAFE:
-   new_conf = PI3USB30532_CONF_OPEN;
+   new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
+  PI3USB30532_CONF_OPEN;
break;
case TYPEC_STATE_USB:
new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
-- 
2.20.1



[PATCH 7/8] usb: typec: fusb302: Simplify suspend/resume handling

2019-02-22 Thread Hans de Goede
Remove the DIY code to avoid doing i2c-transfers while our parent
i2c-adapter may be suspended.

Instead simply disable our irq from our suspend handler and re-enable
it on resume. This is a much cleaner way to avoid this problem and
mirrors how most i2c drivers handle this.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 62 ++--
 1 file changed, 3 insertions(+), 59 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 637ea1232fa0..940e096a4ac6 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -85,9 +85,6 @@ struct fusb302_chip {
struct workqueue_struct *wq;
struct delayed_work bc_lvl_handler;
 
-   atomic_t pm_suspend;
-   atomic_t i2c_busy;
-
/* lock for sharing chip states */
struct mutex lock;
 
@@ -236,40 +233,15 @@ static void fusb302_debugfs_exit(const struct 
fusb302_chip *chip) { }
 #define FUSB302_RESUME_RETRY 10
 #define FUSB302_RESUME_RETRY_SLEEP 50
 
-static bool fusb302_is_suspended(struct fusb302_chip *chip)
-{
-   int retry_cnt;
-
-   for (retry_cnt = 0; retry_cnt < FUSB302_RESUME_RETRY; retry_cnt++) {
-   if (atomic_read(&chip->pm_suspend)) {
-   dev_err(chip->dev, "i2c: pm suspend, retry %d/%d\n",
-   retry_cnt + 1, FUSB302_RESUME_RETRY);
-   msleep(FUSB302_RESUME_RETRY_SLEEP);
-   } else {
-   return false;
-   }
-   }
-
-   return true;
-}
-
 static int fusb302_i2c_write(struct fusb302_chip *chip,
 u8 address, u8 data)
 {
int ret = 0;
 
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
-
ret = i2c_smbus_write_byte_data(chip->i2c_client, address, data);
if (ret < 0)
fusb302_log(chip, "cannot write 0x%02x to 0x%02x, ret=%d",
data, address, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -281,19 +253,12 @@ static int fusb302_i2c_block_write(struct fusb302_chip 
*chip, u8 address,
 
if (length <= 0)
return ret;
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
 
ret = i2c_smbus_write_i2c_block_data(chip->i2c_client, address,
 length, data);
if (ret < 0)
fusb302_log(chip, "cannot block write 0x%02x, len=%d, ret=%d",
address, length, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -303,18 +268,10 @@ static int fusb302_i2c_read(struct fusb302_chip *chip,
 {
int ret = 0;
 
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
-
ret = i2c_smbus_read_byte_data(chip->i2c_client, address);
*data = (u8)ret;
if (ret < 0)
fusb302_log(chip, "cannot read %02x, ret=%d", address, ret);
-   atomic_set(&chip->i2c_busy, 0);
 
return ret;
 }
@@ -326,19 +283,13 @@ static int fusb302_i2c_block_read(struct fusb302_chip 
*chip, u8 address,
 
if (length <= 0)
return ret;
-   atomic_set(&chip->i2c_busy, 1);
-
-   if (fusb302_is_suspended(chip)) {
-   atomic_set(&chip->i2c_busy, 0);
-   return -ETIMEDOUT;
-   }
 
ret = i2c_smbus_read_i2c_block_data(chip->i2c_client, address,
length, data);
if (ret < 0) {
fusb302_log(chip, "cannot block read 0x%02x, len=%d, ret=%d",
address, length, ret);
-   goto done;
+   return ret;
}
if (ret != length) {
fusb302_log(chip, "only read %d/%d bytes from 0x%02x",
@@ -346,9 +297,6 @@ static int fusb302_i2c_block_read(struct fusb302_chip 
*chip, u8 address,
ret = -EIO;
}
 
-done:
-   atomic_set(&chip->i2c_busy, 0);
-
return ret;
 }
 
@@ -1791,10 +1739,7 @@ static int fusb302_pm_suspend(struct device *dev)
 {
struct fusb302_chip *chip = dev->driver_data;
 
-   if (atomic_read(&chip->i2c_busy))
-   return -EBUSY;
-   atomic_set(&chip->pm_suspend, 1);
-
+   disable_irq(chip->gpio_int_n_irq);
return 0;
 }
 
@@ -1802,8 +1747,7 @@ static int fusb302_pm_resume(struct device *dev)
 {
struct fusb302_chip *chip = dev->driver_data;
 
-   atomic_set(&chip->pm_suspend, 0);
-
+   enable_irq(chip->gpio_int_n_irq);
return 0;
 }
 
-- 
2.20.1



[PATCH 2/8] usb: typec: fusb302: Refactor / simplify tcpm_set_cc()

2019-02-22 Thread Hans de Goede
After commit ea3b4d5523bc ("usb: typec: fusb302: Resolve fixed power role
contract setup"), tcpm_set_cc always calls fusb302_set_toggling.

Before this refactor tcpm_set_cc does the following:

1) fusb302_set_toggling(TOGGLING_MODE_OFF),
   this sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG.
2) fusb302_set_cc_pull(...).
3) "reset cc status".
4) if pull-up fusb302_set_src_current(...).
5) if pull-up or pull-down enable bc-lvl resp comp-chng irq.
6) fusb302_set_toggling(new-toggling-mode), which again
   sets both FUSB_REG_MASK_BC_LVL and FUSB_REG_MASK_COMP_CHNG disabling
   the just enabled irq. fusb302_set_toggling is skipped when the new
   toggling mode is TOGGLING_MODE_OFF because this is already done in 1,
   note in this case 5) is a no-op.

When we are toggling the bits set by fusb302_set_cc_pull will be ignored
until we turn toggling off, so we can safely move the fusb302_set_cc_pull
call to before setting TOGGLING_MODE_OFF.

Either we are not toggling yet, or the src-current has already been set,
so we can also safely set the src-current earlier, allowing us to do the
fusb302_set_toggling(TOGGLING_MODE_OFF) call at the same time as we
set the other toggling modes. Also setting the src-current is a no-op
when not enabling pull-ups, so we can drop the if.

And since the second fusb302_set_toggling undoes the effects of step 5,
we can skip step 5, the bc-lvl resp comp-chng irq wil be enabled by
fusb302_handle_togdone_snk resp. fusb302_handle_togdone_src when toggling
is done.

Together this allows us to simplify things to:

1) fusb302_set_cc_pull(...)
2) "reset cc status"
3) fusb302_set_src_current(...)
4) fusb302_set_toggling(new-toggling-mode)

This commit does this, leading to a nice cleanup.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 85 ++--
 1 file changed, 15 insertions(+), 70 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 3ad92d68b6af..552b762d262c 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -676,7 +676,6 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 tcpc_dev);
int ret = 0;
bool pull_up, pull_down;
-   u8 rd_mda;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
@@ -684,16 +683,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
case TYPEC_CC_OPEN:
pull_up = false;
pull_down = false;
+   mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
pull_up = false;
pull_down = true;
+   mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
pull_up = true;
pull_down = false;
+   mode = TOGGLING_MODE_SRC;
break;
default:
fusb302_log(chip, "unsupported cc value %s",
@@ -701,11 +703,9 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
ret = -EINVAL;
goto done;
}
-   ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot stop toggling, ret=%d", ret);
-   goto done;
-   }
+
+   fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
+
ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
if (ret < 0) {
fusb302_log(chip,
@@ -718,74 +718,19 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
/* reset the cc status */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
+
/* adjust current for SRC */
-   if (pull_up) {
-   ret = fusb302_set_src_current(chip, cc_src_current[cc]);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set src current %s, ret=%d",
-   typec_cc_status_name[cc], ret);
-   goto done;
-   }
-   }
-   /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */
-   if (pull_up) {
-   rd_mda = rd_mda_value[cc_src_current[cc]];
-   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
-   if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set SRC measure value, ret=%d",
-   ret);
-   goto done;
-   }
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK,
-FUSB_REG_MASK_BC_LVL |
-FUSB_REG_MASK_COMP

[PATCH 6/8] usb: typec: fusb302: 2 small misc. fixes

2019-02-22 Thread Hans de Goede
Fix a copy and paste error in an error message and a spelling error
in a comment.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 05e54fcb2819..637ea1232fa0 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1385,7 +1385,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip 
*chip,
 FUSB_REG_MASK_COMP_CHNG);
if (ret < 0) {
fusb302_log(chip,
-   "cannot unmask bc_lcl interrupt, ret=%d", ret);
+   "cannot unmask comp_chng interrupt, ret=%d", ret);
return ret;
}
chip->intr_comp_chng = true;
@@ -1560,7 +1560,7 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id)
fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s",
comp_result ? "true" : "false");
if (comp_result) {
-   /* cc level > Rd_threashold, detach */
+   /* cc level > Rd_threshold, detach */
chip->cc1 = TYPEC_CC_OPEN;
chip->cc2 = TYPEC_CC_OPEN;
tcpm_cc_change(chip->tcpm_port);
-- 
2.20.1



[PATCH 1/8] usb: typec: fusb302: Make fusb302_set_cc_polarity also set pull ups / downs

2019-02-22 Thread Hans de Goede
The 2 callers of fusb302_set_cc_polarity both call fusb302_set_cc_pull
directly before calling fusb302_set_cc_polarity, this is not ideal for
2 reasons:

1) fusb302_set_cc_pull uses the cached polarity when applying pull-ups,
which maybe changed immediately afterwards, to fix this set_cc_polarity
already does the pull-up setting.

2) Both touch the SWITCHES0 register in a r-w-modify cycle, this leads to
read reg, write reg, read reg, write reg. If we fold the setting of
the pull-downs into fusb302_set_cc_polarity then not only can we avoid
doing the reads / writes twice, at this point we set all bits, so we
can skip the read, turning 4 (slowish) i2c-transfers into 1.

Doing this also avoids the need to cache the pull_up state in
struct fusb302_chip.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 48 +++-
 1 file changed, 16 insertions(+), 32 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index c25d98fe24ac..3ad92d68b6af 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -99,7 +99,6 @@ struct fusb302_chip {
bool intr_comp_chng;
 
/* port status */
-   bool pull_up;
bool vconn_on;
bool vbus_on;
bool charge_on;
@@ -540,7 +539,6 @@ static int fusb302_set_cc_pull(struct fusb302_chip *chip,
 mask, data);
if (ret < 0)
return ret;
-   chip->pull_up = pull_up;
 
return ret;
 }
@@ -1231,38 +1229,36 @@ static const char * const cc_polarity_name[] = {
[TYPEC_POLARITY_CC2]= "Polarity_CC2",
 };
 
-static int fusb302_set_cc_polarity(struct fusb302_chip *chip,
-  enum typec_cc_polarity cc_polarity)
+static int fusb302_set_cc_polarity_and_pull(struct fusb302_chip *chip,
+   enum typec_cc_polarity cc_polarity,
+   bool pull_up, bool pull_down)
 {
int ret = 0;
-   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
-   FUSB_REG_SWITCHES0_CC2_PU_EN |
-   FUSB_REG_SWITCHES0_VCONN_CC1 |
-   FUSB_REG_SWITCHES0_VCONN_CC2 |
-   FUSB_REG_SWITCHES0_MEAS_CC1 |
-   FUSB_REG_SWITCHES0_MEAS_CC2;
u8 switches0_data = 0x00;
u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN |
FUSB_REG_SWITCHES1_TXCC2_EN;
u8 switches1_data = 0x00;
 
+   if (pull_down)
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
+
if (cc_polarity == TYPEC_POLARITY_CC1) {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC1;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC1;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN;
} else {
-   switches0_data = FUSB_REG_SWITCHES0_MEAS_CC2;
+   switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC2;
if (chip->vconn_on)
switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1;
-   if (chip->pull_up)
+   if (pull_up)
switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN;
switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN;
}
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-switches0_mask, switches0_data);
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
if (ret < 0)
return ret;
ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES1,
@@ -1283,16 +1279,10 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
enum typec_cc_polarity cc_polarity;
enum typec_cc_status cc_status_active, cc1, cc2;
 
-   /* set pull_up, pull_down */
-   ret = fusb302_set_cc_pull(chip, false, true);
-   if (ret < 0) {
-   fusb302_log(chip, "cannot set cc to pull down, ret=%d", ret);
-   return ret;
-   }
-   /* set polarity */
+   /* set polarity and pull_up, pull_down */
cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ?
  TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2;
-   ret = fusb302_set_cc_polarity(chip, cc_polarity);
+   ret = fusb302_set_cc_polarity_and_pull(chip, cc_polarity, false, true);
if (ret < 0) {
fusb302_log(chip, "cannot set cc polarity %s, ret=%d",
cc_polarity_name[cc_polarity], ret);
@@ -

[PATCH 4/8] usb: typec: fusb302: Check vconn is off when we start toggling

2019-02-22 Thread Hans de Goede
The datasheet says the vconn MUST be off when we start toggling. The
tcpm.c state-machine is responsible to make sure vconn is off, but
lets add a WARN_ON check to catch any cases where vconn is not off
for some reason.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 4e75526b3874..f83e777aeabf 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -607,6 +607,8 @@ static int fusb302_set_toggling(struct fusb302_chip *chip,
return ret;
chip->intr_togdone = false;
} else {
+   /* Datasheet says vconn MUST be off when toggling */
+   WARN_ON(chip->vconn_on);
/* unmask TOGDONE interrupt */
ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA,
 FUSB_REG_MASKA_TOGDONE);
-- 
2.20.1



[PATCH 5/8] usb: typec: fusb302: Fix fusb302_handle_togdone_src Ra handling

2019-02-22 Thread Hans de Goede
The FUSB302 will stop toggling with a FUSB_REG_STATUS1A_TOGSS_SRC? status,
as soon as it sees either Ra or Rd on a CC pin.

Before this commit fusb302_handle_togdone_src would assume that the toggle-
engine always stopped at the CC pin indicating the polarity, IOW it assumed
that it stopped at the pin connected to Rd. It did check the CC-status of
that pin, but it did not expect to get a CC-status of Ra and therefore
treated this as CC-open. This lead to the following 2 problems:

1) If a powered cable/adapter gets plugged in with Ra on CC1 and Rd on CC2
then 4 of 5 times when plugged in toggling will stop with a togdone_result
of FUSB_REG_STATUS1A_TOGSS_SRC1.  3/5th of the time the toggle-engine is
testing for being connected as a sink and after that it tests 1/5th of the
time for connected as a src through CC1 before finally testing the last
1/5th of the time for being a src connected through CC2.

This was a problem because we would only check the CC pin status for the
pin on which the toggling stopped which in this polarity 4 out of 5
times would be the Ra pin. The code before this commit would treat Ra as
CC-open and then restart toggling. Once toggling is restarted we are
guaranteed to end with FUSB_REG_STATUS1A_TOGSS_SRC1 as CC1 is tested first,
leading to a CC-status of Ra again and an infinite restart toggling loop.
So 4 out of 5 times when plugged in in this polarity a powered adapter
will not work.

2) Even if we happen to have the right polarity or 1/5th of the time in
the polarity with problem 1), we would report the non Rd pin as CC-open
rather then as Ra, resulting in the tcpm.c code not enabling Vconn which
is a problem for some adapters.

This commit fixes this by getting the CC-status of *both* pins and then
determining the polarity based on that, rather then on where the toggling
stopped.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 149 ---
 1 file changed, 97 insertions(+), 52 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index f83e777aeabf..05e54fcb2819 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -1254,6 +1254,62 @@ static int fusb302_handle_togdone_snk(struct 
fusb302_chip *chip,
return ret;
 }
 
+/* On error returns < 0, otherwise a typec_cc_status value */
+static int fusb302_get_src_cc_status(struct fusb302_chip *chip,
+enum typec_cc_polarity cc_polarity,
+enum typec_cc_status *cc)
+{
+   u8 ra_mda = ra_mda_value[chip->src_current_status];
+   u8 rd_mda = rd_mda_value[chip->src_current_status];
+   u8 switches0_data, status0;
+   int ret;
+
+   /* Step 1: Set switches so that we measure the right CC pin */
+   switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ?
+   FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 :
+   FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2;
+   ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data);
+   if (ret < 0)
+   return ret;
+
+   fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0);
+   fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0);
+
+   /* Step 2: Set compararator volt to differentiate between Open and Rd */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(5000, 1);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP) {
+   *cc = TYPEC_CC_OPEN;
+   return 0;
+   }
+
+   /* Step 3: Set compararator input to differentiate between Rd and Ra. */
+   ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, ra_mda);
+   if (ret < 0)
+   return ret;
+
+   usleep_range(5000, 1);
+   ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0);
+   if (ret < 0)
+   return ret;
+
+   fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0);
+   if (status0 & FUSB_REG_STATUS0_COMP)
+   *cc = TYPEC_CC_RD;
+   else
+   *cc = TYPEC_CC_RA;
+
+   return 0;
+}
+
 static int fusb302_handle_togdone_src(struct fusb302_chip *chip,
  u8 togdone_result)
 {
@@ -1264,71 +1320,62 @@ static int fusb302_handle_togdone_src(struct 
fusb302_chip *chip,
 * - set I_COMP interrupt on
 */
int ret = 0;
-   u8 status0;
-   u8 ra_mda = ra_mda_value[chip->src_current_status];
u8 rd_mda = rd_mda_value[chip->src_current_status];
-   bool ra_comp, rd_comp;
+   enum toggling_mode

[PATCH 3/8] usb: typec: fusb302: Fold fusb302_set_cc_pull into tcpm_set_cc

2019-02-22 Thread Hans de Goede
After the recent cleanups, tcpm_set_cc is the only caller of
fusb302_set_cc_pull, fold fusb302_set_cc_pull directly into
tcpm_set_cc for a nice cleanup.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 51 
 1 file changed, 13 insertions(+), 38 deletions(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 552b762d262c..4e75526b3874 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -518,31 +518,6 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev)
return current_limit;
 }
 
-static int fusb302_set_cc_pull(struct fusb302_chip *chip,
-  bool pull_up, bool pull_down)
-{
-   int ret = 0;
-   u8 data = 0x00;
-   u8 mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
- FUSB_REG_SWITCHES0_CC2_PU_EN |
- FUSB_REG_SWITCHES0_CC1_PD_EN |
- FUSB_REG_SWITCHES0_CC2_PD_EN;
-
-   if (pull_up)
-   data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
-   FUSB_REG_SWITCHES0_CC1_PU_EN :
-   FUSB_REG_SWITCHES0_CC2_PU_EN;
-   if (pull_down)
-   data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
-   FUSB_REG_SWITCHES0_CC2_PD_EN;
-   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
-mask, data);
-   if (ret < 0)
-   return ret;
-
-   return ret;
-}
-
 static int fusb302_set_src_current(struct fusb302_chip *chip,
   enum src_current_status status)
 {
@@ -674,27 +649,30 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 {
struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
 tcpc_dev);
+   u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN |
+   FUSB_REG_SWITCHES0_CC2_PU_EN |
+   FUSB_REG_SWITCHES0_CC1_PD_EN |
+   FUSB_REG_SWITCHES0_CC2_PD_EN;
+   u8 switches0_data = 0x00;
int ret = 0;
-   bool pull_up, pull_down;
enum toggling_mode mode;
 
mutex_lock(&chip->lock);
switch (cc) {
case TYPEC_CC_OPEN:
-   pull_up = false;
-   pull_down = false;
mode = TOGGLING_MODE_OFF;
break;
case TYPEC_CC_RD:
-   pull_up = false;
-   pull_down = true;
+   switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN |
+ FUSB_REG_SWITCHES0_CC2_PD_EN;
mode = TOGGLING_MODE_SNK;
break;
case TYPEC_CC_RP_DEF:
case TYPEC_CC_RP_1_5:
case TYPEC_CC_RP_3_0:
-   pull_up = true;
-   pull_down = false;
+   switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ?
+ FUSB_REG_SWITCHES0_CC1_PU_EN :
+ FUSB_REG_SWITCHES0_CC2_PU_EN;
mode = TOGGLING_MODE_SRC;
break;
default:
@@ -706,13 +684,10 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum 
typec_cc_status cc)
 
fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]);
 
-   ret = fusb302_set_cc_pull(chip, pull_up, pull_down);
+   ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0,
+switches0_mask, switches0_data);
if (ret < 0) {
-   fusb302_log(chip,
-   "cannot set cc pulling up %s, down %s, ret = %d",
-   pull_up ? "True" : "False",
-   pull_down ? "True" : "False",
-   ret);
+   fusb302_log(chip, "cannot set pull-up/-down, ret = %d", ret);
goto done;
}
/* reset the cc status */
-- 
2.20.1



[PATCH 8/8] usb: typec: fusb302: Add __printf attribute to fusb302_log function

2019-02-22 Thread Hans de Goede
Add __printf attribute to fusb302_log function, so that we get
compiler warnings when specifying wrong vararg parameters.

Signed-off-by: Hans de Goede 
---
 drivers/usb/typec/tcpm/fusb302.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c
index 940e096a4ac6..73b26eaea10c 100644
--- a/drivers/usb/typec/tcpm/fusb302.c
+++ b/drivers/usb/typec/tcpm/fusb302.c
@@ -120,13 +120,13 @@ struct fusb302_chip {
  */
 
 #ifdef CONFIG_DEBUG_FS
-
 static bool fusb302_log_full(struct fusb302_chip *chip)
 {
return chip->logbuffer_tail ==
(chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES;
 }
 
+__printf(2, 0)
 static void _fusb302_log(struct fusb302_chip *chip, const char *fmt,
 va_list args)
 {
-- 
2.20.1



Re: [PATCH 1/8] platform/x86: intel_cht_int33fe: Remove connection for the alt mode mux

2019-01-31 Thread Hans de Goede

Hi,

On 28-01-19 16:27, Heikki Krogerus wrote:

Hi Hans,

On Mon, Jan 28, 2019 at 11:44:29AM +0100, Hans de Goede wrote:

Hi,

On 28-01-19 10:45, Andy Shevchenko wrote:

On Fri, Jan 25, 2019 at 3:17 PM Heikki Krogerus
 wrote:


Driver for fusb302 does not support alternate modes, so the
connection is not really needed for now. Removing that
connection description allows us to improve the USB Type-C
mux API.



Acked-by: Andy Shevchenko 
supposed to go via USB tree.


I missed the original posting of this, so let me reply here:

Nack to this change, I've a patch-set in the works to
make display-port over type-c work with 2 devices with a fusb302
mux and that needs this connection.


I can add the connections back in this series after the API
modification patches, but should the connections be added back only
after we actually support the alt mode in the driver?

Btw. I'm preparing patches where I remove struct tcpc_config
completely. We can do that by taking advantage of the software fwnodes
(I'll send the patches RFC to give you an idea what I'm talking about).

That's related as we don't need struct tcpc_config for anything else
except for alternate modes (which no driver supports currently) after
that series, and even with the alt modes, it's only a question of
supplying DT bindings that define the appropriate device properties.

Also, as a "heads-up": As I explained in the cover-letter, my plan is
to take advantage of the software fwnodes also with the connections.
By adding support for reference handling to the software nodes, we
don't need to maintain the list of connections as we do today. And
more importantly, we don't need to match using device names, which is
always fragile.

That means we will change the connection registration, actually,
remove connection registration :-). The connections after that can
always be described in the fwnode for the device.


I see that you've posted a v2 series now and that you've kept the dev_name
matching for platforms where there are no fwnodes to match on, thanks.

I've just reviewed the v2 series and it looks good to me, I will reply
there.

Regards,

Hans


Re: [PATCH v2 0/9] device connection: Add support for device graphs

2019-01-31 Thread Hans de Goede

Hi,

On 30-01-19 17:02, Heikki Krogerus wrote:

Hi,

This is the second version of this series. On top the two code style
improvements requested by Andy, I also renamed the connection
identifiers used with the USB Type-C muxes for something that I felt
are better, especially after we start using them to name reference
device properties in fwnodes. That's why the first patch is now split
in two, 1/9 and 3/9.

Hans! Please note that there is no functional change. The alt mode
device is still getting a handle to the mux, just like before.


Ack.

I've reviewed the entire series and it looks good to me.

Patches 1-3 are:

Reviewed-by: Hans de Goede 

I'm slightly less familiar with the material in patches 4-9, so they
are:

Acked-by: Hans de Goede 

I will also add this series to my personal git tree for testing.

Regards,

Hans





That was actually happening also in the first version of the series.

The commit message from v1:

This series adds support for OF and ACPI device graph parsing to the
device connection API.

Handling the graph is straightforward, but because I'm adding that
fwnode member to struct device_connection, I had to make sure all the
existing users consider it.

The plan is to only support matching with fwnode in the future, so no
more device name matching. The software fwnodes that we now have in
kernel should make that possible, once we add support for references
to them.

The original RFC:
https://lkml.org/lkml/2018/10/24/619

thanks,

Heikki Krogerus (9):
   platform/x86: intel_cht_int33fe: Prepare for better mux naming scheme
   usb: typec: Rationalize the API for the muxes
   platform/x86: intel_cht_int33fe: Remove old style mux connections
   device connection: Add fwnode member to struct device_connection
   usb: typec: mux: Find the muxes by also matching against the device
 node
   usb: roles: Find the muxes by also matching against the device node
   usb: typec: Find the ports by also matching against the device node
   device connection: Prepare support for firmware described connections
   device connection: Find device connections also from device graphs

  drivers/base/devcon.c| 62 ++-
  drivers/platform/x86/intel_cht_int33fe.c | 15 ++--
  drivers/usb/roles/class.c| 21 +-
  drivers/usb/typec/class.c| 31 ++--
  drivers/usb/typec/mux.c  | 96 
  include/linux/device.h   |  6 ++
  include/linux/usb/role.h |  1 +
  include/linux/usb/typec_mux.h|  3 +-
  8 files changed, 195 insertions(+), 40 deletions(-)



Re: [PATCH 1/8] platform/x86: intel_cht_int33fe: Remove connection for the alt mode mux

2019-01-28 Thread Hans de Goede

Hi,

On 28-01-19 10:45, Andy Shevchenko wrote:

On Fri, Jan 25, 2019 at 3:17 PM Heikki Krogerus
 wrote:


Driver for fusb302 does not support alternate modes, so the
connection is not really needed for now. Removing that
connection description allows us to improve the USB Type-C
mux API.



Acked-by: Andy Shevchenko 
supposed to go via USB tree.


I missed the original posting of this, so let me reply here:

Nack to this change, I've a patch-set in the works to
make display-port over type-c work with 2 devices with a fusb302
mux and that needs this connection.

Regards,

Hans






Signed-off-by: Heikki Krogerus 
---
  drivers/platform/x86/intel_cht_int33fe.c | 11 ---
  1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/x86/intel_cht_int33fe.c 
b/drivers/platform/x86/intel_cht_int33fe.c
index 02bc74608cf3..fbd24daa7f8d 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -32,7 +32,7 @@ struct cht_int33fe_data {
 struct i2c_client *fusb302;
 struct i2c_client *pi3usb30532;
 /* Contain a list-head must be per device */
-   struct device_connection connections[5];
+   struct device_connection connections[4];
  };

  /*
@@ -178,12 +178,9 @@ static int cht_int33fe_probe(struct platform_device *pdev)
 data->connections[1].endpoint[0] = "port0";
 data->connections[1].endpoint[1] = "i2c-pi3usb30532";
 data->connections[1].id = "typec-mux";
-   data->connections[2].endpoint[0] = "port0";
-   data->connections[2].endpoint[1] = "i2c-pi3usb30532";
-   data->connections[2].id = "idff01m01";
-   data->connections[3].endpoint[0] = "i2c-fusb302";
-   data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch";
-   data->connections[3].id = "usb-role-switch";
+   data->connections[2].endpoint[0] = "i2c-fusb302";
+   data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
+   data->connections[2].id = "usb-role-switch";

 device_connections_add(data->connections);

--
2.20.1






Re: [PATCH V2] roles: Fix for Enabling USB ROLE SWITCH QUIRK on INTEL_SUNRISEPOINT_LP_XHCI

2019-01-07 Thread Hans de Goede

Hi,

On 08-01-19 11:04, m.bal...@intel.com wrote:

From: M, Balaji 

This fix enables USB role feature on intel commercial nuc
platform which is based on Kabylake chipset.

Signed-off-by: M, Balaji 
Reviewed-by: Hans de Goede 
---
  Changes from v1: Added Reviewed-by


There is no need to send out a v2 just to add a Reviewed-by,
the subsys-maintainer will pick the Reviewed-by up when merging.

If you need to do a v2 to add some other minor change adding the
Reviewed-by is fine.

Regards,

Hans



  drivers/usb/host/xhci-pci.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index a9ec7051f286..c2fe218e051f 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -194,6 +194,7 @@ static void xhci_pci_quirks(struct device *dev, struct 
xhci_hcd *xhci)
xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
 pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&



Re: [PATCH] roles: Fix for Enabling USB ROLE SWITCH QUIRK on INTEL_SUNRISEPOINT_LP_XHCI

2019-01-07 Thread Hans de Goede

Hi,

On 08-01-19 07:25, m.bal...@intel.com wrote:

From: M, Balaji 

This fix enables USB role feature on intel commercial nuc
platform which is based on Kabylake chipset.

Signed-off-by: M, Balaji 


Patch looks good to me:

Reviewed-by: Hans de Goede 

Regards,

Hans




---
  drivers/usb/host/xhci-pci.c | 1 +
  1 file changed, 1 insertion(+)

diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index a9ec7051f286..c2fe218e051f 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -194,6 +194,7 @@ static void xhci_pci_quirks(struct device *dev, struct 
xhci_hcd *xhci)
xhci->quirks |= XHCI_SSIC_PORT_UNUSED;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
(pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI ||
+pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_XHCI ||
 pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI))
xhci->quirks |= XHCI_INTEL_USB_ROLE_SW;
if (pdev->vendor == PCI_VENDOR_ID_INTEL &&



Re: tusb1210 probe of dwc3.0.auto.ulpi fails with EBUSY on 4.19+

2018-12-16 Thread Hans de Goede

Hi,

On 16-12-18 18:36, Stephan Gerhold wrote:

On Mon, Dec 03, 2018 at 11:50:53AM +0100, Hans de Goede wrote:

Hi,


Somewhat off topic, but:

To be exact my device does not have them in the (original) ACPI table
either. At the moment I override the ACPI DSDT table because there are
some things I haven't found other workarounds for. (It's horrible..)

Some examples:
   - The BCM2E3A Bluetooth device is listed as child under the wrong UART
 controller device, so the kernel never manages to power it up properly
   - The rt5640 (audio codec) device has one of the Bluetooth GPIOs listed
 as interrupt instead of the correct one
   - The GPIOs for the goodix touchscreen were hardcoded in the stock kernel,
 and are therefore entirely missing in the ACPI table

Granted, this device was never intended to be used with a generic
kernel (see my response to your question what hardware I have below),
but nevertheless it is really annoying.


I've one BYT tablet which is/was Android only, which also has some seriously
borked DSTD, but it has an unlocked BIOS and I flipped the OS choice there
(this is a weird thing BYT BIOSes have) to Windows then all of sudden I got
the right DSTD. Asus BIOS-es are typically locked and don't show this option,
but it is probably worth it to take a look.



For reference: I decided to go ahead and tried changing that option on
my device. It still booted normally as usual, but everything else was
as usual too: still exactly the same DSDT. That option does not seem to
have any effect on my device. :/

I have found workarounds for all of the problems, so I guess I will just
have to live with it..

Anyway, thanks for the suggestion!


Ok, thank you for the status update.

Regards,

Hans



Re: [PATCH] Revert "usb: dwc3: pci: Use devm functions to get the phy GPIOs"

2018-12-09 Thread Hans de Goede

Hi,

On 09-12-18 16:07, Stephan Gerhold wrote:

On Sun, Dec 09, 2018 at 04:44:16PM +0200, Andy Shevchenko wrote:

On Thu, Dec 6, 2018 at 8:49 PM Stephan Gerhold  wrote:


Commit 211f658b7b40 ("usb: dwc3: pci: Use devm functions to get
the phy GPIOs") changed the code to claim the PHY GPIOs permanently
for Intel Baytrail devices.

This causes issues when the actual PHY driver attempts to claim the
same GPIO descriptors. For example, tusb1210 now fails to probe with:

   tusb1210: probe of dwc3.0.auto.ulpi failed with error -16 (EBUSY)

dwc3-pci needs to turn on the PHY once before dwc3 is loaded, but
usually the PHY driver will then hold the GPIOs to turn off the
PHY when requested (e.g. during suspend).

To fix the problem, this reverts the commit to restore the old
behavior to put the GPIOs immediately after usage.

Link: https://www.spinics.net/lists/linux-usb/msg174681.html
Cc: sta...@vger.kernel.org
Signed-off-by: Stephan Gerhold 
---
  drivers/usb/dwc3/dwc3-pci.c | 8 
  1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 842795856bf4..fdc6e4e403e8 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -170,20 +170,20 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
  * put the gpio descriptors again here because the phy 
driver
  * might want to grab them, too.
  */
-   gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "cs", 
GPIOD_OUT_LOW);
 if (IS_ERR(gpio))
 return PTR_ERR(gpio);

 gpiod_set_value_cansleep(gpio, 1);
+   gpiod_put(gpio);

-   gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "reset", 
GPIOD_OUT_LOW);
 if (IS_ERR(gpio))
 return PTR_ERR(gpio);

 if (gpio) {
 gpiod_set_value_cansleep(gpio, 1);



+   gpiod_put(gpio);
 usleep_range(1, 11000);


If something happens to GPIO line in between of these lines, the sleep
might become obsolete. Shouldn't gpiod_put() be placed after?


That's a good point, but I believe this would be more appropriately
fixed in a separate patch, since this is just an exact revert of
211f658b7b40 ("usb: dwc3: pci: Use devm functions to get the phy GPIOs")
(This is the way it was written when it was added to mainline 4 years
ago...)

I can send a separate patch for this, or would you like to?


Properly fixing this would require releasing *both* GPIOs *after* the
ULPI vendor and product IDs have been read. Which will require adding
some generic callback just for this to the generic non platform/pci
specific dwc3 code. Which IMHO is not worth the trouble since in
practice this is not really a problem.

Regards,

Hans



Re: [PATCH] Revert "usb: dwc3: pci: Use devm functions to get the phy GPIOs"

2018-12-09 Thread Hans de Goede

Hi,

On 09-12-18 15:44, Andy Shevchenko wrote:

On Thu, Dec 6, 2018 at 8:49 PM Stephan Gerhold  wrote:


Commit 211f658b7b40 ("usb: dwc3: pci: Use devm functions to get
the phy GPIOs") changed the code to claim the PHY GPIOs permanently
for Intel Baytrail devices.

This causes issues when the actual PHY driver attempts to claim the
same GPIO descriptors. For example, tusb1210 now fails to probe with:

   tusb1210: probe of dwc3.0.auto.ulpi failed with error -16 (EBUSY)

dwc3-pci needs to turn on the PHY once before dwc3 is loaded, but
usually the PHY driver will then hold the GPIOs to turn off the
PHY when requested (e.g. during suspend).

To fix the problem, this reverts the commit to restore the old
behavior to put the GPIOs immediately after usage.

Link: https://www.spinics.net/lists/linux-usb/msg174681.html
Cc: sta...@vger.kernel.org
Signed-off-by: Stephan Gerhold 
---
  drivers/usb/dwc3/dwc3-pci.c | 8 
  1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 842795856bf4..fdc6e4e403e8 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -170,20 +170,20 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
  * put the gpio descriptors again here because the phy 
driver
  * might want to grab them, too.
  */
-   gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "cs", 
GPIOD_OUT_LOW);
 if (IS_ERR(gpio))
 return PTR_ERR(gpio);

 gpiod_set_value_cansleep(gpio, 1);
+   gpiod_put(gpio);

-   gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "reset", 
GPIOD_OUT_LOW);
 if (IS_ERR(gpio))
 return PTR_ERR(gpio);

 if (gpio) {
 gpiod_set_value_cansleep(gpio, 1);



+   gpiod_put(gpio);
 usleep_range(1, 11000);


If something happens to GPIO line in between of these lines, the sleep
might become obsolete. Shouldn't gpiod_put() be placed after?


The actual reading of the ULPI product and vendor IDs happens a whole
bunch of functions after the dwc3_pci_quirks() function runs, so the
assumption is that nothing touches the GPIO until the phy driver
loads.

Also the current version of this patch is a straight revert of my patch,
IOW the put allowing potential mucking with the GPIO before the
IDs are read is a pre-existing problem.

Regards,

Hans



Re: [PATCH] Revert "usb: dwc3: pci: Use devm functions to get the phy GPIOs"

2018-12-09 Thread Hans de Goede

Hi,

Thank you.

On 06-12-18 19:42, Stephan Gerhold wrote:

Commit 211f658b7b40 ("usb: dwc3: pci: Use devm functions to get
the phy GPIOs") changed the code to claim the PHY GPIOs permanently
for Intel Baytrail devices.

This causes issues when the actual PHY driver attempts to claim the
same GPIO descriptors. For example, tusb1210 now fails to probe with:

   tusb1210: probe of dwc3.0.auto.ulpi failed with error -16 (EBUSY)

dwc3-pci needs to turn on the PHY once before dwc3 is loaded, but
usually the PHY driver will then hold the GPIOs to turn off the
PHY when requested (e.g. during suspend).

To fix the problem, this reverts the commit to restore the old
behavior to put the GPIOs immediately after usage.

Link: https://www.spinics.net/lists/linux-usb/msg174681.html
Cc: sta...@vger.kernel.org
Signed-off-by: Stephan Gerhold 


Right, the original change was done because I did not realize
that the phy driver would take over managing the GPIOs (and on
my test device it doesn't due to an unrelated issue).

So reverting this is the right thing to do:

Acked-by: Hans de Goede 

Regards,

Hans




---
  drivers/usb/dwc3/dwc3-pci.c | 8 
  1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 842795856bf4..fdc6e4e403e8 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -170,20 +170,20 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
 * put the gpio descriptors again here because the phy 
driver
 * might want to grab them, too.
 */
-   gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "cs", 
GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
  
  			gpiod_set_value_cansleep(gpio, 1);

+   gpiod_put(gpio);
  
-			gpio = devm_gpiod_get_optional(&pdev->dev, "reset",

-  GPIOD_OUT_LOW);
+   gpio = gpiod_get_optional(&pdev->dev, "reset", 
GPIOD_OUT_LOW);
if (IS_ERR(gpio))
return PTR_ERR(gpio);
  
  			if (gpio) {

gpiod_set_value_cansleep(gpio, 1);
+   gpiod_put(gpio);
usleep_range(1, 11000);
}
}



Re: tusb1210 probe of dwc3.0.auto.ulpi fails with EBUSY on 4.19+

2018-12-03 Thread Hans de Goede

Hi,

On 03-12-18 17:21, Stephan Gerhold wrote:

On Mon, Dec 03, 2018 at 11:50:53AM +0100, Hans de Goede wrote:

Hi,

On 02-12-18 18:08, Stephan Gerhold wrote:

Hi,

thanks for the quick reply! :)

On Sun, Dec 02, 2018 at 03:41:29PM +0100, Hans de Goede wrote:

Hi,

On 01-12-18 13:22, Stephan Gerhold wrote:

Hi,

I have been updating my Intel Baytrail tablet from 4.14 to 4.19 and
noticed that the tusb1210 PHY driver now fails to probe on 4.19.x and
4.20-rc4:

 tusb1210: probe of dwc3.0.auto.ulpi failed with error -16 (EBUSY)

The commit that broke this is 211f658b7b40 ("usb: dwc3: pci: Use devm
functions to get the phy GPIOs") because it now claims the phy GPIOs
permanently so the PHY driver (here: tusb1210) cannot get them.

Gadget mode still works with this error and even completely without the
tusb1210 driver, but I have been using the PHY driver additionally
because it has the advantage that it will also power off the PHY during
suspend. (Plus I have some custom hacky code for charger detection in
it at the moment, but I did not have it applied for testing this
problem..)

The comment that still exists above the changed code also mentions why
the GPIO descriptors were put immediately after use:

 /*
  * These GPIOs will turn on the USB2 PHY. Note that we have to
  * put the gpio descriptors again here because the phy driver
  * might want to grab them, too.
  */

Reverting the commit makes everything work again for me. Does this
change fix a problem on another device or was it mostly just cleanup?


It was just a cleanup, I did not realize that another driver would be
claiming the GPIOs and I noticed them not being claimed in
"cat /sys/kernel/debug/gpio" while testing.

But it makes sense that the PHY driver itsef wants to use the GPIOs,
which is likely why the dwc3-pci code was written the way it was
in the first place.

So yes my commit should be reverted. Do you want to submit a revert,
or shall I ?


Hmm, let me try to send it :) I have it mostly prepared locally, just
wanted to ask before I send it.


Ok.


I wanted to suggest that turning on the PHY may not actually be
necessary in dwc3-pci since the tusb1210 driver has the same code in its
probe() method. However, when I tested it it did not work at all because
the tusb1210 driver is not even loaded if the PHY is not turned on
before dwc3 is loaded...
(The ULPI vendor/product ID is wrong with the PHY turned off)


Right, the phy must be turned on, so that the dwc3 driver can create
the struct device representing the phy with the right vendor/product id
in its modalias. This is why the dwc3 code turns it on.


Additional note: The probe error above happens only if:
- The tablet has a TUSB1210/TUSB1211 external PHY (not sure if this is
  the case for all Baytrail tablets..)
- CONFIG_USB_DWC3_ULPI and CONFIG_PHY_TUSB1210 are enabled
- GPIOs are defined in the ACPI DSDT table (Unlike the ACPI GPIOs, the
  fallback GPIO mappings are not inherited to the ULPI device..)


This is why I was not seeing this problem, all my devices lack the GPIO
definition in the ACPI tables. I've put looking into adding the fallback
GPIOs to the tusb1210 driver too on my TODO list, but this is rather low
priority for me.


Somewhat off topic, but:

To be exact my device does not have them in the (original) ACPI table
either. At the moment I override the ACPI DSDT table because there are
some things I haven't found other workarounds for. (It's horrible..)

Some examples:
   - The BCM2E3A Bluetooth device is listed as child under the wrong UART
 controller device, so the kernel never manages to power it up properly
   - The rt5640 (audio codec) device has one of the Bluetooth GPIOs listed
 as interrupt instead of the correct one
   - The GPIOs for the goodix touchscreen were hardcoded in the stock kernel,
 and are therefore entirely missing in the ACPI table

Granted, this device was never intended to be used with a generic
kernel (see my response to your question what hardware I have below),
but nevertheless it is really annoying.


I've one BYT tablet which is/was Android only, which also has some seriously
borked DSTD, but it has an unlocked BIOS and I flipped the OS choice there
(this is a weird thing BYT BIOSes have) to Windows then all of sudden I got
the right DSTD. Asus BIOS-es are typically locked and don't show this option,
but it is probably worth it to take a look.



The BIOS is not locked on my device either. Otherwise I could have
probably never installed something other than Android. It has a "locked"
Android bootloader, but they did not enable UEFI Secure Boot...

I just checked for the OS selection and there is a "Windows 8.X" /
"Android" selection in Advanced -> LPSS & SCC Configuration -> OS
Selection. I'm considering trying it out, but I have to admit that I'm
a bit cautious with changing anything in t

  1   2   3   4   5   6   7   8   9   10   >