aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/usb/typec/tps6598x.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:42:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:42:16 -0700
commite611c0fe318c6d6827ee2bba660fbc23cf73f7dc (patch)
tree00854551e810b32cceab84157882eab147f2a98c /drivers/usb/typec/tps6598x.c
parentMerge tag 'sh-for-5.8' of git://git.libc.org/linux-sh (diff)
parentusb: dwc3: meson-g12a: fix USB2 PHY initialization on G12A and A1 SoCs (diff)
downloadwireguard-linux-e611c0fe318c6d6827ee2bba660fbc23cf73f7dc.tar.xz
wireguard-linux-e611c0fe318c6d6827ee2bba660fbc23cf73f7dc.zip
Merge tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY driver updates from Greg KH: "Here are the large set of USB and PHY driver updates for 5.8-rc1. Nothing huge, just lots of little things: - USB gadget fixes and additions all over the place - new PHY drivers - PHY driver fixes and updates - XHCI driver updates - musb driver updates - more USB-serial driver ids added - various USB quirks added - thunderbolt minor updates and fixes - typec updates and additions All of these have been in linux-next for a while with no reported issues" * tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (245 commits) usb: dwc3: meson-g12a: fix USB2 PHY initialization on G12A and A1 SoCs usb: dwc3: meson-g12a: fix error path when fetching the reset line fails Revert "dt-bindings: usb: qcom,dwc3: Convert USB DWC3 bindings" Revert "dt-bindings: usb: qcom,dwc3: Add compatible for SC7180" Revert "dt-bindings: usb: qcom,dwc3: Introduce interconnect properties for Qualcomm DWC3 driver" USB: serial: ch341: fix lockup of devices with limited prescaler USB: serial: ch341: add basis for quirk detection CDC-ACM: heed quirk also in error handling USB: serial: option: add Telit LE910C1-EUX compositions usb: musb: Fix runtime PM imbalance on error usb: musb: jz4740: Prevent lockup when CONFIG_SMP is set usb: musb: mediatek: add reset FADDR to zero in reset interrupt handle usb: musb: use true for 'use_dma' usb: musb: start session in resume for host port usb: musb: return -ESHUTDOWN in urb when three-strikes error happened USB: serial: qcserial: add DW5816e QDL support thunderbolt: Add trivial .shutdown usb: dwc3: keystone: Turn on USB3 PHY before controller dt-bindings: usb: ti,keystone-dwc3.yaml: Add USB3.0 PHY property dt-bindings: usb: convert keystone-usb.txt to YAML ...
Diffstat (limited to 'drivers/usb/typec/tps6598x.c')
-rw-r--r--drivers/usb/typec/tps6598x.c64
1 files changed, 57 insertions, 7 deletions
diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c
index 0698addd1185..b7c9fe5caabe 100644
--- a/drivers/usb/typec/tps6598x.c
+++ b/drivers/usb/typec/tps6598x.c
@@ -12,6 +12,7 @@
#include <linux/regmap.h>
#include <linux/interrupt.h>
#include <linux/usb/typec.h>
+#include <linux/usb/role.h>
/* Register offsets */
#define TPS_REG_VID 0x00
@@ -94,6 +95,7 @@ struct tps6598x {
struct typec_port *port;
struct typec_partner *partner;
struct usb_pd_identity partner_identity;
+ struct usb_role_switch *role_sw;
};
/*
@@ -190,6 +192,23 @@ static int tps6598x_read_partner_identity(struct tps6598x *tps)
return 0;
}
+static void tps6598x_set_data_role(struct tps6598x *tps,
+ enum typec_data_role role, bool connected)
+{
+ enum usb_role role_val;
+
+ if (role == TYPEC_HOST)
+ role_val = USB_ROLE_HOST;
+ else
+ role_val = USB_ROLE_DEVICE;
+
+ if (!connected)
+ role_val = USB_ROLE_NONE;
+
+ usb_role_switch_set_role(tps->role_sw, role_val);
+ typec_set_data_role(tps->port, role);
+}
+
static int tps6598x_connect(struct tps6598x *tps, u32 status)
{
struct typec_partner_desc desc;
@@ -220,7 +239,7 @@ static int tps6598x_connect(struct tps6598x *tps, u32 status)
typec_set_pwr_opmode(tps->port, mode);
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status));
- typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status));
+ tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), true);
tps->partner = typec_register_partner(tps->port, &desc);
if (IS_ERR(tps->partner))
@@ -240,7 +259,7 @@ static void tps6598x_disconnect(struct tps6598x *tps, u32 status)
typec_set_pwr_opmode(tps->port, TYPEC_PWR_MODE_USB);
typec_set_pwr_role(tps->port, TPS_STATUS_PORTROLE(status));
typec_set_vconn_role(tps->port, TPS_STATUS_VCONN(status));
- typec_set_data_role(tps->port, TPS_STATUS_DATAROLE(status));
+ tps6598x_set_data_role(tps, TPS_STATUS_DATAROLE(status), false);
}
static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd,
@@ -328,7 +347,7 @@ static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role)
goto out_unlock;
}
- typec_set_data_role(tps->port, role);
+ tps6598x_set_data_role(tps, role, true);
out_unlock:
mutex_unlock(&tps->lock);
@@ -452,6 +471,7 @@ static int tps6598x_probe(struct i2c_client *client)
{
struct typec_capability typec_cap = { };
struct tps6598x *tps;
+ struct fwnode_handle *fwnode;
u32 status;
u32 conf;
u32 vid;
@@ -495,11 +515,22 @@ static int tps6598x_probe(struct i2c_client *client)
if (ret < 0)
return ret;
+ fwnode = device_get_named_child_node(&client->dev, "connector");
+ if (IS_ERR(fwnode))
+ return PTR_ERR(fwnode);
+
+ tps->role_sw = fwnode_usb_role_switch_get(fwnode);
+ if (IS_ERR(tps->role_sw)) {
+ ret = PTR_ERR(tps->role_sw);
+ goto err_fwnode_put;
+ }
+
typec_cap.revision = USB_TYPEC_REV_1_2;
typec_cap.pd_revision = 0x200;
typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
typec_cap.driver_data = tps;
typec_cap.ops = &tps6598x_ops;
+ typec_cap.fwnode = fwnode;
switch (TPS_SYSCONF_PORTINFO(conf)) {
case TPS_PORTINFO_SINK_ACCESSORY:
@@ -525,12 +556,16 @@ static int tps6598x_probe(struct i2c_client *client)
typec_cap.data = TYPEC_PORT_DFP;
break;
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_role_put;
}
tps->port = typec_register_port(&client->dev, &typec_cap);
- if (IS_ERR(tps->port))
- return PTR_ERR(tps->port);
+ if (IS_ERR(tps->port)) {
+ ret = PTR_ERR(tps->port);
+ goto err_role_put;
+ }
+ fwnode_handle_put(fwnode);
if (status & TPS_STATUS_PLUG_PRESENT) {
ret = tps6598x_connect(tps, status);
@@ -545,12 +580,19 @@ static int tps6598x_probe(struct i2c_client *client)
if (ret) {
tps6598x_disconnect(tps, 0);
typec_unregister_port(tps->port);
- return ret;
+ goto err_role_put;
}
i2c_set_clientdata(client, tps);
return 0;
+
+err_role_put:
+ usb_role_switch_put(tps->role_sw);
+err_fwnode_put:
+ fwnode_handle_put(fwnode);
+
+ return ret;
}
static int tps6598x_remove(struct i2c_client *client)
@@ -559,10 +601,17 @@ static int tps6598x_remove(struct i2c_client *client)
tps6598x_disconnect(tps, 0);
typec_unregister_port(tps->port);
+ usb_role_switch_put(tps->role_sw);
return 0;
}
+static const struct of_device_id tps6598x_of_match[] = {
+ { .compatible = "ti,tps6598x", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, tps6598x_of_match);
+
static const struct i2c_device_id tps6598x_id[] = {
{ "tps6598x" },
{ }
@@ -572,6 +621,7 @@ MODULE_DEVICE_TABLE(i2c, tps6598x_id);
static struct i2c_driver tps6598x_i2c_driver = {
.driver = {
.name = "tps6598x",
+ .of_match_table = tps6598x_of_match,
},
.probe_new = tps6598x_probe,
.remove = tps6598x_remove,