usb: typec: Add typec_get_driver_from_usb() API
The typec_get_driver_from_usb() allows to retrieve a Type-C device from an USB device. typec_get_driver_from_usb() checks in USB device node for port and endpoint sub-node, if exist, retrieve the connector node, probe the associated Type-C device and return it. Signed-off-by: Patrice Chotard <patrice.chotard@foss.st.com> Change-Id: If564cdf463f3915bec26f17a4717c9ab9d42f692 Reviewed-on: https://gerrit.st.com/c/mpu/oe/st/u-boot/+/232353 Reviewed-by: CITOOLS <MDG-smet-aci-reviews@list.st.com> Reviewed-by: Patrick DELAUNAY <patrick.delaunay@foss.st.com>
This commit is contained in:
@ -10,6 +10,74 @@
|
||||
#include <errno.h>
|
||||
#include <typec.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/uclass-internal.h>
|
||||
|
||||
int typec_get_device_from_usb(struct udevice *dev, struct udevice **typec, u8 index)
|
||||
{
|
||||
ofnode node, child;
|
||||
u32 endpoint_phandle;
|
||||
u32 reg;
|
||||
int ret;
|
||||
|
||||
/* 'port' nodes can be grouped under an optional 'ports' node */
|
||||
node = dev_read_subnode(dev, "ports");
|
||||
if (!ofnode_valid(node)) {
|
||||
node = dev_read_subnode(dev, "port");
|
||||
} else {
|
||||
/* several 'port' nodes, found the requested port@index one */
|
||||
ofnode_for_each_subnode(child, node) {
|
||||
ofnode_read_u32(child, "reg", ®);
|
||||
if (index == reg) {
|
||||
node = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
node = child;
|
||||
}
|
||||
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_dbg(dev, "connector port or port@%d subnode not found\n", index);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* get endpoint node */
|
||||
node = ofnode_first_subnode(node);
|
||||
if (!ofnode_valid(node))
|
||||
return -EINVAL;
|
||||
|
||||
ret = ofnode_read_u32(node, "remote-endpoint", &endpoint_phandle);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* retrieve connector endpoint phandle */
|
||||
node = ofnode_get_by_phandle(endpoint_phandle);
|
||||
if (!ofnode_valid(node))
|
||||
return -EINVAL;
|
||||
/*
|
||||
* Use a while to retrieve an USB Type-C device either at connector
|
||||
* level or just above (depending if UCSI uclass is used or not)
|
||||
*/
|
||||
while (ofnode_valid(node)) {
|
||||
node = ofnode_get_parent(node);
|
||||
if (!ofnode_valid(node)) {
|
||||
dev_err(dev, "No UCLASS_USB_TYPEC for remote-endpoint\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uclass_find_device_by_ofnode(UCLASS_USB_TYPEC, node, typec);
|
||||
if (*typec)
|
||||
break;
|
||||
}
|
||||
|
||||
ret = device_probe(*typec);
|
||||
if (ret) {
|
||||
dev_err(dev, "Type-C won't probe (ret=%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int typec_get_data_role(struct udevice *dev, u8 con_idx)
|
||||
{
|
||||
|
||||
@ -70,6 +70,66 @@ int typec_get_data_role(struct udevice *dev, u8 con_idx);
|
||||
* @return Type-C connector number or -ve on error.
|
||||
*/
|
||||
int typec_get_nb_connector(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* typec_get_device_from_usb() - Allows to retrieve a Type-C device from
|
||||
* an USB device. typec_get_driver_from_usb() checks in USB device node
|
||||
* for port and endpoint sub-node, if exist, retrieve the connector node,
|
||||
* probe the associated Type-C device and return it (see DT example below).
|
||||
* See Documentation/devicetree/bindings/connector/usb-connector.yaml for more
|
||||
* details
|
||||
*
|
||||
* @dev: USB device
|
||||
* @typec: Type-C device
|
||||
* @index: USB controller port number
|
||||
* @return -ve on error.
|
||||
*
|
||||
* usb_dwc3_0: usb@10000000 {
|
||||
* ...
|
||||
* port@0 {
|
||||
* reg = <0>;
|
||||
* typec_hs: endpoint {
|
||||
* remote-endpoint = <&usb_con_hs>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* port@1 {
|
||||
* reg = <1>;
|
||||
* typec_ss: endpoint {
|
||||
* remote-endpoint = <&usb_con_ss>;
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* usb-typec@1 {
|
||||
* ...
|
||||
* connector {
|
||||
* compatible = "usb-c-connector";
|
||||
* label = "USB-C";
|
||||
*
|
||||
* ports {
|
||||
* #address-cells = <1>;
|
||||
* #size-cells = <0>;
|
||||
*
|
||||
* port@0 {
|
||||
* reg = <0>;
|
||||
* usb_con_hs: endpoint {
|
||||
* remote-endpoint = <&typec_hs>;
|
||||
* };
|
||||
* };
|
||||
*
|
||||
* port@1 {
|
||||
* reg = <1>;
|
||||
* usb_con_ss: endpoint {
|
||||
* remote-endpoint = <&typec_ss>;
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
* };
|
||||
*/
|
||||
int typec_get_device_from_usb(struct udevice *dev, struct udevice **typec, u8
|
||||
index);
|
||||
#else
|
||||
static inline int typec_is_attached(struct udevice *dev, u8 con_idx)
|
||||
{
|
||||
@ -85,5 +145,10 @@ static inline int typec_get_nb_connector(struct udevice *dev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int typec_get_device_from_usb(struct udevice *dev, struct udevice **typec,
|
||||
u8 index)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user