Merge: USB/TBT code rebase of supported drivers to upstream v7.0

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/8370

JIRA: https://issues.redhat.com/browse/RHEL-147798

This MR rebases supported usb/tbt/memstick/extcon drivers to upstream
kernel v7.0. By design, rebase changes are limited to supported drivers
and their relevant physical infrastructure. Treewide changes which touch
these drivers are partially pulled in, whenever found out to be relevant.

1) CVEs:
```
CVE: CVE-2026-43259
CVE: CVE-2026-43170
CVE: CVE-2026-43425
CVE: CVE-2026-43429
CVE: CVE-2026-43428
CVE: CVE-2026-43427
CVE: CVE-2026-43432
CVE: CVE-2026-43488
CVE: CVE-2026-31758
CVE: CVE-2026-31729
CVE: CVE-2026-31759
CVE: CVE-2026-46109
```

2) Addition/Removal of code:
This MR also adds ethtool speed codes to allow the Thunderbolt/USB4 net-
working driver to be used with the bonding driver. Furthermore, the MR
also passes IRQF_ONESHOT directly in devm_request_irq() at genirq,
since this flag is being removed from irqflags in multiple drivers.

Signed-off-by: Desnes Nunes <desnesn@redhat.com>

Approved-by: Tony Camuso <tcamuso@redhat.com>
Approved-by: mheib <mheib@redhat.com>
Approved-by: Jarod Wilson <jarod@redhat.com>
Approved-by: José Ignacio Tornos Martínez <jtornosm@redhat.com>
Approved-by: Dennis Chen <dechen@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-08-04 08:11:41 +00:00
108 changed files with 2394 additions and 4510 deletions
@@ -85,3 +85,45 @@ Description:
up to 5000. The default value is 64 ms.
This polling interval is used while DbC is enabled but has no
active data transfers.
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_serial
Date: January 2026
Contact: Łukasz Bartosik <ukaszb@chromium.org>
Description:
The dbc_serial attribute allows to change the serial number
string descriptor presented by the debug device when a host
requests a string descriptor with iSerialNumber index.
Index is found in the iSerialNumber field in the device
descriptor.
Value can only be changed while debug capability (DbC) is in
disabled state to prevent USB device descriptor change while
connected to a USB host.
The default value is "0001".
The field length can be from 1 to 126 characters.
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_product
Date: January 2026
Contact: Łukasz Bartosik <ukaszb@chromium.org>
Description:
The dbc_product attribute allows to change the product string
descriptor presented by the debug device when a host requests
a string descriptor with iProduct index.
Index is found in the iProduct field in the device descriptor.
Value can only be changed while debug capability (DbC) is in
disabled state to prevent USB device descriptor change while
connected to a USB host.
The default value is "Linux USB Debug Target".
The field length can be from 1 to 126 characters.
What: /sys/bus/pci/drivers/xhci_hcd/.../dbc_manufacturer
Date: January 2026
Contact: Łukasz Bartosik <ukaszb@chromium.org>
Description:
The dbc_manufacturer attribute allows to change the manufacturer
string descriptor presented by the debug device when a host
requests a string descriptor with iManufacturer index.
Value can only be changed while debug capability (DbC) is in
disabled state to prevent USB device descriptor change while
connected to a USB host.
The default value is "Linux Foundation".
The field length can be from 1 to 126 characters.
@@ -162,6 +162,17 @@ Description: Lists the supported USB Modes. The default USB mode that is used
- usb3 (USB 3.2)
- usb4 (USB4)
What: /sys/class/typec/<port>/<alt-mode>/priority
Date: July 2025
Contact: Andrei Kuchynski <akuchynski@chromium.org>
Description:
Displays and allows setting the priority for a specific alternate mode.
The priority is an integer in the range 0-255. A lower numerical value
indicates a higher priority (0 is the highest).
If the new value is already in use by another mode, the priority of the
conflicting mode and any subsequent modes will be incremented until they
are all unique.
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
What: /sys/class/typec/<port>-partner/accessory_mode
@@ -7011,6 +7011,9 @@
p = USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT
(Reduce timeout of the SET_ADDRESS
request from 5000 ms to 500 ms);
q = USB_QUIRK_FORCE_ONE_CONFIG (Device
claims zero configurations,
forcing to 1);
Example: quirks=0781:5580:bk,0a5c:5834:gij
usbhid.mousepoll=
+1 -1
View File
@@ -370,7 +370,7 @@ is built-in to the kernel image, there is no need to do anything.
The driver will create one virtual ethernet interface per Thunderbolt
port which are named like ``thunderbolt0`` and so on. From this point
you can either use standard userspace tools like ``ifconfig`` to
you can either use standard userspace tools like ``ip`` to
configure the interface or let your GUI handle it automatically.
Forcing power
@@ -301,8 +301,9 @@ properties:
maxItems: 4
dependencies:
sink-vdos-v1: [ 'sink-vdos' ]
sink-vdos: [ 'sink-vdos-v1' ]
pd-disable: [typec-power-opmode]
sink-vdos-v1: [ sink-vdos ]
sink-vdos: [ sink-vdos-v1 ]
required:
- compatible
@@ -90,6 +90,8 @@ properties:
minItems: 1
maxItems: 2
dma-coherent: true
interrupts:
maxItems: 1
@@ -61,6 +61,8 @@ properties:
reg:
maxItems: 1
dma-coherent: true
interrupts:
maxItems: 1
@@ -0,0 +1,65 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/usb/wch,ch334.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: WCH CH334/CH335 USB 2.0 Hub Controller
maintainers:
- Chaoyi Chen <kernel@airkyi.com>
allOf:
- $ref: usb-hub.yaml#
properties:
compatible:
enum:
- usb1a86,8091
reg: true
reset-gpios:
description: GPIO controlling the RESET# pin.
vdd33-supply:
description:
The regulator that provides 3.3V core power to the hub.
v5-supply:
description:
The regulator that provides 3.3V or 5V power to the hub.
ports:
$ref: /schemas/graph.yaml#/properties/ports
patternProperties:
'^port@':
$ref: /schemas/graph.yaml#/properties/port
properties:
reg:
minimum: 1
maximum: 4
required:
- compatible
- reg
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
usb {
#address-cells = <1>;
#size-cells = <0>;
hub: hub@1 {
compatible = "usb1a86,8091";
reg = <1>;
reset-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
v5-supply = <&vcc_3v3>;
vdd33-supply = <&vcc_3v3>;
};
};
+9
View File
@@ -72,6 +72,7 @@ enum ad_link_speed_type {
AD_LINK_SPEED_40000MBPS,
AD_LINK_SPEED_50000MBPS,
AD_LINK_SPEED_56000MBPS,
AD_LINK_SPEED_80000MBPS,
AD_LINK_SPEED_100000MBPS,
AD_LINK_SPEED_200000MBPS,
AD_LINK_SPEED_400000MBPS,
@@ -249,6 +250,7 @@ static inline int __check_agg_selection_timer(struct port *port)
* %AD_LINK_SPEED_40000MBPS
* %AD_LINK_SPEED_50000MBPS
* %AD_LINK_SPEED_56000MBPS
* %AD_LINK_SPEED_80000MBPS
* %AD_LINK_SPEED_100000MBPS
* %AD_LINK_SPEED_200000MBPS
* %AD_LINK_SPEED_400000MBPS
@@ -316,6 +318,10 @@ static u16 __get_link_speed(struct port *port)
speed = AD_LINK_SPEED_56000MBPS;
break;
case SPEED_80000:
speed = AD_LINK_SPEED_80000MBPS;
break;
case SPEED_100000:
speed = AD_LINK_SPEED_100000MBPS;
break;
@@ -750,6 +756,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
case AD_LINK_SPEED_56000MBPS:
bandwidth = nports * 56000;
break;
case AD_LINK_SPEED_80000MBPS:
bandwidth = nports * 80000;
break;
case AD_LINK_SPEED_100000MBPS:
bandwidth = nports * 100000;
break;
+1
View File
@@ -25,6 +25,7 @@ enum {
LINK_CAPA_40000FD,
LINK_CAPA_50000FD,
LINK_CAPA_56000FD,
LINK_CAPA_80000FD,
LINK_CAPA_100000FD,
LINK_CAPA_200000FD,
LINK_CAPA_400000FD,
+2
View File
@@ -47,6 +47,8 @@ const char *phy_speed_to_str(int speed)
return "50Gbps";
case SPEED_56000:
return "56Gbps";
case SPEED_80000:
return "80Gbps";
case SPEED_100000:
return "100Gbps";
case SPEED_200000:
+2
View File
@@ -21,6 +21,7 @@ static struct link_capabilities link_caps[__LINK_CAPA_MAX] __ro_after_init = {
{ SPEED_40000, DUPLEX_FULL, {0} }, /* LINK_CAPA_40000FD */
{ SPEED_50000, DUPLEX_FULL, {0} }, /* LINK_CAPA_50000FD */
{ SPEED_56000, DUPLEX_FULL, {0} }, /* LINK_CAPA_56000FD */
{ SPEED_80000, DUPLEX_FULL, {0} }, /* LINK_CAPA_80000FD */
{ SPEED_100000, DUPLEX_FULL, {0} }, /* LINK_CAPA_100000FD */
{ SPEED_200000, DUPLEX_FULL, {0} }, /* LINK_CAPA_200000FD */
{ SPEED_400000, DUPLEX_FULL, {0} }, /* LINK_CAPA_400000FD */
@@ -49,6 +50,7 @@ static int speed_duplex_to_capa(int speed, unsigned int duplex)
case SPEED_40000: return LINK_CAPA_40000FD;
case SPEED_50000: return LINK_CAPA_50000FD;
case SPEED_56000: return LINK_CAPA_56000FD;
case SPEED_80000: return LINK_CAPA_80000FD;
case SPEED_100000: return LINK_CAPA_100000FD;
case SPEED_200000: return LINK_CAPA_200000FD;
case SPEED_400000: return LINK_CAPA_400000FD;
+1
View File
@@ -311,6 +311,7 @@ static struct {
{ MAC_400000FD, SPEED_400000, DUPLEX_FULL, BIT(LINK_CAPA_400000FD) },
{ MAC_200000FD, SPEED_200000, DUPLEX_FULL, BIT(LINK_CAPA_200000FD) },
{ MAC_100000FD, SPEED_100000, DUPLEX_FULL, BIT(LINK_CAPA_100000FD) },
{ MAC_80000FD, SPEED_80000, DUPLEX_FULL, BIT(LINK_CAPA_80000FD) },
{ MAC_56000FD, SPEED_56000, DUPLEX_FULL, BIT(LINK_CAPA_56000FD) },
{ MAC_50000FD, SPEED_50000, DUPLEX_FULL, BIT(LINK_CAPA_50000FD) },
{ MAC_40000FD, SPEED_40000, DUPLEX_FULL, BIT(LINK_CAPA_40000FD) },
+53
View File
@@ -10,6 +10,7 @@
*/
#include <linux/atomic.h>
#include <linux/ethtool.h>
#include <linux/highmem.h>
#include <linux/if_vlan.h>
#include <linux/jhash.h>
@@ -1261,9 +1262,57 @@ static const struct net_device_ops tbnet_netdev_ops = {
.ndo_open = tbnet_open,
.ndo_stop = tbnet_stop,
.ndo_start_xmit = tbnet_start_xmit,
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = tbnet_get_stats64,
};
static int tbnet_get_link_ksettings(struct net_device *dev,
struct ethtool_link_ksettings *cmd)
{
const struct tbnet *net = netdev_priv(dev);
const struct tb_xdomain *xd = net->xd;
int speed;
ethtool_link_ksettings_zero_link_mode(cmd, supported);
ethtool_link_ksettings_zero_link_mode(cmd, advertising);
/* Figure out the current link speed and width */
switch (xd->link_speed) {
case 40:
speed = SPEED_80000;
break;
case 20:
if (xd->link_width == 2)
speed = SPEED_40000;
else
speed = SPEED_20000;
break;
case 10:
if (xd->link_width == 2) {
speed = SPEED_20000;
break;
}
fallthrough;
default:
speed = SPEED_10000;
break;
}
cmd->base.speed = speed;
cmd->base.duplex = DUPLEX_FULL;
cmd->base.autoneg = AUTONEG_DISABLE;
cmd->base.port = PORT_OTHER;
return 0;
}
static const struct ethtool_ops tbnet_ethtool_ops = {
.get_link_ksettings = tbnet_get_link_ksettings,
};
static void tbnet_generate_mac(struct net_device *dev)
{
const struct tbnet *net = netdev_priv(dev);
@@ -1279,6 +1328,9 @@ static void tbnet_generate_mac(struct net_device *dev)
memcpy(dev->dev_addr + 1, &hash, sizeof(hash));
hash = jhash2((u32 *)xd->local_uuid, 4, hash);
dev->dev_addr[5] = hash & 0xff;
/* Allow changing it if needed */
dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
}
static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id)
@@ -1309,6 +1361,7 @@ static int tbnet_probe(struct tb_service *svc, const struct tb_service_id *id)
strcpy(dev->name, "thunderbolt%d");
dev->netdev_ops = &tbnet_netdev_ops;
dev->ethtool_ops = &tbnet_ethtool_ops;
/* ThunderboltIP takes advantage of TSO packets but instead of
* segmenting them we just split the packet into Thunderbolt
+2 -2
View File
@@ -926,7 +926,7 @@ err:
static const struct driver_info qmi_wwan_info = {
.description = "WWAN/QMI device",
.flags = FLAG_WWAN | FLAG_SEND_ZLP,
.flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
@@ -935,7 +935,7 @@ static const struct driver_info qmi_wwan_info = {
static const struct driver_info qmi_wwan_info_quirk_dtr = {
.description = "WWAN/QMI device",
.flags = FLAG_WWAN | FLAG_SEND_ZLP,
.flags = FLAG_WWAN | FLAG_NOMAXMTU | FLAG_SEND_ZLP,
.bind = qmi_wwan_bind,
.unbind = qmi_wwan_unbind,
.manage_power = qmi_wwan_manage_power,
+1
View File
@@ -9860,6 +9860,7 @@ static const struct usb_device_id rtl8152_table[] = {
{ USB_DEVICE(VENDOR_ID_DLINK, 0xb301) },
{ USB_DEVICE(VENDOR_ID_DELL, 0xb097) },
{ USB_DEVICE(VENDOR_ID_ASUS, 0x1976) },
{ USB_DEVICE(VENDOR_ID_TRENDNET, 0xe02b) },
{}
};
+5 -1
View File
@@ -1813,9 +1813,13 @@ usbnet_probe(struct usb_interface *udev, const struct usb_device_id *prod)
if ((dev->driver_info->flags & FLAG_NOARP) != 0)
net->flags |= IFF_NOARP;
/* maybe the remote can't receive an Ethernet MTU */
if ((dev->driver_info->flags & FLAG_NOMAXMTU) == 0 &&
net->max_mtu > (dev->hard_mtu - net->hard_header_len))
net->max_mtu = dev->hard_mtu - net->hard_header_len;
if (net->mtu > (dev->hard_mtu - net->hard_header_len))
net->mtu = dev->hard_mtu - net->hard_header_len;
} else if (!info->in || !info->out)
status = usbnet_get_endpoints(dev, udev);
else {
+10
View File
@@ -4476,6 +4476,16 @@ static void quirk_fix_vulcan_ahci_bars(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_BROADCOM, 0x9027, quirk_fix_vulcan_ahci_bars);
/*
* AST1150 doesn't use a real PCI bus and always forwards the requester ID
* from downstream devices.
*/
static void quirk_aspeed_pci_bridge_no_alias(struct pci_dev *pdev)
{
pdev->dev_flags |= PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ASPEED, 0x1150, quirk_aspeed_pci_bridge_no_alias);
/*
* Intersil/Techwell TW686[4589]-based video capture cards have an empty (zero)
* class code. Fix it.
+2
View File
@@ -86,6 +86,8 @@ int pci_for_each_dma_alias(struct pci_dev *pdev,
case PCI_EXP_TYPE_DOWNSTREAM:
continue;
case PCI_EXP_TYPE_PCI_BRIDGE:
if (tmp->dev_flags & PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS)
continue;
ret = fn(tmp,
PCI_DEVID(tmp->subordinate->number,
PCI_DEVFN(0, 0)), data);
+24 -1
View File
@@ -17,6 +17,10 @@
#define PHY_CTRL0_FSEL_MASK GENMASK(10, 5)
#define PHY_CTRL0_FSEL_24M 0x2a
#define PHY_CTRL0_FSEL_100M 0x27
#define PHY_CTRL0_SSC_RANGE_MASK GENMASK(23, 21)
#define PHY_CTRL0_SSC_RANGE_4003PPM 0x2
#define PHY_CTRL0_SSC_RANGE_4492PPM 0x1
#define PHY_CTRL0_SSC_RANGE_4980PPM 0x0
#define PHY_CTRL1 0x4
#define PHY_CTRL1_RESET BIT(0)
@@ -47,6 +51,7 @@
#define PHY_CTRL5_PCS_TX_SWING_FULL_MASK GENMASK(6, 0)
#define PHY_CTRL6 0x18
#define PHY_CTRL6_RXTERM_OVERRIDE_SEL BIT(29)
#define PHY_CTRL6_ALT_CLK_EN BIT(1)
#define PHY_CTRL6_ALT_CLK_SEL BIT(0)
@@ -587,6 +592,9 @@ static int imx8mp_usb_phy_init(struct phy *phy)
value = readl(imx_phy->base + PHY_CTRL0);
value |= PHY_CTRL0_REF_SSP_EN;
value &= ~PHY_CTRL0_SSC_RANGE_MASK;
value |= FIELD_PREP(PHY_CTRL0_SSC_RANGE_MASK,
PHY_CTRL0_SSC_RANGE_4003PPM);
writel(value, imx_phy->base + PHY_CTRL0);
value = readl(imx_phy->base + PHY_CTRL2);
@@ -610,6 +618,7 @@ static int imx8mp_usb_phy_init(struct phy *phy)
static int imx8mq_phy_power_on(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
u32 value;
int ret;
ret = regulator_enable(imx_phy->vbus);
@@ -626,12 +635,23 @@ static int imx8mq_phy_power_on(struct phy *phy)
return ret;
}
return ret;
/* Disable rx term override */
value = readl(imx_phy->base + PHY_CTRL6);
value &= ~PHY_CTRL6_RXTERM_OVERRIDE_SEL;
writel(value, imx_phy->base + PHY_CTRL6);
return 0;
}
static int imx8mq_phy_power_off(struct phy *phy)
{
struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
u32 value;
/* Override rx term to be 0 */
value = readl(imx_phy->base + PHY_CTRL6);
value |= PHY_CTRL6_RXTERM_OVERRIDE_SEL;
writel(value, imx_phy->base + PHY_CTRL6);
clk_disable_unprepare(imx_phy->alt_clk);
clk_disable_unprepare(imx_phy->clk);
@@ -676,6 +696,8 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev)
if (!imx_phy)
return -ENOMEM;
platform_set_drvdata(pdev, imx_phy);
imx_phy->clk = devm_clk_get(dev, "phy");
if (IS_ERR(imx_phy->clk)) {
dev_err(dev, "failed to get imx8mq usb phy clock\n");
@@ -730,6 +752,7 @@ static struct platform_driver imx8mq_usb_phy_driver = {
.driver = {
.name = "imx8mq-usb-phy",
.of_match_table = imx8mq_usb_phy_of_match,
.suppress_bind_attrs = true,
}
};
module_platform_driver(imx8mq_usb_phy_driver);
+6 -9
View File
@@ -138,17 +138,14 @@ static struct phy *phy_find(struct device *dev, const char *con_id)
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
{
struct phy_provider *phy_provider;
struct device_node *child;
list_for_each_entry(phy_provider, &phy_provider_list, list) {
if (phy_provider->dev->of_node == node)
return phy_provider;
for_each_child_of_node(phy_provider->children, child)
if (child == node) {
of_node_put(child);
for_each_child_of_node_scoped(phy_provider->children, child)
if (child == node)
return phy_provider;
}
}
return ERR_PTR(-EPROBE_DEFER);
@@ -190,15 +187,15 @@ int phy_pm_runtime_get_sync(struct phy *phy)
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_get_sync);
int phy_pm_runtime_put(struct phy *phy)
void phy_pm_runtime_put(struct phy *phy)
{
if (!phy)
return 0;
return;
if (!pm_runtime_enabled(&phy->dev))
return -ENOTSUPP;
return;
return pm_runtime_put(&phy->dev);
pm_runtime_put(&phy->dev);
}
EXPORT_SYMBOL_GPL(phy_pm_runtime_put);
-1
View File
@@ -69,7 +69,6 @@ struct tegra_xusb_usb2_lane {
struct tegra_xusb_lane base;
u32 hs_curr_level_offset;
bool powered_on;
};
static inline struct tegra_xusb_usb2_lane *
+13 -17
View File
@@ -474,14 +474,14 @@ static const struct pinconf_ops tegra_xusb_padctl_pinconf_ops = {
#endif
};
static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
static void tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
{
u32 value;
mutex_lock(&padctl->lock);
guard(mutex)(&padctl->lock);
if (padctl->enable++ > 0)
goto out;
return;
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
@@ -498,23 +498,19 @@ static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
out:
mutex_unlock(&padctl->lock);
return 0;
}
static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
static void tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
{
u32 value;
mutex_lock(&padctl->lock);
guard(mutex)(&padctl->lock);
if (WARN_ON(padctl->enable == 0))
goto out;
return;
if (--padctl->enable > 0)
goto out;
return;
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
@@ -531,24 +527,24 @@ static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
out:
mutex_unlock(&padctl->lock);
return 0;
}
static int tegra_xusb_phy_init(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
return tegra_xusb_padctl_enable(padctl);
tegra_xusb_padctl_enable(padctl);
return 0;
}
static int tegra_xusb_phy_exit(struct phy *phy)
{
struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
return tegra_xusb_padctl_disable(padctl);
tegra_xusb_padctl_disable(padctl);
return 0;
}
static int pcie_phy_power_on(struct phy *phy)
+1 -1
View File
@@ -1020,7 +1020,7 @@ static bool nhi_wake_supported(struct pci_dev *pdev)
* If power rails are sustainable for wakeup from S4 this
* property is set by the BIOS.
*/
if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val))
return !!val;
return true;
+1 -1
View File
@@ -586,7 +586,7 @@ int tb_path_activate(struct tb_path *path)
tb_dbg(path->tb, "%s path activation complete\n", path->name);
return 0;
err:
tb_WARN(path->tb, "%s path activation failed\n", path->name);
tb_warn(path->tb, "%s path activation failed: %d\n", path->name, res);
return res;
}
-1
View File
@@ -28,7 +28,6 @@ obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_FSL_USB2) += host/
obj-$(CONFIG_USB_FOTG210_HCD) += host/
+8 -1
View File
@@ -385,6 +385,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
const char *irq_name;
imx_platform_flag = of_device_get_match_data(&pdev->dev);
@@ -525,10 +526,16 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
data->wakeup_irq = platform_get_irq_optional(pdev, 1);
if (data->wakeup_irq > 0) {
irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s:wakeup", pdata.name);
if (!irq_name) {
dev_err_probe(dev, -ENOMEM, "failed to create irq_name\n");
goto err_clk;
}
ret = devm_request_threaded_irq(dev, data->wakeup_irq,
NULL, ci_wakeup_irq_handler,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
pdata.name, data);
irq_name, data);
if (ret)
goto err_clk;
}
+14
View File
@@ -1225,6 +1225,12 @@ static int acm_probe(struct usb_interface *intf,
if (!data_interface || !control_interface)
return -ENODEV;
goto skip_normal_probe;
} else if (quirks == NO_UNION_12) {
data_interface = usb_ifnum_to_if(usb_dev, 2);
control_interface = usb_ifnum_to_if(usb_dev, 1);
if (!data_interface || !control_interface)
return -ENODEV;
goto skip_normal_probe;
}
/* normal probing*/
@@ -1379,6 +1385,8 @@ made_compressed_probe:
acm->ctrl_caps = h.usb_cdc_acm_descriptor->bmCapabilities;
if (quirks & NO_CAP_LINE)
acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
if (quirks & MISSING_CAP_BRK)
acm->ctrl_caps |= USB_CDC_CAP_BRK;
acm->ctrlsize = ctrlsize;
acm->readsize = readsize;
acm->rx_buflimit = num_rx_buf;
@@ -1746,6 +1754,9 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
{ USB_DEVICE(0x04b8, 0x0d12), /* EPSON HMD Com&Sens */
.driver_info = NO_UNION_12, /* union descriptor is garbage */
},
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
@@ -2002,6 +2013,9 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = IGNORE_DEVICE,
},
/* CH343 supports CAP_BRK, but doesn't advertise it */
{ USB_DEVICE(0x1a86, 0x55d3), .driver_info = MISSING_CAP_BRK, },
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
+2
View File
@@ -113,3 +113,5 @@ struct acm {
#define CLEAR_HALT_CONDITIONS BIT(5)
#define SEND_ZERO_PACKET BIT(6)
#define DISABLE_ECHO BIT(7)
#define MISSING_CAP_BRK BIT(8)
#define NO_UNION_12 BIT(9)
+3 -1
View File
@@ -225,7 +225,8 @@ static void wdm_in_callback(struct urb *urb)
/* we may already be in overflow */
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
memmove(desc->ubuf + desc->length, desc->inbuf, length);
desc->length += length;
smp_wmb(); /* against wdm_read() */
WRITE_ONCE(desc->length, desc->length + length);
}
}
skip_error:
@@ -533,6 +534,7 @@ static ssize_t wdm_read
return -ERESTARTSYS;
cntr = READ_ONCE(desc->length);
smp_rmb(); /* against wdm_in_callback() */
if (cntr == 0) {
desc->read = 0;
retry:
+6 -3
View File
@@ -254,6 +254,9 @@ static int usbtmc_release(struct inode *inode, struct file *file)
list_del(&file_data->file_elem);
spin_unlock_irq(&file_data->data->dev_lock);
/* flush anchored URBs */
usbtmc_draw_down(file_data);
mutex_unlock(&file_data->data->io_mutex);
kref_put(&file_data->data->kref, usbtmc_delete);
@@ -727,7 +730,7 @@ static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
buffer[1] = data->bTag;
buffer[2] = ~data->bTag;
retval = usb_bulk_msg(data->usb_dev,
retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1347,7 +1350,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
buffer[11] = 0; /* Reserved */
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
retval = usb_bulk_msg_killable(data->usb_dev,
usb_sndbulkpipe(data->usb_dev,
data->bulk_out),
buffer, USBTMC_HEADER_SIZE,
@@ -1419,7 +1422,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
actual = 0;
/* Send bulk URB */
retval = usb_bulk_msg(data->usb_dev,
retval = usb_bulk_msg_killable(data->usb_dev,
usb_rcvbulkpipe(data->usb_dev,
data->bulk_in),
buffer, bufsize, &actual,
+6 -4
View File
@@ -286,12 +286,15 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi)
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
ret = ulpi_of_register(ulpi);
if (ret)
if (ret) {
kfree(ulpi);
return ret;
}
ret = ulpi_read_id(ulpi);
if (ret) {
of_node_put(ulpi->dev.of_node);
kfree(ulpi);
return ret;
}
@@ -331,10 +334,9 @@ struct ulpi *ulpi_register_interface(struct device *dev,
ulpi->ops = ops;
ret = ulpi_register(dev, ulpi);
if (ret) {
kfree(ulpi);
if (ret)
return ERR_PTR(ret);
}
return ulpi;
}
+5 -1
View File
@@ -927,7 +927,11 @@ int usb_get_configuration(struct usb_device *dev)
dev->descriptor.bNumConfigurations = ncfg = USB_MAXCONFIG;
}
if (ncfg < 1) {
if (ncfg < 1 && dev->quirks & USB_QUIRK_FORCE_ONE_CONFIG) {
dev_info(ddev, "Device claims zero configurations, forcing to 1\n");
dev->descriptor.bNumConfigurations = 1;
ncfg = 1;
} else if (ncfg < 1) {
dev_err(ddev, "no configurations\n");
return -EINVAL;
}
+17 -14
View File
@@ -1415,14 +1415,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i = 0, n = 0;
struct usb_interface *intf;
bool offload_active = false;
if (udev->state == USB_STATE_NOTATTACHED ||
udev->state == USB_STATE_SUSPENDED)
goto done;
usb_offload_set_pm_locked(udev, true);
if (msg.event == PM_EVENT_SUSPEND && usb_offload_check(udev)) {
dev_dbg(&udev->dev, "device offloaded, skip suspend.\n");
udev->offload_at_suspend = 1;
offload_active = true;
}
/* Suspend all the interfaces and then udev itself */
@@ -1436,8 +1438,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
* interrupt urbs, allowing interrupt events to be
* handled during system suspend.
*/
if (udev->offload_at_suspend &&
intf->needs_remote_wakeup) {
if (offload_active && intf->needs_remote_wakeup) {
dev_dbg(&intf->dev,
"device offloaded, skip suspend.\n");
continue;
@@ -1452,7 +1453,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
}
if (status == 0) {
if (!udev->offload_at_suspend)
if (!offload_active)
status = usb_suspend_device(udev, msg);
/*
@@ -1498,7 +1499,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
*/
} else {
udev->can_submit = 0;
if (!udev->offload_at_suspend) {
if (!offload_active) {
for (i = 0; i < 16; ++i) {
usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
@@ -1507,6 +1508,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
}
done:
if (status != 0)
usb_offload_set_pm_locked(udev, false);
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
return status;
}
@@ -1536,16 +1539,19 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
int status = 0;
int i;
struct usb_interface *intf;
bool offload_active = false;
if (udev->state == USB_STATE_NOTATTACHED) {
status = -ENODEV;
goto done;
}
udev->can_submit = 1;
if (msg.event == PM_EVENT_RESUME)
offload_active = usb_offload_check(udev);
/* Resume the device */
if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) {
if (!udev->offload_at_suspend)
if (!offload_active)
status = usb_resume_device(udev, msg);
else
dev_dbg(&udev->dev,
@@ -1562,8 +1568,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
* pending interrupt urbs, allowing interrupt events
* to be handled during system suspend.
*/
if (udev->offload_at_suspend &&
intf->needs_remote_wakeup) {
if (offload_active && intf->needs_remote_wakeup) {
dev_dbg(&intf->dev,
"device offloaded, skip resume.\n");
continue;
@@ -1572,11 +1577,11 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
udev->reset_resume);
}
}
udev->offload_at_suspend = 0;
usb_mark_last_busy(udev);
done:
dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status);
usb_offload_set_pm_locked(udev, false);
if (!status)
udev->reset_resume = 0;
return status;
@@ -1810,13 +1815,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
void usb_autopm_put_interface_async(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
int status;
usb_mark_last_busy(udev);
status = pm_runtime_put(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
__func__, atomic_read(&intf->dev.power.usage_count),
status);
pm_runtime_put(&intf->dev);
dev_vdbg(&intf->dev, "%s: cnt %d\n",
__func__, atomic_read(&intf->dev.power.usage_count));
}
EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
-4
View File
@@ -77,10 +77,6 @@
/*-------------------------------------------------------------------------*/
/* Keep track of which host controller drivers are loaded */
unsigned long usb_hcds_loaded;
EXPORT_SYMBOL_GPL(usb_hcds_loaded);
/* host controllers we manage */
DEFINE_IDR (usb_bus_idr);
EXPORT_SYMBOL_GPL (usb_bus_idr);
+79 -21
View File
@@ -42,16 +42,19 @@ static void usb_api_blocking_completion(struct urb *urb)
/*
* Starts urb and waits for completion or timeout. Note that this call
* is NOT interruptible. Many device driver i/o requests should be
* interruptible and therefore these drivers should implement their
* own interruptible routines.
* Starts urb and waits for completion or timeout.
* Whether or not the wait is killable depends on the flag passed in.
* For example, compare usb_bulk_msg() and usb_bulk_msg_killable().
*
* For non-killable waits, we enforce a maximum limit on the timeout value.
*/
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length,
bool killable)
{
struct api_context ctx;
unsigned long expire;
int retval;
long rc;
init_completion(&ctx.done);
urb->context = &ctx;
@@ -60,13 +63,24 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
if (unlikely(retval))
goto out;
expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (!wait_for_completion_timeout(&ctx.done, expire)) {
if (!killable && (timeout <= 0 || timeout > USB_MAX_SYNCHRONOUS_TIMEOUT))
timeout = USB_MAX_SYNCHRONOUS_TIMEOUT;
expire = (timeout > 0) ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
if (killable)
rc = wait_for_completion_killable_timeout(&ctx.done, expire);
else
rc = wait_for_completion_timeout(&ctx.done, expire);
if (rc <= 0) {
usb_kill_urb(urb);
retval = (ctx.status == -ENOENT ? -ETIMEDOUT : ctx.status);
if (ctx.status != -ENOENT)
retval = ctx.status;
else if (rc == 0)
retval = -ETIMEDOUT;
else
retval = rc;
dev_dbg(&urb->dev->dev,
"%s timed out on ep%d%s len=%u/%u\n",
"%s timed out or killed on ep%d%s len=%u/%u\n",
current->comm,
usb_endpoint_num(&urb->ep->desc),
usb_urb_dir_in(urb) ? "in" : "out",
@@ -100,7 +114,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
len, usb_api_blocking_completion, NULL);
retv = usb_start_wait_urb(urb, timeout, &length);
retv = usb_start_wait_urb(urb, timeout, &length, false);
if (retv < 0)
return retv;
else
@@ -117,8 +131,7 @@ static int usb_internal_control_msg(struct usb_device *usb_dev,
* @index: USB message index value
* @data: pointer to the data to send
* @size: length in bytes of the data to send
* @timeout: time in msecs to wait for the message to complete before timing
* out (if 0 the wait is forever)
* @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -173,8 +186,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg);
* @index: USB message index value
* @driver_data: pointer to the data to send
* @size: length in bytes of the data to send
* @timeout: time in msecs to wait for the message to complete before timing
* out (if 0 the wait is forever)
* @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -232,8 +244,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_send);
* @index: USB message index value
* @driver_data: pointer to the data to be filled in by the message
* @size: length in bytes of the data to be received
* @timeout: time in msecs to wait for the message to complete before timing
* out (if 0 the wait is forever)
* @timeout: time in msecs to wait for the message to complete before timing out
* @memflags: the flags for memory allocation for buffers
*
* Context: !in_interrupt ()
@@ -304,8 +315,7 @@ EXPORT_SYMBOL_GPL(usb_control_msg_recv);
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
* @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
* @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -337,8 +347,7 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg);
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
* @timeout: time in msecs to wait for the message to complete before
* timing out (if 0 the wait is forever)
* @timeout: time in msecs to wait for the message to complete before timing out
*
* Context: task context, might sleep.
*
@@ -385,10 +394,59 @@ int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length);
return usb_start_wait_urb(urb, timeout, actual_length, false);
}
EXPORT_SYMBOL_GPL(usb_bulk_msg);
/**
* usb_bulk_msg_killable - Builds a bulk urb, sends it off and waits for completion in a killable state
* @usb_dev: pointer to the usb device to send the message to
* @pipe: endpoint "pipe" to send the message to
* @data: pointer to the data to send
* @len: length in bytes of the data to send
* @actual_length: pointer to a location to put the actual length transferred
* in bytes
* @timeout: time in msecs to wait for the message to complete before
* timing out (if <= 0, the wait is as long as possible)
*
* Context: task context, might sleep.
*
* This function is just like usb_blk_msg(), except that it waits in a
* killable state and there is no limit on the timeout length.
*
* Return:
* If successful, 0. Otherwise a negative error number. The number of actual
* bytes transferred will be stored in the @actual_length parameter.
*
*/
int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout)
{
struct urb *urb;
struct usb_host_endpoint *ep;
ep = usb_pipe_endpoint(usb_dev, pipe);
if (!ep || len < 0)
return -EINVAL;
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
return -ENOMEM;
if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT) {
pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL,
ep->desc.bInterval);
} else
usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
usb_api_blocking_completion, NULL);
return usb_start_wait_urb(urb, timeout, actual_length, true);
}
EXPORT_SYMBOL_GPL(usb_bulk_msg_killable);
/*-------------------------------------------------------------------*/
static void sg_clean(struct usb_sg_request *io)
+59 -43
View File
@@ -25,33 +25,30 @@
*/
int usb_offload_get(struct usb_device *udev)
{
int ret;
int ret = 0;
usb_lock_device(udev);
if (udev->state == USB_STATE_NOTATTACHED) {
usb_unlock_device(udev);
if (!usb_get_dev(udev))
return -ENODEV;
if (pm_runtime_get_if_active(&udev->dev) != 1) {
ret = -EBUSY;
goto err_rpm;
}
if (udev->state == USB_STATE_SUSPENDED ||
udev->offload_at_suspend) {
usb_unlock_device(udev);
return -EBUSY;
}
spin_lock(&udev->offload_lock);
/*
* offload_usage could only be modified when the device is active, since
* it will alter the suspend flow of the device.
*/
ret = usb_autoresume_device(udev);
if (ret < 0) {
usb_unlock_device(udev);
return ret;
if (udev->offload_pm_locked) {
ret = -EAGAIN;
goto err;
}
udev->offload_usage++;
usb_autosuspend_device(udev);
usb_unlock_device(udev);
err:
spin_unlock(&udev->offload_lock);
pm_runtime_put_autosuspend(&udev->dev);
err_rpm:
usb_put_dev(udev);
return ret;
}
@@ -69,35 +66,32 @@ EXPORT_SYMBOL_GPL(usb_offload_get);
*/
int usb_offload_put(struct usb_device *udev)
{
int ret;
int ret = 0;
usb_lock_device(udev);
if (udev->state == USB_STATE_NOTATTACHED) {
usb_unlock_device(udev);
if (!usb_get_dev(udev))
return -ENODEV;
if (pm_runtime_get_if_active(&udev->dev) != 1) {
ret = -EBUSY;
goto err_rpm;
}
if (udev->state == USB_STATE_SUSPENDED ||
udev->offload_at_suspend) {
usb_unlock_device(udev);
return -EBUSY;
}
spin_lock(&udev->offload_lock);
/*
* offload_usage could only be modified when the device is active, since
* it will alter the suspend flow of the device.
*/
ret = usb_autoresume_device(udev);
if (ret < 0) {
usb_unlock_device(udev);
return ret;
if (udev->offload_pm_locked) {
ret = -EAGAIN;
goto err;
}
/* Drop the count when it wasn't 0, ignore the operation otherwise. */
if (udev->offload_usage)
udev->offload_usage--;
usb_autosuspend_device(udev);
usb_unlock_device(udev);
err:
spin_unlock(&udev->offload_lock);
pm_runtime_put_autosuspend(&udev->dev);
err_rpm:
usb_put_dev(udev);
return ret;
}
@@ -112,25 +106,47 @@ EXPORT_SYMBOL_GPL(usb_offload_put);
* management.
*
* The caller must hold @udev's device lock. In addition, the caller should
* ensure downstream usb devices are all either suspended or marked as
* "offload_at_suspend" to ensure the correctness of the return value.
* ensure the device itself and the downstream usb devices are all marked as
* "offload_pm_locked" to ensure the correctness of the return value.
*
* Returns true on any offload activity, false otherwise.
*/
bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex)
{
struct usb_device *child;
bool active;
bool active = false;
int port1;
if (udev->offload_usage)
return true;
usb_hub_for_each_child(udev, port1, child) {
usb_lock_device(child);
active = usb_offload_check(child);
usb_unlock_device(child);
if (active)
return true;
break;
}
return !!udev->offload_usage;
return active;
}
EXPORT_SYMBOL_GPL(usb_offload_check);
/**
* usb_offload_set_pm_locked - set the PM lock state of a USB device
* @udev: the USB device to modify
* @locked: the new lock state
*
* Setting @locked to true prevents offload_usage from being modified. This
* ensures that offload activities cannot be started or stopped during critical
* power management transitions, maintaining a stable state for the duration
* of the transition.
*/
void usb_offload_set_pm_locked(struct usb_device *udev, bool locked)
{
spin_lock(&udev->offload_lock);
udev->offload_pm_locked = locked;
spin_unlock(&udev->offload_lock);
}
EXPORT_SYMBOL_GPL(usb_offload_set_pm_locked);
+12 -8
View File
@@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
{
struct usb_phy_roothub *phy_roothub;
int num_phys;
int num_phys, usb2_phy_index;
if (!IS_ENABLED(CONFIG_GENERIC_PHY))
return NULL;
@@ -124,6 +124,16 @@ struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev)
if (num_phys <= 0)
return NULL;
/*
* If 'usb2-phy' is not present, usb_phy_roothub_alloc() added
* all PHYs to the primary HCD's phy_roothub already, so skip
* adding 'usb3-phy' here to avoid double use of that.
*/
usb2_phy_index = of_property_match_string(dev->of_node, "phy-names",
"usb2-phy");
if (usb2_phy_index < 0)
return NULL;
phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
if (!phy_roothub)
return ERR_PTR(-ENOMEM);
@@ -200,16 +210,10 @@ int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
list_for_each_entry(roothub_entry, head, list) {
err = phy_set_mode(roothub_entry->phy, mode);
if (err)
goto err_out;
return err;
}
return 0;
err_out:
list_for_each_entry_continue_reverse(roothub_entry, head, list)
phy_power_off(roothub_entry->phy);
return err;
}
EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
+28
View File
@@ -141,6 +141,8 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp)
case 'p':
flags |= USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT;
break;
case 'q':
flags |= USB_QUIRK_FORCE_ONE_CONFIG;
/* Ignore unrecognized flag characters */
}
}
@@ -208,6 +210,10 @@ static const struct usb_device_id usb_quirk_list[] = {
/* HP v222w 16GB Mini USB Drive */
{ USB_DEVICE(0x03f0, 0x3f40), .driver_info = USB_QUIRK_DELAY_INIT },
/* Huawei 4G LTE module ME906S */
{ USB_DEVICE(0x03f0, 0xa31d), .driver_info =
USB_QUIRK_DISCONNECT_SUSPEND },
/* Creative SB Audigy 2 NX */
{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -377,6 +383,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* SanDisk Extreme 55AE */
{ USB_DEVICE(0x0781, 0x55ae), .driver_info = USB_QUIRK_NO_LPM },
/* Avermedia Live Gamer Ultra 2.1 (GC553G2) - BOS descriptor fetch hangs at SuperSpeed Plus */
{ USB_DEVICE(0x07ca, 0x2553), .driver_info = USB_QUIRK_NO_BOS },
/* Realforce 87U Keyboard */
{ USB_DEVICE(0x0853, 0x011b), .driver_info = USB_QUIRK_NO_LPM },
@@ -393,6 +402,7 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Silicon Motion Flash Drive */
{ USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT },
{ USB_DEVICE(0x090c, 0x2000), .driver_info = USB_QUIRK_DELAY_INIT },
/* Sound Devices USBPre2 */
{ USB_DEVICE(0x0926, 0x0202), .driver_info =
@@ -437,6 +447,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
USB_QUIRK_IGNORE_REMOTE_WAKEUP },
/* ASUS TUF 4K PRO - BOS descriptor fetch hangs at SuperSpeed Plus */
{ USB_DEVICE(0x0b05, 0x1ab9), .driver_info = USB_QUIRK_NO_BOS },
/* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/
{ USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
@@ -481,6 +494,12 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Razer - Razer Blade Keyboard */
{ USB_DEVICE(0x1532, 0x0116), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
/* Razer - Razer Kiyo Pro Webcam */
{ USB_DEVICE(0x1532, 0x0e05), .driver_info = USB_QUIRK_NO_LPM },
/* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */
{ USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME },
{ USB_DEVICE(0x17ef, 0x1019), .driver_info = USB_QUIRK_RESET_RESUME },
/* Lenovo USB-C to Ethernet Adapter RTL8153-04 */
{ USB_DEVICE(0x17ef, 0x720c), .driver_info = USB_QUIRK_NO_LPM },
@@ -561,6 +580,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM },
/* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */
{ USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS },
/* APTIV AUTOMOTIVE HUB */
{ USB_DEVICE(0x2c48, 0x0132), .driver_info =
USB_QUIRK_SHORT_SET_ADDRESS_REQ_TIMEOUT },
@@ -571,12 +593,18 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Alcor Link AK9563 SC Reader used in 2022 Lenovo ThinkPads */
{ USB_DEVICE(0x2ce3, 0x9563), .driver_info = USB_QUIRK_NO_LPM },
/* ezcap401 - BOS descriptor fetch hangs at SuperSpeed Plus */
{ USB_DEVICE(0x32ed, 0x0401), .driver_info = USB_QUIRK_NO_BOS },
/* DELL USB GEN2 */
{ USB_DEVICE(0x413c, 0xb062), .driver_info = USB_QUIRK_NO_LPM | USB_QUIRK_RESET_RESUME },
/* VCOM device */
{ USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS },
/* Noji-MCS SmartCard Reader */
{ USB_DEVICE(0x5131, 0x2007), .driver_info = USB_QUIRK_FORCE_ONE_CONFIG },
/* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
+1
View File
@@ -671,6 +671,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
dev->state = USB_STATE_ATTACHED;
dev->lpm_disable_count = 1;
spin_lock_init(&dev->offload_lock);
dev->offload_usage = 0;
atomic_set(&dev->urbnum, 0);
+136 -99
View File
@@ -114,23 +114,23 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
int i;
for (i = 0; i < dwc->num_usb3_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(i));
reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(i));
if (enable && !dwc->dis_u3_susphy_quirk)
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
else
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(i), reg);
dwc3_writel(dwc, DWC3_GUSB3PIPECTL(i), reg);
}
for (i = 0; i < dwc->num_usb2_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i));
if (enable && !dwc->dis_u2_susphy_quirk)
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
else
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg);
}
}
EXPORT_SYMBOL_GPL(dwc3_enable_susphy);
@@ -140,7 +140,7 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
unsigned int hw_mode;
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
/*
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
@@ -155,10 +155,10 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
reg |= DWC3_GCTL_PRTCAPDIR(mode);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
dwc->current_dr_role = mode;
trace_dwc3_set_prtcap(mode);
trace_dwc3_set_prtcap(dwc, mode);
}
EXPORT_SYMBOL_GPL(dwc3_set_prtcap);
@@ -216,9 +216,9 @@ static void __dwc3_set_mode(struct work_struct *work)
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
reg |= DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
/*
* Wait for internal clocks to synchronized. DWC_usb31 and
@@ -228,9 +228,9 @@ static void __dwc3_set_mode(struct work_struct *work)
*/
msleep(100);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
reg &= ~DWC3_GCTL_CORESOFTRESET;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
}
spin_lock_irqsave(&dwc->lock, flags);
@@ -254,9 +254,9 @@ static void __dwc3_set_mode(struct work_struct *work)
phy_set_mode(dwc->usb3_generic_phy[i], PHY_MODE_USB_HOST);
if (dwc->dis_split_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
reg = dwc3_readl(dwc, DWC3_GUCTL3);
reg |= DWC3_GUCTL3_SPLITDISABLE;
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
dwc3_writel(dwc, DWC3_GUCTL3, reg);
}
}
break;
@@ -306,11 +306,11 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
struct dwc3 *dwc = dep->dwc;
u32 reg;
dwc3_writel(dwc->regs, DWC3_GDBGFIFOSPACE,
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
DWC3_GDBGFIFOSPACE_TYPE(type));
dwc3_writel(dwc, DWC3_GDBGFIFOSPACE,
DWC3_GDBGFIFOSPACE_NUM(dep->number) |
DWC3_GDBGFIFOSPACE_TYPE(type));
reg = dwc3_readl(dwc->regs, DWC3_GDBGFIFOSPACE);
reg = dwc3_readl(dwc, DWC3_GDBGFIFOSPACE);
return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg);
}
@@ -332,7 +332,7 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST)
return 0;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg |= DWC3_DCTL_CSFTRST;
reg &= ~DWC3_DCTL_RUN_STOP;
dwc3_gadget_dctl_write_safe(dwc, reg);
@@ -347,7 +347,7 @@ int dwc3_core_soft_reset(struct dwc3 *dwc)
retries = 10;
do {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (!(reg & DWC3_DCTL_CSFTRST))
goto done;
@@ -387,12 +387,12 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc)
if (dwc->fladj == 0)
return;
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
reg = dwc3_readl(dwc, DWC3_GFLADJ);
dft = reg & DWC3_GFLADJ_30MHZ_MASK;
if (dft != dwc->fladj) {
reg &= ~DWC3_GFLADJ_30MHZ_MASK;
reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj;
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
dwc3_writel(dwc, DWC3_GFLADJ, reg);
}
}
@@ -424,10 +424,10 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
return;
}
reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
reg = dwc3_readl(dwc, DWC3_GUCTL);
reg &= ~DWC3_GUCTL_REFCLKPER_MASK;
reg |= FIELD_PREP(DWC3_GUCTL_REFCLKPER_MASK, period);
dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
dwc3_writel(dwc, DWC3_GUCTL, reg);
if (DWC3_VER_IS_PRIOR(DWC3, 250A))
return;
@@ -455,7 +455,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
*/
decr = 480000000 / rate;
reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
reg = dwc3_readl(dwc, DWC3_GFLADJ);
reg &= ~DWC3_GFLADJ_REFCLK_FLADJ_MASK
& ~DWC3_GFLADJ_240MHZDECR
& ~DWC3_GFLADJ_240MHZDECR_PLS1;
@@ -466,7 +466,7 @@ static void dwc3_ref_clk_period(struct dwc3 *dwc)
if (dwc->gfladj_refclk_lpm_sel)
reg |= DWC3_GFLADJ_REFCLK_LPM_SEL;
dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
dwc3_writel(dwc, DWC3_GFLADJ, reg);
}
/**
@@ -569,16 +569,16 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc)
evt = dwc->ev_buf;
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0),
lower_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0),
upper_32_bits(evt->dma));
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));
dwc3_writel(dwc, DWC3_GEVNTADRLO(0),
lower_32_bits(evt->dma));
dwc3_writel(dwc, DWC3_GEVNTADRHI(0),
upper_32_bits(evt->dma));
dwc3_writel(dwc, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));
/* Clear any stale event */
reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
reg = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0));
dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), reg);
return 0;
}
@@ -593,7 +593,7 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
* Exynos platforms may not be able to access event buffer if the
* controller failed to halt on dwc3_core_exit().
*/
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
if (!(reg & DWC3_DSTS_DEVCTRLHLT))
return;
@@ -601,14 +601,14 @@ void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
evt->lpos = 0;
dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(0), 0);
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
dwc3_writel(dwc, DWC3_GEVNTADRLO(0), 0);
dwc3_writel(dwc, DWC3_GEVNTADRHI(0), 0);
dwc3_writel(dwc, DWC3_GEVNTSIZ(0), DWC3_GEVNTSIZ_INTMASK
| DWC3_GEVNTSIZ_SIZE(0));
/* Clear any stale event */
reg = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), reg);
reg = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0));
dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), reg);
}
static void dwc3_core_num_eps(struct dwc3 *dwc)
@@ -622,18 +622,18 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
parms->hwparams0 = dwc3_readl(dwc, DWC3_GHWPARAMS0);
parms->hwparams1 = dwc3_readl(dwc, DWC3_GHWPARAMS1);
parms->hwparams2 = dwc3_readl(dwc, DWC3_GHWPARAMS2);
parms->hwparams3 = dwc3_readl(dwc, DWC3_GHWPARAMS3);
parms->hwparams4 = dwc3_readl(dwc, DWC3_GHWPARAMS4);
parms->hwparams5 = dwc3_readl(dwc, DWC3_GHWPARAMS5);
parms->hwparams6 = dwc3_readl(dwc, DWC3_GHWPARAMS6);
parms->hwparams7 = dwc3_readl(dwc, DWC3_GHWPARAMS7);
parms->hwparams8 = dwc3_readl(dwc, DWC3_GHWPARAMS8);
if (DWC3_IP_IS(DWC32))
parms->hwparams9 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS9);
parms->hwparams9 = dwc3_readl(dwc, DWC3_GHWPARAMS9);
}
static void dwc3_config_soc_bus(struct dwc3 *dwc)
@@ -641,10 +641,10 @@ static void dwc3_config_soc_bus(struct dwc3 *dwc)
if (dwc->gsbuscfg0_reqinfo != DWC3_GSBUSCFG0_REQINFO_UNSPECIFIED) {
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
reg = dwc3_readl(dwc, DWC3_GSBUSCFG0);
reg &= ~DWC3_GSBUSCFG0_REQINFO(~0);
reg |= DWC3_GSBUSCFG0_REQINFO(dwc->gsbuscfg0_reqinfo);
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, reg);
dwc3_writel(dwc, DWC3_GSBUSCFG0, reg);
}
}
@@ -668,7 +668,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index));
reg = dwc3_readl(dwc, DWC3_GUSB3PIPECTL(index));
/*
* Make sure UX_EXIT_PX is cleared as that causes issues with some
@@ -706,7 +706,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
if (dwc->dis_del_phy_power_chg_quirk)
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(index), reg);
dwc3_writel(dwc, DWC3_GUSB3PIPECTL(index), reg);
return 0;
}
@@ -715,7 +715,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
/* Select the HS PHY interface */
switch (DWC3_GHWPARAMS3_HSPHY_IFC(dwc->hwparams.hwparams3)) {
@@ -727,7 +727,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
} else if (dwc->hsphy_interface &&
!strncmp(dwc->hsphy_interface, "ulpi", 4)) {
reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
} else {
/* Relying on default value. */
if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
@@ -777,11 +777,29 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
if (dwc->ulpi_ext_vbus_drv)
reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(index), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
return 0;
}
static void dwc3_ulpi_setup(struct dwc3 *dwc)
{
int index;
u32 reg;
/* Don't do anything if there is no ULPI PHY */
if (!dwc->ulpi)
return;
if (dwc->enable_usb2_transceiver_delay) {
for (index = 0; index < dwc->num_usb2_ports; index++) {
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(index));
reg |= DWC3_GUSB2PHYCFG_XCVRDLY;
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(index), reg);
}
}
}
/**
* dwc3_phy_setup - Configure USB PHY Interface of DWC3 Core
* @dwc: Pointer to our controller context structure
@@ -991,7 +1009,7 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
reg = dwc3_readl(dwc, DWC3_GSNPSID);
dwc->ip = DWC3_GSNPS_ID(reg);
if (dwc->ip == DWC4_IP)
dwc->ip = DWC32_IP;
@@ -1000,8 +1018,8 @@ static bool dwc3_core_is_valid(struct dwc3 *dwc)
if (DWC3_IP_IS(DWC3)) {
dwc->revision = reg;
} else if (DWC3_IP_IS(DWC31) || DWC3_IP_IS(DWC32)) {
dwc->revision = dwc3_readl(dwc->regs, DWC3_VER_NUMBER);
dwc->version_type = dwc3_readl(dwc->regs, DWC3_VER_TYPE);
dwc->revision = dwc3_readl(dwc, DWC3_VER_NUMBER);
dwc->version_type = dwc3_readl(dwc, DWC3_VER_TYPE);
} else {
return false;
}
@@ -1015,7 +1033,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
unsigned int hw_mode;
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
power_opt = DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1);
@@ -1093,7 +1111,7 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
if (DWC3_VER_IS_PRIOR(DWC3, 190A))
reg |= DWC3_GCTL_U2RSTECN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
}
static int dwc3_core_get_phy(struct dwc3 *dwc);
@@ -1113,7 +1131,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
int ret;
int i;
cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
cfg = dwc3_readl(dwc, DWC3_GSBUSCFG0);
/*
* Handle property "snps,incr-burst-type-adjustment".
@@ -1188,7 +1206,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
break;
}
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
dwc3_writel(dwc, DWC3_GSBUSCFG0, cfg);
}
static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
@@ -1213,12 +1231,12 @@ static void dwc3_set_power_down_clk_scale(struct dwc3 *dwc)
* (3x or more) to be within the requirement.
*/
scale = DIV_ROUND_UP(clk_get_rate(dwc->susp_clk), 16000);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
if ((reg & DWC3_GCTL_PWRDNSCALE_MASK) < DWC3_GCTL_PWRDNSCALE(scale) ||
(reg & DWC3_GCTL_PWRDNSCALE_MASK) > DWC3_GCTL_PWRDNSCALE(scale*3)) {
reg &= ~(DWC3_GCTL_PWRDNSCALE_MASK);
reg |= DWC3_GCTL_PWRDNSCALE(scale);
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
}
}
@@ -1241,7 +1259,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
tx_maxburst = dwc->tx_max_burst_prd;
if (rx_thr_num && rx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GRXTHRCFG);
reg |= DWC31_RXTHRNUMPKTSEL_PRD;
reg &= ~DWC31_RXTHRNUMPKT_PRD(~0);
@@ -1250,11 +1268,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC31_MAXRXBURSTSIZE_PRD(~0);
reg |= DWC31_MAXRXBURSTSIZE_PRD(rx_maxburst);
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GRXTHRCFG, reg);
}
if (tx_thr_num && tx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GTXTHRCFG);
reg |= DWC31_TXTHRNUMPKTSEL_PRD;
reg &= ~DWC31_TXTHRNUMPKT_PRD(~0);
@@ -1263,7 +1281,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC31_MAXTXBURSTSIZE_PRD(~0);
reg |= DWC31_MAXTXBURSTSIZE_PRD(tx_maxburst);
dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GTXTHRCFG, reg);
}
}
@@ -1274,7 +1292,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
if (DWC3_IP_IS(DWC3)) {
if (rx_thr_num && rx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GRXTHRCFG);
reg |= DWC3_GRXTHRCFG_PKTCNTSEL;
reg &= ~DWC3_GRXTHRCFG_RXPKTCNT(~0);
@@ -1283,11 +1301,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC3_GRXTHRCFG_MAXRXBURSTSIZE(~0);
reg |= DWC3_GRXTHRCFG_MAXRXBURSTSIZE(rx_maxburst);
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GRXTHRCFG, reg);
}
if (tx_thr_num && tx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GTXTHRCFG);
reg |= DWC3_GTXTHRCFG_PKTCNTSEL;
reg &= ~DWC3_GTXTHRCFG_TXPKTCNT(~0);
@@ -1296,11 +1314,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC3_GTXTHRCFG_MAXTXBURSTSIZE(~0);
reg |= DWC3_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GTXTHRCFG, reg);
}
} else {
if (rx_thr_num && rx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GRXTHRCFG);
reg |= DWC31_GRXTHRCFG_PKTCNTSEL;
reg &= ~DWC31_GRXTHRCFG_RXPKTCNT(~0);
@@ -1309,11 +1327,11 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC31_GRXTHRCFG_MAXRXBURSTSIZE(~0);
reg |= DWC31_GRXTHRCFG_MAXRXBURSTSIZE(rx_maxburst);
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GRXTHRCFG, reg);
}
if (tx_thr_num && tx_maxburst) {
reg = dwc3_readl(dwc->regs, DWC3_GTXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GTXTHRCFG);
reg |= DWC31_GTXTHRCFG_PKTCNTSEL;
reg &= ~DWC31_GTXTHRCFG_TXPKTCNT(~0);
@@ -1322,7 +1340,7 @@ static void dwc3_config_threshold(struct dwc3 *dwc)
reg &= ~DWC31_GTXTHRCFG_MAXTXBURSTSIZE(~0);
reg |= DWC31_GTXTHRCFG_MAXTXBURSTSIZE(tx_maxburst);
dwc3_writel(dwc->regs, DWC3_GTXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GTXTHRCFG, reg);
}
}
}
@@ -1345,7 +1363,7 @@ int dwc3_core_init(struct dwc3 *dwc)
* Write Linux Version Code to our GUID register so it's easy to figure
* out which kernel version a bug was found.
*/
dwc3_writel(dwc->regs, DWC3_GUID, LINUX_VERSION_CODE);
dwc3_writel(dwc, DWC3_GUID, LINUX_VERSION_CODE);
ret = dwc3_phy_setup(dwc);
if (ret)
@@ -1363,6 +1381,8 @@ int dwc3_core_init(struct dwc3 *dwc)
dwc->ulpi_ready = true;
}
dwc3_ulpi_setup(dwc);
if (!dwc->phys_ready) {
ret = dwc3_core_get_phy(dwc);
if (ret)
@@ -1410,9 +1430,9 @@ int dwc3_core_init(struct dwc3 *dwc)
* DWC_usb31 controller.
*/
if (DWC3_VER_IS_WITHIN(DWC3, 310A, ANY)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
reg = dwc3_readl(dwc, DWC3_GUCTL2);
reg |= DWC3_GUCTL2_RST_ACTBITLATER;
dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
dwc3_writel(dwc, DWC3_GUCTL2, reg);
}
/*
@@ -1425,9 +1445,9 @@ int dwc3_core_init(struct dwc3 *dwc)
* setting GUCTL2[19] by default; instead, use GUCTL2[19] = 0.
*/
if (DWC3_VER_IS(DWC3, 320A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL2);
reg = dwc3_readl(dwc, DWC3_GUCTL2);
reg &= ~DWC3_GUCTL2_LC_TIMER;
dwc3_writel(dwc->regs, DWC3_GUCTL2, reg);
dwc3_writel(dwc, DWC3_GUCTL2, reg);
}
/*
@@ -1440,13 +1460,13 @@ int dwc3_core_init(struct dwc3 *dwc)
* legacy ULPI PHYs.
*/
if (dwc->resume_hs_terminations) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
reg = dwc3_readl(dwc, DWC3_GUCTL1);
reg |= DWC3_GUCTL1_RESUME_OPMODE_HS_HOST;
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
dwc3_writel(dwc, DWC3_GUCTL1, reg);
}
if (!DWC3_VER_IS_PRIOR(DWC3, 250A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL1);
reg = dwc3_readl(dwc, DWC3_GUCTL1);
/*
* Enable hardware control of sending remote wakeup
@@ -1481,7 +1501,7 @@ int dwc3_core_init(struct dwc3 *dwc)
reg &= ~DWC3_GUCTL1_DEV_FORCE_20_CLK_FOR_30_CLK;
}
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
dwc3_writel(dwc, DWC3_GUCTL1, reg);
}
dwc3_config_threshold(dwc);
@@ -1492,9 +1512,9 @@ int dwc3_core_init(struct dwc3 *dwc)
int i;
for (i = 0; i < dwc->num_usb3_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_LLUCTL(i));
reg = dwc3_readl(dwc, DWC3_LLUCTL(i));
reg |= DWC3_LLUCTL_FORCE_GEN1;
dwc3_writel(dwc->regs, DWC3_LLUCTL(i), reg);
dwc3_writel(dwc, DWC3_LLUCTL(i), reg);
}
}
@@ -1513,9 +1533,9 @@ int dwc3_core_init(struct dwc3 *dwc)
* function is available only from version 1.70a.
*/
if (DWC3_VER_IS_WITHIN(DWC31, 170A, 180A)) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
reg = dwc3_readl(dwc, DWC3_GUCTL3);
reg |= DWC3_GUCTL3_USB20_RETRY_DISABLE;
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
dwc3_writel(dwc, DWC3_GUCTL3, reg);
}
return 0;
@@ -2155,6 +2175,20 @@ static int dwc3_get_num_ports(struct dwc3 *dwc)
return 0;
}
static void dwc3_vbus_draw_work(struct work_struct *work)
{
struct dwc3 *dwc = container_of(work, struct dwc3, vbus_draw_work);
union power_supply_propval val = {0};
int ret;
val.intval = 1000 * (dwc->current_limit);
ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
if (ret < 0)
dev_dbg(dwc->dev, "Error (%d) setting vbus draw (%d mA)\n",
ret, dwc->current_limit);
}
static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
{
struct power_supply *usb_psy;
@@ -2169,6 +2203,7 @@ static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc)
if (!usb_psy)
return ERR_PTR(-EPROBE_DEFER);
INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work);
return usb_psy;
}
@@ -2395,8 +2430,10 @@ void dwc3_core_remove(struct dwc3 *dwc)
dwc3_free_event_buffers(dwc);
if (dwc->usb_psy)
if (dwc->usb_psy) {
cancel_work_sync(&dwc->vbus_draw_work);
power_supply_put(dwc->usb_psy);
}
}
EXPORT_SYMBOL_GPL(dwc3_core_remove);
@@ -2439,9 +2476,9 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
int ret;
if (!pm_runtime_suspended(dwc->dev) && !PMSG_IS_AUTO(msg)) {
dwc->susphy_state = (dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0)) &
dwc->susphy_state = (dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0)) &
DWC3_GUSB2PHYCFG_SUSPHY) ||
(dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0)) &
(dwc3_readl(dwc, DWC3_GUSB3PIPECTL(0)) &
DWC3_GUSB3PIPECTL_SUSPHY);
/*
* TI AM62 platform requires SUSPHY to be
@@ -2471,10 +2508,10 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
if (dwc->dis_u2_susphy_quirk ||
dwc->dis_enblslpm_quirk) {
for (i = 0; i < dwc->num_usb2_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i));
reg |= DWC3_GUSB2PHYCFG_ENBLSLPM |
DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg);
}
/* Give some time for USB2 PHY to suspend */
@@ -2534,14 +2571,14 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
}
/* Restore GUSB2PHYCFG bits that were modified in suspend */
for (i = 0; i < dwc->num_usb2_ports; i++) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(i));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(i));
if (dwc->dis_u2_susphy_quirk)
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
if (dwc->dis_enblslpm_quirk)
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(i), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(i), reg);
}
for (i = 0; i < dwc->num_usb2_ports; i++)
@@ -2723,9 +2760,9 @@ void dwc3_pm_complete(struct dwc3 *dwc)
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST &&
dwc->dis_split_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUCTL3);
reg = dwc3_readl(dwc, DWC3_GUCTL3);
reg |= DWC3_GUCTL3_SPLITDISABLE;
dwc3_writel(dwc->regs, DWC3_GUCTL3, reg);
dwc3_writel(dwc, DWC3_GUCTL3, reg);
}
}
EXPORT_SYMBOL_GPL(dwc3_pm_complete);
+12 -6
View File
@@ -165,10 +165,10 @@
#define DWC3_DCFG1 0xc740 /* DWC_usb32 only */
#define DWC3_DEP_BASE(n) (0xc800 + ((n) * 0x10))
#define DWC3_DEPCMDPAR2 0x00
#define DWC3_DEPCMDPAR1 0x04
#define DWC3_DEPCMDPAR0 0x08
#define DWC3_DEPCMD 0x0c
#define DWC3_DEPCMDPAR2(n) (DWC3_DEP_BASE(n) + 0x00)
#define DWC3_DEPCMDPAR1(n) (DWC3_DEP_BASE(n) + 0x04)
#define DWC3_DEPCMDPAR0(n) (DWC3_DEP_BASE(n) + 0x08)
#define DWC3_DEPCMD(n) (DWC3_DEP_BASE(n) + 0x0c)
#define DWC3_DEV_IMOD(n) (0xca00 + ((n) * 0x4))
@@ -302,6 +302,7 @@
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
#define DWC3_GUSB2PHYCFG_XCVRDLY BIT(9)
#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
@@ -749,8 +750,6 @@ struct dwc3_ep {
struct list_head pending_list;
struct list_head started_list;
void __iomem *regs;
struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
struct dwc3 *dwc;
@@ -1060,6 +1059,8 @@ struct dwc3_glue_ops {
* @role_switch_default_mode: default operation mode of controller while
* usb role is USB_ROLE_NONE.
* @usb_psy: pointer to power supply interface.
* @vbus_draw_work: Work to set the vbus drawing limit
* @current_limit: How much current to draw from vbus, in milliAmperes.
* @usb2_phy: pointer to USB2 PHY
* @usb3_phy: pointer to USB3 PHY
* @usb2_generic_phy: pointer to array of USB2 PHYs
@@ -1161,6 +1162,8 @@ struct dwc3_glue_ops {
* 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk.
* @dis_split_quirk: set to disable split boundary.
* @enable_usb2_transceiver_delay: Set to insert a delay before the
* assertion of the TxValid signal during a HS Chirp.
* @sys_wakeup: set if the device may do system wakeup.
* @wakeup_configured: set if the device is configured for remote wakeup.
* @suspended: set to track suspend event due to U3/L2.
@@ -1246,6 +1249,8 @@ struct dwc3 {
enum usb_dr_mode role_switch_default_mode;
struct power_supply *usb_psy;
struct work_struct vbus_draw_work;
unsigned int current_limit;
u32 fladj;
u32 ref_clk_per;
@@ -1401,6 +1406,7 @@ struct dwc3 {
unsigned dis_metastability_quirk:1;
unsigned dis_split_quirk:1;
unsigned enable_usb2_transceiver_delay:1;
unsigned async_callbacks:1;
unsigned sys_wakeup:1;
unsigned wakeup_configured:1;
+20 -24
View File
@@ -36,23 +36,19 @@
#define dump_ep_register_set(n) \
{ \
.name = "DEPCMDPAR2("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR2, \
.offset = DWC3_DEPCMDPAR2(n), \
}, \
{ \
.name = "DEPCMDPAR1("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR1, \
.offset = DWC3_DEPCMDPAR1(n), \
}, \
{ \
.name = "DEPCMDPAR0("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMDPAR0, \
.offset = DWC3_DEPCMDPAR0(n), \
}, \
{ \
.name = "DEPCMD("__stringify(n)")", \
.offset = DWC3_DEP_BASE(n) + \
DWC3_DEPCMD, \
.offset = DWC3_DEPCMD(n), \
}
@@ -300,14 +296,14 @@ static void dwc3_host_lsp(struct seq_file *s)
reg = DWC3_GDBGLSPMUX_HOSTSELECT(sel);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", sel, val);
if (dbc_enabled && sel < 256) {
reg |= DWC3_GDBGLSPMUX_ENDBC;
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg);
val = dwc3_readl(dwc, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP_DBC[%d] = 0x%08x\n", sel, val);
}
}
@@ -320,8 +316,8 @@ static void dwc3_gadget_lsp(struct seq_file *s)
for (i = 0; i < 16; i++) {
reg = DWC3_GDBGLSPMUX_DEVSELECT(i);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
reg = dwc3_readl(dwc->regs, DWC3_GDBGLSP);
dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg);
reg = dwc3_readl(dwc, DWC3_GDBGLSP);
seq_printf(s, "GDBGLSP[%d] = 0x%08x\n", i, reg);
}
}
@@ -339,7 +335,7 @@ static int dwc3_lsp_show(struct seq_file *s, void *unused)
return ret;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
reg = dwc3_readl(dwc, DWC3_GSTS);
current_mode = DWC3_GSTS_CURMOD(reg);
switch (current_mode) {
@@ -410,7 +406,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
return ret;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
spin_unlock_irqrestore(&dwc->lock, flags);
mode = DWC3_GCTL_PRTCAP(reg);
@@ -482,7 +478,7 @@ static int dwc3_testmode_show(struct seq_file *s, void *unused)
return ret;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= DWC3_DCTL_TSTCTRL_MASK;
reg >>= 1;
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -581,7 +577,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
return ret;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
reg = dwc3_readl(dwc, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
seq_puts(s, "Not available\n");
spin_unlock_irqrestore(&dwc->lock, flags);
@@ -589,7 +585,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
return 0;
}
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
state = DWC3_DSTS_USBLNKST(reg);
speed = reg & DWC3_DSTS_CONNECTSPD;
@@ -643,14 +639,14 @@ static ssize_t dwc3_link_state_write(struct file *file,
return ret;
spin_lock_irqsave(&dwc->lock, flags);
reg = dwc3_readl(dwc->regs, DWC3_GSTS);
reg = dwc3_readl(dwc, DWC3_GSTS);
if (DWC3_GSTS_CURMOD(reg) != DWC3_GSTS_CURMOD_DEVICE) {
spin_unlock_irqrestore(&dwc->lock, flags);
pm_runtime_put_sync(dwc->dev);
return -EINVAL;
}
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
if (speed < DWC3_DSTS_SUPERSPEED &&
@@ -946,10 +942,10 @@ static int dwc3_ep_info_register_show(struct seq_file *s, void *unused)
spin_lock_irqsave(&dwc->lock, flags);
reg = DWC3_GDBGLSPMUX_EPSELECT(dep->number);
dwc3_writel(dwc->regs, DWC3_GDBGLSPMUX, reg);
dwc3_writel(dwc, DWC3_GDBGLSPMUX, reg);
lower_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO0);
upper_32_bits = dwc3_readl(dwc->regs, DWC3_GDBGEPINFO1);
lower_32_bits = dwc3_readl(dwc, DWC3_GDBGEPINFO0);
upper_32_bits = dwc3_readl(dwc, DWC3_GDBGEPINFO1);
ep_info = ((u64)upper_32_bits << 32) | lower_32_bits;
seq_printf(s, "0x%016llx\n", ep_info);
+45 -41
View File
@@ -18,25 +18,25 @@
static void dwc3_otg_disable_events(struct dwc3 *dwc, u32 disable_mask)
{
u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
u32 reg = dwc3_readl(dwc, DWC3_OEVTEN);
reg &= ~(disable_mask);
dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
dwc3_writel(dwc, DWC3_OEVTEN, reg);
}
static void dwc3_otg_enable_events(struct dwc3 *dwc, u32 enable_mask)
{
u32 reg = dwc3_readl(dwc->regs, DWC3_OEVTEN);
u32 reg = dwc3_readl(dwc, DWC3_OEVTEN);
reg |= (enable_mask);
dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
dwc3_writel(dwc, DWC3_OEVTEN, reg);
}
static void dwc3_otg_clear_events(struct dwc3 *dwc)
{
u32 reg = dwc3_readl(dwc->regs, DWC3_OEVT);
u32 reg = dwc3_readl(dwc, DWC3_OEVT);
dwc3_writel(dwc->regs, DWC3_OEVTEN, reg);
dwc3_writel(dwc, DWC3_OEVTEN, reg);
}
#define DWC3_OTG_ALL_EVENTS (DWC3_OEVTEN_XHCIRUNSTPSETEN | \
@@ -72,18 +72,18 @@ static irqreturn_t dwc3_otg_irq(int irq, void *_dwc)
struct dwc3 *dwc = _dwc;
irqreturn_t ret = IRQ_NONE;
reg = dwc3_readl(dwc->regs, DWC3_OEVT);
reg = dwc3_readl(dwc, DWC3_OEVT);
if (reg) {
/* ignore non OTG events, we can't disable them in OEVTEN */
if (!(reg & DWC3_OTG_ALL_EVENTS)) {
dwc3_writel(dwc->regs, DWC3_OEVT, reg);
dwc3_writel(dwc, DWC3_OEVT, reg);
return IRQ_NONE;
}
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST &&
!(reg & DWC3_OEVT_DEVICEMODE))
dwc->otg_restart_host = true;
dwc3_writel(dwc->regs, DWC3_OEVT, reg);
dwc3_writel(dwc, DWC3_OEVT, reg);
ret = IRQ_WAKE_THREAD;
}
@@ -100,23 +100,23 @@ static void dwc3_otgregs_init(struct dwc3 *dwc)
* the signal outputs sent to the PHY, the OTG FSM logic of the
* core and also the resets to the VBUS filters inside the core.
*/
reg = dwc3_readl(dwc->regs, DWC3_OCFG);
reg = dwc3_readl(dwc, DWC3_OCFG);
reg |= DWC3_OCFG_SFTRSTMASK;
dwc3_writel(dwc->regs, DWC3_OCFG, reg);
dwc3_writel(dwc, DWC3_OCFG, reg);
/* Disable hibernation for simplicity */
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
reg = dwc3_readl(dwc, DWC3_GCTL);
reg &= ~DWC3_GCTL_GBLHIBERNATIONEN;
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
dwc3_writel(dwc, DWC3_GCTL, reg);
/*
* Initialize OTG registers as per
* Figure 11-4 OTG Driver Overall Programming Flow
*/
/* OCFG.SRPCap = 0, OCFG.HNPCap = 0 */
reg = dwc3_readl(dwc->regs, DWC3_OCFG);
reg = dwc3_readl(dwc, DWC3_OCFG);
reg &= ~(DWC3_OCFG_SRPCAP | DWC3_OCFG_HNPCAP);
dwc3_writel(dwc->regs, DWC3_OCFG, reg);
dwc3_writel(dwc, DWC3_OCFG, reg);
/* OEVT = FFFF */
dwc3_otg_clear_events(dwc);
/* OEVTEN = 0 */
@@ -127,11 +127,11 @@ static void dwc3_otgregs_init(struct dwc3 *dwc)
* OCTL.PeriMode = 1, OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0,
* OCTL.HNPReq = 0
*/
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg |= DWC3_OCTL_PERIMODE;
reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN |
DWC3_OCTL_HNPREQ);
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
}
static int dwc3_otg_get_irq(struct dwc3 *dwc)
@@ -175,9 +175,9 @@ void dwc3_otg_init(struct dwc3 *dwc)
/* GCTL.PrtCapDir=2'b11 */
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
/* GUSB2PHYCFG0.SusPHY=0 */
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
/* Initialize OTG registers */
dwc3_otgregs_init(dwc);
@@ -203,17 +203,17 @@ void dwc3_otg_host_init(struct dwc3 *dwc)
* OCTL.PeriMode=0, OCTL.TermSelDLPulse = 0,
* OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
*/
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg &= ~(DWC3_OCTL_PERIMODE | DWC3_OCTL_TERMSELIDPULSE |
DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
/*
* OCFG.DisPrtPwrCutoff = 0/1
*/
reg = dwc3_readl(dwc->regs, DWC3_OCFG);
reg = dwc3_readl(dwc, DWC3_OCFG);
reg &= ~DWC3_OCFG_DISPWRCUTTOFF;
dwc3_writel(dwc->regs, DWC3_OCFG, reg);
dwc3_writel(dwc, DWC3_OCFG, reg);
/*
* OCFG.SRPCap = 1, OCFG.HNPCap = GHWPARAMS6.HNP_CAP
@@ -229,15 +229,15 @@ void dwc3_otg_host_init(struct dwc3 *dwc)
/* GUSB2PHYCFG.ULPIAutoRes = 1/0, GUSB2PHYCFG.SusPHY = 1 */
if (!dwc->dis_u2_susphy_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
}
/* Set Port Power to enable VBUS: OCTL.PrtPwrCtl = 1 */
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg |= DWC3_OCTL_PRTPWRCTL;
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
}
/* should be called after Host controller driver is stopped */
@@ -258,9 +258,9 @@ static void dwc3_otg_host_exit(struct dwc3 *dwc)
*/
/* OCTL.HstSetHNPEn = 0, OCTL.PrtPwrCtl=0 */
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg &= ~(DWC3_OCTL_HSTSETHNPEN | DWC3_OCTL_PRTPWRCTL);
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
}
/* should be called before the gadget controller driver is started */
@@ -274,27 +274,27 @@ static void dwc3_otg_device_init(struct dwc3 *dwc)
* OCFG.HNPCap = GHWPARAMS6.HNP_CAP, OCFG.SRPCap = 1
* but we keep them 0 for simple dual-role operation.
*/
reg = dwc3_readl(dwc->regs, DWC3_OCFG);
reg = dwc3_readl(dwc, DWC3_OCFG);
/* OCFG.OTGSftRstMsk = 0/1 */
reg |= DWC3_OCFG_SFTRSTMASK;
dwc3_writel(dwc->regs, DWC3_OCFG, reg);
dwc3_writel(dwc, DWC3_OCFG, reg);
/*
* OCTL.PeriMode = 1
* OCTL.TermSelDLPulse = 0/1, OCTL.HNPReq = 0
* OCTL.DevSetHNPEn = 0, OCTL.HstSetHNPEn = 0
*/
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg |= DWC3_OCTL_PERIMODE;
reg &= ~(DWC3_OCTL_TERMSELIDPULSE | DWC3_OCTL_HNPREQ |
DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HSTSETHNPEN);
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
/* OEVTEN.OTGBDevSesVldDetEvntEn = 1 */
dwc3_otg_enable_events(dwc, DWC3_OEVTEN_BDEVSESSVLDDETEN);
/* GUSB2PHYCFG.ULPIAutoRes = 0, GUSB2PHYCFG0.SusPHY = 1 */
if (!dwc->dis_u2_susphy_quirk) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
}
/* GCTL.GblHibernationEn = 0. Already 0. */
}
@@ -319,10 +319,10 @@ static void dwc3_otg_device_exit(struct dwc3 *dwc)
DWC3_OEVTEN_BDEVBHOSTENDEN);
/* OCTL.DevSetHNPEn = 0, OCTL.HNPReq = 0, OCTL.PeriMode=1 */
reg = dwc3_readl(dwc->regs, DWC3_OCTL);
reg = dwc3_readl(dwc, DWC3_OCTL);
reg &= ~(DWC3_OCTL_DEVSETHNPEN | DWC3_OCTL_HNPREQ);
reg |= DWC3_OCTL_PERIMODE;
dwc3_writel(dwc->regs, DWC3_OCTL, reg);
dwc3_writel(dwc, DWC3_OCTL, reg);
}
void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
@@ -341,7 +341,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
return;
if (!ignore_idstatus) {
reg = dwc3_readl(dwc->regs, DWC3_OSTS);
reg = dwc3_readl(dwc, DWC3_OSTS);
id = !!(reg & DWC3_OSTS_CONIDSTS);
dwc->desired_otg_role = id ? DWC3_OTG_ROLE_DEVICE :
@@ -381,6 +381,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
dwc3_otgregs_init(dwc);
dwc3_otg_host_init(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
dwc3_pre_set_role(dwc, USB_ROLE_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dwc->dev, "failed to initialize host\n");
@@ -406,6 +407,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
otg_set_vbus(dwc->usb2_phy->otg, false);
if (dwc->usb2_generic_phy[0])
phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
dwc3_pre_set_role(dwc, USB_ROLE_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");
@@ -433,10 +435,12 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
u32 mode = event ? DWC3_GCTL_PRTCAP_HOST : DWC3_GCTL_PRTCAP_DEVICE;
enum usb_role role = mode == DWC3_GCTL_PRTCAP_HOST ?
USB_ROLE_HOST : USB_ROLE_DEVICE;
dwc3_set_mode(dwc, event ?
DWC3_GCTL_PRTCAP_HOST :
DWC3_GCTL_PRTCAP_DEVICE);
dwc3_pre_set_role(dwc, role);
dwc3_set_mode(dwc, mode);
return NOTIFY_DONE;
}
+39 -8
View File
@@ -51,7 +51,7 @@
struct dwc3_imx8mp {
struct device *dev;
struct platform_device *dwc3;
struct platform_device *dwc3_pdev;
void __iomem *hsio_blk_base;
void __iomem *glue_base;
struct clk *hsio_clk;
@@ -100,7 +100,7 @@ static void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx)
static void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx,
pm_message_t msg)
{
struct dwc3 *dwc3 = platform_get_drvdata(dwc3_imx->dwc3);
struct dwc3 *dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
u32 val;
if (!dwc3)
@@ -142,7 +142,7 @@ static const struct software_node dwc3_imx8mp_swnode = {
static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
{
struct dwc3_imx8mp *dwc3_imx = _dwc3_imx;
struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3);
struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
if (!dwc3_imx->pm_suspended)
return IRQ_HANDLED;
@@ -158,11 +158,31 @@ static irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx)
return IRQ_HANDLED;
}
static void dwc3_imx_pre_set_role(struct dwc3 *dwc, enum usb_role role)
{
if (role == USB_ROLE_HOST)
/*
* For xhci host, we need disable dwc core auto
* suspend, because during this auto suspend delay(5s),
* xhci host RUN_STOP is cleared and wakeup is not
* enabled, if device is inserted, xhci host can't
* response the connection.
*/
pm_runtime_dont_use_autosuspend(dwc->dev);
else
pm_runtime_use_autosuspend(dwc->dev);
}
struct dwc3_glue_ops dwc3_imx_glue_ops = {
.pre_set_role = dwc3_imx_pre_set_role,
};
static int dwc3_imx8mp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct dwc3_imx8mp *dwc3_imx;
struct dwc3 *dwc3;
struct resource *res;
int err, irq;
@@ -233,13 +253,24 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
goto remove_swnode;
}
dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np);
if (!dwc3_imx->dwc3) {
dwc3_imx->dwc3_pdev = of_find_device_by_node(dwc3_np);
if (!dwc3_imx->dwc3_pdev) {
dev_err(dev, "failed to get dwc3 platform device\n");
err = -ENODEV;
goto depopulate;
}
dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev);
if (!dwc3) {
err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n");
goto put_dwc3;
}
dwc3->glue_ops = &dwc3_imx_glue_ops;
if (dwc3->dr_mode == USB_DR_MODE_HOST)
pm_runtime_dont_use_autosuspend(dwc3->dev);
err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt,
IRQF_ONESHOT, dev_name(dev), dwc3_imx);
if (err) {
@@ -253,7 +284,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev)
return 0;
put_dwc3:
put_device(&dwc3_imx->dwc3->dev);
put_device(&dwc3_imx->dwc3_pdev->dev);
depopulate:
of_platform_depopulate(dev);
remove_swnode:
@@ -270,7 +301,7 @@ static void dwc3_imx8mp_remove(struct platform_device *pdev)
struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
put_device(&dwc3_imx->dwc3->dev);
put_device(&dwc3_imx->dwc3_pdev->dev);
pm_runtime_get_sync(dev);
of_platform_depopulate(dev);
@@ -296,7 +327,7 @@ static int dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
static int dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, pm_message_t msg)
{
struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3);
struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3_pdev);
int ret = 0;
if (!dwc3_imx->pm_suspended)
+11 -11
View File
@@ -361,7 +361,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
if ((dwc->speed == DWC3_DSTS_SUPERSPEED) ||
(dwc->speed == DWC3_DSTS_SUPERSPEED_PLUS)) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU1ENA)
usb_status |= 1 << USB_DEV_STAT_U1_ENABLED;
if (reg & DWC3_DCTL_INITU2ENA)
@@ -417,12 +417,12 @@ static int dwc3_ep0_handle_u1(struct dwc3 *dwc, enum usb_device_state state,
if (set && dwc->dis_u1_entry_quirk)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU1ENA;
else
reg &= ~DWC3_DCTL_INITU1ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
return 0;
}
@@ -441,12 +441,12 @@ static int dwc3_ep0_handle_u2(struct dwc3 *dwc, enum usb_device_state state,
if (set && dwc->dis_u2_entry_quirk)
return -EINVAL;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (set)
reg |= DWC3_DCTL_INITU2ENA;
else
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
return 0;
}
@@ -612,10 +612,10 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
return -EINVAL;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
reg |= DWC3_DCFG_DEVADDR(addr);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
if (addr)
usb_gadget_set_state(dwc->gadget, USB_STATE_ADDRESS);
@@ -672,12 +672,12 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
* Enable transition to U1/U2 state when
* nothing is pending from application.
*/
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (!dwc->dis_u1_entry_quirk)
reg |= DWC3_DCTL_ACCEPTU1ENA;
if (!dwc->dis_u2_entry_quirk)
reg |= DWC3_DCTL_ACCEPTU2ENA;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
}
break;
@@ -717,7 +717,7 @@ static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req)
dwc->u2sel = le16_to_cpu(timing.u2sel);
dwc->u2pel = le16_to_cpu(timing.u2pel);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (reg & DWC3_DCTL_INITU2ENA)
param = dwc->u2pel;
if (reg & DWC3_DCTL_INITU1ENA)
@@ -833,7 +833,7 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
if (!dwc->gadget_driver || !dwc->softconnect || !dwc->connected)
goto out;
trace_dwc3_ctrl_req(ctrl);
trace_dwc3_ctrl_req(dwc, ctrl);
len = le16_to_cpu(ctrl->wLength);
if (!len) {
+85 -87
View File
@@ -42,7 +42,7 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
switch (mode) {
@@ -73,7 +73,7 @@ int dwc3_gadget_get_link_state(struct dwc3 *dwc)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
return DWC3_DSTS_USBLNKST(reg);
}
@@ -97,7 +97,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
*/
if (!DWC3_VER_IS_PRIOR(DWC3, 194A)) {
while (--retries) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
if (reg & DWC3_DSTS_DCNRD)
udelay(5);
else
@@ -108,15 +108,15 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
return -ETIMEDOUT;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
/* set no action before sending new link state change */
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
/* set requested state */
reg |= DWC3_DCTL_ULSTCHNGREQ(state);
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
/*
* The following code is racy when called from dwc3_gadget_wakeup,
@@ -128,7 +128,7 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
/* wait for a change in DSTS */
retries = 10000;
while (--retries) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
if (DWC3_DSTS_USBLNKST(reg) == state)
return 0;
@@ -260,11 +260,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
int ret = 0;
u32 reg;
dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param);
dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
dwc3_writel(dwc, DWC3_DGCMDPAR, param);
dwc3_writel(dwc, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT);
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
reg = dwc3_readl(dwc, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
status = DWC3_DGCMD_STATUS(reg);
if (status)
@@ -278,7 +278,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd,
status = -ETIMEDOUT;
}
trace_dwc3_gadget_generic_cmd(cmd, param, status);
trace_dwc3_gadget_generic_cmd(dwc, cmd, param, status);
return ret;
}
@@ -320,6 +320,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
int cmd_status = 0;
int ret = -EINVAL;
u8 epnum = dep->number;
/*
* When operating in USB 2.0 speeds (HS/FS), if GUSB2PHYCFG.ENBLSLPM or
@@ -333,7 +334,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
*/
if (dwc->gadget->speed <= USB_SPEED_HIGH ||
DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
if (unlikely(reg & DWC3_GUSB2PHYCFG_SUSPHY)) {
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
@@ -345,7 +346,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
}
if (saved_config)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
}
/*
@@ -355,9 +356,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
* improve performance.
*/
if (DWC3_DEPCMD_CMD(cmd) != DWC3_DEPCMD_UPDATETRANSFER) {
dwc3_writel(dep->regs, DWC3_DEPCMDPAR0, params->param0);
dwc3_writel(dep->regs, DWC3_DEPCMDPAR1, params->param1);
dwc3_writel(dep->regs, DWC3_DEPCMDPAR2, params->param2);
dwc3_writel(dwc, DWC3_DEPCMDPAR0(epnum), params->param0);
dwc3_writel(dwc, DWC3_DEPCMDPAR1(epnum), params->param1);
dwc3_writel(dwc, DWC3_DEPCMDPAR2(epnum), params->param2);
}
/*
@@ -381,7 +382,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
else
cmd |= DWC3_DEPCMD_CMDACT;
dwc3_writel(dep->regs, DWC3_DEPCMD, cmd);
dwc3_writel(dwc, DWC3_DEPCMD(epnum), cmd);
if (!(cmd & DWC3_DEPCMD_CMDACT) ||
(DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_ENDTRANSFER &&
@@ -391,7 +392,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd,
}
do {
reg = dwc3_readl(dep->regs, DWC3_DEPCMD);
reg = dwc3_readl(dwc, DWC3_DEPCMD(epnum));
if (!(reg & DWC3_DEPCMD_CMDACT)) {
cmd_status = DWC3_DEPCMD_STATUS(reg);
@@ -447,9 +448,9 @@ skip_status:
mdelay(1);
if (saved_config) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
reg |= saved_config;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
}
return ret;
@@ -726,7 +727,7 @@ static int dwc3_gadget_calc_ram_depth(struct dwc3 *dwc)
u32 reg;
/* Check if TXFIFOs start at non-zero addr */
reg = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
reg = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0));
fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(reg);
ram_depth -= (fifo_0_start >> 16);
@@ -754,7 +755,7 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)
/* Read ep0IN related TXFIFO size */
dep = dwc->eps[1];
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
size = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0));
if (DWC3_IP_IS(DWC3))
fifo_depth = DWC3_GTXFIFOSIZ_TXFDEP(size);
else
@@ -769,10 +770,10 @@ void dwc3_gadget_clear_tx_fifos(struct dwc3 *dwc)
/* Don't change TXFRAMNUM on usb31 version */
size = DWC3_IP_IS(DWC3) ? 0 :
dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1)) &
dwc3_readl(dwc, DWC3_GTXFIFOSIZ(num >> 1)) &
DWC31_GTXFIFOSIZ_TXFRAMNUM;
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num >> 1), size);
dwc3_writel(dwc, DWC3_GTXFIFOSIZ(num >> 1), size);
dep->flags &= ~DWC3_EP_TXFIFO_RESIZED;
}
dwc->num_ep_resized = 0;
@@ -875,7 +876,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
fifo_size++;
/* Check if TXFIFOs start at non-zero addr */
tmp = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(0));
tmp = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(0));
fifo_0_start = DWC3_GTXFIFOSIZ_TXFSTADDR(tmp);
fifo_size |= (fifo_0_start + (dwc->last_fifo_depth << 16));
@@ -898,7 +899,7 @@ static int dwc3_gadget_resize_tx_fifos(struct dwc3_ep *dep)
return -ENOMEM;
}
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size);
dwc3_writel(dwc, DWC3_GTXFIFOSIZ(dep->number >> 1), fifo_size);
dep->flags |= DWC3_EP_TXFIFO_RESIZED;
dwc->num_ep_resized++;
@@ -942,9 +943,9 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
dep->type = usb_endpoint_type(desc);
dep->flags |= DWC3_EP_ENABLED;
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg = dwc3_readl(dwc, DWC3_DALEPENA);
reg |= DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
dwc3_writel(dwc, DWC3_DALEPENA, reg);
dep->trb_dequeue = 0;
dep->trb_enqueue = 0;
@@ -1079,9 +1080,9 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
if (dep->flags & DWC3_EP_STALL)
__dwc3_gadget_ep_set_halt(dep, 0, false);
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
reg = dwc3_readl(dwc, DWC3_DALEPENA);
reg &= ~DWC3_DALEPENA_EP(dep->number);
dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
dwc3_writel(dwc, DWC3_DALEPENA, reg);
dwc3_remove_requests(dwc, dep, -ESHUTDOWN);
@@ -1742,7 +1743,7 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
{
u32 reg;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
return DWC3_DSTS_SOFFN(reg);
}
@@ -2350,13 +2351,13 @@ static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set)
if (DWC3_VER_IS_PRIOR(DWC3, 250A))
return;
reg = dwc3_readl(dwc->regs, DWC3_DEVTEN);
reg = dwc3_readl(dwc, DWC3_DEVTEN);
if (set)
reg |= DWC3_DEVTEN_ULSTCNGEN;
else
reg &= ~DWC3_DEVTEN_ULSTCNGEN;
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
dwc3_writel(dwc, DWC3_DEVTEN, reg);
}
static int dwc3_gadget_get_frame(struct usb_gadget *g)
@@ -2379,7 +2380,7 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
*
* We can check that via USB Link State bits in DSTS register.
*/
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
link_state = DWC3_DSTS_USBLNKST(reg);
@@ -2407,9 +2408,9 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc)
/* Recent versions do this automatically */
if (DWC3_VER_IS_PRIOR(DWC3, 194A)) {
/* write zeroes to Link Change Request */
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
}
/*
@@ -2529,7 +2530,7 @@ static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc)
if (ssp_rate == USB_SSP_GEN_UNKNOWN)
ssp_rate = dwc->max_ssp_rate;
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~DWC3_DCFG_SPEED_MASK;
reg &= ~DWC3_DCFG_NUMLANES(~0);
@@ -2542,7 +2543,7 @@ static void __dwc3_gadget_set_ssp_rate(struct dwc3 *dwc)
dwc->max_ssp_rate != USB_SSP_GEN_2x1)
reg |= DWC3_DCFG_NUMLANES(1);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
}
static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
@@ -2560,7 +2561,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
return;
}
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~(DWC3_DCFG_SPEED_MASK);
/*
@@ -2611,7 +2612,7 @@ static void __dwc3_gadget_set_speed(struct dwc3 *dwc)
speed < USB_SPEED_SUPER_PLUS)
reg &= ~DWC3_DCFG_NUMLANES(~0);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
}
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
@@ -2636,7 +2637,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
* mentioned in the dwc3 programming guide. It has been tested on an
* Exynos platforms.
*/
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
@@ -2648,9 +2649,9 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
}
if (saved_config)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
if (is_on) {
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 187A)) {
reg &= ~DWC3_DCTL_TRGTULST_MASK;
@@ -2674,14 +2675,14 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
do {
usleep_range(1000, 2000);
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
reg &= DWC3_DSTS_DEVCTRLHLT;
} while (--timeout && !(!is_on ^ !reg));
if (saved_config) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
reg |= saved_config;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYCFG(0), reg);
}
if (!timeout)
@@ -2857,13 +2858,13 @@ static void dwc3_gadget_enable_irq(struct dwc3 *dwc)
if (!DWC3_VER_IS_PRIOR(DWC3, 230A))
reg |= DWC3_DEVTEN_U3L2L1SUSPEN;
dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
dwc3_writel(dwc, DWC3_DEVTEN, reg);
}
static void dwc3_gadget_disable_irq(struct dwc3 *dwc)
{
/* mask all interrupts */
dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
dwc3_writel(dwc, DWC3_DEVTEN, 0x00);
}
static irqreturn_t dwc3_interrupt(int irq, void *_dwc);
@@ -2904,10 +2905,10 @@ static void dwc3_gadget_setup_nump(struct dwc3 *dwc)
nump = min_t(u32, nump, 16);
/* update NumP */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~DWC3_DCFG_NUMP_MASK;
reg |= nump << DWC3_DCFG_NUMP_SHIFT;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
}
static int __dwc3_gadget_start(struct dwc3 *dwc)
@@ -2921,10 +2922,10 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
* the core supports IMOD, disable it.
*/
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
} else if (dwc3_has_imod(dwc)) {
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), 0);
dwc3_writel(dwc, DWC3_DEV_IMOD(0), 0);
}
/*
@@ -2934,13 +2935,13 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
* This way, we maximize the chances that we'll be able to get several
* bursts of data without going through any sort of endpoint throttling.
*/
reg = dwc3_readl(dwc->regs, DWC3_GRXTHRCFG);
reg = dwc3_readl(dwc, DWC3_GRXTHRCFG);
if (DWC3_IP_IS(DWC3))
reg &= ~DWC3_GRXTHRCFG_PKTCNTSEL;
else
reg &= ~DWC31_GRXTHRCFG_PKTCNTSEL;
dwc3_writel(dwc->regs, DWC3_GRXTHRCFG, reg);
dwc3_writel(dwc, DWC3_GRXTHRCFG, reg);
dwc3_gadget_setup_nump(dwc);
@@ -2951,15 +2952,15 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
* ACK with NumP=0 and PP=0 (for IN direction). This slightly improves
* the stream performance.
*/
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg |= DWC3_DCFG_IGNSTRMPP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
/* Enable MST by default if the device is capable of MST */
if (DWC3_MST_CAPABLE(&dwc->hwparams)) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG1);
reg = dwc3_readl(dwc, DWC3_DCFG1);
reg &= ~DWC3_DCFG1_DIS_MST_ENH;
dwc3_writel(dwc->regs, DWC3_DCFG1, reg);
dwc3_writel(dwc, DWC3_DCFG1, reg);
}
/* Start with SuperSpeed Default */
@@ -3123,8 +3124,6 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gadget *g,
static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
{
struct dwc3 *dwc = gadget_to_dwc(g);
union power_supply_propval val = {0};
int ret;
if (dwc->usb2_phy)
return usb_phy_set_power(dwc->usb2_phy, mA);
@@ -3132,10 +3131,10 @@ static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA)
if (!dwc->usb_psy)
return -EOPNOTSUPP;
val.intval = 1000 * mA;
ret = power_supply_set_property(dwc->usb_psy, POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, &val);
dwc->current_limit = mA;
schedule_work(&dwc->vbus_draw_work);
return ret;
return 0;
}
/**
@@ -3239,7 +3238,7 @@ static int dwc3_gadget_init_in_endpoint(struct dwc3_ep *dep)
/* MDWIDTH is represented in bits, we need it in bytes */
mdwidth /= 8;
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(dep->number >> 1));
size = dwc3_readl(dwc, DWC3_GTXFIFOSIZ(dep->number >> 1));
if (DWC3_IP_IS(DWC3))
size = DWC3_GTXFIFOSIZ_TXFDEP(size);
else
@@ -3288,7 +3287,7 @@ static int dwc3_gadget_init_out_endpoint(struct dwc3_ep *dep)
mdwidth /= 8;
/* All OUT endpoints share a single RxFIFO space */
size = dwc3_readl(dwc->regs, DWC3_GRXFIFOSIZ(0));
size = dwc3_readl(dwc, DWC3_GRXFIFOSIZ(0));
if (DWC3_IP_IS(DWC3))
size = DWC3_GRXFIFOSIZ_RXFDEP(size);
else
@@ -3381,7 +3380,6 @@ static int dwc3_gadget_init_endpoint(struct dwc3 *dwc, u8 epnum)
dep->dwc = dwc;
dep->number = epnum;
dep->direction = direction;
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
dwc->eps[epnum] = dep;
dep->combo_num = 0;
dep->start_cmd_status = 0;
@@ -3742,9 +3740,9 @@ out:
return no_started_trb;
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg |= dwc->u1u2;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
dwc3_writel(dwc, DWC3_DCTL, reg);
dwc->u1u2 = 0;
}
@@ -4074,7 +4072,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RX_DET);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_INITU1ENA;
reg &= ~DWC3_DCTL_INITU2ENA;
dwc3_gadget_dctl_write_safe(dwc, reg);
@@ -4163,7 +4161,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dwc3_stop_active_transfers(dwc);
dwc->connected = true;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg);
dwc->test_mode = false;
@@ -4172,9 +4170,9 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
dwc3_clear_stall_all_ep(dwc);
/* Reset device address to zero */
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~(DWC3_DCFG_DEVADDR_MASK);
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
}
static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
@@ -4188,7 +4186,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
if (!dwc->softconnect)
return;
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
reg = dwc3_readl(dwc, DWC3_DSTS);
speed = reg & DWC3_DSTS_CONNECTSPD;
dwc->speed = speed;
@@ -4263,11 +4261,11 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
!dwc->usb2_gadget_lpm_disable &&
(speed != DWC3_DSTS_SUPERSPEED) &&
(speed != DWC3_DSTS_SUPERSPEED_PLUS)) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg |= DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~(DWC3_DCTL_HIRD_THRES_MASK | DWC3_DCTL_L1_HIBER_EN);
reg |= DWC3_DCTL_HIRD_THRES(dwc->hird_threshold |
@@ -4290,12 +4288,12 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
dwc3_gadget_dctl_write_safe(dwc, reg);
} else {
if (dwc->usb2_gadget_lpm_disable) {
reg = dwc3_readl(dwc->regs, DWC3_DCFG);
reg = dwc3_readl(dwc, DWC3_DCFG);
reg &= ~DWC3_DCFG_LPM_CAP;
dwc3_writel(dwc->regs, DWC3_DCFG, reg);
dwc3_writel(dwc, DWC3_DCFG, reg);
}
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
reg &= ~DWC3_DCTL_HIRD_THRES_MASK;
dwc3_gadget_dctl_write_safe(dwc, reg);
}
@@ -4401,7 +4399,7 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
switch (dwc->link_state) {
case DWC3_LINK_STATE_U1:
case DWC3_LINK_STATE_U2:
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg = dwc3_readl(dwc, DWC3_DCTL);
u1u2 = reg & (DWC3_DCTL_INITU2ENA
| DWC3_DCTL_ACCEPTU2ENA
| DWC3_DCTL_INITU1ENA
@@ -4558,7 +4556,7 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
ret = IRQ_HANDLED;
/* Unmask interrupt */
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
dwc3_writel(dwc, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_SIZE(evt->length));
evt->flags &= ~DWC3_EVENT_PENDING;
@@ -4569,8 +4567,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3_event_buffer *evt)
wmb();
if (dwc->imod_interval) {
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc->regs, DWC3_DEV_IMOD(0), dwc->imod_interval);
dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), DWC3_GEVNTCOUNT_EHB);
dwc3_writel(dwc, DWC3_DEV_IMOD(0), dwc->imod_interval);
}
return ret;
@@ -4619,7 +4617,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
if (evt->flags & DWC3_EVENT_PENDING)
return IRQ_HANDLED;
count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(0));
count = dwc3_readl(dwc, DWC3_GEVNTCOUNT(0));
count &= DWC3_GEVNTCOUNT_MASK;
if (!count)
return IRQ_NONE;
@@ -4634,7 +4632,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
evt->flags |= DWC3_EVENT_PENDING;
/* Mask interrupt */
dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(0),
dwc3_writel(dwc, DWC3_GEVNTSIZ(0),
DWC3_GEVNTSIZ_INTMASK | DWC3_GEVNTSIZ_SIZE(evt->length));
amount = min(count, evt->length - evt->lpos);
@@ -4643,7 +4641,7 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
if (amount < count)
memcpy(evt->cache, evt->buf, count - amount);
dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(0), count);
dwc3_writel(dwc, DWC3_GEVNTCOUNT(0), count);
return IRQ_WAKE_THREAD;
}
+2 -2
View File
@@ -132,7 +132,7 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
{
u32 res_id;
res_id = dwc3_readl(dep->regs, DWC3_DEPCMD);
res_id = dwc3_readl(dep->dwc, DWC3_DEPCMD(dep->number));
dep->resource_index = DWC3_DEPCMD_GET_RSC_IDX(res_id);
}
@@ -147,7 +147,7 @@ static inline void dwc3_gadget_ep_get_transfer_index(struct dwc3_ep *dep)
static inline void dwc3_gadget_dctl_write_safe(struct dwc3 *dwc, u32 value)
{
value &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, value);
dwc3_writel(dwc, DWC3_DCTL, value);
}
#endif /* __DRIVERS_USB_DWC3_GADGET_H */
+7 -4
View File
@@ -16,9 +16,10 @@
#include "debug.h"
#include "core.h"
static inline u32 dwc3_readl(void __iomem *base, u32 offset)
static inline u32 dwc3_readl(struct dwc3 *dwc, u32 offset)
{
u32 value;
void __iomem *base = dwc->regs;
/*
* We requested the mem region starting from the Globals address
@@ -32,13 +33,15 @@ static inline u32 dwc3_readl(void __iomem *base, u32 offset)
* documentation, so we revert it back to the proper addresses, the
* same way they are described on SNPS documentation
*/
trace_dwc3_readl(base - DWC3_GLOBALS_REGS_START, offset, value);
trace_dwc3_readl(dwc, base - DWC3_GLOBALS_REGS_START, offset, value);
return value;
}
static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
static inline void dwc3_writel(struct dwc3 *dwc, u32 offset, u32 value)
{
void __iomem *base = dwc->regs;
/*
* We requested the mem region starting from the Globals address
* space, see dwc3_probe in core.c.
@@ -51,7 +54,7 @@ static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
* documentation, so we revert it back to the proper addresses, the
* same way they are described on SNPS documentation
*/
trace_dwc3_writel(base - DWC3_GLOBALS_REGS_START, offset, value);
trace_dwc3_writel(dwc, base - DWC3_GLOBALS_REGS_START, offset, value);
}
#endif /* __DRIVERS_USB_DWC3_IO_H */
+55 -33
View File
@@ -20,63 +20,70 @@
#include "debug.h"
DECLARE_EVENT_CLASS(dwc3_log_set_prtcap,
TP_PROTO(u32 mode),
TP_ARGS(mode),
TP_PROTO(struct dwc3 *dwc, u32 mode),
TP_ARGS(dwc, mode),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__field(u32, mode)
),
TP_fast_assign(
__entry->base_address = dwc->xhci_resources[0].start;
__entry->mode = mode;
),
TP_printk("mode %s", dwc3_mode_string(__entry->mode))
TP_printk("%pa: mode %s", &__entry->base_address, dwc3_mode_string(__entry->mode))
);
DEFINE_EVENT(dwc3_log_set_prtcap, dwc3_set_prtcap,
TP_PROTO(u32 mode),
TP_ARGS(mode)
TP_PROTO(struct dwc3 *dwc, u32 mode),
TP_ARGS(dwc, mode)
);
DECLARE_EVENT_CLASS(dwc3_log_io,
TP_PROTO(void *base, u32 offset, u32 value),
TP_ARGS(base, offset, value),
TP_PROTO(struct dwc3 *dwc, void *base, u32 offset, u32 value),
TP_ARGS(dwc, base, offset, value),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__field(void *, base)
__field(u32, offset)
__field(u32, value)
),
TP_fast_assign(
__entry->base_address = dwc->xhci_resources[0].start;
__entry->base = base;
__entry->offset = offset;
__entry->value = value;
),
TP_printk("addr %p offset %04x value %08x",
TP_printk("%pa: addr %p offset %04x value %08x",
&__entry->base_address,
__entry->base + __entry->offset,
__entry->offset,
__entry->value)
);
DEFINE_EVENT(dwc3_log_io, dwc3_readl,
TP_PROTO(void __iomem *base, u32 offset, u32 value),
TP_ARGS(base, offset, value)
TP_PROTO(struct dwc3 *dwc, void __iomem *base, u32 offset, u32 value),
TP_ARGS(dwc, base, offset, value)
);
DEFINE_EVENT(dwc3_log_io, dwc3_writel,
TP_PROTO(void __iomem *base, u32 offset, u32 value),
TP_ARGS(base, offset, value)
TP_PROTO(struct dwc3 *dwc, void __iomem *base, u32 offset, u32 value),
TP_ARGS(dwc, base, offset, value)
);
DECLARE_EVENT_CLASS(dwc3_log_event,
TP_PROTO(u32 event, struct dwc3 *dwc),
TP_ARGS(event, dwc),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__field(u32, event)
__field(u32, ep0state)
),
TP_fast_assign(
__entry->base_address = dwc->xhci_resources[0].start;
__entry->event = event;
__entry->ep0state = dwc->ep0state;
),
TP_printk("event (%08x): %s", __entry->event,
TP_printk("%pa: event (%08x): %s", &__entry->base_address, __entry->event,
dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
__entry->event, __entry->ep0state))
);
@@ -87,9 +94,10 @@ DEFINE_EVENT(dwc3_log_event, dwc3_event,
);
DECLARE_EVENT_CLASS(dwc3_log_ctrl,
TP_PROTO(struct usb_ctrlrequest *ctrl),
TP_ARGS(ctrl),
TP_PROTO(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl),
TP_ARGS(dwc, ctrl),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__field(__u8, bRequestType)
__field(__u8, bRequest)
__field(__u16, wValue)
@@ -97,13 +105,15 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
__field(__u16, wLength)
),
TP_fast_assign(
__entry->base_address = dwc->xhci_resources[0].start;
__entry->bRequestType = ctrl->bRequestType;
__entry->bRequest = ctrl->bRequest;
__entry->wValue = le16_to_cpu(ctrl->wValue);
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
__entry->wLength = le16_to_cpu(ctrl->wLength);
),
TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
TP_printk("%pa: %s", &__entry->base_address, usb_decode_ctrl(__get_buf(DWC3_MSG_MAX),
DWC3_MSG_MAX,
__entry->bRequestType,
__entry->bRequest, __entry->wValue,
__entry->wIndex, __entry->wLength)
@@ -111,14 +121,15 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
);
DEFINE_EVENT(dwc3_log_ctrl, dwc3_ctrl_req,
TP_PROTO(struct usb_ctrlrequest *ctrl),
TP_ARGS(ctrl)
TP_PROTO(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl),
TP_ARGS(dwc, ctrl)
);
DECLARE_EVENT_CLASS(dwc3_log_request,
TP_PROTO(struct dwc3_request *req),
TP_ARGS(req),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__string(name, req->dep->name)
__field(struct dwc3_request *, req)
__field(unsigned int, actual)
@@ -129,7 +140,7 @@ DECLARE_EVENT_CLASS(dwc3_log_request,
__field(int, no_interrupt)
),
TP_fast_assign(
__assign_str(name, req->dep->name);
__entry->base_address = req->dep->dwc->xhci_resources[0].start;
__entry->req = req;
__entry->actual = req->request.actual;
__entry->length = req->request.length;
@@ -138,8 +149,10 @@ DECLARE_EVENT_CLASS(dwc3_log_request,
__entry->short_not_ok = req->request.short_not_ok;
__entry->no_interrupt = req->request.no_interrupt;
),
TP_printk("%s: req %p length %u/%u %s%s%s ==> %d",
__get_str(name), __entry->req, __entry->actual, __entry->length,
TP_printk("%pa: %s: req %p length %u/%u %s%s%s ==> %d",
&__entry->base_address,
__get_str(name), __entry->req,
__entry->actual, __entry->length,
__entry->zero ? "Z" : "z",
__entry->short_not_ok ? "S" : "s",
__entry->no_interrupt ? "i" : "I",
@@ -173,28 +186,30 @@ DEFINE_EVENT(dwc3_log_request, dwc3_gadget_giveback,
);
DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
TP_PROTO(unsigned int cmd, u32 param, int status),
TP_ARGS(cmd, param, status),
TP_PROTO(struct dwc3 *dwc, unsigned int cmd, u32 param, int status),
TP_ARGS(dwc, cmd, param, status),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__field(unsigned int, cmd)
__field(u32, param)
__field(int, status)
),
TP_fast_assign(
__entry->base_address = dwc->xhci_resources[0].start;
__entry->cmd = cmd;
__entry->param = param;
__entry->status = status;
),
TP_printk("cmd '%s' [%x] param %08x --> status: %s",
dwc3_gadget_generic_cmd_string(__entry->cmd),
TP_printk("%pa: cmd '%s' [%x] param %08x --> status: %s",
&__entry->base_address, dwc3_gadget_generic_cmd_string(__entry->cmd),
__entry->cmd, __entry->param,
dwc3_gadget_generic_cmd_status_string(__entry->status)
)
);
DEFINE_EVENT(dwc3_log_generic_cmd, dwc3_gadget_generic_cmd,
TP_PROTO(unsigned int cmd, u32 param, int status),
TP_ARGS(cmd, param, status)
TP_PROTO(struct dwc3 *dwc, unsigned int cmd, u32 param, int status),
TP_ARGS(dwc, cmd, param, status)
);
DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
@@ -202,6 +217,7 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
struct dwc3_gadget_ep_cmd_params *params, int cmd_status),
TP_ARGS(dep, cmd, params, cmd_status),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__string(name, dep->name)
__field(unsigned int, cmd)
__field(u32, param0)
@@ -210,6 +226,7 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
__field(int, cmd_status)
),
TP_fast_assign(
__entry->base_address = dep->dwc->xhci_resources[0].start;
__assign_str(name, dep->name);
__entry->cmd = cmd;
__entry->param0 = params->param0;
@@ -217,8 +234,9 @@ DECLARE_EVENT_CLASS(dwc3_log_gadget_ep_cmd,
__entry->param2 = params->param2;
__entry->cmd_status = cmd_status;
),
TP_printk("%s: cmd '%s' [%x] params %08x %08x %08x --> status: %s",
__get_str(name), dwc3_gadget_ep_cmd_string(__entry->cmd),
TP_printk("%pa: %s: cmd '%s' [%x] params %08x %08x %08x --> status: %s",
&__entry->base_address, __get_str(name),
dwc3_gadget_ep_cmd_string(__entry->cmd),
__entry->cmd, __entry->param0,
__entry->param1, __entry->param2,
dwc3_ep_cmd_status_string(__entry->cmd_status)
@@ -235,6 +253,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
TP_PROTO(struct dwc3_ep *dep, struct dwc3_trb *trb),
TP_ARGS(dep, trb),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__string(name, dep->name)
__field(struct dwc3_trb *, trb)
__field(u32, bpl)
@@ -246,6 +265,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
__field(u32, dequeue)
),
TP_fast_assign(
__entry->base_address = dep->dwc->xhci_resources[0].start;
__assign_str(name, dep->name);
__entry->trb = trb;
__entry->bpl = trb->bpl;
@@ -256,8 +276,8 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
__entry->enqueue = dep->trb_enqueue;
__entry->dequeue = dep->trb_dequeue;
),
TP_printk("%s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x sofn %08x (%c%c%c%c:%c%c:%s)",
__get_str(name), __entry->trb, __entry->enqueue,
TP_printk("%pa: %s: trb %p (E%d:D%d) buf %08x%08x size %s%d ctrl %08x sofn %08x (%c%c%c%c:%c%c:%s)",
&__entry->base_address, __get_str(name), __entry->trb, __entry->enqueue,
__entry->dequeue, __entry->bph, __entry->bpl,
({char *s;
int pcm = ((__entry->size >> 24) & 3) + 1;
@@ -307,6 +327,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep,
TP_PROTO(struct dwc3_ep *dep),
TP_ARGS(dep),
TP_STRUCT__entry(
__field(phys_addr_t, base_address)
__string(name, dep->name)
__field(unsigned int, maxpacket)
__field(unsigned int, maxpacket_limit)
@@ -318,6 +339,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep,
__field(u8, trb_dequeue)
),
TP_fast_assign(
__entry->base_address = dep->dwc->xhci_resources[0].start;
__assign_str(name, dep->name);
__entry->maxpacket = dep->endpoint.maxpacket;
__entry->maxpacket_limit = dep->endpoint.maxpacket_limit;
@@ -328,8 +350,8 @@ DECLARE_EVENT_CLASS(dwc3_log_ep,
__entry->trb_enqueue = dep->trb_enqueue;
__entry->trb_dequeue = dep->trb_dequeue;
),
TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c",
__get_str(name), __entry->maxpacket,
TP_printk("%pa: %s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c",
&__entry->base_address, __get_str(name), __entry->maxpacket,
__entry->maxpacket_limit, __entry->max_streams,
__entry->maxburst, __entry->trb_enqueue,
__entry->trb_dequeue,
+30 -5
View File
@@ -10,10 +10,13 @@
#include <linux/delay.h>
#include <linux/time64.h>
#include <linux/ulpi/regs.h>
#include <linux/ulpi/driver.h>
#include "core.h"
#include "io.h"
#define USB_VENDOR_MICROCHIP 0x0424
#define DWC3_ULPI_ADDR(a) \
((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \
DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \
@@ -33,13 +36,13 @@ static int dwc3_ulpi_busyloop(struct dwc3 *dwc, u8 addr, bool read)
if (read)
ns += DWC3_ULPI_BASE_DELAY;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY)
usleep_range(1000, 1200);
while (count--) {
ndelay(ns);
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0));
if (reg & DWC3_GUSB2PHYACC_DONE)
return 0;
cpu_relax();
@@ -55,13 +58,13 @@ static int dwc3_ulpi_read(struct device *dev, u8 addr)
int ret;
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg);
ret = dwc3_ulpi_busyloop(dwc, addr, true);
if (ret)
return ret;
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0));
reg = dwc3_readl(dwc, DWC3_GUSB2PHYACC(0));
return DWC3_GUSB2PHYACC_DATA(reg);
}
@@ -73,7 +76,7 @@ static int dwc3_ulpi_write(struct device *dev, u8 addr, u8 val)
reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr);
reg |= DWC3_GUSB2PHYACC_WRITE | val;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg);
dwc3_writel(dwc, DWC3_GUSB2PHYACC(0), reg);
return dwc3_ulpi_busyloop(dwc, addr, false);
}
@@ -83,6 +86,26 @@ static const struct ulpi_ops dwc3_ulpi_ops = {
.write = dwc3_ulpi_write,
};
static void dwc3_ulpi_detect_config(struct dwc3 *dwc)
{
struct ulpi *ulpi = dwc->ulpi;
switch (ulpi->id.vendor) {
case USB_VENDOR_MICROCHIP:
switch (ulpi->id.product) {
case 0x0009:
/* Microchip USB3340 ULPI PHY */
dwc->enable_usb2_transceiver_delay = true;
break;
default:
break;
}
break;
default:
break;
}
}
int dwc3_ulpi_init(struct dwc3 *dwc)
{
/* Register the interface */
@@ -92,6 +115,8 @@ int dwc3_ulpi_init(struct dwc3 *dwc)
return PTR_ERR(dwc->ulpi);
}
dwc3_ulpi_detect_config(dwc);
return 0;
}
+9 -3
View File
@@ -3392,17 +3392,18 @@ static void tegra_xudc_device_params_init(struct tegra_xudc *xudc)
{
u32 val, imod;
val = xudc_readl(xudc, BLCG);
if (xudc->soc->has_ipfs) {
val = xudc_readl(xudc, BLCG);
val |= BLCG_ALL;
val &= ~(BLCG_DFPCI | BLCG_UFPCI | BLCG_FE |
BLCG_COREPLL_PWRDN);
val |= BLCG_IOPLL_0_PWRDN;
val |= BLCG_IOPLL_1_PWRDN;
val |= BLCG_IOPLL_2_PWRDN;
xudc_writel(xudc, val, BLCG);
} else {
val &= ~BLCG_COREPLL_PWRDN;
}
xudc_writel(xudc, val, BLCG);
if (xudc->soc->port_speed_quirk)
tegra_xudc_limit_port_speed(xudc);
@@ -3953,6 +3954,7 @@ static void tegra_xudc_remove(struct platform_device *pdev)
static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc)
{
unsigned long flags;
u32 val;
dev_dbg(xudc->dev, "entering ELPG\n");
@@ -3965,6 +3967,10 @@ static int __maybe_unused tegra_xudc_powergate(struct tegra_xudc *xudc)
spin_unlock_irqrestore(&xudc->lock, flags);
val = xudc_readl(xudc, BLCG);
val |= BLCG_COREPLL_PWRDN;
xudc_writel(xudc, val, BLCG);
clk_bulk_disable_unprepare(xudc->soc->num_clks, xudc->clks);
regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
+1 -13
View File
@@ -386,18 +386,6 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
depends on HAS_IOPORT
depends on COMPILE_TEST # nothing uses this
help
Supports the Philips ISP1362 chip as a host controller
This driver does not support isochronous transfers.
To compile this driver as a module, choose M here: the
module will be called isp1362-hcd.
config USB_FOTG210_HCD
tristate "FOTG210 HCD support"
depends on USB && HAS_DMA && HAS_IOMEM
@@ -642,7 +630,7 @@ config USB_UHCI_ASPEED
config USB_FHCI_HCD
tristate "Freescale QE USB Host Controller support"
depends on OF_GPIO && QE_GPIO && QUICC_ENGINE
depends on QE_GPIO && QUICC_ENGINE
select FSL_GTM
select QE_USB
help
-1
View File
@@ -52,7 +52,6 @@ obj-$(CONFIG_USB_EHCI_BRCMSTB) += ehci-brcm.o
obj-$(CONFIG_USB_OXU210HP_HCD) += oxu210hp-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_ISP1362_HCD) += isp1362-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_OHCI_HCD_PCI) += ohci-pci.o
-8
View File
@@ -1354,12 +1354,6 @@ static int __init ehci_hcd_init(void)
if (usb_disabled())
return -ENODEV;
set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
printk(KERN_WARNING "Warning! ehci_hcd should always be loaded"
" before uhci_hcd and ohci_hcd, not after\n");
pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd sitd %zd\n",
hcd_name,
sizeof(struct ehci_qh), sizeof(struct ehci_qtd),
@@ -1390,7 +1384,6 @@ clean0:
debugfs_remove(ehci_debug_root);
ehci_debug_root = NULL;
#endif
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
return retval;
}
module_init(ehci_hcd_init);
@@ -1404,6 +1397,5 @@ static void __exit ehci_hcd_cleanup(void)
#ifdef CONFIG_DYNAMIC_DEBUG
debugfs_remove(ehci_debug_root);
#endif
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}
module_exit(ehci_hcd_cleanup);
-1
View File
@@ -21,7 +21,6 @@ static const char hcd_name[] = "ehci-pci";
/* defined here to avoid adding to pci_ids.h for single instance use */
#define PCI_DEVICE_ID_INTEL_CE4100_USB 0x2e70
#define PCI_VENDOR_ID_ASPEED 0x1a03
#define PCI_DEVICE_ID_ASPEED_EHCI 0x2603
/*-------------------------------------------------------------------------*/
-6
View File
@@ -5692,11 +5692,6 @@ static int __init fotg210_hcd_init(void)
if (usb_disabled())
return -ENODEV;
set_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) ||
test_bit(USB_OHCI_LOADED, &usb_hcds_loaded))
pr_warn("Warning! fotg210_hcd should always be loaded before uhci_hcd and ohci_hcd, not after\n");
pr_debug("%s: block sizes: qh %zd qtd %zd itd %zd\n",
hcd_name, sizeof(struct fotg210_qh),
sizeof(struct fotg210_qtd),
@@ -5722,6 +5717,5 @@ static void __exit fotg210_hcd_cleanup(void)
{
platform_driver_unregister(&fotg210_hcd_driver);
debugfs_remove(fotg210_debug_root);
clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded);
}
module_exit(fotg210_hcd_cleanup);
File diff suppressed because it is too large Load Diff
-914
View File
@@ -1,914 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* ISP1362 HCD (Host Controller Driver) for USB.
*
* COPYRIGHT (C) by L. Wassmann <LW@KARO-electronics.de>
*/
/* ------------------------------------------------------------------------- */
#define MAX_ROOT_PORTS 2
#define USE_32BIT 0
/* These options are mutually exclusive */
#define USE_PLATFORM_DELAY 0
#define USE_NDELAY 0
#define DUMMY_DELAY_ACCESS do {} while (0)
/* ------------------------------------------------------------------------- */
#define USB_RESET_WIDTH 50
#define MAX_XFER_SIZE 1023
/* Buffer sizes */
#define ISP1362_BUF_SIZE 4096
#define ISP1362_ISTL_BUFSIZE 512
#define ISP1362_INTL_BLKSIZE 64
#define ISP1362_INTL_BUFFERS 16
#define ISP1362_ATL_BLKSIZE 64
#define ISP1362_REG_WRITE_OFFSET 0x80
#define REG_WIDTH_16 0x000
#define REG_WIDTH_32 0x100
#define REG_WIDTH_MASK 0x100
#define REG_NO_MASK 0x0ff
#ifdef ISP1362_DEBUG
typedef const unsigned int isp1362_reg_t;
#define REG_ACCESS_R 0x200
#define REG_ACCESS_W 0x400
#define REG_ACCESS_RW 0x600
#define REG_ACCESS_MASK 0x600
#define ISP1362_REG_NO(r) ((r) & REG_NO_MASK)
#define ISP1362_REG(name, addr, width, rw) \
static isp1362_reg_t ISP1362_REG_##name = ((addr) | (width) | (rw))
#define REG_ACCESS_TEST(r) BUG_ON(((r) & ISP1362_REG_WRITE_OFFSET) && !((r) & REG_ACCESS_W))
#define REG_WIDTH_TEST(r, w) BUG_ON(((r) & REG_WIDTH_MASK) != (w))
#else
typedef const unsigned char isp1362_reg_t;
#define ISP1362_REG_NO(r) (r)
#define ISP1362_REG(name, addr, width, rw) \
static isp1362_reg_t __maybe_unused ISP1362_REG_##name = addr
#define REG_ACCESS_TEST(r) do {} while (0)
#define REG_WIDTH_TEST(r, w) do {} while (0)
#endif
/* OHCI compatible registers */
/*
* Note: Some of the ISP1362 'OHCI' registers implement only
* a subset of the bits defined in the OHCI spec.
*
* Bitmasks for the individual bits of these registers are defined in "ohci.h"
*/
ISP1362_REG(HCREVISION, 0x00, REG_WIDTH_32, REG_ACCESS_R);
ISP1362_REG(HCCONTROL, 0x01, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCCMDSTAT, 0x02, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCINTSTAT, 0x03, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCINTENB, 0x04, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCINTDIS, 0x05, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCFMINTVL, 0x0d, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCFMREM, 0x0e, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCFMNUM, 0x0f, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCLSTHRESH, 0x11, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCRHDESCA, 0x12, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCRHDESCB, 0x13, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCRHSTATUS, 0x14, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCRHPORT1, 0x15, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCRHPORT2, 0x16, REG_WIDTH_32, REG_ACCESS_RW);
/* Philips ISP1362 specific registers */
ISP1362_REG(HCHWCFG, 0x20, REG_WIDTH_16, REG_ACCESS_RW);
#define HCHWCFG_DISABLE_SUSPEND (1 << 15)
#define HCHWCFG_GLOBAL_PWRDOWN (1 << 14)
#define HCHWCFG_PULLDOWN_DS2 (1 << 13)
#define HCHWCFG_PULLDOWN_DS1 (1 << 12)
#define HCHWCFG_CLKNOTSTOP (1 << 11)
#define HCHWCFG_ANALOG_OC (1 << 10)
#define HCHWCFG_ONEINT (1 << 9)
#define HCHWCFG_DACK_MODE (1 << 8)
#define HCHWCFG_ONEDMA (1 << 7)
#define HCHWCFG_DACK_POL (1 << 6)
#define HCHWCFG_DREQ_POL (1 << 5)
#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
#define HCHWCFG_INT_POL (1 << 2)
#define HCHWCFG_INT_TRIGGER (1 << 1)
#define HCHWCFG_INT_ENABLE (1 << 0)
ISP1362_REG(HCDMACFG, 0x21, REG_WIDTH_16, REG_ACCESS_RW);
#define HCDMACFG_CTR_ENABLE (1 << 7)
#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
#define HCDMACFG_DMA_ENABLE (1 << 4)
#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
#define HCDMACFG_BUF_TYPE(n) (((n) << 1) & HCDMACFG_BUF_TYPE_MASK)
#define HCDMACFG_BUF_ISTL0 HCDMACFG_BUF_TYPE(0)
#define HCDMACFG_BUF_ISTL1 HCDMACFG_BUF_TYPE(1)
#define HCDMACFG_BUF_INTL HCDMACFG_BUF_TYPE(2)
#define HCDMACFG_BUF_ATL HCDMACFG_BUF_TYPE(3)
#define HCDMACFG_BUF_DIRECT HCDMACFG_BUF_TYPE(4)
#define HCDMACFG_DMA_RW_SELECT (1 << 0)
ISP1362_REG(HCXFERCTR, 0x22, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCuPINT, 0x24, REG_WIDTH_16, REG_ACCESS_RW);
#define HCuPINT_SOF (1 << 0)
#define HCuPINT_ISTL0 (1 << 1)
#define HCuPINT_ISTL1 (1 << 2)
#define HCuPINT_EOT (1 << 3)
#define HCuPINT_OPR (1 << 4)
#define HCuPINT_SUSP (1 << 5)
#define HCuPINT_CLKRDY (1 << 6)
#define HCuPINT_INTL (1 << 7)
#define HCuPINT_ATL (1 << 8)
#define HCuPINT_OTG (1 << 9)
ISP1362_REG(HCuPINTENB, 0x25, REG_WIDTH_16, REG_ACCESS_RW);
/* same bit definitions apply as for HCuPINT */
ISP1362_REG(HCCHIPID, 0x27, REG_WIDTH_16, REG_ACCESS_R);
#define HCCHIPID_MASK 0xff00
#define HCCHIPID_MAGIC 0x3600
ISP1362_REG(HCSCRATCH, 0x28, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCSWRES, 0x29, REG_WIDTH_16, REG_ACCESS_W);
#define HCSWRES_MAGIC 0x00f6
ISP1362_REG(HCBUFSTAT, 0x2c, REG_WIDTH_16, REG_ACCESS_RW);
#define HCBUFSTAT_ISTL0_FULL (1 << 0)
#define HCBUFSTAT_ISTL1_FULL (1 << 1)
#define HCBUFSTAT_INTL_ACTIVE (1 << 2)
#define HCBUFSTAT_ATL_ACTIVE (1 << 3)
#define HCBUFSTAT_RESET_HWPP (1 << 4)
#define HCBUFSTAT_ISTL0_ACTIVE (1 << 5)
#define HCBUFSTAT_ISTL1_ACTIVE (1 << 6)
#define HCBUFSTAT_ISTL0_DONE (1 << 8)
#define HCBUFSTAT_ISTL1_DONE (1 << 9)
#define HCBUFSTAT_PAIRED_PTDPP (1 << 10)
ISP1362_REG(HCDIRADDR, 0x32, REG_WIDTH_32, REG_ACCESS_RW);
#define HCDIRADDR_ADDR_MASK 0x0000ffff
#define HCDIRADDR_ADDR(n) (((n) << 0) & HCDIRADDR_ADDR_MASK)
#define HCDIRADDR_COUNT_MASK 0xffff0000
#define HCDIRADDR_COUNT(n) (((n) << 16) & HCDIRADDR_COUNT_MASK)
ISP1362_REG(HCDIRDATA, 0x45, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCISTLBUFSZ, 0x30, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCISTL0PORT, 0x40, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCISTL1PORT, 0x42, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCISTLRATE, 0x47, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCINTLBUFSZ, 0x33, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCINTLPORT, 0x43, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCINTLBLKSZ, 0x53, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCINTLDONE, 0x17, REG_WIDTH_32, REG_ACCESS_R);
ISP1362_REG(HCINTLSKIP, 0x18, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCINTLLAST, 0x19, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCINTLCURR, 0x1a, REG_WIDTH_16, REG_ACCESS_R);
ISP1362_REG(HCATLBUFSZ, 0x34, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCATLPORT, 0x44, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCATLBLKSZ, 0x54, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCATLDONE, 0x1b, REG_WIDTH_32, REG_ACCESS_R);
ISP1362_REG(HCATLSKIP, 0x1c, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCATLLAST, 0x1d, REG_WIDTH_32, REG_ACCESS_RW);
ISP1362_REG(HCATLCURR, 0x1e, REG_WIDTH_16, REG_ACCESS_R);
ISP1362_REG(HCATLDTC, 0x51, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(HCATLDTCTO, 0x52, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(OTGCONTROL, 0x62, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(OTGSTATUS, 0x67, REG_WIDTH_16, REG_ACCESS_R);
ISP1362_REG(OTGINT, 0x68, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(OTGINTENB, 0x69, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(OTGTIMER, 0x6A, REG_WIDTH_16, REG_ACCESS_RW);
ISP1362_REG(OTGALTTMR, 0x6C, REG_WIDTH_16, REG_ACCESS_RW);
/* Philips transfer descriptor, cpu-endian */
struct ptd {
u16 count;
#define PTD_COUNT_MSK (0x3ff << 0)
#define PTD_TOGGLE_MSK (1 << 10)
#define PTD_ACTIVE_MSK (1 << 11)
#define PTD_CC_MSK (0xf << 12)
u16 mps;
#define PTD_MPS_MSK (0x3ff << 0)
#define PTD_SPD_MSK (1 << 10)
#define PTD_LAST_MSK (1 << 11)
#define PTD_EP_MSK (0xf << 12)
u16 len;
#define PTD_LEN_MSK (0x3ff << 0)
#define PTD_DIR_MSK (3 << 10)
#define PTD_DIR_SETUP (0)
#define PTD_DIR_OUT (1)
#define PTD_DIR_IN (2)
u16 faddr;
#define PTD_FA_MSK (0x7f << 0)
/* PTD Byte 7: [StartingFrame (if ISO PTD) | StartingFrame[0..4], PollingRate[0..2] (if INT PTD)] */
#define PTD_SF_ISO_MSK (0xff << 8)
#define PTD_SF_INT_MSK (0x1f << 8)
#define PTD_PR_MSK (0x07 << 13)
} __attribute__ ((packed, aligned(2)));
#define PTD_HEADER_SIZE sizeof(struct ptd)
/* ------------------------------------------------------------------------- */
/* Copied from ohci.h: */
/*
* Hardware transfer status codes -- CC from PTD
*/
#define PTD_CC_NOERROR 0x00
#define PTD_CC_CRC 0x01
#define PTD_CC_BITSTUFFING 0x02
#define PTD_CC_DATATOGGLEM 0x03
#define PTD_CC_STALL 0x04
#define PTD_DEVNOTRESP 0x05
#define PTD_PIDCHECKFAIL 0x06
#define PTD_UNEXPECTEDPID 0x07
#define PTD_DATAOVERRUN 0x08
#define PTD_DATAUNDERRUN 0x09
/* 0x0A, 0x0B reserved for hardware */
#define PTD_BUFFEROVERRUN 0x0C
#define PTD_BUFFERUNDERRUN 0x0D
/* 0x0E, 0x0F reserved for HCD */
#define PTD_NOTACCESSED 0x0F
/* map OHCI TD status codes (CC) to errno values */
static const int cc_to_error[16] = {
/* No Error */ 0,
/* CRC Error */ -EILSEQ,
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
/* DevNotResp */ -ETIMEDOUT,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
/* DataUnder */ -EREMOTEIO,
/* (for hw) */ -EIO,
/* (for hw) */ -EIO,
/* BufferOver */ -ECOMM,
/* BuffUnder */ -ENOSR,
/* (for HCD) */ -EALREADY,
/* (for HCD) */ -EALREADY
};
/*
* HcControl (control) register masks
*/
#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
/* pre-shifted values for HCFS */
# define OHCI_USB_RESET (0 << 6)
# define OHCI_USB_RESUME (1 << 6)
# define OHCI_USB_OPER (2 << 6)
# define OHCI_USB_SUSPEND (3 << 6)
/*
* HcCommandStatus (cmdstatus) register masks
*/
#define OHCI_HCR (1 << 0) /* host controller reset */
#define OHCI_SOC (3 << 16) /* scheduling overrun count */
/*
* masks used with interrupt registers:
* HcInterruptStatus (intrstatus)
* HcInterruptEnable (intrenable)
* HcInterruptDisable (intrdisable)
*/
#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
#define OHCI_INTR_SF (1 << 2) /* start frame */
#define OHCI_INTR_RD (1 << 3) /* resume detect */
#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
#define OHCI_INTR_OC (1 << 30) /* ownership change */
#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
/* roothub.portstatus [i] bits */
#define RH_PS_CCS 0x00000001 /* current connect status */
#define RH_PS_PES 0x00000002 /* port enable status*/
#define RH_PS_PSS 0x00000004 /* port suspend status */
#define RH_PS_POCI 0x00000008 /* port over current indicator */
#define RH_PS_PRS 0x00000010 /* port reset status */
#define RH_PS_PPS 0x00000100 /* port power status */
#define RH_PS_LSDA 0x00000200 /* low speed device attached */
#define RH_PS_CSC 0x00010000 /* connect status change */
#define RH_PS_PESC 0x00020000 /* port enable status change */
#define RH_PS_PSSC 0x00040000 /* port suspend status change */
#define RH_PS_OCIC 0x00080000 /* over current indicator change */
#define RH_PS_PRSC 0x00100000 /* port reset status change */
/* roothub.status bits */
#define RH_HS_LPS 0x00000001 /* local power status */
#define RH_HS_OCI 0x00000002 /* over current indicator */
#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
#define RH_HS_LPSC 0x00010000 /* local power status change */
#define RH_HS_OCIC 0x00020000 /* over current indicator change */
#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
/* roothub.b masks */
#define RH_B_DR 0x0000ffff /* device removable flags */
#define RH_B_PPCM 0xffff0000 /* port power control mask */
/* roothub.a masks */
#define RH_A_NDP (0xff << 0) /* number of downstream ports */
#define RH_A_PSM (1 << 8) /* power switching mode */
#define RH_A_NPS (1 << 9) /* no power switching */
#define RH_A_DT (1 << 10) /* device type (mbz) */
#define RH_A_OCPM (1 << 11) /* over current protection mode */
#define RH_A_NOCP (1 << 12) /* no over current protection */
#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
#define FI 0x2edf /* 12000 bits per frame (-1) */
#define FSMP(fi) (0x7fff & ((6 * ((fi) - 210)) / 7))
#define LSTHRESH 0x628 /* lowspeed bit threshold */
/* ------------------------------------------------------------------------- */
/* PTD accessor macros. */
#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
#define PTD_GET_SF_INT(p) (((p)->faddr & PTD_SF_INT_MSK) >> 8)
#define PTD_SF_INT(v) (((v) << 8) & PTD_SF_INT_MSK)
#define PTD_GET_SF_ISO(p) (((p)->faddr & PTD_SF_ISO_MSK) >> 8)
#define PTD_SF_ISO(v) (((v) << 8) & PTD_SF_ISO_MSK)
#define PTD_GET_PR(p) (((p)->faddr & PTD_PR_MSK) >> 13)
#define PTD_PR(v) (((v) << 13) & PTD_PR_MSK)
#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
struct isp1362_ep {
struct usb_host_endpoint *hep;
struct usb_device *udev;
/* philips transfer descriptor */
struct ptd ptd;
u8 maxpacket;
u8 epnum;
u8 nextpid;
u16 error_count;
u16 length; /* of current packet */
s16 ptd_offset; /* buffer offset in ISP1362 where
PTD has been stored
(for access thru HCDIRDATA) */
int ptd_index;
int num_ptds;
void *data; /* to databuf */
/* queue of active EPs (the ones transmitted to the chip) */
struct list_head active;
/* periodic schedule */
u8 branch;
u16 interval;
u16 load;
u16 last_iso;
/* async schedule */
struct list_head schedule; /* list of all EPs that need processing */
struct list_head remove_list;
int num_req;
};
struct isp1362_ep_queue {
struct list_head active; /* list of PTDs currently processed by HC */
atomic_t finishing;
unsigned long buf_map;
unsigned long skip_map;
int free_ptd;
u16 buf_start;
u16 buf_size;
u16 blk_size; /* PTD buffer block size for ATL and INTL */
u8 buf_count;
u8 buf_avail;
char name[16];
/* for statistical tracking */
u8 stat_maxptds; /* Max # of ptds seen simultaneously in fifo */
u8 ptd_count; /* number of ptds submitted to this queue */
};
struct isp1362_hcd {
spinlock_t lock;
void __iomem *addr_reg;
void __iomem *data_reg;
struct isp1362_platform_data *board;
unsigned long stat1, stat2, stat4, stat8, stat16;
/* HC registers */
u32 intenb; /* "OHCI" interrupts */
u16 irqenb; /* uP interrupts */
/* Root hub registers */
u32 rhdesca;
u32 rhdescb;
u32 rhstatus;
u32 rhport[MAX_ROOT_PORTS];
unsigned long next_statechange;
/* HC control reg shadow copy */
u32 hc_control;
/* async schedule: control, bulk */
struct list_head async;
/* periodic schedule: int */
u16 load[PERIODIC_SIZE];
struct list_head periodic;
u16 fmindex;
/* periodic schedule: isochronous */
struct list_head isoc;
unsigned int istl_flip:1;
unsigned int irq_active:1;
/* Schedules for the current frame */
struct isp1362_ep_queue atl_queue;
struct isp1362_ep_queue intl_queue;
struct isp1362_ep_queue istl_queue[2];
/* list of PTDs retrieved from HC */
struct list_head remove_list;
enum {
ISP1362_INT_SOF,
ISP1362_INT_ISTL0,
ISP1362_INT_ISTL1,
ISP1362_INT_EOT,
ISP1362_INT_OPR,
ISP1362_INT_SUSP,
ISP1362_INT_CLKRDY,
ISP1362_INT_INTL,
ISP1362_INT_ATL,
ISP1362_INT_OTG,
NUM_ISP1362_IRQS
} IRQ_NAMES;
unsigned int irq_stat[NUM_ISP1362_IRQS];
int req_serial;
};
static inline const char *ISP1362_INT_NAME(int n)
{
switch (n) {
case ISP1362_INT_SOF: return "SOF";
case ISP1362_INT_ISTL0: return "ISTL0";
case ISP1362_INT_ISTL1: return "ISTL1";
case ISP1362_INT_EOT: return "EOT";
case ISP1362_INT_OPR: return "OPR";
case ISP1362_INT_SUSP: return "SUSP";
case ISP1362_INT_CLKRDY: return "CLKRDY";
case ISP1362_INT_INTL: return "INTL";
case ISP1362_INT_ATL: return "ATL";
case ISP1362_INT_OTG: return "OTG";
default: return "unknown";
}
}
static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr)
{
unsigned long p = (unsigned long)ptr;
if (!(p & 0xf))
isp1362_hcd->stat16++;
else if (!(p & 0x7))
isp1362_hcd->stat8++;
else if (!(p & 0x3))
isp1362_hcd->stat4++;
else if (!(p & 0x1))
isp1362_hcd->stat2++;
else
isp1362_hcd->stat1++;
}
static inline struct isp1362_hcd *hcd_to_isp1362_hcd(struct usb_hcd *hcd)
{
return (struct isp1362_hcd *) (hcd->hcd_priv);
}
static inline struct usb_hcd *isp1362_hcd_to_hcd(struct isp1362_hcd *isp1362_hcd)
{
return container_of((void *)isp1362_hcd, struct usb_hcd, hcd_priv);
}
#define frame_before(f1, f2) ((s16)((u16)f1 - (u16)f2) < 0)
/*
* ISP1362 HW Interface
*/
#define DBG(level, fmt...) \
do { \
if (dbg_level > level) \
pr_debug(fmt); \
} while (0)
#ifdef VERBOSE
# define VDBG(fmt...) DBG(3, fmt)
#else
# define VDBG(fmt...) do {} while (0)
#endif
#ifdef REGISTERS
# define RDBG(fmt...) DBG(1, fmt)
#else
# define RDBG(fmt...) do {} while (0)
#endif
#ifdef URB_TRACE
#define URB_DBG(fmt...) DBG(0, fmt)
#else
#define URB_DBG(fmt...) do {} while (0)
#endif
#if USE_PLATFORM_DELAY
#if USE_NDELAY
#error USE_PLATFORM_DELAY and USE_NDELAY defined simultaneously.
#endif
#define isp1362_delay(h, d) (h)->board->delay(isp1362_hcd_to_hcd(h)->self.controller, d)
#elif USE_NDELAY
#define isp1362_delay(h, d) ndelay(d)
#else
#define isp1362_delay(h, d) do {} while (0)
#endif
#define get_urb(ep) ({ \
BUG_ON(list_empty(&ep->hep->urb_list)); \
container_of(ep->hep->urb_list.next, struct urb, urb_list); \
})
/* basic access functions for ISP1362 chip registers */
/* NOTE: The contents of the address pointer register cannot be read back! The driver must ensure,
* that all register accesses are performed with interrupts disabled, since the interrupt
* handler has no way of restoring the previous state.
*/
static void isp1362_write_addr(struct isp1362_hcd *isp1362_hcd, isp1362_reg_t reg)
{
REG_ACCESS_TEST(reg);
DUMMY_DELAY_ACCESS;
writew(ISP1362_REG_NO(reg), isp1362_hcd->addr_reg);
DUMMY_DELAY_ACCESS;
isp1362_delay(isp1362_hcd, 1);
}
static void isp1362_write_data16(struct isp1362_hcd *isp1362_hcd, u16 val)
{
DUMMY_DELAY_ACCESS;
writew(val, isp1362_hcd->data_reg);
}
static u16 isp1362_read_data16(struct isp1362_hcd *isp1362_hcd)
{
u16 val;
DUMMY_DELAY_ACCESS;
val = readw(isp1362_hcd->data_reg);
return val;
}
static void isp1362_write_data32(struct isp1362_hcd *isp1362_hcd, u32 val)
{
#if USE_32BIT
DUMMY_DELAY_ACCESS;
writel(val, isp1362_hcd->data_reg);
#else
DUMMY_DELAY_ACCESS;
writew((u16)val, isp1362_hcd->data_reg);
DUMMY_DELAY_ACCESS;
writew(val >> 16, isp1362_hcd->data_reg);
#endif
}
static u32 isp1362_read_data32(struct isp1362_hcd *isp1362_hcd)
{
u32 val;
#if USE_32BIT
DUMMY_DELAY_ACCESS;
val = readl(isp1362_hcd->data_reg);
#else
DUMMY_DELAY_ACCESS;
val = (u32)readw(isp1362_hcd->data_reg);
DUMMY_DELAY_ACCESS;
val |= (u32)readw(isp1362_hcd->data_reg) << 16;
#endif
return val;
}
/* use readsw/writesw to access the fifo whenever possible */
/* assume HCDIRDATA or XFERCTR & addr_reg have been set up */
static void isp1362_read_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 len)
{
u8 *dp = buf;
u16 data;
if (!len)
return;
RDBG("%s: Reading %d byte from fifo to mem @ %p\n", __func__, len, buf);
#if USE_32BIT
if (len >= 4) {
RDBG("%s: Using readsl for %d dwords\n", __func__, len >> 2);
readsl(isp1362_hcd->data_reg, dp, len >> 2);
dp += len & ~3;
len &= 3;
}
#endif
if (len >= 2) {
RDBG("%s: Using readsw for %d words\n", __func__, len >> 1);
insw((unsigned long)isp1362_hcd->data_reg, dp, len >> 1);
dp += len & ~1;
len &= 1;
}
BUG_ON(len & ~1);
if (len > 0) {
data = isp1362_read_data16(isp1362_hcd);
RDBG("%s: Reading trailing byte %02x to mem @ %08x\n", __func__,
(u8)data, (u32)dp);
*dp = (u8)data;
}
}
static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 len)
{
u8 *dp = buf;
u16 data;
if (!len)
return;
if ((unsigned long)dp & 0x1) {
/* not aligned */
for (; len > 1; len -= 2) {
data = *dp++;
data |= *dp++ << 8;
isp1362_write_data16(isp1362_hcd, data);
}
if (len)
isp1362_write_data16(isp1362_hcd, *dp);
return;
}
RDBG("%s: Writing %d byte to fifo from memory @%p\n", __func__, len, buf);
#if USE_32BIT
if (len >= 4) {
RDBG("%s: Using writesl for %d dwords\n", __func__, len >> 2);
writesl(isp1362_hcd->data_reg, dp, len >> 2);
dp += len & ~3;
len &= 3;
}
#endif
if (len >= 2) {
RDBG("%s: Using writesw for %d words\n", __func__, len >> 1);
outsw((unsigned long)isp1362_hcd->data_reg, dp, len >> 1);
dp += len & ~1;
len &= 1;
}
BUG_ON(len & ~1);
if (len > 0) {
/* finally write any trailing byte; we don't need to care
* about the high byte of the last word written
*/
data = (u16)*dp;
RDBG("%s: Sending trailing byte %02x from mem @ %08x\n", __func__,
data, (u32)dp);
isp1362_write_data16(isp1362_hcd, data);
}
}
#define isp1362_read_reg16(d, r) ({ \
u16 __v; \
REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_16); \
isp1362_write_addr(d, ISP1362_REG_##r); \
__v = isp1362_read_data16(d); \
RDBG("%s: Read %04x from %s[%02x]\n", __func__, __v, #r, \
ISP1362_REG_NO(ISP1362_REG_##r)); \
__v; \
})
#define isp1362_read_reg32(d, r) ({ \
u32 __v; \
REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_32); \
isp1362_write_addr(d, ISP1362_REG_##r); \
__v = isp1362_read_data32(d); \
RDBG("%s: Read %08x from %s[%02x]\n", __func__, __v, #r, \
ISP1362_REG_NO(ISP1362_REG_##r)); \
__v; \
})
#define isp1362_write_reg16(d, r, v) { \
REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_16); \
isp1362_write_addr(d, (ISP1362_REG_##r) | ISP1362_REG_WRITE_OFFSET); \
isp1362_write_data16(d, (u16)(v)); \
RDBG("%s: Wrote %04x to %s[%02x]\n", __func__, (u16)(v), #r, \
ISP1362_REG_NO(ISP1362_REG_##r)); \
}
#define isp1362_write_reg32(d, r, v) { \
REG_WIDTH_TEST(ISP1362_REG_##r, REG_WIDTH_32); \
isp1362_write_addr(d, (ISP1362_REG_##r) | ISP1362_REG_WRITE_OFFSET); \
isp1362_write_data32(d, (u32)(v)); \
RDBG("%s: Wrote %08x to %s[%02x]\n", __func__, (u32)(v), #r, \
ISP1362_REG_NO(ISP1362_REG_##r)); \
}
#define isp1362_set_mask16(d, r, m) { \
u16 __v; \
__v = isp1362_read_reg16(d, r); \
if ((__v | m) != __v) \
isp1362_write_reg16(d, r, __v | m); \
}
#define isp1362_clr_mask16(d, r, m) { \
u16 __v; \
__v = isp1362_read_reg16(d, r); \
if ((__v & ~m) != __v) \
isp1362_write_reg16(d, r, __v & ~m); \
}
#define isp1362_set_mask32(d, r, m) { \
u32 __v; \
__v = isp1362_read_reg32(d, r); \
if ((__v | m) != __v) \
isp1362_write_reg32(d, r, __v | m); \
}
#define isp1362_clr_mask32(d, r, m) { \
u32 __v; \
__v = isp1362_read_reg32(d, r); \
if ((__v & ~m) != __v) \
isp1362_write_reg32(d, r, __v & ~m); \
}
#define isp1362_show_reg(d, r) { \
if ((ISP1362_REG_##r & REG_WIDTH_MASK) == REG_WIDTH_32) \
DBG(0, "%-12s[%02x]: %08x\n", #r, \
ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg32(d, r)); \
else \
DBG(0, "%-12s[%02x]: %04x\n", #r, \
ISP1362_REG_NO(ISP1362_REG_##r), isp1362_read_reg16(d, r)); \
}
static void isp1362_write_diraddr(struct isp1362_hcd *isp1362_hcd, u16 offset, u16 len)
{
len = (len + 1) & ~1;
isp1362_clr_mask16(isp1362_hcd, HCDMACFG, HCDMACFG_CTR_ENABLE);
isp1362_write_reg32(isp1362_hcd, HCDIRADDR,
HCDIRADDR_ADDR(offset) | HCDIRADDR_COUNT(len));
}
static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
{
isp1362_write_diraddr(isp1362_hcd, offset, len);
DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
__func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA);
isp1362_read_fifo(isp1362_hcd, buf, len);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
}
static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16 offset, int len)
{
isp1362_write_diraddr(isp1362_hcd, offset, len);
DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
__func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
isp1362_write_addr(isp1362_hcd, ISP1362_REG_HCDIRDATA | ISP1362_REG_WRITE_OFFSET);
isp1362_write_fifo(isp1362_hcd, buf, len);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
}
static void __attribute__((unused)) dump_data(char *buf, int len)
{
if (dbg_level > 0) {
int k;
int lf = 0;
for (k = 0; k < len; ++k) {
if (!lf)
DBG(0, "%04x:", k);
printk(" %02x", ((u8 *) buf)[k]);
lf = 1;
if (!k)
continue;
if (k % 16 == 15) {
printk("\n");
lf = 0;
continue;
}
if (k % 8 == 7)
printk(" ");
if (k % 4 == 3)
printk(" ");
}
if (lf)
printk("\n");
}
}
#if defined(PTD_TRACE)
static void dump_ptd(struct ptd *ptd)
{
DBG(0, "EP %p: CC=%x EP=%d DIR=%x CNT=%d LEN=%d MPS=%d TGL=%x ACT=%x FA=%d SPD=%x SF=%x PR=%x LST=%x\n",
container_of(ptd, struct isp1362_ep, ptd),
PTD_GET_CC(ptd), PTD_GET_EP(ptd), PTD_GET_DIR(ptd),
PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd), PTD_GET_FA(ptd),
PTD_GET_SPD(ptd), PTD_GET_SF_INT(ptd), PTD_GET_PR(ptd), PTD_GET_LAST(ptd));
DBG(0, " %04x %04x %04x %04x\n", ptd->count, ptd->mps, ptd->len, ptd->faddr);
}
static void dump_ptd_out_data(struct ptd *ptd, u8 *buf)
{
if (dbg_level > 0) {
if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
DBG(0, "--out->\n");
dump_data(buf, PTD_GET_LEN(ptd));
}
}
}
static void dump_ptd_in_data(struct ptd *ptd, u8 *buf)
{
if (dbg_level > 0) {
if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
DBG(0, "<--in--\n");
dump_data(buf, PTD_GET_COUNT(ptd));
}
DBG(0, "-----\n");
}
}
static void dump_ptd_queue(struct isp1362_ep_queue *epq)
{
struct isp1362_ep *ep;
int dbg = dbg_level;
dbg_level = 1;
list_for_each_entry(ep, &epq->active, active) {
dump_ptd(&ep->ptd);
dump_data(ep->data, ep->length);
}
dbg_level = dbg;
}
#else
#define dump_ptd(ptd) do {} while (0)
#define dump_ptd_in_data(ptd, buf) do {} while (0)
#define dump_ptd_out_data(ptd, buf) do {} while (0)
#define dump_ptd_data(ptd, buf) do {} while (0)
#define dump_ptd_queue(epq) do {} while (0)
#endif
-3
View File
@@ -1282,7 +1282,6 @@ static int __init ohci_hcd_mod_init(void)
pr_debug ("%s: block sizes: ed %zd td %zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
@@ -1332,7 +1331,6 @@ static int __init ohci_hcd_mod_init(void)
debugfs_remove(ohci_debug_root);
ohci_debug_root = NULL;
clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
return retval;
}
module_init(ohci_hcd_mod_init);
@@ -1352,7 +1350,6 @@ static void __exit ohci_hcd_mod_exit(void)
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
#endif
debugfs_remove(ohci_debug_root);
clear_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
}
module_exit(ohci_hcd_mod_exit);
-5
View File
@@ -867,8 +867,6 @@ static int __init uhci_hcd_init(void)
if (usb_disabled())
return -ENODEV;
set_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
#ifdef CONFIG_DYNAMIC_DEBUG
errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
if (!errbuf)
@@ -912,8 +910,6 @@ up_failed:
errbuf_failed:
#endif
clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
return retval;
}
@@ -930,7 +926,6 @@ static void __exit uhci_hcd_cleanup(void)
#ifdef CONFIG_DYNAMIC_DEBUG
kfree(errbuf);
#endif
clear_bit(USB_UHCI_LOADED, &usb_hcds_loaded);
}
module_init(uhci_hcd_init);
+192 -67
View File
@@ -29,6 +29,12 @@
#include "xhci-trace.h"
#include "xhci-dbgcap.h"
static const struct dbc_str dbc_str_default = {
.manufacturer = "Linux Foundation",
.product = "Linux USB Debug Target",
.serial = "0001",
};
static void dbc_free_ctx(struct device *dev, struct xhci_container_ctx *ctx)
{
if (!ctx)
@@ -52,55 +58,6 @@ static void dbc_ring_free(struct device *dev, struct xhci_ring *ring)
kfree(ring);
}
static u32 xhci_dbc_populate_strings(struct dbc_str_descs *strings)
{
struct usb_string_descriptor *s_desc;
u32 string_length;
/* Serial string: */
s_desc = (struct usb_string_descriptor *)strings->serial;
utf8s_to_utf16s(DBC_STRING_SERIAL, strlen(DBC_STRING_SERIAL),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_SERIAL) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length = s_desc->bLength;
string_length <<= 8;
/* Product string: */
s_desc = (struct usb_string_descriptor *)strings->product;
utf8s_to_utf16s(DBC_STRING_PRODUCT, strlen(DBC_STRING_PRODUCT),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_PRODUCT) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* Manufacture string: */
s_desc = (struct usb_string_descriptor *)strings->manufacturer;
utf8s_to_utf16s(DBC_STRING_MANUFACTURER,
strlen(DBC_STRING_MANUFACTURER),
UTF16_LITTLE_ENDIAN, (wchar_t *)s_desc->wData,
DBC_MAX_STRING_LENGTH);
s_desc->bLength = (strlen(DBC_STRING_MANUFACTURER) + 1) * 2;
s_desc->bDescriptorType = USB_DT_STRING;
string_length += s_desc->bLength;
string_length <<= 8;
/* String0: */
strings->string0[0] = 4;
strings->string0[1] = USB_DT_STRING;
strings->string0[2] = 0x09;
strings->string0[3] = 0x04;
string_length += 4;
return string_length;
}
static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc)
{
struct xhci_ep_ctx *ep_ctx;
@@ -124,7 +81,65 @@ static void xhci_dbc_init_ep_contexts(struct xhci_dbc *dbc)
ep_ctx->deq = cpu_to_le64(deq | dbc->ring_in->cycle_state);
}
static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
static u8 get_str_desc_len(const char *desc)
{
return ((struct usb_string_descriptor *)desc)->bLength;
}
static u32 dbc_prepare_info_context_str_len(struct dbc_str_descs *descs)
{
u32 len;
len = get_str_desc_len(descs->serial);
len <<= 8;
len += get_str_desc_len(descs->product);
len <<= 8;
len += get_str_desc_len(descs->manufacturer);
len <<= 8;
len += get_str_desc_len(descs->string0);
return len;
}
static int xhci_dbc_populate_str_desc(char *desc, const char *src)
{
struct usb_string_descriptor *s_desc;
int len;
s_desc = (struct usb_string_descriptor *)desc;
/* len holds number of 2 byte UTF-16 characters */
len = utf8s_to_utf16s(src, strlen(src), UTF16_LITTLE_ENDIAN,
(wchar_t *)s_desc->wData, USB_MAX_STRING_LEN * 2);
if (len < 0)
return len;
s_desc->bLength = len * 2 + 2;
s_desc->bDescriptorType = USB_DT_STRING;
return s_desc->bLength;
}
static void xhci_dbc_populate_str_descs(struct dbc_str_descs *str_descs,
struct dbc_str *str)
{
/* Serial string: */
xhci_dbc_populate_str_desc(str_descs->serial, str->serial);
/* Product string: */
xhci_dbc_populate_str_desc(str_descs->product, str->product);
/* Manufacturer string: */
xhci_dbc_populate_str_desc(str_descs->manufacturer, str->manufacturer);
/* String0: */
str_descs->string0[0] = 4;
str_descs->string0[1] = USB_DT_STRING;
str_descs->string0[2] = 0x09;
str_descs->string0[3] = 0x04;
}
static void xhci_dbc_init_contexts(struct xhci_dbc *dbc)
{
struct dbc_info_context *info;
u32 dev_info;
@@ -135,12 +150,12 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length)
/* Populate info Context: */
info = (struct dbc_info_context *)dbc->ctx->bytes;
dma = dbc->string_dma;
dma = dbc->str_descs_dma;
info->string0 = cpu_to_le64(dma);
info->manufacturer = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH);
info->product = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 2);
info->serial = cpu_to_le64(dma + DBC_MAX_STRING_LENGTH * 3);
info->length = cpu_to_le32(string_length);
info->manufacturer = cpu_to_le64(dma + USB_MAX_STRING_DESC_LEN);
info->product = cpu_to_le64(dma + USB_MAX_STRING_DESC_LEN * 2);
info->serial = cpu_to_le64(dma + USB_MAX_STRING_DESC_LEN * 3);
info->length = cpu_to_le32(dbc_prepare_info_context_str_len(dbc->str_descs));
/* Populate bulk in and out endpoint contexts: */
xhci_dbc_init_ep_contexts(dbc);
@@ -525,7 +540,6 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags)
{
int ret;
dma_addr_t deq;
u32 string_length;
struct device *dev = dbc->dev;
/* Allocate various rings for events and transfers: */
@@ -552,11 +566,11 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags)
goto ctx_fail;
/* Allocate the string table: */
dbc->string_size = sizeof(*dbc->string);
dbc->string = dma_alloc_coherent(dev, dbc->string_size,
&dbc->string_dma, flags);
if (!dbc->string)
goto string_fail;
dbc->str_descs_size = sizeof(*dbc->str_descs);
dbc->str_descs = dma_alloc_coherent(dev, dbc->str_descs_size,
&dbc->str_descs_dma, flags);
if (!dbc->str_descs)
goto str_descs_fail;
/* Setup ERST register: */
writel(dbc->erst.num_entries, &dbc->regs->ersts);
@@ -566,16 +580,16 @@ static int xhci_dbc_mem_init(struct xhci_dbc *dbc, gfp_t flags)
dbc->ring_evt->dequeue);
lo_hi_writeq(deq, &dbc->regs->erdp);
/* Setup strings and contexts: */
string_length = xhci_dbc_populate_strings(dbc->string);
xhci_dbc_init_contexts(dbc, string_length);
/* Setup string descriptors and contexts: */
xhci_dbc_populate_str_descs(dbc->str_descs, &dbc->str);
xhci_dbc_init_contexts(dbc);
xhci_dbc_eps_init(dbc);
dbc->state = DS_INITIALIZED;
return 0;
string_fail:
str_descs_fail:
dbc_free_ctx(dev, dbc->ctx);
dbc->ctx = NULL;
ctx_fail:
@@ -600,8 +614,8 @@ static void xhci_dbc_mem_cleanup(struct xhci_dbc *dbc)
xhci_dbc_eps_exit(dbc);
dma_free_coherent(dbc->dev, dbc->string_size, dbc->string, dbc->string_dma);
dbc->string = NULL;
dma_free_coherent(dbc->dev, dbc->str_descs_size, dbc->str_descs, dbc->str_descs_dma);
dbc->str_descs = NULL;
dbc_free_ctx(dbc->dev, dbc->ctx);
dbc->ctx = NULL;
@@ -1196,6 +1210,108 @@ static ssize_t dbc_bcdDevice_store(struct device *dev,
return size;
}
static ssize_t dbc_manufacturer_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
return sysfs_emit(buf, "%s\n", dbc->str.manufacturer);
}
static ssize_t dbc_manufacturer_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
size_t len;
if (dbc->state != DS_DISABLED)
return -EBUSY;
len = strcspn(buf, "\n");
if (!len)
return -EINVAL;
if (len > USB_MAX_STRING_LEN)
return -E2BIG;
memcpy(dbc->str.manufacturer, buf, len);
dbc->str.manufacturer[len] = '\0';
return size;
}
static ssize_t dbc_product_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
return sysfs_emit(buf, "%s\n", dbc->str.product);
}
static ssize_t dbc_product_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
size_t len;
if (dbc->state != DS_DISABLED)
return -EBUSY;
len = strcspn(buf, "\n");
if (!len)
return -EINVAL;
if (len > USB_MAX_STRING_LEN)
return -E2BIG;
memcpy(dbc->str.product, buf, len);
dbc->str.product[len] = '\0';
return size;
}
static ssize_t dbc_serial_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
return sysfs_emit(buf, "%s\n", dbc->str.serial);
}
static ssize_t dbc_serial_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
struct xhci_hcd *xhci = hcd_to_xhci(dev_get_drvdata(dev));
struct xhci_dbc *dbc = xhci->dbc;
size_t len;
if (dbc->state != DS_DISABLED)
return -EBUSY;
len = strcspn(buf, "\n");
if (!len)
return -EINVAL;
if (len > USB_MAX_STRING_LEN)
return -E2BIG;
memcpy(dbc->str.serial, buf, len);
dbc->str.serial[len] = '\0';
return size;
}
static ssize_t dbc_bInterfaceProtocol_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -1283,6 +1399,9 @@ static DEVICE_ATTR_RW(dbc);
static DEVICE_ATTR_RW(dbc_idVendor);
static DEVICE_ATTR_RW(dbc_idProduct);
static DEVICE_ATTR_RW(dbc_bcdDevice);
static DEVICE_ATTR_RW(dbc_serial);
static DEVICE_ATTR_RW(dbc_product);
static DEVICE_ATTR_RW(dbc_manufacturer);
static DEVICE_ATTR_RW(dbc_bInterfaceProtocol);
static DEVICE_ATTR_RW(dbc_poll_interval_ms);
@@ -1291,6 +1410,9 @@ static struct attribute *dbc_dev_attrs[] = {
&dev_attr_dbc_idVendor.attr,
&dev_attr_dbc_idProduct.attr,
&dev_attr_dbc_bcdDevice.attr,
&dev_attr_dbc_serial.attr,
&dev_attr_dbc_product.attr,
&dev_attr_dbc_manufacturer.attr,
&dev_attr_dbc_bInterfaceProtocol.attr,
&dev_attr_dbc_poll_interval_ms.attr,
NULL
@@ -1316,6 +1438,9 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *
dbc->bInterfaceProtocol = DBC_PROTOCOL;
dbc->poll_interval = DBC_POLL_INTERVAL_DEFAULT;
/* initialize serial, product and manufacturer with default values */
dbc->str = dbc_str_default;
if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE)
goto err;
+28 -11
View File
@@ -47,10 +47,6 @@ struct dbc_info_context {
#define DBC_DOOR_BELL_TARGET(p) (((p) & 0xff) << 8)
#define DBC_MAX_PACKET 1024
#define DBC_MAX_STRING_LENGTH 64
#define DBC_STRING_MANUFACTURER "Linux Foundation"
#define DBC_STRING_PRODUCT "Linux USB Debug Target"
#define DBC_STRING_SERIAL "0001"
#define DBC_CONTEXT_SIZE 64
/*
@@ -63,11 +59,31 @@ struct dbc_info_context {
#define DBC_PORTSC_LINK_CHANGE BIT(22)
#define DBC_PORTSC_CONFIG_CHANGE BIT(23)
/*
* The maximum length of a string descriptor is 255, because the bLength
* field in the usb_string_descriptor struct is __u8. In practice the
* maximum length is 254, because a string descriptor consists of a 2 byte
* header followed by UTF-16 characters (2 bytes each). This allows for
* only 126 characters (code points) in the string, which is where
* USB_MAX_STRING_LEN comes from.
*/
#define USB_MAX_STRING_DESC_LEN 254
struct dbc_str_descs {
char string0[DBC_MAX_STRING_LENGTH];
char manufacturer[DBC_MAX_STRING_LENGTH];
char product[DBC_MAX_STRING_LENGTH];
char serial[DBC_MAX_STRING_LENGTH];
char string0[USB_MAX_STRING_DESC_LEN];
char manufacturer[USB_MAX_STRING_DESC_LEN];
char product[USB_MAX_STRING_DESC_LEN];
char serial[USB_MAX_STRING_DESC_LEN];
};
/*
* NULL terminated UTF-8 strings used to create UTF-16 strings
* (with maxiumum USB_MAX_STRING_LEN 2 byte characters).
*/
struct dbc_str {
char manufacturer[USB_MAX_STRING_LEN+1];
char product[USB_MAX_STRING_LEN+1];
char serial[USB_MAX_STRING_LEN+1];
};
#define DBC_PROTOCOL 1 /* GNU Remote Debug Command */
@@ -133,9 +149,10 @@ struct xhci_dbc {
struct xhci_erst erst;
struct xhci_container_ctx *ctx;
struct dbc_str_descs *string;
dma_addr_t string_dma;
size_t string_size;
struct dbc_str_descs *str_descs;
dma_addr_t str_descs_dma;
size_t str_descs_size;
struct dbc_str str;
u16 idVendor;
u16 idProduct;
u16 bcdDevice;
+1
View File
@@ -3195,6 +3195,7 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
if (status & STS_HCE) {
xhci_warn(xhci, "WARNING: Host Controller Error\n");
xhci_halt(xhci);
goto out;
}
+3 -15
View File
@@ -93,8 +93,6 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e
static void
__xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
{
struct usb_device *udev;
lockdep_assert_held(&sb->mutex);
if (!sb->ir)
@@ -102,10 +100,6 @@ __xhci_sideband_remove_interrupter(struct xhci_sideband *sb)
xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir);
sb->ir = NULL;
udev = sb->vdev->udev;
if (udev->state != USB_STATE_NOTATTACHED)
usb_offload_put(udev);
}
/* sideband api functions */
@@ -291,8 +285,8 @@ EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer);
* Allow other drivers, such as usb controller driver, to check if there are
* any sideband activity on the host controller. This information could be used
* for power management or other forms of resource management. The caller should
* ensure downstream usb devices are all either suspended or marked as
* "offload_at_suspend" to ensure the correctness of the return value.
* ensure downstream usb devices are all marked as "offload_pm_locked" to ensure
* the correctness of the return value.
*
* Returns true on any active sideband existence, false otherwise.
*/
@@ -328,9 +322,6 @@ int
xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
bool ip_autoclear, u32 imod_interval, int intr_num)
{
int ret = 0;
struct usb_device *udev;
if (!sb || !sb->xhci)
return -ENODEV;
@@ -348,12 +339,9 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg,
if (!sb->ir)
return -ENOMEM;
udev = sb->vdev->udev;
ret = usb_offload_get(udev);
sb->ir->ip_autoclear = ip_autoclear;
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter);
+2 -2
View File
@@ -4146,7 +4146,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
if (state == 0xffffffff || (xhci->xhc_state & XHCI_STATE_DYING) ||
(xhci->xhc_state & XHCI_STATE_HALTED)) {
spin_unlock_irqrestore(&xhci->lock, flags);
kfree(command);
xhci_free_command(xhci, command);
return -ENODEV;
}
@@ -4154,7 +4154,7 @@ int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)
slot_id);
if (ret) {
spin_unlock_irqrestore(&xhci->lock, flags);
kfree(command);
xhci_free_command(xhci, command);
return ret;
}
xhci_ring_cmd_db(xhci);
+4 -2
View File
@@ -707,7 +707,7 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
if (signal_pending (current))
{
mutex_unlock(&mdc800->io_lock);
return -EINTR;
return len == left ? -EINTR : len-left;
}
sts=left > (mdc800->out_count-mdc800->out_ptr)?mdc800->out_count-mdc800->out_ptr:left;
@@ -730,9 +730,11 @@ static ssize_t mdc800_device_read (struct file *file, char __user *buf, size_t l
mutex_unlock(&mdc800->io_lock);
return len-left;
}
wait_event_timeout(mdc800->download_wait,
retval = wait_event_timeout(mdc800->download_wait,
mdc800->downloaded,
msecs_to_jiffies(TO_DOWNLOAD_GET_READY));
if (!retval)
usb_kill_urb(mdc800->download_urb);
mdc800->downloaded = 0;
if (mdc800->download_urb->status != 0)
{
+8
View File
@@ -115,6 +115,13 @@ static const struct onboard_dev_pdata vialab_vl817_data = {
.is_hub = true,
};
static const struct onboard_dev_pdata wch_ch334_data = {
.reset_us = 14000,
.num_supplies = 2,
.supply_names = { "vdd33", "v5" },
.is_hub = true,
};
static const struct onboard_dev_pdata xmos_xvf3500_data = {
.reset_us = 1,
.num_supplies = 2,
@@ -146,6 +153,7 @@ static const struct of_device_id onboard_dev_match[] = {
{ .compatible = "usbbda,5411", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,414", .data = &realtek_rts5411_data, },
{ .compatible = "usbbda,5414", .data = &realtek_rts5411_data, },
{ .compatible = "usb1a86,8091", .data = &wch_ch334_data, },
{ .compatible = "usb1da0,5511", .data = &parade_ps5511_data, },
{ .compatible = "usb1da0,55a1", .data = &parade_ps5511_data, },
{ .compatible = "usb2109,817", .data = &vialab_vl817_data, },
+1 -1
View File
@@ -736,7 +736,7 @@ static int uss720_probe(struct usb_interface *intf,
ret = get_1284_register(pp, 0, &reg, GFP_KERNEL);
dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
if (ret < 0)
return ret;
goto probe_abort;
ret = usb_find_last_int_in_endpoint(interface, &epd);
if (!ret) {
+26 -48
View File
@@ -20,7 +20,7 @@
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
@@ -49,15 +49,13 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
int ret = 0;
if (suspend) {
if (!IS_ERR(nop->clk))
clk_disable_unprepare(nop->clk);
clk_disable_unprepare(nop->clk);
if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev))
ret = regulator_disable(nop->vcc);
} else {
if (!IS_ERR(nop->vcc) && !device_may_wakeup(x->dev))
ret = regulator_enable(nop->vcc);
if (!IS_ERR(nop->clk))
clk_prepare_enable(nop->clk);
clk_prepare_enable(nop->clk);
}
return ret;
@@ -137,11 +135,9 @@ int usb_gen_phy_init(struct usb_phy *phy)
dev_err(phy->dev, "Failed to enable power\n");
}
if (!IS_ERR(nop->clk)) {
ret = clk_prepare_enable(nop->clk);
if (ret)
return ret;
}
ret = clk_prepare_enable(nop->clk);
if (ret)
return ret;
nop_reset(nop);
@@ -155,8 +151,7 @@ void usb_gen_phy_shutdown(struct usb_phy *phy)
gpiod_set_value_cansleep(nop->gpiod_reset, 1);
if (!IS_ERR(nop->clk))
clk_disable_unprepare(nop->clk);
clk_disable_unprepare(nop->clk);
if (!IS_ERR(nop->vcc)) {
if (regulator_disable(nop->vcc))
@@ -202,18 +197,9 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
{
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err = 0;
u32 clk_rate = 0;
bool needs_clk = false;
if (dev->of_node) {
struct device_node *node = dev->of_node;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_clk = of_property_present(node, "clocks");
}
device_property_read_u32(dev, "clock-frequency", &clk_rate);
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_ASIS);
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
@@ -235,20 +221,16 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
if (!nop->phy.otg)
return -ENOMEM;
nop->clk = devm_clk_get(dev, "main_clk");
if (IS_ERR(nop->clk)) {
dev_dbg(dev, "Can't get phy clock: %ld\n",
PTR_ERR(nop->clk));
if (needs_clk)
return PTR_ERR(nop->clk);
}
nop->clk = devm_clk_get_optional(dev, "main_clk");
if (IS_ERR(nop->clk))
return dev_err_probe(dev, PTR_ERR(nop->clk),
"Can't get phy clock\n");
if (!IS_ERR(nop->clk) && clk_rate) {
if (clk_rate) {
err = clk_set_rate(nop->clk, clk_rate);
if (err) {
dev_err(dev, "Error setting clock rate\n");
return err;
}
if (err)
return dev_err_probe(dev, err,
"Error setting clock rate\n");
}
nop->vcc = devm_regulator_get_optional(dev, "vcc");
@@ -282,7 +264,6 @@ EXPORT_SYMBOL_GPL(usb_phy_gen_create_phy);
static int usb_phy_generic_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node;
struct usb_phy_generic *nop;
int err;
@@ -293,17 +274,17 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
err = usb_phy_gen_create_phy(dev, nop);
if (err)
return err;
if (nop->gpiod_vbus) {
err = devm_request_threaded_irq(&pdev->dev,
err = devm_request_threaded_irq(dev,
gpiod_to_irq(nop->gpiod_vbus),
NULL, nop_gpio_vbus_thread,
VBUS_IRQ_FLAGS, "vbus_detect",
nop);
if (err) {
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
gpiod_to_irq(nop->gpiod_vbus), err);
return err;
}
if (err)
return dev_err_probe(dev, err, "can't request irq %i\n",
gpiod_to_irq(nop->gpiod_vbus));
nop->phy.otg->state = gpiod_get_value(nop->gpiod_vbus) ?
OTG_STATE_B_PERIPHERAL : OTG_STATE_B_IDLE;
}
@@ -312,16 +293,13 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
nop->phy.shutdown = usb_gen_phy_shutdown;
err = usb_add_phy_dev(&nop->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
return err;
}
if (err)
return dev_err_probe(dev, err, "can't register transceiver\n");
platform_set_drvdata(pdev, nop);
device_set_wakeup_capable(&pdev->dev,
of_property_read_bool(dn, "wakeup-source"));
device_set_wakeup_capable(dev,
device_property_read_bool(dev, "wakeup-source"));
return 0;
}
+267 -30
View File
@@ -29,17 +29,26 @@
#include <linux/usb/tegra_usb_phy.h>
#include <linux/usb/ulpi.h>
#define USB_TXFILLTUNING 0x154
#define USB_FIFO_TXFILL_THRES(x) (((x) & 0x1f) << 16)
#define USB_FIFO_TXFILL_MASK 0x1f0000
#define ULPI_VIEWPORT 0x170
/* PORTSC PTS/PHCD bits, Tegra20 only */
#define TEGRA_USB_PORTSC1 0x184
#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define TEGRA_USB_PORTSC1_PHCD BIT(23)
#define TEGRA_USB_PORTSC1_PTS(x) (((x) & 0x3) << 30)
#define TEGRA_USB_PORTSC1_PHCD BIT(23)
#define TEGRA_USB_PORTSC1_WKOC BIT(22)
#define TEGRA_USB_PORTSC1_WKDS BIT(21)
#define TEGRA_USB_PORTSC1_WKCN BIT(20)
/* HOSTPC1 PTS/PHCD bits, Tegra30 and above */
#define TEGRA30_USB_PORTSC1 0x174
#define TEGRA_USB_HOSTPC1_DEVLC 0x1b4
#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
#define TEGRA_USB_HOSTPC1_DEVLC_PHCD BIT(22)
#define TEGRA_USB_HOSTPC1_DEVLC_PTS(x) (((x) & 0x7) << 29)
#define TEGRA_USB_HOSTPC1_DEVLC_PHCD BIT(22)
#define TEGRA_USB_HOSTPC1_DEVLC_PTS_HSIC 4
/* Bits of PORTSC1, which will get cleared by writing 1 into them */
#define TEGRA_PORTSC1_RWC_BITS (PORT_CSC | PORT_PEC | PORT_OCC)
@@ -51,11 +60,12 @@
#define USB_SUSP_CLR BIT(5)
#define USB_PHY_CLK_VALID BIT(7)
#define UTMIP_RESET BIT(11)
#define UHSIC_RESET BIT(11)
#define UTMIP_PHY_ENABLE BIT(12)
#define ULPI_PHY_ENABLE BIT(13)
#define USB_SUSP_SET BIT(14)
#define UHSIC_RESET BIT(14)
#define USB_WAKEUP_DEBOUNCE_COUNT(x) (((x) & 0x7) << 16)
#define UHSIC_PHY_ENABLE BIT(19)
#define USB_PHY_VBUS_SENSORS 0x404
#define B_SESS_VLD_WAKEUP_EN BIT(14)
@@ -156,6 +166,58 @@
#define UTMIP_BIAS_CFG1 0x83c
#define UTMIP_BIAS_PDTRK_COUNT(x) (((x) & 0x1f) << 3)
/*
* Tegra20 has no UTMIP registers on PHY2 and UHSIC registers start from 0x800
* just where UTMIP registers should have been. This is the case only with Tegra20
* Tegra30+ have UTMIP registers at 0x800 and UHSIC registers are shifted by 0x400
* to 0xc00, but register layout is preserved.
*/
#define UHSIC_PLL_CFG1 0x804
#define UHSIC_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0)
#define UHSIC_PLLU_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 14)
#define UHSIC_HSRX_CFG0 0x808
#define UHSIC_ELASTIC_UNDERRUN_LIMIT(x) (((x) & 0x1f) << 2)
#define UHSIC_ELASTIC_OVERRUN_LIMIT(x) (((x) & 0x1f) << 8)
#define UHSIC_IDLE_WAIT(x) (((x) & 0x1f) << 13)
#define UHSIC_HSRX_CFG1 0x80c
#define UHSIC_HS_SYNC_START_DLY(x) (((x) & 0x1f) << 1)
#define UHSIC_TX_CFG0 0x810
#define UHSIC_HS_READY_WAIT_FOR_VALID BIT(9)
#define UHSIC_MISC_CFG0 0x814
#define UHSIC_SUSPEND_EXIT_ON_EDGE BIT(7)
#define UHSIC_DETECT_SHORT_CONNECT BIT(8)
#define UHSIC_FORCE_XCVR_MODE BIT(15)
#define UHSIC_DISABLE_BUSRESET BIT(20)
#define UHSIC_MISC_CFG1 0x818
#define UHSIC_PLLU_STABLE_COUNT(x) (((x) & 0xfff) << 2)
#define UHSIC_PADS_CFG0 0x81c
#define UHSIC_TX_RTUNEN 0xf000
#define UHSIC_TX_RTUNE(x) (((x) & 0xf) << 12)
#define UHSIC_PADS_CFG1 0x820
#define UHSIC_PD_BG BIT(2)
#define UHSIC_PD_TX BIT(3)
#define UHSIC_PD_TRK BIT(4)
#define UHSIC_PD_RX BIT(5)
#define UHSIC_PD_ZI BIT(6)
#define UHSIC_RX_SEL BIT(7)
#define UHSIC_RPD_DATA BIT(9)
#define UHSIC_RPD_STROBE BIT(10)
#define UHSIC_RPU_DATA BIT(11)
#define UHSIC_RPU_STROBE BIT(12)
#define UHSIC_CMD_CFG0 0x824
#define UHSIC_PRETEND_CONNECT_DETECT BIT(5)
#define UHSIC_STAT_CFG0 0x828
#define UHSIC_CONNECT_DETECT BIT(0)
/* For Tegra30 and above only, the address is different in Tegra20 */
#define USB_USBMODE 0x1f8
#define USB_USBMODE_MASK (3 << 0)
@@ -174,7 +236,8 @@ struct tegra_xtal_freq {
u8 enable_delay;
u8 stable_count;
u8 active_delay;
u8 xtal_freq_count;
u8 utmi_xtal_freq_count;
u16 hsic_xtal_freq_count;
u16 debounce;
};
@@ -184,7 +247,8 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
.enable_delay = 0x02,
.stable_count = 0x2F,
.active_delay = 0x04,
.xtal_freq_count = 0x76,
.utmi_xtal_freq_count = 0x76,
.hsic_xtal_freq_count = 0x1CA,
.debounce = 0x7530,
},
{
@@ -192,7 +256,8 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
.enable_delay = 0x02,
.stable_count = 0x33,
.active_delay = 0x05,
.xtal_freq_count = 0x7F,
.utmi_xtal_freq_count = 0x7F,
.hsic_xtal_freq_count = 0x1F0,
.debounce = 0x7EF4,
},
{
@@ -200,7 +265,8 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
.enable_delay = 0x03,
.stable_count = 0x4B,
.active_delay = 0x06,
.xtal_freq_count = 0xBB,
.utmi_xtal_freq_count = 0xBB,
.hsic_xtal_freq_count = 0x2DD,
.debounce = 0xBB80,
},
{
@@ -208,7 +274,8 @@ static const struct tegra_xtal_freq tegra_freq_table[] = {
.enable_delay = 0x04,
.stable_count = 0x66,
.active_delay = 0x09,
.xtal_freq_count = 0xFE,
.utmi_xtal_freq_count = 0xFE,
.hsic_xtal_freq_count = 0x3E0,
.debounce = 0xFDE8,
},
};
@@ -532,7 +599,7 @@ static int utmi_phy_power_on(struct tegra_usb_phy *phy)
val = readl_relaxed(base + UTMIP_PLL_CFG1);
val &= ~(UTMIP_XTAL_FREQ_COUNT(~0) |
UTMIP_PLLU_ENABLE_DLY_COUNT(~0));
val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->xtal_freq_count) |
val |= UTMIP_XTAL_FREQ_COUNT(phy->freq->utmi_xtal_freq_count) |
UTMIP_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
writel_relaxed(val, base + UTMIP_PLL_CFG1);
}
@@ -803,17 +870,170 @@ static int ulpi_phy_power_off(struct tegra_usb_phy *phy)
return 0;
}
static u32 tegra_hsic_readl(struct tegra_usb_phy *phy, u32 reg)
{
void __iomem *base = phy->regs;
u32 shift = phy->soc_config->uhsic_registers_offset;
return readl_relaxed(base + shift + reg);
}
static void tegra_hsic_writel(struct tegra_usb_phy *phy, u32 reg, u32 value)
{
void __iomem *base = phy->regs;
u32 shift = phy->soc_config->uhsic_registers_offset;
writel_relaxed(value, base + shift + reg);
}
static int uhsic_phy_power_on(struct tegra_usb_phy *phy)
{
struct tegra_utmip_config *config = phy->config;
void __iomem *base = phy->regs;
u32 val;
int err = 0;
val = tegra_hsic_readl(phy, UHSIC_PADS_CFG1);
val &= ~(UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX |
UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
val |= UHSIC_RX_SEL;
tegra_hsic_writel(phy, UHSIC_PADS_CFG1, val);
udelay(2);
val = readl_relaxed(base + USB_SUSP_CTRL);
val |= UHSIC_RESET;
writel_relaxed(val, base + USB_SUSP_CTRL);
udelay(30);
val = readl_relaxed(base + USB_SUSP_CTRL);
val |= UHSIC_PHY_ENABLE;
writel_relaxed(val, base + USB_SUSP_CTRL);
val = tegra_hsic_readl(phy, UHSIC_HSRX_CFG0);
val &= ~(UHSIC_IDLE_WAIT(~0) |
UHSIC_ELASTIC_UNDERRUN_LIMIT(~0) |
UHSIC_ELASTIC_OVERRUN_LIMIT(~0));
val |= UHSIC_IDLE_WAIT(config->idle_wait_delay) |
UHSIC_ELASTIC_UNDERRUN_LIMIT(config->elastic_limit) |
UHSIC_ELASTIC_OVERRUN_LIMIT(config->elastic_limit);
tegra_hsic_writel(phy, UHSIC_HSRX_CFG0, val);
val = tegra_hsic_readl(phy, UHSIC_HSRX_CFG1);
val &= ~UHSIC_HS_SYNC_START_DLY(~0);
val |= UHSIC_HS_SYNC_START_DLY(config->hssync_start_delay);
tegra_hsic_writel(phy, UHSIC_HSRX_CFG1, val);
val = tegra_hsic_readl(phy, UHSIC_MISC_CFG0);
val |= UHSIC_SUSPEND_EXIT_ON_EDGE;
tegra_hsic_writel(phy, UHSIC_MISC_CFG0, val);
val = tegra_hsic_readl(phy, UHSIC_MISC_CFG1);
val &= ~UHSIC_PLLU_STABLE_COUNT(~0);
val |= UHSIC_PLLU_STABLE_COUNT(phy->freq->stable_count);
tegra_hsic_writel(phy, UHSIC_MISC_CFG1, val);
val = tegra_hsic_readl(phy, UHSIC_PLL_CFG1);
val &= ~(UHSIC_XTAL_FREQ_COUNT(~0) |
UHSIC_PLLU_ENABLE_DLY_COUNT(~0));
val |= UHSIC_XTAL_FREQ_COUNT(phy->freq->hsic_xtal_freq_count) |
UHSIC_PLLU_ENABLE_DLY_COUNT(phy->freq->enable_delay);
tegra_hsic_writel(phy, UHSIC_PLL_CFG1, val);
val = readl_relaxed(base + USB_SUSP_CTRL);
val &= ~UHSIC_RESET;
writel_relaxed(val, base + USB_SUSP_CTRL);
udelay(2);
if (phy->soc_config->requires_usbmode_setup) {
val = readl_relaxed(base + USB_USBMODE);
val &= ~USB_USBMODE_MASK;
if (phy->mode == USB_DR_MODE_HOST)
val |= USB_USBMODE_HOST;
else
val |= USB_USBMODE_DEVICE;
writel_relaxed(val, base + USB_USBMODE);
}
set_pts(phy, phy->soc_config->uhsic_pts_value);
val = readl_relaxed(base + USB_TXFILLTUNING);
if ((val & USB_FIFO_TXFILL_MASK) != USB_FIFO_TXFILL_THRES(0x10)) {
val = USB_FIFO_TXFILL_THRES(0x10);
writel_relaxed(val, base + USB_TXFILLTUNING);
}
val = readl_relaxed(base + phy->soc_config->portsc1_offset);
val &= ~(TEGRA_USB_PORTSC1_WKOC | TEGRA_USB_PORTSC1_WKDS |
TEGRA_USB_PORTSC1_WKCN);
writel_relaxed(val, base + phy->soc_config->portsc1_offset);
val = tegra_hsic_readl(phy, UHSIC_PADS_CFG0);
val &= ~UHSIC_TX_RTUNEN;
val |= UHSIC_TX_RTUNE(phy->soc_config->uhsic_tx_rtune);
tegra_hsic_writel(phy, UHSIC_PADS_CFG0, val);
err = utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID,
USB_PHY_CLK_VALID);
if (err)
dev_err(phy->u_phy.dev,
"Timeout waiting for PHY to stabilize on enable (HSIC)\n");
return err;
}
static int uhsic_phy_power_off(struct tegra_usb_phy *phy)
{
void __iomem *base = phy->regs;
u32 val;
set_phcd(phy, true);
val = tegra_hsic_readl(phy, UHSIC_PADS_CFG1);
val |= (UHSIC_PD_BG | UHSIC_PD_TX | UHSIC_PD_TRK | UHSIC_PD_RX |
UHSIC_PD_ZI | UHSIC_RPD_DATA | UHSIC_RPD_STROBE);
tegra_hsic_writel(phy, UHSIC_PADS_CFG1, val);
val = readl_relaxed(base + USB_SUSP_CTRL);
val |= UHSIC_RESET;
writel_relaxed(val, base + USB_SUSP_CTRL);
udelay(30);
val = readl_relaxed(base + USB_SUSP_CTRL);
val &= ~UHSIC_PHY_ENABLE;
writel_relaxed(val, base + USB_SUSP_CTRL);
return 0;
}
static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
{
int err;
int err = 0;
if (phy->powered_on)
return 0;
if (phy->is_ulpi_phy)
err = ulpi_phy_power_on(phy);
else
switch (phy->phy_type) {
case USBPHY_INTERFACE_MODE_UTMI:
err = utmi_phy_power_on(phy);
break;
case USBPHY_INTERFACE_MODE_ULPI:
err = ulpi_phy_power_on(phy);
break;
case USBPHY_INTERFACE_MODE_HSIC:
err = uhsic_phy_power_on(phy);
break;
default:
break;
}
if (err)
return err;
@@ -827,15 +1047,28 @@ static int tegra_usb_phy_power_on(struct tegra_usb_phy *phy)
static int tegra_usb_phy_power_off(struct tegra_usb_phy *phy)
{
int err;
int err = 0;
if (!phy->powered_on)
return 0;
if (phy->is_ulpi_phy)
err = ulpi_phy_power_off(phy);
else
switch (phy->phy_type) {
case USBPHY_INTERFACE_MODE_UTMI:
err = utmi_phy_power_off(phy);
break;
case USBPHY_INTERFACE_MODE_ULPI:
err = ulpi_phy_power_off(phy);
break;
case USBPHY_INTERFACE_MODE_HSIC:
err = uhsic_phy_power_off(phy);
break;
default:
break;
}
if (err)
return err;
@@ -854,7 +1087,7 @@ static void tegra_usb_phy_shutdown(struct usb_phy *u_phy)
usb_phy_set_wakeup(u_phy, false);
tegra_usb_phy_power_off(phy);
if (!phy->is_ulpi_phy)
if (phy->phy_type == USBPHY_INTERFACE_MODE_UTMI)
utmip_pad_close(phy);
regulator_disable(phy->vbus);
@@ -1040,7 +1273,7 @@ static int tegra_usb_phy_init(struct usb_phy *u_phy)
goto disable_clk;
}
if (!phy->is_ulpi_phy) {
if (phy->phy_type == USBPHY_INTERFACE_MODE_UTMI) {
err = utmip_pad_open(phy);
if (err)
goto disable_vbus;
@@ -1057,7 +1290,7 @@ static int tegra_usb_phy_init(struct usb_phy *u_phy)
return 0;
close_phy:
if (!phy->is_ulpi_phy)
if (phy->phy_type == USBPHY_INTERFACE_MODE_UTMI)
utmip_pad_close(phy);
disable_vbus:
@@ -1095,8 +1328,6 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
struct resource *res;
int err;
tegra_phy->is_ulpi_phy = false;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "Failed to get UTMI pad regs\n");
@@ -1231,6 +1462,10 @@ static const struct tegra_phy_soc_config tegra20_soc_config = {
.requires_usbmode_setup = false,
.requires_extra_tuning_parameters = false,
.requires_pmc_ao_power_up = false,
.uhsic_registers_offset = 0,
.uhsic_tx_rtune = 0, /* 40 ohm */
.uhsic_pts_value = 0, /* UTMI */
.portsc1_offset = TEGRA_USB_PORTSC1,
};
static const struct tegra_phy_soc_config tegra30_soc_config = {
@@ -1239,6 +1474,10 @@ static const struct tegra_phy_soc_config tegra30_soc_config = {
.requires_usbmode_setup = true,
.requires_extra_tuning_parameters = true,
.requires_pmc_ao_power_up = true,
.uhsic_registers_offset = 0x400,
.uhsic_tx_rtune = 8, /* 50 ohm */
.uhsic_pts_value = TEGRA_USB_HOSTPC1_DEVLC_PTS_HSIC,
.portsc1_offset = TEGRA30_USB_PORTSC1,
};
static const struct of_device_id tegra_usb_phy_id_table[] = {
@@ -1252,7 +1491,6 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct tegra_usb_phy *tegra_phy;
enum usb_phy_interface phy_type;
struct reset_control *reset;
struct gpio_desc *gpiod;
struct resource *res;
@@ -1314,9 +1552,10 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
return err;
}
phy_type = of_usb_get_phy_mode(np);
switch (phy_type) {
tegra_phy->phy_type = of_usb_get_phy_mode(np);
switch (tegra_phy->phy_type) {
case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_HSIC:
err = utmi_phy_probe(tegra_phy, pdev);
if (err)
return err;
@@ -1341,8 +1580,6 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
break;
case USBPHY_INTERFACE_MODE_ULPI:
tegra_phy->is_ulpi_phy = true;
tegra_phy->clk = devm_clk_get(&pdev->dev, "ulpi-link");
err = PTR_ERR_OR_ZERO(tegra_phy->clk);
if (err) {
@@ -1382,7 +1619,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
default:
dev_err(&pdev->dev, "phy_type %u is invalid or unsupported\n",
phy_type);
tegra_phy->phy_type);
return -EINVAL;
}
+3
View File
@@ -73,6 +73,7 @@ static const struct usb_device_id edgeport_4port_id_table[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ }
};
@@ -121,6 +122,7 @@ static const struct usb_device_id id_table_combined[] = {
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
@@ -470,6 +472,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
case ION_DEVICE_ID_EDGEPORT_2_DIN:
case ION_DEVICE_ID_EDGEPORT_4_DIN:
case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU:
case ION_DEVICE_ID_BLACKBOX_IC135A:
product_info->IsRS232 = 1;
break;
+1
View File
@@ -211,6 +211,7 @@
//
// Definitions for other product IDs
#define ION_DEVICE_ID_BLACKBOX_IC135A 0x0801 // OEM device (rebranded Edgeport/4)
#define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device
#define ION_DEVICE_ID_E5805A 0x1A01 // OEM device (rebranded Edgeport/4)
+11
View File
@@ -1401,12 +1401,16 @@ static const struct usb_device_id option_ids[] = {
.driver_info = NCTRL(0) | RSVD(1) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a0, 0xff), /* Telit FN20C04 (rmnet) */
.driver_info = RSVD(0) | NCTRL(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a1, 0xff), /* Telit FN20C04 (RNDIS) */
.driver_info = NCTRL(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a2, 0xff), /* Telit FN920C04 (MBIM) */
.driver_info = NCTRL(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a3, 0xff), /* Telit FN920C04 (ECM) */
.driver_info = NCTRL(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a4, 0xff), /* Telit FN20C04 (rmnet) */
.driver_info = RSVD(0) | NCTRL(3) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a6, 0xff), /* Telit FN920C04 (RNDIS) */
.driver_info = NCTRL(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a7, 0xff), /* Telit FN920C04 (MBIM) */
.driver_info = NCTRL(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10a8, 0xff), /* Telit FN920C04 (ECM) */
@@ -1415,6 +1419,8 @@ static const struct usb_device_id option_ids[] = {
.driver_info = RSVD(0) | NCTRL(2) | RSVD(3) | RSVD(4) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10aa, 0xff), /* Telit FN920C04 (MBIM) */
.driver_info = NCTRL(3) | RSVD(4) | RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(TELIT_VENDOR_ID, 0x10ab, 0xff), /* Telit FN920C04 (RNDIS) */
.driver_info = NCTRL(3) | RSVD(4) | RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x30), /* Telit FE990B (rmnet) */
.driver_info = NCTRL(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(TELIT_VENDOR_ID, 0x10b0, 0xff, 0xff, 0x40) },
@@ -2435,6 +2441,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */
{ USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */
{ USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */
{ USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */
@@ -2455,6 +2464,8 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */
.driver_info = RSVD(5) },
{ USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff), /* Rolling RW135R-GL (laptop MBIM) */
.driver_info = RSVD(5) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) },
{ USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) },
+1 -1
View File
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_TYPEC) += typec.o
typec-y := class.o mux.o bus.o pd.o retimer.o
typec-y := class.o mux.o bus.o pd.o retimer.o mode_selection.o
typec-$(CONFIG_ACPI) += port-mapper.o
obj-$(CONFIG_TYPEC) += altmodes/
obj-$(CONFIG_TYPEC_TCPM) += tcpm/
+10 -3
View File
@@ -100,9 +100,14 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
{
u8 pin_assign = 0;
u32 conf;
u32 signal;
/* DP Signalling */
conf = (dp->data.conf & DP_CONF_SIGNALLING_MASK) >> DP_CONF_SIGNALLING_SHIFT;
signal = DP_CAP_DP_SIGNALLING(dp->port->vdo) & DP_CAP_DP_SIGNALLING(dp->alt->vdo);
if (dp->plug_prime)
signal &= DP_CAP_DP_SIGNALLING(dp->plug_prime->vdo);
conf = signal << DP_CONF_SIGNALLING_SHIFT;
switch (con) {
case DP_STATUS_CON_DISABLED:
@@ -804,8 +809,10 @@ int dp_altmode_probe(struct typec_altmode *alt)
if (plug)
typec_altmode_set_drvdata(plug, dp);
dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
schedule_work(&dp->work);
if (!alt->mode_selection) {
dp->state = plug ? DP_STATE_ENTER_PRIME : DP_STATE_ENTER;
schedule_work(&dp->work);
}
return 0;
}
+23 -23
View File
@@ -39,28 +39,7 @@ static bool tbt_ready(struct typec_altmode *alt);
static int tbt_enter_mode(struct tbt_altmode *tbt)
{
struct typec_altmode *plug = tbt->plug[TYPEC_PLUG_SOP_P];
u32 vdo;
vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1);
vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0;
vdo |= TBT_MODE;
if (plug) {
if (typec_cable_is_active(tbt->cable))
vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo));
vdo |= plug->vdo & TBT_CABLE_ROUNDED;
vdo |= plug->vdo & TBT_CABLE_OPTICAL;
vdo |= plug->vdo & TBT_CABLE_RETIMER;
vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING;
} else {
vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE);
}
tbt->enter_vdo = vdo;
return typec_altmode_enter(tbt->alt, &vdo);
return typec_altmode_enter(tbt->alt, &tbt->enter_vdo);
}
static void tbt_altmode_work(struct work_struct *work)
@@ -307,7 +286,7 @@ static int tbt_altmode_probe(struct typec_altmode *alt)
typec_altmode_set_drvdata(alt, tbt);
typec_altmode_set_ops(alt, &tbt_altmode_ops);
if (tbt_ready(alt)) {
if (!alt->mode_selection && tbt_ready(alt)) {
if (tbt->plug[TYPEC_PLUG_SOP_P])
tbt->state = TBT_STATE_SOP_P_ENTER;
else if (tbt->plug[TYPEC_PLUG_SOP_PP])
@@ -337,6 +316,7 @@ static bool tbt_ready(struct typec_altmode *alt)
{
struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt);
struct typec_altmode *plug;
u32 vdo;
if (tbt->cable)
return true;
@@ -364,6 +344,26 @@ static bool tbt_ready(struct typec_altmode *alt)
tbt->plug[i] = plug;
}
vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1);
vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0;
vdo |= TBT_MODE;
plug = tbt->plug[TYPEC_PLUG_SOP_P];
if (plug) {
if (typec_cable_is_active(tbt->cable))
vdo |= TBT_ENTER_MODE_ACTIVE_CABLE;
vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo));
vdo |= plug->vdo & TBT_CABLE_ROUNDED;
vdo |= plug->vdo & TBT_CABLE_OPTICAL;
vdo |= plug->vdo & TBT_CABLE_RETIMER;
vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING;
} else {
vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE);
}
tbt->enter_vdo = vdo;
return true;
}
+24 -1
View File
@@ -445,7 +445,23 @@ static struct attribute *typec_attrs[] = {
&dev_attr_description.attr,
NULL
};
ATTRIBUTE_GROUPS(typec);
static umode_t typec_is_visible(struct kobject *kobj, struct attribute *attr, int n)
{
if (is_typec_partner_altmode(kobj_to_dev(kobj)))
return attr->mode;
return 0;
}
static const struct attribute_group typec_group = {
.is_visible = typec_is_visible,
.attrs = typec_attrs,
};
static const struct attribute_group *typec_groups[] = {
&typec_group,
NULL
};
static int typec_match(struct device *dev, const struct device_driver *driver)
{
@@ -453,6 +469,9 @@ static int typec_match(struct device *dev, const struct device_driver *driver)
struct typec_altmode *altmode = to_typec_altmode(dev);
const struct typec_device_id *id;
if (!is_typec_partner_altmode(dev))
return 0;
for (id = drv->id_table; id->svid; id++)
if (id->svid == altmode->svid)
return 1;
@@ -463,6 +482,9 @@ static int typec_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
const struct typec_altmode *altmode = to_typec_altmode(dev);
if (!is_typec_partner_altmode(dev))
return 0;
if (add_uevent_var(env, "SVID=%04X", altmode->svid))
return -ENOMEM;
@@ -547,3 +569,4 @@ const struct bus_type typec_bus = {
.probe = typec_probe,
.remove = typec_remove,
};
EXPORT_SYMBOL_GPL(typec_bus);
-6
View File
@@ -5,7 +5,6 @@
#include <linux/usb/typec_altmode.h>
struct bus_type;
struct typec_mux;
struct typec_retimer;
@@ -28,9 +27,4 @@ struct altmode {
#define to_altmode(d) container_of(d, struct altmode, adev)
extern const struct bus_type typec_bus;
extern const struct device_type typec_altmode_dev_type;
#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
#endif /* __USB_TYPEC_ALTMODE_H__ */
+121 -19
View File
@@ -235,7 +235,7 @@ static int altmode_match(struct device *dev, const void *data)
struct typec_altmode *adev = to_typec_altmode(dev);
const struct typec_device_id *id = data;
if (!is_typec_altmode(dev))
if (!is_typec_port_altmode(dev))
return 0;
return (adev->svid == id->svid);
@@ -445,11 +445,88 @@ svid_show(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR_RO(svid);
static int increment_duplicated_priority(struct device *dev, void *data)
{
if (is_typec_port_altmode(dev)) {
struct typec_altmode **alt_target = (struct typec_altmode **)data;
struct typec_altmode *alt = to_typec_altmode(dev);
if (alt != *alt_target && alt->priority == (*alt_target)->priority) {
alt->priority++;
*alt_target = alt;
return 1;
}
}
return 0;
}
static int find_duplicated_priority(struct device *dev, void *data)
{
if (is_typec_port_altmode(dev)) {
struct typec_altmode **alt_target = (struct typec_altmode **)data;
struct typec_altmode *alt = to_typec_altmode(dev);
if (alt != *alt_target && alt->priority == (*alt_target)->priority)
return 1;
}
return 0;
}
static int typec_mode_set_priority(struct typec_altmode *alt, const u8 priority)
{
struct typec_port *port = to_typec_port(alt->dev.parent);
const u8 old_priority = alt->priority;
int res = 1;
alt->priority = priority;
while (res) {
res = device_for_each_child(&port->dev, &alt, find_duplicated_priority);
if (res) {
alt->priority++;
if (alt->priority == 0) {
alt->priority = old_priority;
return -EOVERFLOW;
}
}
}
res = 1;
alt->priority = priority;
while (res)
res = device_for_each_child(&port->dev, &alt,
increment_duplicated_priority);
return 0;
}
static ssize_t priority_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t size)
{
u8 val;
int err = kstrtou8(buf, 10, &val);
if (!err)
err = typec_mode_set_priority(to_typec_altmode(dev), val);
if (!err)
return size;
return err;
}
static ssize_t priority_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sysfs_emit(buf, "%u\n", to_typec_altmode(dev)->priority);
}
static DEVICE_ATTR_RW(priority);
static struct attribute *typec_altmode_attrs[] = {
&dev_attr_active.attr,
&dev_attr_mode.attr,
&dev_attr_svid.attr,
&dev_attr_vdo.attr,
&dev_attr_priority.attr,
NULL
};
@@ -457,11 +534,17 @@ static umode_t typec_altmode_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct typec_altmode *adev = to_typec_altmode(kobj_to_dev(kobj));
struct typec_port *port = typec_altmode2port(adev);
if (attr == &dev_attr_active.attr)
if (!is_typec_port(adev->dev.parent) &&
(!adev->ops || !adev->ops->activate))
return 0444;
if (attr == &dev_attr_active.attr) {
if (!is_typec_port(adev->dev.parent)) {
if (!port->mode_control || !adev->ops || !adev->ops->activate)
return 0444;
}
} else if (attr == &dev_attr_priority.attr) {
if (!is_typec_port(adev->dev.parent) || !port->mode_control)
return 0;
}
return attr->mode;
}
@@ -532,15 +615,31 @@ static void typec_altmode_release(struct device *dev)
kfree(alt);
}
const struct device_type typec_altmode_dev_type = {
.name = "typec_alternate_mode",
const struct device_type typec_port_altmode_dev_type = {
.name = "typec_port_alternate_mode",
.groups = typec_altmode_groups,
.release = typec_altmode_release,
};
EXPORT_SYMBOL_GPL(typec_port_altmode_dev_type);
const struct device_type typec_plug_altmode_dev_type = {
.name = "typec_plug_alternate_mode",
.groups = typec_altmode_groups,
.release = typec_altmode_release,
};
EXPORT_SYMBOL_GPL(typec_plug_altmode_dev_type);
const struct device_type typec_partner_altmode_dev_type = {
.name = "typec_partner_alternate_mode",
.groups = typec_altmode_groups,
.release = typec_altmode_release,
};
EXPORT_SYMBOL_GPL(typec_partner_altmode_dev_type);
static struct typec_altmode *
typec_register_altmode(struct device *parent,
const struct typec_altmode_desc *desc)
const struct typec_altmode_desc *desc,
const struct device_type *type)
{
unsigned int id = altmode_id_get(parent);
bool is_port = is_typec_port(parent);
@@ -556,6 +655,7 @@ typec_register_altmode(struct device *parent,
alt->adev.svid = desc->svid;
alt->adev.mode = desc->mode;
alt->adev.vdo = desc->vdo;
alt->adev.mode_selection = desc->mode_selection;
alt->roles = desc->roles;
alt->id = id;
@@ -575,7 +675,7 @@ typec_register_altmode(struct device *parent,
alt->adev.dev.parent = parent;
alt->adev.dev.groups = alt->groups;
alt->adev.dev.type = &typec_altmode_dev_type;
alt->adev.dev.type = type;
dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
get_device(alt->adev.dev.parent);
@@ -584,13 +684,7 @@ typec_register_altmode(struct device *parent,
if (!is_port)
typec_altmode_set_partner(alt);
/* The partners are bind to drivers */
if (is_typec_partner(parent))
alt->adev.dev.bus = &typec_bus;
/* Plug alt modes need a class to generate udev events. */
if (is_typec_plug(parent))
alt->adev.dev.class = &typec_class;
alt->adev.dev.bus = &typec_bus;
ret = device_register(&alt->adev.dev);
if (ret) {
@@ -963,7 +1057,7 @@ struct typec_altmode *
typec_partner_register_altmode(struct typec_partner *partner,
const struct typec_altmode_desc *desc)
{
return typec_register_altmode(&partner->dev, desc);
return typec_register_altmode(&partner->dev, desc, &typec_partner_altmode_dev_type);
}
EXPORT_SYMBOL_GPL(typec_partner_register_altmode);
@@ -1193,7 +1287,7 @@ struct typec_altmode *
typec_plug_register_altmode(struct typec_plug *plug,
const struct typec_altmode_desc *desc)
{
return typec_register_altmode(&plug->dev, desc);
return typec_register_altmode(&plug->dev, desc, &typec_plug_altmode_dev_type);
}
EXPORT_SYMBOL_GPL(typec_plug_register_altmode);
@@ -2485,6 +2579,7 @@ typec_port_register_altmode(struct typec_port *port,
struct typec_altmode *adev;
struct typec_mux *mux;
struct typec_retimer *retimer;
int ret;
mux = typec_mux_get(&port->dev);
if (IS_ERR(mux))
@@ -2496,13 +2591,19 @@ typec_port_register_altmode(struct typec_port *port,
return ERR_CAST(retimer);
}
adev = typec_register_altmode(&port->dev, desc);
adev = typec_register_altmode(&port->dev, desc, &typec_port_altmode_dev_type);
if (IS_ERR(adev)) {
typec_retimer_put(retimer);
typec_mux_put(mux);
} else {
to_altmode(adev)->mux = mux;
to_altmode(adev)->retimer = retimer;
ret = typec_mode_set_priority(adev, 0);
if (ret) {
typec_unregister_altmode(adev);
return ERR_PTR(ret);
}
}
return adev;
@@ -2697,6 +2798,7 @@ struct typec_port *typec_register_port(struct device *parent,
}
port->pd = cap->pd;
port->mode_control = !cap->no_mode_control;
ret = device_add(&port->dev);
if (ret) {
+3
View File
@@ -9,6 +9,7 @@
struct typec_mux;
struct typec_switch;
struct usb_device;
struct mode_selection;
struct typec_plug {
struct device dev;
@@ -39,6 +40,7 @@ struct typec_partner {
u8 usb_capability;
struct usb_power_delivery *pd;
struct mode_selection *sel;
void (*attach)(struct typec_partner *partner, struct device *dev);
void (*deattach)(struct typec_partner *partner, struct device *dev);
@@ -62,6 +64,7 @@ struct typec_port {
struct mutex partner_link_lock;
enum typec_orientation orientation;
bool mode_control;
struct typec_switch *sw;
struct typec_mux *mux;
struct typec_retimer *retimer;
+283
View File
@@ -0,0 +1,283 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright 2025 Google LLC.
*/
#include <linux/types.h>
#include <linux/list_sort.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/usb/typec_altmode.h>
#include "class.h"
/**
* struct mode_state - State tracking for a specific Type-C alternate mode
* @svid: Standard or Vendor ID of the Alternate Mode
* @priority: Mode priority
* @error: Outcome of the last attempt to enter the mode
* @list: List head to link this mode state into a prioritized list
*/
struct mode_state {
u16 svid;
u8 priority;
int error;
struct list_head list;
};
/**
* struct mode_selection - Manages the selection and state of Alternate Modes
* @mode_list: Prioritized list of available Alternate Modes
* @lock: Mutex to protect mode_list
* @work: Work structure
* @partner: Handle to the Type-C partner device
* @active_svid: svid of currently active mode
* @timeout: Timeout for a mode entry attempt, ms
* @delay: Delay between mode entry/exit attempts, ms
*/
struct mode_selection {
struct list_head mode_list;
/* Protects the mode_list*/
struct mutex lock;
struct delayed_work work;
struct typec_partner *partner;
u16 active_svid;
unsigned int timeout;
unsigned int delay;
};
/**
* struct mode_order - Mode activation tracking
* @svid: Standard or Vendor ID of the Alternate Mode
* @enter: Flag indicating if the driver is currently attempting to enter or
* exit the mode
* @result: Outcome of the attempt to activate the mode
*/
struct mode_order {
u16 svid;
int enter;
int result;
};
static int activate_altmode(struct device *dev, void *data)
{
if (is_typec_partner_altmode(dev)) {
struct typec_altmode *alt = to_typec_altmode(dev);
struct mode_order *order = (struct mode_order *)data;
if (order->svid == alt->svid) {
if (alt->ops && alt->ops->activate)
order->result = alt->ops->activate(alt, order->enter);
else
order->result = -EOPNOTSUPP;
return 1;
}
}
return 0;
}
static int mode_selection_activate(struct mode_selection *sel,
const u16 svid, const int enter)
__must_hold(&sel->lock)
{
struct mode_order order = {.svid = svid, .enter = enter, .result = -ENODEV};
/*
* The port driver may acquire its internal mutex during alternate mode
* activation. Since this is the same mutex that may be held during the
* execution of typec_altmode_state_update(), it is crucial to release
* sel->mutex before activation to avoid potential deadlock.
* Note that sel->mode_list must remain invariant throughout this unlocked
* interval.
*/
mutex_unlock(&sel->lock);
device_for_each_child(&sel->partner->dev, &order, activate_altmode);
mutex_lock(&sel->lock);
return order.result;
}
static void mode_list_clean(struct mode_selection *sel)
{
struct mode_state *ms, *tmp;
list_for_each_entry_safe(ms, tmp, &sel->mode_list, list) {
list_del(&ms->list);
kfree(ms);
}
}
/**
* mode_selection_work_fn() - Alternate mode activation task
* @work: work structure
*
* - If the Alternate Mode currently prioritized at the top of the list is already
* active, the entire selection process is considered finished.
* - If a different Alternate Mode is currently active, the system must exit that
* active mode first before attempting any new entry.
*
* The function then checks the result of the attempt to entre the current mode,
* stored in the `ms->error` field:
* - if the attempt FAILED, the mode is deactivated and removed from the list.
* - `ms->error` value of 0 signifies that the mode has not yet been activated.
*
* Once successfully activated, the task is scheduled for subsequent entry after
* a timeout period. The alternate mode driver is expected to call back with the
* actual mode entry result via `typec_altmode_state_update()`.
*/
static void mode_selection_work_fn(struct work_struct *work)
{
struct mode_selection *sel = container_of(work,
struct mode_selection, work.work);
struct mode_state *ms;
unsigned int delay = sel->delay;
int result;
guard(mutex)(&sel->lock);
ms = list_first_entry_or_null(&sel->mode_list, struct mode_state, list);
if (!ms)
return;
if (sel->active_svid == ms->svid) {
dev_dbg(&sel->partner->dev, "%x altmode is active\n", ms->svid);
mode_list_clean(sel);
} else if (sel->active_svid != 0) {
result = mode_selection_activate(sel, sel->active_svid, 0);
if (result)
mode_list_clean(sel);
else
sel->active_svid = 0;
} else if (ms->error) {
dev_err(&sel->partner->dev, "%x: entry error %pe\n",
ms->svid, ERR_PTR(ms->error));
mode_selection_activate(sel, ms->svid, 0);
list_del(&ms->list);
kfree(ms);
} else {
result = mode_selection_activate(sel, ms->svid, 1);
if (result) {
dev_err(&sel->partner->dev, "%x: activation error %pe\n",
ms->svid, ERR_PTR(result));
list_del(&ms->list);
kfree(ms);
} else {
delay = sel->timeout;
ms->error = -ETIMEDOUT;
}
}
if (!list_empty(&sel->mode_list))
schedule_delayed_work(&sel->work, msecs_to_jiffies(delay));
}
void typec_altmode_state_update(struct typec_partner *partner, const u16 svid,
const int error)
{
struct mode_selection *sel = partner->sel;
struct mode_state *ms;
if (sel) {
mutex_lock(&sel->lock);
ms = list_first_entry_or_null(&sel->mode_list, struct mode_state, list);
if (ms && ms->svid == svid) {
ms->error = error;
if (cancel_delayed_work(&sel->work))
schedule_delayed_work(&sel->work, 0);
}
if (!error)
sel->active_svid = svid;
else
sel->active_svid = 0;
mutex_unlock(&sel->lock);
}
}
EXPORT_SYMBOL_GPL(typec_altmode_state_update);
static int compare_priorities(void *priv,
const struct list_head *a, const struct list_head *b)
{
const struct mode_state *msa = container_of(a, struct mode_state, list);
const struct mode_state *msb = container_of(b, struct mode_state, list);
if (msa->priority < msb->priority)
return -1;
return 1;
}
static int altmode_add_to_list(struct device *dev, void *data)
{
if (is_typec_partner_altmode(dev)) {
struct list_head *list = (struct list_head *)data;
struct typec_altmode *altmode = to_typec_altmode(dev);
const struct typec_altmode *pdev = typec_altmode_get_partner(altmode);
struct mode_state *ms;
if (pdev && altmode->ops && altmode->ops->activate) {
ms = kzalloc(sizeof(*ms), GFP_KERNEL);
if (!ms)
return -ENOMEM;
ms->svid = pdev->svid;
ms->priority = pdev->priority;
INIT_LIST_HEAD(&ms->list);
list_add_tail(&ms->list, list);
}
}
return 0;
}
int typec_mode_selection_start(struct typec_partner *partner,
const unsigned int delay, const unsigned int timeout)
{
struct mode_selection *sel;
int ret;
if (partner->usb_mode == USB_MODE_USB4)
return -EBUSY;
if (partner->sel)
return -EALREADY;
sel = kzalloc(sizeof(*sel), GFP_KERNEL);
if (!sel)
return -ENOMEM;
INIT_LIST_HEAD(&sel->mode_list);
ret = device_for_each_child(&partner->dev, &sel->mode_list,
altmode_add_to_list);
if (ret || list_empty(&sel->mode_list)) {
mode_list_clean(sel);
kfree(sel);
return ret;
}
list_sort(NULL, &sel->mode_list, compare_priorities);
sel->partner = partner;
sel->delay = delay;
sel->timeout = timeout;
mutex_init(&sel->lock);
INIT_DELAYED_WORK(&sel->work, mode_selection_work_fn);
schedule_delayed_work(&sel->work, msecs_to_jiffies(delay));
partner->sel = sel;
return 0;
}
EXPORT_SYMBOL_GPL(typec_mode_selection_start);
void typec_mode_selection_delete(struct typec_partner *partner)
{
struct mode_selection *sel = partner->sel;
if (sel) {
partner->sel = NULL;
cancel_delayed_work_sync(&sel->work);
mode_list_clean(sel);
mutex_destroy(&sel->lock);
kfree(sel);
}
}
EXPORT_SYMBOL_GPL(typec_mode_selection_delete);
+1 -2
View File
@@ -1757,8 +1757,7 @@ static int fusb302_probe(struct i2c_client *client,
}
ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn,
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
"fsc_interrupt_int_n", chip);
IRQF_TRIGGER_LOW, "fsc_interrupt_int_n", chip);
if (ret < 0) {
dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret);
goto tcpm_unregister_port;
+1 -1
View File
@@ -1808,7 +1808,7 @@ static bool svdm_consume_svids(struct tcpm_port *port, const u32 *p, int cnt,
/*
* PD3.0 Spec 6.4.4.3.2: The SVIDs are returned 2 per VDO (see Table
* 6-43), and can be returned maximum 6 VDOs per response (see Figure
* 6-19). If the Respondersupports 12 or more SVID then the Discover
* 6-19). If the Responder supports 12 or more SVID then the Discover
* SVIDs Command Shall be executed multiple times until a Discover
* SVIDs VDO is returned ending either with a SVID value of 0x0000 in
* the last part of the last VDO or with a VDO containing two SVIDs
-1
View File
@@ -73,7 +73,6 @@ config CROS_EC_UCSI
tristate "UCSI Driver for ChromeOS EC"
depends on MFD_CROS_EC_DEV
depends on CROS_USBPD_NOTIFY
depends on !EXTCON_TCSS_CROS_EC
default MFD_CROS_EC_DEV
help
This driver enables UCSI support for a ChromeOS EC. The EC is
+4
View File
@@ -17,6 +17,10 @@ ifneq ($(CONFIG_TYPEC_DP_ALTMODE),)
typec_ucsi-y += displayport.o
endif
ifneq ($(CONFIG_TYPEC_TBT_ALTMODE),)
typec_ucsi-y += thunderbolt.o
endif
obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o
obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o
obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o
+41 -13
View File
@@ -112,15 +112,20 @@ static int ucsi_psy_get_voltage_max(struct ucsi_connector *con,
union power_supply_propval *val)
{
u32 pdo;
int max_voltage = 0;
switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
if (con->num_pdos > 0) {
pdo = con->src_pdos[con->num_pdos - 1];
val->intval = pdo_fixed_voltage(pdo) * 1000;
} else {
val->intval = 0;
for (int i = 0; i < con->num_pdos; i++) {
int pdo_voltage = 0;
pdo = con->src_pdos[i];
if (pdo_type(pdo) == PDO_TYPE_FIXED)
pdo_voltage = pdo_fixed_voltage(pdo) * 1000;
max_voltage = (pdo_voltage > max_voltage) ? pdo_voltage
: max_voltage;
}
val->intval = max_voltage;
break;
case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
@@ -168,6 +173,7 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
union power_supply_propval *val)
{
u32 pdo;
int max_current = 0;
if (!UCSI_CONSTAT(con, CONNECTED)) {
val->intval = 0;
@@ -176,12 +182,16 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
if (con->num_pdos > 0) {
pdo = con->src_pdos[con->num_pdos - 1];
val->intval = pdo_max_current(pdo) * 1000;
} else {
val->intval = 0;
for (int i = 0; i < con->num_pdos; i++) {
int pdo_current = 0;
pdo = con->src_pdos[i];
if (pdo_type(pdo) == PDO_TYPE_FIXED)
pdo_current = pdo_max_current(pdo) * 1000;
max_current = (pdo_current > max_current) ? pdo_current
: max_current;
}
val->intval = max_current;
break;
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
val->intval = UCSI_TYPEC_1_5_CURRENT * 1000;
@@ -202,10 +212,28 @@ static int ucsi_psy_get_current_max(struct ucsi_connector *con,
static int ucsi_psy_get_current_now(struct ucsi_connector *con,
union power_supply_propval *val)
{
if (UCSI_CONSTAT(con, PWR_OPMODE) == UCSI_CONSTAT_PWR_OPMODE_PD)
val->intval = rdo_op_current(con->rdo) * 1000;
else
if (!UCSI_CONSTAT(con, CONNECTED)) {
val->intval = 0;
return 0;
}
switch (UCSI_CONSTAT(con, PWR_OPMODE)) {
case UCSI_CONSTAT_PWR_OPMODE_PD:
val->intval = rdo_op_current(con->rdo) * 1000;
break;
case UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5:
val->intval = UCSI_TYPEC_1_5_CURRENT * 1000;
break;
case UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0:
val->intval = UCSI_TYPEC_3_0_CURRENT * 1000;
break;
case UCSI_CONSTAT_PWR_OPMODE_BC:
case UCSI_CONSTAT_PWR_OPMODE_DEFAULT:
/* UCSI can't tell b/w DCP/CDP or USB2/3x1/3x2 SDP chargers */
default:
val->intval = UCSI_TYPEC_DEFAULT_CURRENT * 1000;
break;
}
return 0;
}
+212
View File
@@ -0,0 +1,212 @@
// SPDX-License-Identifier: GPL-2.0
/*
* UCSI Thunderbolt Alternate Mode Support
*
* Copyright 2026 Google LLC
*/
#include <linux/usb/typec_tbt.h>
#include <linux/usb/pd_vdo.h>
#include <linux/err.h>
#include <linux/dev_printk.h>
#include <linux/device/devres.h>
#include <linux/gfp_types.h>
#include <linux/types.h>
#include <linux/usb/typec_altmode.h>
#include <linux/workqueue.h>
#include "ucsi.h"
/**
* struct ucsi_tbt - Thunderbolt Alternate Mode private data structure
* @con: Pointer to UCSI connector structure
* @alt: Pointer to typec altmode structure
* @work: Work structure
* @cam: An offset into the list of alternate modes supported by the PPM
* @header: VDO header
*/
struct ucsi_tbt {
struct ucsi_connector *con;
struct typec_altmode *alt;
struct work_struct work;
int cam;
u32 header;
};
static void ucsi_thunderbolt_work(struct work_struct *work)
{
struct ucsi_tbt *tbt = container_of(work, struct ucsi_tbt, work);
if (typec_altmode_vdm(tbt->alt, tbt->header, NULL, 0))
dev_err(&tbt->alt->dev, "VDM 0x%x failed\n", tbt->header);
tbt->header = 0;
}
static int ucsi_thunderbolt_set_altmode(struct ucsi_tbt *tbt,
bool enter, u32 vdo)
{
int svdm_version;
int cmd;
int ret;
u64 command = UCSI_SET_NEW_CAM |
UCSI_CONNECTOR_NUMBER(tbt->con->num) |
UCSI_SET_NEW_CAM_SET_AM(tbt->cam) |
((u64)vdo << 32);
if (enter)
command |= (1 << 23);
ret = ucsi_send_command(tbt->con->ucsi, command, NULL, 0);
if (ret < 0)
return ret;
svdm_version = typec_altmode_get_svdm_version(tbt->alt);
if (svdm_version < 0)
return svdm_version;
if (enter)
cmd = CMD_ENTER_MODE;
else
cmd = CMD_EXIT_MODE;
tbt->header = VDO(USB_TYPEC_TBT_SID, 1, svdm_version, cmd);
tbt->header |= VDO_OPOS(TYPEC_TBT_MODE);
tbt->header |= VDO_CMDT(CMDT_RSP_ACK);
schedule_work(&tbt->work);
return 0;
}
static int ucsi_thunderbolt_enter(struct typec_altmode *alt, u32 *vdo)
{
struct ucsi_tbt *tbt = typec_altmode_get_drvdata(alt);
struct ucsi_connector *con = tbt->con;
u64 command;
u8 cur = 0;
int ret;
if (!ucsi_con_mutex_lock(con))
return -ENOTCONN;
command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num);
ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur));
if (ret < 0) {
if (con->ucsi->version > 0x0100)
goto err_unlock;
cur = 0xff;
}
if (cur != 0xff) {
if (cur >= UCSI_MAX_ALTMODES || con->port_altmode[cur] != alt)
ret = -EBUSY;
else
ret = 0;
goto err_unlock;
}
ret = ucsi_thunderbolt_set_altmode(tbt, true, *vdo);
ucsi_altmode_update_active(tbt->con);
err_unlock:
ucsi_con_mutex_unlock(con);
return ret;
}
static int ucsi_thunderbolt_exit(struct typec_altmode *alt)
{
struct ucsi_tbt *tbt = typec_altmode_get_drvdata(alt);
int ret;
if (!ucsi_con_mutex_lock(tbt->con))
return -ENOTCONN;
ret = ucsi_thunderbolt_set_altmode(tbt, false, 0);
ucsi_con_mutex_unlock(tbt->con);
return ret;
}
static int ucsi_thunderbolt_vdm(struct typec_altmode *alt,
u32 header, const u32 *data, int count)
{
struct ucsi_tbt *tbt = typec_altmode_get_drvdata(alt);
int cmd_type = PD_VDO_CMDT(header);
int cmd = PD_VDO_CMD(header);
int svdm_version;
if (!ucsi_con_mutex_lock(tbt->con))
return -ENOTCONN;
svdm_version = typec_altmode_get_svdm_version(alt);
if (svdm_version < 0) {
ucsi_con_mutex_unlock(tbt->con);
return svdm_version;
}
switch (cmd_type) {
case CMDT_INIT:
if (PD_VDO_SVDM_VER(header) < svdm_version) {
svdm_version = PD_VDO_SVDM_VER(header);
typec_partner_set_svdm_version(tbt->con->partner, svdm_version);
}
tbt->header = VDO(USB_TYPEC_TBT_SID, 1, svdm_version, cmd);
tbt->header |= VDO_OPOS(TYPEC_TBT_MODE);
tbt->header |= VDO_CMDT(CMDT_RSP_ACK);
schedule_work(&tbt->work);
break;
default:
break;
}
ucsi_con_mutex_unlock(tbt->con);
return 0;
}
static const struct typec_altmode_ops ucsi_thunderbolt_ops = {
.enter = ucsi_thunderbolt_enter,
.exit = ucsi_thunderbolt_exit,
.vdm = ucsi_thunderbolt_vdm,
};
struct typec_altmode *ucsi_register_thunderbolt(struct ucsi_connector *con,
bool override, int offset,
struct typec_altmode_desc *desc)
{
struct typec_altmode *alt;
struct ucsi_tbt *tbt;
alt = typec_port_register_altmode(con->port, desc);
if (IS_ERR(alt) || !override)
return alt;
tbt = devm_kzalloc(&alt->dev, sizeof(*tbt), GFP_KERNEL);
if (!tbt) {
typec_unregister_altmode(alt);
return ERR_PTR(-ENOMEM);
}
tbt->cam = offset;
tbt->con = con;
tbt->alt = alt;
INIT_WORK(&tbt->work, ucsi_thunderbolt_work);
typec_altmode_set_drvdata(alt, tbt);
typec_altmode_set_ops(alt, &ucsi_thunderbolt_ops);
return alt;
}
void ucsi_thunderbolt_remove_partner(struct typec_altmode *alt)
{
struct ucsi_tbt *tbt;
if (alt) {
tbt = typec_altmode_get_drvdata(alt);
if (tbt)
cancel_work_sync(&tbt->work);
}
}
+33 -7
View File
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/usb/typec_dp.h>
#include <linux/usb/typec_tbt.h>
#include "ucsi.h"
#include "trace.h"
@@ -42,8 +43,14 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci)
if (cci & UCSI_CCI_BUSY)
return;
if (UCSI_CCI_CONNECTOR(cci))
ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
if (UCSI_CCI_CONNECTOR(cci)) {
if (!ucsi->cap.num_connectors ||
UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors)
ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci));
else
dev_err(ucsi->dev, "bogus connector number in CCI: %lu\n",
UCSI_CCI_CONNECTOR(cci));
}
if (cci & UCSI_CCI_ACK_COMPLETE &&
test_and_clear_bit(ACK_PENDING, &ucsi->flags))
@@ -314,6 +321,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
{
const struct typec_altmode *altmode = NULL;
u64 command;
u16 svid = 0;
int ret;
u8 cur;
int i;
@@ -335,6 +343,10 @@ void ucsi_altmode_update_active(struct ucsi_connector *con)
for (i = 0; con->partner_altmode[i]; i++)
typec_altmode_update_active(con->partner_altmode[i],
con->partner_altmode[i] == altmode);
if (altmode)
svid = altmode->svid;
typec_altmode_state_update(con->partner, svid, 0);
}
static int ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid)
@@ -412,6 +424,9 @@ static int ucsi_register_altmode(struct ucsi_connector *con,
alt = ucsi_register_displayport(con, override,
i, desc);
break;
case USB_TYPEC_TBT_SID:
alt = ucsi_register_thunderbolt(con, override, i, desc);
break;
default:
alt = typec_port_register_altmode(con->port, desc);
break;
@@ -609,6 +624,8 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient)
desc.vdo = alt[j].mid;
desc.svid = alt[j].svid;
desc.roles = TYPEC_PORT_DRD;
desc.mode_selection = con->ucsi->ops->add_partner_altmodes &&
!con->typec_cap.no_mode_control;
ret = ucsi_register_altmode(con, &desc, recipient);
if (ret)
@@ -640,12 +657,15 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient)
}
while (adev[i]) {
if (recipient == UCSI_RECIPIENT_SOP &&
(adev[i]->svid == USB_TYPEC_DP_SID ||
(adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID &&
adev[i]->vdo != USB_TYPEC_NVIDIA_VLINK_DBG_VDO))) {
if (recipient == UCSI_RECIPIENT_SOP) {
pdev = typec_altmode_get_partner(adev[i]);
ucsi_displayport_remove_partner((void *)pdev);
if (adev[i]->svid == USB_TYPEC_DP_SID ||
(adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID &&
adev[i]->vdo != USB_TYPEC_NVIDIA_VLINK_DBG_VDO))
ucsi_displayport_remove_partner((void *)pdev);
else if (adev[i]->svid == USB_TYPEC_TBT_SID)
ucsi_thunderbolt_remove_partner((void *)pdev);
}
typec_unregister_altmode(adev[i]);
adev[i++] = NULL;
@@ -831,6 +851,8 @@ static int ucsi_check_altmodes(struct ucsi_connector *con)
if (con->partner_altmode[0]) {
num_partner_am = ucsi_get_num_altmode(con->partner_altmode);
typec_partner_set_num_altmodes(con->partner, num_partner_am);
if (con->ucsi->ops->add_partner_altmodes)
con->ucsi->ops->add_partner_altmodes(con);
ucsi_altmode_update_active(con);
return 0;
} else {
@@ -1119,6 +1141,8 @@ static void ucsi_unregister_partner(struct ucsi_connector *con)
return;
typec_set_mode(con->port, TYPEC_STATE_SAFE);
if (con->ucsi->ops->remove_partner_altmodes)
con->ucsi->ops->remove_partner_altmodes(con);
typec_partner_set_usb_power_delivery(con->partner, NULL);
ucsi_unregister_partner_pdos(con);
@@ -1307,6 +1331,7 @@ static void ucsi_handle_connector_change(struct work_struct *work)
if (con->partner && (change & UCSI_CONSTAT_PARTNER_CHANGE)) {
ucsi_partner_change(con);
ucsi_altmode_update_active(con);
/* Complete pending data role swap */
if (!completion_done(&con->complete))
@@ -1659,6 +1684,7 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con)
cap->driver_data = con;
cap->ops = &ucsi_ops;
cap->no_mode_control = !(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE);
if (ucsi->version >= UCSI_VERSION_2_0)
con->typec_cap.orientation_aware = true;
+24
View File
@@ -70,6 +70,8 @@ struct dentry;
* @update_altmodes: Squashes duplicate DP altmodes
* @update_connector: Update connector capabilities before registering
* @connector_status: Updates connector status, called holding connector lock
* @add_partner_altmodes: Start mode selection
* @remove_partner_altmodes: Clean mode selection
*
* Read and write routines for UCSI interface. @sync_write must wait for the
* Command Completion Event from the PPM before returning, and @async_write must
@@ -88,6 +90,8 @@ struct ucsi_operations {
struct ucsi_altmode *updated);
void (*update_connector)(struct ucsi_connector *con);
void (*connector_status)(struct ucsi_connector *con);
void (*add_partner_altmodes)(struct ucsi_connector *con);
void (*remove_partner_altmodes)(struct ucsi_connector *con);
};
struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops);
@@ -596,6 +600,26 @@ static inline void
ucsi_displayport_remove_partner(struct typec_altmode *adev) { }
#endif /* CONFIG_TYPEC_DP_ALTMODE */
#if IS_ENABLED(CONFIG_TYPEC_TBT_ALTMODE)
struct typec_altmode *
ucsi_register_thunderbolt(struct ucsi_connector *con,
bool override, int offset,
struct typec_altmode_desc *desc);
void ucsi_thunderbolt_remove_partner(struct typec_altmode *adev);
#else
static inline struct typec_altmode *
ucsi_register_thunderbolt(struct ucsi_connector *con,
bool override, int offset,
struct typec_altmode_desc *desc)
{
return typec_port_register_altmode(con->port, desc);
}
static inline void
ucsi_thunderbolt_remove_partner(struct typec_altmode *adev) { }
#endif /* CONFIG_TYPEC_TBT_ALTMODE */
#ifdef CONFIG_DEBUG_FS
void ucsi_debugfs_init(void);
void ucsi_debugfs_exit(void);
+2 -2
View File
@@ -55,8 +55,8 @@ void stub_complete(struct urb *urb)
"stopped by a call to usb_kill_urb() because of cleaning up a virtual connection\n");
return;
case -ECONNRESET:
dev_info(&urb->dev->dev,
"unlinked by a call to usb_unlink_urb()\n");
dev_dbg(&urb->dev->dev,
"unlinked by a call to usb_unlink_urb()\n");
break;
case -EPIPE:
dev_info(&urb->dev->dev, "endpoint %d is stalled\n",
+1 -1
View File
@@ -215,7 +215,7 @@ static inline int __must_check
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags,
return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags | IRQF_COND_ONESHOT,
devname, dev_id);
}
+5
View File
@@ -247,6 +247,11 @@ enum pci_dev_flags {
PCI_DEV_FLAGS_NO_RELAXED_ORDERING = (__force pci_dev_flags_t) (1 << 11),
/* Device does honor MSI masking despite saying otherwise */
PCI_DEV_FLAGS_HAS_MSI_MASKING = (__force pci_dev_flags_t) (1 << 12),
/*
* PCIe to PCI bridge does not create RID aliases because the bridge is
* integrated with the downstream devices and doesn't use real PCI.
*/
PCI_DEV_FLAGS_PCI_BRIDGE_NO_ALIAS = (__force pci_dev_flags_t) (1 << 14),
};
enum pci_irq_reroute_variant {
+2
View File
@@ -2577,6 +2577,8 @@
#define PCI_DEVICE_ID_NETRONOME_NFP3800_VF 0x3803
#define PCI_DEVICE_ID_NETRONOME_NFP6000_VF 0x6003
#define PCI_VENDOR_ID_ASPEED 0x1a03
#define PCI_VENDOR_ID_QMI 0x1a32
#define PCI_VENDOR_ID_AZWAVE 0x1a3b
+2 -5
View File
@@ -238,7 +238,7 @@ static inline void *phy_get_drvdata(struct phy *phy)
#if IS_ENABLED(CONFIG_GENERIC_PHY)
int phy_pm_runtime_get(struct phy *phy);
int phy_pm_runtime_get_sync(struct phy *phy);
int phy_pm_runtime_put(struct phy *phy);
void phy_pm_runtime_put(struct phy *phy);
int phy_pm_runtime_put_sync(struct phy *phy);
int phy_init(struct phy *phy);
int phy_exit(struct phy *phy);
@@ -319,11 +319,8 @@ static inline int phy_pm_runtime_get_sync(struct phy *phy)
return -ENOSYS;
}
static inline int phy_pm_runtime_put(struct phy *phy)
static inline void phy_pm_runtime_put(struct phy *phy)
{
if (!phy)
return 0;
return -ENOSYS;
}
static inline int phy_pm_runtime_put_sync(struct phy *phy)
+4 -3
View File
@@ -90,9 +90,10 @@ enum {
MAC_40000FD = BIT(13),
MAC_50000FD = BIT(14),
MAC_56000FD = BIT(15),
MAC_100000FD = BIT(16),
MAC_200000FD = BIT(17),
MAC_400000FD = BIT(18),
MAC_80000FD = BIT(16),
MAC_100000FD = BIT(17),
MAC_200000FD = BIT(18),
MAC_400000FD = BIT(19),
};
static inline bool phylink_autoneg_inband(unsigned int mode)
+15 -6
View File
@@ -21,6 +21,7 @@
#include <linux/completion.h> /* for struct completion */
#include <linux/sched.h> /* for current && schedule_timeout */
#include <linux/mutex.h> /* for struct mutex */
#include <linux/spinlock.h> /* for spinlock_t */
#include <linux/pm_runtime.h> /* for runtime PM */
struct usb_device;
@@ -636,8 +637,9 @@ struct usb3_lpm_parameters {
* @do_remote_wakeup: remote wakeup should be enabled
* @reset_resume: needs reset instead of resume
* @port_is_suspended: the upstream port is suspended (L2 or U3)
* @offload_at_suspend: offload activities during suspend is enabled.
* @offload_pm_locked: prevents offload_usage changes during PM transitions.
* @offload_usage: number of offload activities happening on this usb device.
* @offload_lock: protects offload_usage and offload_pm_locked
* @slot_id: Slot ID assigned by xHCI
* @l1_params: best effor service latency for USB2 L1 LPM state, and L1 timeout.
* @u1_params: exit latencies for USB3 U1 LPM state, and hub-initiated timeout.
@@ -726,8 +728,9 @@ struct usb_device {
unsigned do_remote_wakeup:1;
unsigned reset_resume:1;
unsigned port_is_suspended:1;
unsigned offload_at_suspend:1;
unsigned offload_pm_locked:1;
int offload_usage;
spinlock_t offload_lock;
enum usb_link_tunnel_mode tunnel_mode;
struct device_link *usb4_link;
@@ -849,6 +852,7 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
int usb_offload_get(struct usb_device *udev);
int usb_offload_put(struct usb_device *udev);
bool usb_offload_check(struct usb_device *udev);
void usb_offload_set_pm_locked(struct usb_device *udev, bool locked);
#else
static inline int usb_offload_get(struct usb_device *udev)
@@ -857,6 +861,8 @@ static inline int usb_offload_put(struct usb_device *udev)
{ return 0; }
static inline bool usb_offload_check(struct usb_device *udev)
{ return false; }
static inline void usb_offload_set_pm_locked(struct usb_device *udev, bool locked)
{ }
#endif
extern int usb_disable_lpm(struct usb_device *udev);
@@ -1295,8 +1301,7 @@ struct usb_driver {
* resume and suspend functions will be called in addition to the driver's
* own, so this part of the setup does not need to be replicated.
*
* USB drivers must provide all the fields listed above except driver,
* match, and id_table.
* USB device drivers must provide a name, other driver fields are optional.
*/
struct usb_device_driver {
const char *name;
@@ -1863,14 +1868,18 @@ void usb_free_noncoherent(struct usb_device *dev, size_t size,
* SYNCHRONOUS CALL SUPPORT *
*-------------------------------------------------------------------*/
/* Maximum value allowed for timeout in synchronous routines below */
#define USB_MAX_SYNCHRONOUS_TIMEOUT 60000 /* ms */
extern int usb_control_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
extern int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
extern int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length,
int timeout);
void *data, int len, int *actual_length, int timeout);
extern int usb_bulk_msg_killable(struct usb_device *usb_dev, unsigned int pipe,
void *data, int len, int *actual_length, int timeout);
/* wrappers around usb_control_msg() for the most common standard requests */
int usb_control_msg_send(struct usb_device *dev, __u8 endpoint, __u8 request,
-6
View File
@@ -760,12 +760,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
*/
extern struct rw_semaphore ehci_cf_port_reset_rwsem;
/* Keep track of which host controller drivers are loaded */
#define USB_UHCI_LOADED 0
#define USB_OHCI_LOADED 1
#define USB_EHCI_LOADED 2
extern unsigned long usb_hcds_loaded;
#endif /* __KERNEL__ */
#endif /* __USB_CORE_HCD_H */
-47
View File
@@ -1,47 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* board initialization code should put one of these into dev->platform_data
* and place the isp1362 onto platform_bus.
*/
#ifndef __LINUX_USB_ISP1362_H__
#define __LINUX_USB_ISP1362_H__
struct isp1362_platform_data {
/* Enable internal pulldown resistors on downstream ports */
unsigned sel15Kres:1;
/* Clock cannot be stopped */
unsigned clknotstop:1;
/* On-chip overcurrent protection */
unsigned oc_enable:1;
/* INT output polarity */
unsigned int_act_high:1;
/* INT edge or level triggered */
unsigned int_edge_triggered:1;
/* DREQ output polarity */
unsigned dreq_act_high:1;
/* DACK input polarity */
unsigned dack_act_high:1;
/* chip can be resumed via H_WAKEUP pin */
unsigned remote_wakeup_connected:1;
/* Switch or not to switch (keep always powered) */
unsigned no_power_switching:1;
/* Ganged port power switching (0) or individual port power switching (1) */
unsigned power_switching_mode:1;
/* Given port_power, msec/2 after power on till power good */
u8 potpg;
/* Hardware reset set/clear */
void (*reset) (struct device *dev, int set);
/* Clock start/stop */
void (*clock) (struct device *dev, int start);
/* Inter-io delay (ns). The chip is picky about access timings; it
* expects at least:
* 110ns delay between consecutive accesses to DATA_REG,
* 300ns delay between access to ADDR_REG and DATA_REG (registers)
* 462ns delay between access to ADDR_REG and DATA_REG (buffer memory)
* WE MUST NOT be activated during these intervals (even without CS!)
*/
void (*delay) (struct device *dev, unsigned int delay);
};
#endif
+3
View File
@@ -78,4 +78,7 @@
/* skip BOS descriptor request */
#define USB_QUIRK_NO_BOS BIT(17)
/* Device claims zero configurations, forcing to 1 */
#define USB_QUIRK_FORCE_ONE_CONFIG BIT(18)
#endif /* __LINUX_USB_QUIRKS_H */

Some files were not shown because too many files have changed in this diff Show More