usb: dwc3: msm: update framework to support redriver
Snapshot redriver framework from msm-5.15 branch commit 32dbffee2bb3 ("usb: redriver: add nb7vpq904m rework driver") commit 4465e83b503c ("usb: redriver: add core api"). Change-Id: Ie9b84641fc97f9e45bfd7f7eeeee1eba4bfd64f1 Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
This commit is contained in:
parent
cf133f3f84
commit
d69ea46d24
@ -178,4 +178,6 @@ source "drivers/usb/pd/Kconfig"
|
||||
|
||||
source "drivers/usb/repeater/Kconfig"
|
||||
|
||||
source "drivers/usb/redriver/Kconfig"
|
||||
|
||||
endif # USB_SUPPORT
|
||||
|
@ -69,3 +69,5 @@ obj-$(CONFIG_TYPEC) += typec/
|
||||
obj-$(CONFIG_USB_ROLE_SWITCH) += roles/
|
||||
|
||||
obj-$(CONFIG_USB_REPEATER) += repeater/
|
||||
|
||||
obj-$(CONFIG_USB_REDRIVER) += redriver/
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -477,6 +478,7 @@ struct dwc3_msm {
|
||||
struct regulator *dwc3_gdsc;
|
||||
|
||||
struct usb_phy *hs_phy, *ss_phy;
|
||||
struct usb_redriver *redriver;
|
||||
|
||||
const struct dbm_reg_data *dbm_reg_table;
|
||||
int dbm_num_eps;
|
||||
@ -556,8 +558,6 @@ struct dwc3_msm {
|
||||
bool ss_release_called;
|
||||
int orientation_override;
|
||||
|
||||
struct device_node *ss_redriver_node;
|
||||
|
||||
#define MAX_ERROR_RECOVERY_TRIES 3
|
||||
bool err_evt_seen;
|
||||
int retries_on_error;
|
||||
@ -3020,15 +3020,13 @@ void dwc3_msm_notify_event(struct dwc3 *dwc,
|
||||
dev_dbg(mdwc->dev, "DWC3_CONTROLLER_PULLUP_ENTER %d\n", value);
|
||||
/* ignore pullup when role switch from device to host */
|
||||
if (mdwc->vbus_active)
|
||||
redriver_gadget_pullup_enter(mdwc->ss_redriver_node,
|
||||
value);
|
||||
usb_redriver_gadget_pullup_enter(mdwc->redriver, value);
|
||||
break;
|
||||
case DWC3_CONTROLLER_PULLUP_EXIT:
|
||||
dev_dbg(mdwc->dev, "DWC3_CONTROLLER_PULLUP_EXIT %d\n", value);
|
||||
/* ignore pullup when role switch from device to host */
|
||||
if (mdwc->vbus_active)
|
||||
redriver_gadget_pullup_exit(mdwc->ss_redriver_node,
|
||||
value);
|
||||
usb_redriver_gadget_pullup_exit(mdwc->redriver, value);
|
||||
break;
|
||||
case DWC3_GSI_EVT_BUF_SETUP:
|
||||
dev_dbg(mdwc->dev, "DWC3_GSI_EVT_BUF_SETUP\n");
|
||||
@ -3325,15 +3323,15 @@ static void dwc3_set_ssphy_orientation_flag(struct dwc3_msm *mdwc)
|
||||
union extcon_property_value val;
|
||||
struct extcon_dev *edev = NULL;
|
||||
unsigned int extcon_id;
|
||||
int ret;
|
||||
int ret, orientation;
|
||||
|
||||
mdwc->ss_phy->flags &= ~(PHY_LANE_A | PHY_LANE_B);
|
||||
|
||||
if (mdwc->orientation_override) {
|
||||
mdwc->ss_phy->flags |= mdwc->orientation_override;
|
||||
} else if (mdwc->ss_redriver_node) {
|
||||
ret = redriver_orientation_get(mdwc->ss_redriver_node);
|
||||
if (ret == 0)
|
||||
} else if (usb_redriver_has_orientation(mdwc->redriver)) {
|
||||
orientation = usb_redriver_get_orientation(mdwc->redriver);
|
||||
if (orientation == ORIENTATION_CC1)
|
||||
mdwc->ss_phy->flags |= PHY_LANE_A;
|
||||
else
|
||||
mdwc->ss_phy->flags |= PHY_LANE_B;
|
||||
@ -4890,10 +4888,15 @@ static void dwc3_msm_clear_dp_only_params(struct dwc3_msm *mdwc)
|
||||
mdwc->ss_release_called = false;
|
||||
mdwc->ss_phy->flags &= ~PHY_DP_MODE;
|
||||
dwc3_msm_set_max_speed(mdwc, USB_SPEED_UNKNOWN);
|
||||
|
||||
usb_redriver_notify_disconnect(mdwc->redriver);
|
||||
}
|
||||
|
||||
static void dwc3_msm_set_dp_only_params(struct dwc3_msm *mdwc)
|
||||
{
|
||||
usb_redriver_release_lanes(mdwc->redriver, mdwc->ss_phy->flags & PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2, 4);
|
||||
|
||||
/* restart USB host mode into high speed */
|
||||
mdwc->ss_release_called = true;
|
||||
dwc3_msm_set_max_speed(mdwc, USB_SPEED_HIGH);
|
||||
@ -4953,14 +4956,14 @@ int dwc3_msm_set_dp_mode(struct device *dev, bool dp_connected, int lanes)
|
||||
mdwc->dp_state = DP_2_LANE;
|
||||
mdwc->refcnt_dp_usb++;
|
||||
mutex_unlock(&mdwc->role_switch_mutex);
|
||||
usb_redriver_release_lanes(mdwc->redriver, mdwc->ss_phy->flags & PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2, 2);
|
||||
pm_runtime_get_sync(&mdwc->dwc3->dev);
|
||||
mdwc->ss_phy->flags |= PHY_USB_DP_CONCURRENT_MODE;
|
||||
pm_runtime_put_sync(&mdwc->dwc3->dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
redriver_release_usb_lanes(mdwc->ss_redriver_node);
|
||||
|
||||
mutex_lock(&mdwc->role_switch_mutex);
|
||||
/* 4 lanes handling */
|
||||
if (mdwc->dp_state != DP_2_LANE)
|
||||
@ -5260,6 +5263,14 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* redriver may not probe, check it at start here */
|
||||
mdwc->redriver = usb_get_redriver_by_phandle(node, "ssusb_redriver", 0);
|
||||
if (IS_ERR(mdwc->redriver)) {
|
||||
ret = PTR_ERR(mdwc->redriver);
|
||||
mdwc->redriver = NULL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get all clks and gdsc reference */
|
||||
ret = dwc3_msm_get_clk_gdsc(mdwc);
|
||||
if (ret) {
|
||||
@ -5478,12 +5489,6 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
||||
mutex_init(&mdwc->suspend_resume_mutex);
|
||||
mutex_init(&mdwc->role_switch_mutex);
|
||||
|
||||
mdwc->ss_redriver_node = of_parse_phandle(node, "ssusb_redriver", 0);
|
||||
if (!of_device_is_available(mdwc->ss_redriver_node)) {
|
||||
of_node_put(mdwc->ss_redriver_node);
|
||||
mdwc->ss_redriver_node = NULL;
|
||||
}
|
||||
|
||||
mdwc->force_gen1 = of_property_read_bool(node, "qcom,force-gen1");
|
||||
|
||||
if (of_property_read_bool(node, "usb-role-switch")) {
|
||||
@ -5578,13 +5583,13 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
||||
|
||||
put_dwc3:
|
||||
usb_role_switch_unregister(mdwc->role_switch);
|
||||
of_node_put(mdwc->ss_redriver_node);
|
||||
for (i = 0; i < ARRAY_SIZE(mdwc->icc_paths); i++)
|
||||
icc_put(mdwc->icc_paths[i]);
|
||||
|
||||
err:
|
||||
destroy_workqueue(mdwc->sm_usb_wq);
|
||||
destroy_workqueue(mdwc->dwc3_wq);
|
||||
usb_put_redriver(mdwc->redriver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5595,7 +5600,6 @@ static int dwc3_msm_remove(struct platform_device *pdev)
|
||||
int i, ret_pm;
|
||||
|
||||
usb_role_switch_unregister(mdwc->role_switch);
|
||||
of_node_put(mdwc->ss_redriver_node);
|
||||
|
||||
if (mdwc->dpdm_nb.notifier_call) {
|
||||
regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb);
|
||||
@ -5629,6 +5633,8 @@ static int dwc3_msm_remove(struct platform_device *pdev)
|
||||
platform_device_put(mdwc->dwc3);
|
||||
of_platform_depopulate(&pdev->dev);
|
||||
|
||||
usb_put_redriver(mdwc->redriver);
|
||||
|
||||
dbg_event(0xFF, "Remov put", 0);
|
||||
pm_runtime_disable(mdwc->dev);
|
||||
pm_runtime_barrier(mdwc->dev);
|
||||
@ -5767,7 +5773,7 @@ static int dwc3_msm_host_notifier(struct notifier_block *nb,
|
||||
dwc3_msm_host_ss_powerup(mdwc);
|
||||
|
||||
if (udev->parent->speed >= USB_SPEED_SUPER)
|
||||
redriver_powercycle(mdwc->ss_redriver_node);
|
||||
usb_redriver_host_powercycle(mdwc->redriver);
|
||||
}
|
||||
} else if (!udev->parent) {
|
||||
/* USB root hub device */
|
||||
@ -5837,12 +5843,11 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
|
||||
pm_runtime_get_sync(mdwc->dev);
|
||||
dbg_event(0xFF, "StrtHost gync",
|
||||
atomic_read(&mdwc->dev->power.usage_count));
|
||||
redriver_notify_connect(mdwc->ss_redriver_node,
|
||||
mdwc->orientation_override ?
|
||||
(mdwc->orientation_override == PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2) : ORIENTATION_UNKNOWN);
|
||||
clk_set_rate(mdwc->core_clk, mdwc->core_clk_rate);
|
||||
dwc3_msm_set_clk_sel(mdwc);
|
||||
usb_redriver_notify_connect(mdwc->redriver,
|
||||
mdwc->ss_phy->flags & PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2);
|
||||
if (dwc->maximum_speed >= USB_SPEED_SUPER) {
|
||||
mdwc->ss_phy->flags |= PHY_HOST_MODE;
|
||||
usb_phy_notify_connect(mdwc->ss_phy,
|
||||
@ -5953,7 +5958,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on)
|
||||
USB_SPEED_SUPER);
|
||||
mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
|
||||
}
|
||||
redriver_notify_disconnect(mdwc->ss_redriver_node);
|
||||
usb_redriver_notify_disconnect(mdwc->redriver);
|
||||
|
||||
mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
|
||||
usb_unregister_notify(&mdwc->host_nb);
|
||||
@ -6034,12 +6039,14 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
|
||||
dwc3_msm_notify_event(dwc, DWC3_GSI_EVT_BUF_SETUP, 0);
|
||||
|
||||
dwc3_override_vbus_status(mdwc, true);
|
||||
redriver_notify_connect(mdwc->ss_redriver_node,
|
||||
mdwc->orientation_override ?
|
||||
(mdwc->orientation_override == PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2) : ORIENTATION_UNKNOWN);
|
||||
|
||||
usb_redriver_notify_connect(mdwc->redriver,
|
||||
mdwc->ss_phy->flags & PHY_LANE_A ?
|
||||
ORIENTATION_CC1 : ORIENTATION_CC2);
|
||||
if (dwc3_msm_get_max_speed(mdwc) >= USB_SPEED_SUPER)
|
||||
usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER);
|
||||
|
||||
usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
|
||||
usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER);
|
||||
|
||||
/*
|
||||
* Core reset is not required during start peripheral. Only
|
||||
@ -6081,9 +6088,9 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
|
||||
dwc3_override_vbus_status(mdwc, false);
|
||||
mdwc->in_device_mode = false;
|
||||
usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
|
||||
usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);
|
||||
redriver_notify_disconnect(mdwc->ss_redriver_node);
|
||||
usb_phy_set_power(mdwc->hs_phy, 0);
|
||||
usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);
|
||||
usb_redriver_notify_disconnect(mdwc->redriver);
|
||||
|
||||
dwc3_msm_notify_event(dwc, DWC3_GSI_EVT_BUF_CLEAR, 0);
|
||||
dwc3_override_vbus_status(mdwc, false);
|
||||
|
@ -275,13 +275,3 @@ config USB_CHAOSKEY
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called chaoskey.
|
||||
|
||||
config USB_REDRIVER
|
||||
bool
|
||||
|
||||
config USB_REDRIVER_NB7VPQ904M
|
||||
tristate "USB 3.1 Gen1/Gen2 10Gbps re-driver driver for NB7VPQ904M"
|
||||
depends on USB_PHY
|
||||
select USB_REDRIVER
|
||||
help
|
||||
Say Y here if you want to support USB super speed re-driver NB7VPQ904M.
|
||||
|
@ -31,4 +31,3 @@ obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
|
||||
obj-$(CONFIG_USB_LINK_LAYER_TEST) += lvstest.o
|
||||
obj-$(CONFIG_USB_REDRIVER_NB7VPQ904M) += ssusb-redriver-nb7vpq904m.o
|
||||
|
24
drivers/usb/redriver/Kconfig
Normal file
24
drivers/usb/redriver/Kconfig
Normal file
@ -0,0 +1,24 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
menu "USB3 linear redriver"
|
||||
|
||||
config USB_REDRIVER
|
||||
tristate "USB super speed (plus) redriver support"
|
||||
help
|
||||
USB super speed (plus) redriver chip used to improve
|
||||
USB signal which have long path(USB connector <-->
|
||||
FPC cable <---> USB PHY).
|
||||
|
||||
Normally this kind of chip have i2c bus interface.
|
||||
|
||||
config USB_REDRIVER_NB7VPQ904M
|
||||
tristate "NB7VPQ904M USB 3.1 Gen1/Gen2 10Gbps redriver"
|
||||
select REGMAP_I2C
|
||||
select USB_REDRIVER
|
||||
help
|
||||
NB7VPQ904M come from ON-SEMI company,
|
||||
it enhance USB super (plus) signal on mobile platform.
|
||||
it have i2c program interface.
|
||||
Say Y/M here if you want to support it.
|
||||
|
||||
endmenu
|
4
drivers/usb/redriver/Makefile
Normal file
4
drivers/usb/redriver/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
obj-$(CONFIG_USB_REDRIVER) += redriver.o
|
||||
obj-$(CONFIG_USB_REDRIVER_NB7VPQ904M) += nb7vpq904m.o
|
File diff suppressed because it is too large
Load Diff
204
drivers/usb/redriver/redriver.c
Normal file
204
drivers/usb/redriver/redriver.c
Normal file
@ -0,0 +1,204 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* USB Super Speed (Plus) redriver core module
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "redriver-core: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb/redriver.h>
|
||||
|
||||
static LIST_HEAD(usb_redriver_list);
|
||||
static DEFINE_SPINLOCK(usb_rediver_lock);
|
||||
|
||||
/**
|
||||
* usb_add_redriver() - register a redriver from a specific chip driver.
|
||||
* @redriver: redriver allocated by specific chip driver.
|
||||
*
|
||||
* Return:
|
||||
* -EINVAL - if of node not exist
|
||||
* 0 - if exist, add redriver to global list.
|
||||
*/
|
||||
int usb_add_redriver(struct usb_redriver *redriver)
|
||||
{
|
||||
struct usb_redriver *iter;
|
||||
|
||||
if (!redriver->of_node || redriver->bounded ||
|
||||
(redriver->has_orientation && !redriver->get_orientation))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&usb_rediver_lock);
|
||||
|
||||
list_for_each_entry(iter, &usb_redriver_list, list) {
|
||||
if (iter == redriver) {
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
|
||||
pr_debug("add redriver %s\n", of_node_full_name(redriver->of_node));
|
||||
list_add_tail(&redriver->list, &usb_redriver_list);
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_add_redriver);
|
||||
|
||||
/**
|
||||
* usb_remove_redriver() - remove a redriver from a specific chip driver.
|
||||
* @redriver: redriver allocated by specific chip driver.
|
||||
*
|
||||
* remove redriver from global list.
|
||||
* if redriver rmmod, it is better change to default state inside it's driver,
|
||||
* no unbind operation here.
|
||||
*
|
||||
* Return:
|
||||
* -EINVAL - redriver still used by uppper layer.
|
||||
* 0 - redriver removed.
|
||||
*/
|
||||
int usb_remove_redriver(struct usb_redriver *redriver)
|
||||
{
|
||||
spin_lock(&usb_rediver_lock);
|
||||
|
||||
if (redriver->bounded) {
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("remove redriver %s\n", of_node_full_name(redriver->of_node));
|
||||
list_del(&redriver->list);
|
||||
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_remove_redriver);
|
||||
|
||||
/**
|
||||
* usb_get_redriver_by_phandle() - find redriver to be used.
|
||||
* @np: device node of device which use the redriver
|
||||
* @phandle_name: phandle name which refer to the redriver
|
||||
* @index: phandle index which refer to the redriver
|
||||
*
|
||||
* Return:
|
||||
* NULL - if no phandle or redriver device tree status is disabled.
|
||||
* ERR_PTR(-EPROBE_DEFER) - if redriver is not registered
|
||||
* if redriver registered, return pointer of it.
|
||||
*/
|
||||
struct usb_redriver *usb_get_redriver_by_phandle(const struct device_node *np,
|
||||
const char *phandle_name, int index)
|
||||
{
|
||||
struct usb_redriver *redriver;
|
||||
struct device_node *node;
|
||||
bool found = false;
|
||||
|
||||
node = of_parse_phandle(np, phandle_name, index);
|
||||
if (!of_device_is_available(node)) {
|
||||
of_node_put(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
spin_lock(&usb_rediver_lock);
|
||||
list_for_each_entry(redriver, &usb_redriver_list, list) {
|
||||
if (redriver->of_node == node) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
of_node_put(node);
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
}
|
||||
|
||||
pr_debug("get redriver %s\n", of_node_full_name(redriver->of_node));
|
||||
redriver->bounded = true;
|
||||
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
|
||||
return redriver;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_get_redriver_by_phandle);
|
||||
|
||||
/**
|
||||
* usb_put_redriver() - redriver will not be used.
|
||||
* @redriver: redriver allocated by specific chip driver.
|
||||
*
|
||||
* when user module exit, unbind redriver.
|
||||
*/
|
||||
void usb_put_redriver(struct usb_redriver *redriver)
|
||||
{
|
||||
if (!redriver)
|
||||
return;
|
||||
|
||||
spin_lock(&usb_rediver_lock);
|
||||
of_node_put(redriver->of_node);
|
||||
pr_debug("put redriver %s\n", of_node_full_name(redriver->of_node));
|
||||
redriver->bounded = false;
|
||||
spin_unlock(&usb_rediver_lock);
|
||||
|
||||
if (redriver->unbind)
|
||||
redriver->unbind(redriver);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_put_redriver);
|
||||
|
||||
/* note: following exported symbol can be inlined in header file,
|
||||
* export here to avoid unexpected CFI(Clang Control Flow Integrity) issue.
|
||||
*/
|
||||
void usb_redriver_release_lanes(struct usb_redriver *ur, int ort, int num)
|
||||
{
|
||||
if (ur && ur->release_usb_lanes)
|
||||
ur->release_usb_lanes(ur, ort, num);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_release_lanes);
|
||||
|
||||
void usb_redriver_notify_connect(struct usb_redriver *ur, int ort)
|
||||
{
|
||||
if (ur && ur->notify_connect)
|
||||
ur->notify_connect(ur, ort);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_notify_connect);
|
||||
|
||||
void usb_redriver_notify_disconnect(struct usb_redriver *ur)
|
||||
{
|
||||
if (ur && ur->notify_disconnect)
|
||||
ur->notify_disconnect(ur);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_notify_disconnect);
|
||||
|
||||
int usb_redriver_get_orientation(struct usb_redriver *ur)
|
||||
{
|
||||
if (ur && ur->has_orientation)
|
||||
return ur->get_orientation(ur);
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_get_orientation);
|
||||
|
||||
void usb_redriver_gadget_pullup_enter(struct usb_redriver *ur,
|
||||
int is_on)
|
||||
{
|
||||
if (ur && ur->gadget_pullup_enter)
|
||||
ur->gadget_pullup_enter(ur, is_on);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_gadget_pullup_enter);
|
||||
|
||||
void usb_redriver_gadget_pullup_exit(struct usb_redriver *ur,
|
||||
int is_on)
|
||||
{
|
||||
if (ur && ur->gadget_pullup_exit)
|
||||
ur->gadget_pullup_exit(ur, is_on);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_gadget_pullup_exit);
|
||||
|
||||
void usb_redriver_host_powercycle(struct usb_redriver *ur)
|
||||
{
|
||||
if (ur && ur->host_powercycle)
|
||||
ur->host_powercycle(ur);
|
||||
}
|
||||
EXPORT_SYMBOL(usb_redriver_host_powercycle);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("USB Super Speed (Plus) redriver core module");
|
@ -1,67 +1,127 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_REDRIVER_H
|
||||
#define __LINUX_USB_REDRIVER_H
|
||||
|
||||
enum plug_orientation {
|
||||
ORIENTATION_CC1,
|
||||
ORIENTATION_CC2,
|
||||
ORIENTATION_UNKNOWN,
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* design rules,
|
||||
* [a] assume pullup operation happen in kretprobe.
|
||||
* in kretprobe function, mutex lock is not allowed;
|
||||
* in kretprobe function, schedule_work() is allowed;
|
||||
* [b] this is core driver which service lower redriver and upper user.
|
||||
* [c] redriver must probe early than user, or not user will defer probe.
|
||||
* [d] redriver can rmmod only when there is no user bind to it.
|
||||
* [e] if user rmmod, redirver will change to default state.
|
||||
* [f] if redriver module insmod after new change and build,
|
||||
* user module also need insmod to work.
|
||||
* [g] when a redriver probe, set to disable state, all control from user.
|
||||
* as ssphy have no eud function which don't need to keep working.
|
||||
* [h] user should be ssphy, but current user is dwc3,
|
||||
* as seem some redriver have termination issue,
|
||||
* it need to do pullup operation from controller driver.
|
||||
*/
|
||||
|
||||
|
||||
#define ORIENTATION_CC1 0
|
||||
#define ORIENTATION_CC2 1
|
||||
|
||||
/**
|
||||
* struct usb_redriver - present a redriver chip
|
||||
* @list: link all redriver chips
|
||||
* @of_node: redriver chip device tree node
|
||||
* @release_usb_lanes: put redriver into 2/4 lanes display mode
|
||||
* @notify_connect: cable connect
|
||||
* @notify_disconnect: cable disconnect
|
||||
* @get_orientation: report orientation to user if orientation source shared
|
||||
* @gadget_pullup_enter: operation when enter gadget pullup function
|
||||
* @gadget_pullup_exit: operation when exit gadget pullup function
|
||||
* @host_powercycle: workaround for host otg case
|
||||
* @unbind, change to default state when user unbind it
|
||||
* @has_orientation, provide orientation from chip driver or not
|
||||
* @bounded, bound to user or not
|
||||
*/
|
||||
struct usb_redriver {
|
||||
struct list_head list;
|
||||
struct device_node *of_node;
|
||||
|
||||
int (*release_usb_lanes)(struct usb_redriver *ur, int ort, int num);
|
||||
int (*notify_connect)(struct usb_redriver *ur, int ort);
|
||||
int (*notify_disconnect)(struct usb_redriver *ur);
|
||||
int (*get_orientation)(struct usb_redriver *ur);
|
||||
int (*gadget_pullup_enter)(struct usb_redriver *ur, int is_on);
|
||||
int (*gadget_pullup_exit)(struct usb_redriver *ur, int is_on);
|
||||
int (*host_powercycle)(struct usb_redriver *ur);
|
||||
void (*unbind)(struct usb_redriver *ur);
|
||||
|
||||
bool has_orientation;
|
||||
bool bounded;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USB_REDRIVER
|
||||
#if IS_ENABLED(CONFIG_USB_REDRIVER)
|
||||
int usb_add_redriver(struct usb_redriver *ur);
|
||||
int usb_remove_redriver(struct usb_redriver *ur);
|
||||
|
||||
int redriver_release_usb_lanes(struct device_node *node);
|
||||
int redriver_notify_connect(struct device_node *node, enum plug_orientation orientation);
|
||||
int redriver_notify_disconnect(struct device_node *node);
|
||||
int redriver_orientation_get(struct device_node *node);
|
||||
int redriver_gadget_pullup_enter(struct device_node *node, int is_on);
|
||||
int redriver_gadget_pullup_exit(struct device_node *node, int is_on);
|
||||
int redriver_powercycle(struct device_node *node);
|
||||
struct usb_redriver *usb_get_redriver_by_phandle(
|
||||
const struct device_node *np,
|
||||
const char *phandle_name, int index);
|
||||
void usb_put_redriver(struct usb_redriver *ur);
|
||||
void usb_redriver_release_lanes(struct usb_redriver *ur, int ort, int num);
|
||||
void usb_redriver_notify_connect(struct usb_redriver *ur, int ort);
|
||||
void usb_redriver_notify_disconnect(struct usb_redriver *ur);
|
||||
int usb_redriver_get_orientation(struct usb_redriver *ur);
|
||||
void usb_redriver_gadget_pullup_enter(struct usb_redriver *ur, int is_on);
|
||||
void usb_redriver_gadget_pullup_exit(struct usb_redriver *ur, int is_on);
|
||||
void usb_redriver_host_powercycle(struct usb_redriver *ur);
|
||||
|
||||
#else
|
||||
|
||||
static inline int redriver_release_usb_lanes(struct device_node *node)
|
||||
static inline int usb_add_redriver(struct usb_redriver *ur)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int redriver_notify_connect(struct device_node *node,
|
||||
enum plug_orientation orientation)
|
||||
static inline struct usb_redriver *usb_get_redriver_by_phandle(
|
||||
const struct device_node *np,
|
||||
const char *phandle_name, int index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int usb_remove_redriver(struct usb_redriver *ur)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int redriver_notify_disconnect(struct device_node *node)
|
||||
static inline int usb_redriver_get_orientation(struct usb_redriver *ur)
|
||||
{
|
||||
return 0;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int redriver_orientation_get(struct device_node *node)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#define usb_put_redriver(ur) do {} while (0)
|
||||
|
||||
static inline int redriver_gadget_pullup_enter(struct device_node *node,
|
||||
int is_on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int redriver_gadget_pullup_exit(struct device_node *node,
|
||||
int is_on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int redriver_powercycle(struct device_node *node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define usb_redriver_release_lanes(ur, ort, num) do {} while (0)
|
||||
#define usb_redriver_notify_connect(ur, ort) do {} while (0)
|
||||
#define usb_redriver_notify_disconnect(ur) do {} while (0)
|
||||
#define usb_redriver_gadget_pullup_enter(ur, is_on) do {} while (0)
|
||||
#define usb_redriver_gadget_pullup_exit(ur, is_on) do {} while (0)
|
||||
#define usb_redriver_host_powercycle(ur) do {} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool usb_redriver_has_orientation(struct usb_redriver *ur)
|
||||
{
|
||||
if (ur && ur->has_orientation)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /*__LINUX_USB_REDRIVER_H */
|
||||
|
Loading…
Reference in New Issue
Block a user