Commit 2a298679 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB updates from Greg KH:
 "Here's the big USB patchset for 4.2-rc1.  As is normal these days, the
  majority of changes are in the gadget drivers, with a bunch of other
  small driver changes.

  All of these have been in linux-next with no reported issues"

* tag 'usb-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (175 commits)
  usb: dwc3: Use ASCII space in Kconfig
  usb: chipidea: add work-around for Marvell HSIC PHY startup
  usb: chipidea: allow multiple instances to use default ci_default_pdata
  dt-bindings: Consolidate ChipIdea USB ci13xxx bindings
  phy: add Marvell HSIC 28nm PHY
  phy: Add Marvell USB 2.0 OTG 28nm PHY
  dt-bindings: Add Marvell PXA1928 USB and HSIC PHY bindings
  USB: ssb: use devm_kzalloc
  USB: ssb: fix error handling in ssb_hcd_create_pdev()
  usb: isp1760: check for null return from kzalloc
  cdc-acm: Add support of ATOL FPrint fiscal printers
  usb: chipidea: usbmisc_imx: Remove unneeded semicolon
  USB: usbtmc: add device quirk for Rigol DS6104
  USB: serial: mos7840: Use setup_timer
  phy: twl4030-usb: add ABI documentation
  phy: twl4030-usb: remove incorrect pm_runtime_get_sync() in probe function.
  phy: twl4030-usb: remove pointless 'suspended' test in 'suspend' callback.
  phy: twl4030-usb: make runtime pm more reliable.
  drivers:usb:fsl: Fix compilation error for fsl ehci drv
  usb: renesas_usbhs: Don't disable the pipe if Control write status stage
  ...
parents 8c7febe8 50641056
What: /sys/bus/platform/devices/*twl4030-usb/vbus
Description:
Read-only status reporting if VBUS (approx 5V)
is being supplied by the USB bus.
Possible values: "on", "off".
Changes are notified via select/poll.
* Broadcom SATA3 PHY for STB
Required properties:
- compatible: should be one or more of
"brcm,bcm7445-sata-phy"
"brcm,phy-sata3"
- address-cells: should be 1
- size-cells: should be 0
- reg: register range for the PHY PCB interface
- reg-names: should be "phy"
Sub-nodes:
Each port's PHY should be represented as a sub-node.
Sub-nodes required properties:
- reg: the PHY number
- phy-cells: generic PHY binding; must be 0
Optional:
- brcm,enable-ssc: use spread spectrum clocking (SSC) on this port
Example:
sata-phy@f0458100 {
compatible = "brcm,bcm7445-sata-phy", "brcm,phy-sata3";
reg = <0xf0458100 0x1e00>, <0xf045804c 0x10>;
reg-names = "phy";
#address-cells = <1>;
#size-cells = <0>;
sata-phy@0 {
reg = <0>;
#phy-cells = <0>;
};
sata-phy@1 {
reg = <1>;
#phy-cells = <0>;
};
};
* Marvell PXA1928 USB and HSIC PHYs
Required properties:
- compatible: "marvell,pxa1928-usb-phy" or "marvell,pxa1928-hsic-phy"
- reg: base address and length of the registers
- clocks - A single clock. From common clock binding.
- #phys-cells: should be 0. From commmon phy binding.
- resets: reference to the reset controller
Example:
usbphy: phy@7000 {
compatible = "marvell,pxa1928-usb-phy";
reg = <0x7000 0xe0>;
clocks = <&apmu_clocks PXA1928_CLK_USB>;
#phy-cells = <0>;
};
......@@ -6,6 +6,7 @@ This file provides information on what the device node for the R-Car generation
Required properties:
- compatible: "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC.
"renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC.
"renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC.
- reg: offset and length of the register block.
- #address-cells: number of address cells for the USB channel subnodes, must
be <1>.
......
TWL BCI (Battery Charger Interface)
The battery charger needs to interact with the USB phy in order
to know when charging is permissible, and when there is a connection
or disconnection.
The choice of phy cannot be configured at a hardware level, so there
is no value in explicit configuration in device-tree. Rather
if there is a sibling of the BCI node which is compatible with
"ti,twl4030-usb", then that is used to determine when and how
use USB power for charging.
Required properties:
- compatible:
- "ti,twl4030-bci"
......
* Freescale i.MX ci13xxx usb controllers
Required properties:
- compatible: Should be "fsl,imx27-usb"
- reg: Should contain registers location and length
- interrupts: Should contain controller interrupt
- fsl,usbphy: phandle of usb phy that connects to the port
Recommended properies:
- phy_type: the type of the phy connected to the core. Should be one
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
property the PORTSC register won't be touched
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
Optional properties:
- fsl,usbmisc: phandler of non-core register device, with one argument
that indicate usb controller index
- vbus-supply: regulator for vbus
- disable-over-current: disable over current detect
- external-vbus-divider: enables off-chip resistor divider for Vbus
- maximum-speed: limit the maximum connection speed to "full-speed".
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
Examples:
usb@02184000 { /* USB OTG */
compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
reg = <0x02184000 0x200>;
interrupts = <0 43 0x04>;
fsl,usbphy = <&usbphy1>;
fsl,usbmisc = <&usbmisc 0>;
disable-over-current;
external-vbus-divider;
maximum-speed = "full-speed";
tpl-support;
};
Qualcomm CI13xxx (Chipidea) USB controllers
Required properties:
- compatible: should contain "qcom,ci-hdrc"
- reg: offset and length of the register set in the memory map
- interrupts: interrupt-specifier for the controller interrupt.
- usb-phy: phandle for the PHY device
- dr_mode: Should be "peripheral"
Examples:
gadget@f9a55000 {
compatible = "qcom,ci-hdrc";
reg = <0xf9a55000 0x400>;
dr_mode = "peripheral";
interrupts = <0 134 0>;
usb-phy = <&usbphy0>;
};
* USB2 ChipIdea USB controller for ci13xxx
Required properties:
- compatible: should be "chipidea,usb2"
- compatible: should be one of:
"fsl,imx27-usb"
"lsi,zevio-usb"
"qcom,ci-hdrc"
"chipidea,usb2"
- reg: base address and length of the registers
- interrupts: interrupt for the USB controller
Recommended properies:
- phy_type: the type of the phy connected to the core. Should be one
of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
property the PORTSC register won't be touched.
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
Deprecated properties:
- usb-phy: phandle for the PHY device. Use "phys" instead.
- fsl,usbphy: phandle of usb phy that connects to the port. Use "phys" instead.
Optional properties:
- clocks: reference to the USB clock
- phys: reference to the USB PHY
- phy-names: should be "usb-phy"
- vbus-supply: reference to the VBUS regulator
- maximum-speed: limit the maximum connection speed to "full-speed".
- tpl-support: TPL (Targeted Peripheral List) feature for targeted hosts
- fsl,usbmisc: (FSL only) phandler of non-core register device, with one
argument that indicate usb controller index
- disable-over-current: (FSL only) disable over current detect
- external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus
Example:
......
* LSI Zevio USB OTG Controller
Required properties:
- compatible: Should be "lsi,zevio-usb"
- reg: Should contain registers location and length
- interrupts: Should contain controller interrupt
Optional properties:
- vbus-supply: regulator for vbus
Examples:
usb0: usb@b0000000 {
reg = <0xb0000000 0x1000>;
compatible = "lsi,zevio-usb";
interrupts = <8>;
vbus-supply = <&vbus_reg>;
};
......@@ -49,8 +49,7 @@ st_dwc3: dwc3@8f94000 {
st,syscfg = <&syscfg_core>;
resets = <&powerdown STIH407_USB3_POWERDOWN>,
<&softreset STIH407_MIPHY2_SOFTRESET>;
reset-names = "powerdown",
"softreset";
reset-names = "powerdown", "softreset";
#address-cells = <1>;
#size-cells = <1>;
pinctrl-names = "default";
......@@ -62,7 +61,7 @@ st_dwc3: dwc3@8f94000 {
reg = <0x09900000 0x100000>;
interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>;
dr_mode = "host";
phys-names = "usb2-phy", "usb3-phy";
phys = <&usb2_picophy2>, <&phy_port2 MIPHY_TYPE_USB>;
phy-names = "usb2-phy", "usb3-phy";
phys = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>;
};
};
......@@ -38,6 +38,8 @@ Optional properties:
- snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
utmi_l1_suspend_n, false when asserts utmi_sleep_n
- snps,hird-threshold: HIRD threshold
- snps,hsphy_interface: High-Speed PHY interface selection between "utmi" for
UTMI+ and "ulpi" for ULPI when the DWC_USB3_HSPHY_INTERFACE has value 3.
This is usually a subnode to DWC3 glue to which it is connected.
......
......@@ -69,6 +69,17 @@ Optional properties:
(no, min, max) where each value represents either a voltage
in microvolts or a value corresponding to voltage corner.
- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
and controller driver therefore enables pull-up explicitly
before starting controller using usbcmd run/stop bit.
- extcon: phandles to external connector devices. First phandle
should point to external connector, which provide "USB"
cable events, the second should point to external connector
device, which provide "USB-HOST" cable events. If one of
the external connector devices is not required empty <0>
phandle should be specified.
Example HSUSB OTG controller device node:
usb@f9a55000 {
......
......@@ -4,6 +4,7 @@ Required properties:
- compatible: Must contain one of the following:
- "renesas,usbhs-r8a7790"
- "renesas,usbhs-r8a7791"
- "renesas,usbhs-r8a7794"
- reg: Base address and length of the register for the USBHS
- interrupts: Interrupt specifier for the USBHS
- clocks: A list of phandle + clock specifier pairs
......
......@@ -30,6 +30,9 @@ TWL4030 USB PHY AND COMPARATOR
- usb_mode : The mode used by the phy to connect to the controller. "1"
specifies "ULPI" mode and "2" specifies "CEA2011_3PIN" mode.
If a sibling node is compatible "ti,twl4030-bci", then it will find
this device and query it for USB power status.
twl4030-usb {
compatible = "ti,twl4030-usb";
interrupts = < 10 4 >;
......
......@@ -13,6 +13,8 @@ Optional properties:
- big-endian-desc : boolean, set this for hcds with big-endian descriptors
- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
- needs-reset-on-resume : boolean, set this to force EHCI reset after resume
- has-transaction-translator : boolean, set this if EHCI have a Transaction
Translator built into the root hub.
- clocks : a list of phandle + clock specifier pairs
- phys : phandle + phy specifier pair
- phy-names : "usb"
......
......@@ -76,6 +76,8 @@ struct phy *phy_get(struct device *dev, const char *string);
struct phy *phy_optional_get(struct device *dev, const char *string);
struct phy *devm_phy_get(struct device *dev, const char *string);
struct phy *devm_phy_optional_get(struct device *dev, const char *string);
struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
int index);
phy_get, phy_optional_get, devm_phy_get and devm_phy_optional_get can
be used to get the PHY. In the case of dt boot, the string arguments
......@@ -86,7 +88,10 @@ successful PHY get. On driver detach, release function is invoked on
the the devres data and devres data is freed. phy_optional_get and
devm_phy_optional_get should be used when the phy is optional. These
two functions will never return -ENODEV, but instead returns NULL when
the phy cannot be found.
the phy cannot be found.Some generic drivers, such as ehci, may use multiple
phys and for such drivers referencing phy(s) by name(s) does not make sense. In
this case, devm_of_phy_get_by_index can be used to get a phy reference based on
the index.
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
......
......@@ -526,8 +526,6 @@ Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
By default there can be only 1 RNDIS interface in the system.
Testing the RNDIS function
--------------------------
......@@ -629,7 +627,7 @@ Function-specific configfs interface
The function name to use when creating the function directory is "uac2".
The uac2 function provides these attributes in its function directory:
chmask - capture channel mask
c_chmask - capture channel mask
c_srate - capture sampling rate
c_ssize - capture sample size (bytes)
p_chmask - playback channel mask
......
......@@ -10712,6 +10712,13 @@ S: Maintained
F: Documentation/video4linux/zr364xx.txt
F: drivers/media/usb/zr364xx/
ULPI BUS
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org
S: Maintained
F: drivers/usb/common/ulpi.c
F: include/linux/ulpi/
USER-MODE LINUX (UML)
M: Jeff Dike <jdike@addtoit.com>
M: Richard Weinberger <richard@nod.at>
......
......@@ -54,6 +54,26 @@ config PHY_EXYNOS_MIPI_VIDEO
Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
and EXYNOS SoCs.
config PHY_PXA_28NM_HSIC
tristate "Marvell USB HSIC 28nm PHY Driver"
select GENERIC_PHY
help
Enable this to support Marvell USB HSIC PHY driver for Marvell
SoC. This driver will do the PHY initialization and shutdown.
The PHY driver will be used by Marvell ehci driver.
To compile this driver as a module, choose M here.
config PHY_PXA_28NM_USB2
tristate "Marvell USB 2.0 28nm PHY Driver"
select GENERIC_PHY
help
Enable this to support Marvell USB 2.0 PHY driver for Marvell
SoC. This driver will do the PHY initialization and shutdown.
The PHY driver will be used by Marvell udc/ehci/otg driver.
To compile this driver as a module, choose M here.
config PHY_MVEBU_SATA
def_bool y
depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD
......@@ -313,4 +333,20 @@ config PHY_QCOM_UFS
help
Support for UFS PHY on QCOM chipsets.
config PHY_TUSB1210
tristate "TI TUSB1210 ULPI PHY module"
depends on USB_ULPI_BUS
select GENERIC_PHY
help
Support for TI TUSB1210 USB ULPI PHY.
config PHY_BRCMSTB_SATA
tristate "Broadcom STB SATA PHY driver"
depends on ARCH_BRCMSTB
depends on OF
select GENERIC_PHY
help
Enable this to support the SATA3 PHY on 28nm Broadcom STB SoCs.
Likely useful only with CONFIG_SATA_BRCMSTB enabled.
endmenu
......@@ -10,6 +10,8 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
......@@ -40,3 +42,5 @@ obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o
obj-$(CONFIG_PHY_BRCMSTB_SATA) += phy-brcmstb-sata.o
/*
* Broadcom SATA3 AHCI Controller PHY Driver
*
* Copyright © 2009-2015 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define SATA_MDIO_BANK_OFFSET 0x23c
#define SATA_MDIO_REG_OFFSET(ofs) ((ofs) * 4)
#define SATA_MDIO_REG_SPACE_SIZE 0x1000
#define SATA_MDIO_REG_LENGTH 0x1f00
#define MAX_PORTS 2
/* Register offset between PHYs in PCB space */
#define SATA_MDIO_REG_SPACE_SIZE 0x1000
struct brcm_sata_port {
int portnum;
struct phy *phy;
struct brcm_sata_phy *phy_priv;
bool ssc_en;
};
struct brcm_sata_phy {
struct device *dev;
void __iomem *phy_base;
struct brcm_sata_port phys[MAX_PORTS];
};
enum sata_mdio_phy_regs_28nm {
PLL_REG_BANK_0 = 0x50,
PLL_REG_BANK_0_PLLCONTROL_0 = 0x81,
TXPMD_REG_BANK = 0x1a0,
TXPMD_CONTROL1 = 0x81,
TXPMD_CONTROL1_TX_SSC_EN_FRC = BIT(0),
TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL = BIT(1),
TXPMD_TX_FREQ_CTRL_CONTROL1 = 0x82,
TXPMD_TX_FREQ_CTRL_CONTROL2 = 0x83,
TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK = 0x3ff,
TXPMD_TX_FREQ_CTRL_CONTROL3 = 0x84,
TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK = 0x3ff,
};
static inline void __iomem *brcm_sata_phy_base(struct brcm_sata_port *port)
{
struct brcm_sata_phy *priv = port->phy_priv;
return priv->phy_base + (port->portnum * SATA_MDIO_REG_SPACE_SIZE);
}
static void brcm_sata_mdio_wr(void __iomem *addr, u32 bank, u32 ofs,
u32 msk, u32 value)
{
u32 tmp;
writel(bank, addr + SATA_MDIO_BANK_OFFSET);
tmp = readl(addr + SATA_MDIO_REG_OFFSET(ofs));
tmp = (tmp & msk) | value;
writel(tmp, addr + SATA_MDIO_REG_OFFSET(ofs));
}
/* These defaults were characterized by H/W group */
#define FMIN_VAL_DEFAULT 0x3df
#define FMAX_VAL_DEFAULT 0x3df
#define FMAX_VAL_SSC 0x83
static void brcm_sata_cfg_ssc_28nm(struct brcm_sata_port *port)
{
void __iomem *base = brcm_sata_phy_base(port);
struct brcm_sata_phy *priv = port->phy_priv;
u32 tmp;
/* override the TX spread spectrum setting */
tmp = TXPMD_CONTROL1_TX_SSC_EN_FRC_VAL | TXPMD_CONTROL1_TX_SSC_EN_FRC;
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_CONTROL1, ~tmp, tmp);
/* set fixed min freq */
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL2,
~TXPMD_TX_FREQ_CTRL_CONTROL2_FMIN_MASK,
FMIN_VAL_DEFAULT);
/* set fixed max freq depending on SSC config */
if (port->ssc_en) {
dev_info(priv->dev, "enabling SSC on port %d\n", port->portnum);
tmp = FMAX_VAL_SSC;
} else {
tmp = FMAX_VAL_DEFAULT;
}
brcm_sata_mdio_wr(base, TXPMD_REG_BANK, TXPMD_TX_FREQ_CTRL_CONTROL3,
~TXPMD_TX_FREQ_CTRL_CONTROL3_FMAX_MASK, tmp);
}
static int brcm_sata_phy_init(struct phy *phy)
{
struct brcm_sata_port *port = phy_get_drvdata(phy);
brcm_sata_cfg_ssc_28nm(port);
return 0;
}
static struct phy_ops phy_ops_28nm = {
.init = brcm_sata_phy_init,
.owner = THIS_MODULE,
};
static const struct of_device_id brcm_sata_phy_of_match[] = {
{ .compatible = "brcm,bcm7445-sata-phy" },
{},
};
MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match);
static int brcm_sata_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *dn = dev->of_node, *child;
struct brcm_sata_phy *priv;
struct resource *res;
struct phy_provider *provider;
int count = 0;
if (of_get_child_count(dn) == 0)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
dev_set_drvdata(dev, priv);
priv->dev = dev;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
priv->phy_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->phy_base))
return PTR_ERR(priv->phy_base);
for_each_available_child_of_node(dn, child) {
unsigned int id;
struct brcm_sata_port *port;
if (of_property_read_u32(child, "reg", &id)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
return -EINVAL;
}
if (id >= MAX_PORTS) {
dev_err(dev, "invalid reg: %u\n", id);
return -EINVAL;
}
if (priv->phys[id].phy) {
dev_err(dev, "already registered port %u\n", id);
return -EINVAL;
}
port = &priv->phys[id];
port->portnum = id;
port->phy_priv = priv;
port->phy = devm_phy_create(dev, child, &phy_ops_28nm);
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
if (IS_ERR(port->phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(port->phy);
}
phy_set_drvdata(port->phy, port);
count++;
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(provider)) {
dev_err(dev, "could not register PHY provider\n");
return PTR_ERR(provider);
}
dev_info(dev, "registered %d port(s)\n", count);
return 0;
}
static struct platform_driver brcm_sata_phy_driver = {
.probe = brcm_sata_phy_probe,
.driver = {
.of_match_table = brcm_sata_phy_of_match,
.name = "brcmstb-sata-phy",
}
};
module_platform_driver(brcm_sata_phy_driver);
MODULE_DESCRIPTION("Broadcom STB SATA PHY driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Carino");
MODULE_AUTHOR("Brian Norris");
MODULE_ALIAS("platform:phy-brcmstb-sata");
......@@ -367,13 +367,21 @@ static struct phy *_of_phy_get(struct device_node *np, int index)
phy_provider = of_phy_provider_lookup(args.np);
if (IS_ERR(phy_provider) || !try_module_get(phy_provider->owner)) {
phy = ERR_PTR(-EPROBE_DEFER);
goto err0;
goto out_unlock;
}
if (!of_device_is_available(args.np)) {
dev_warn(phy_provider->dev, "Requested PHY is disabled\n");
phy = ERR_PTR(-ENODEV);
goto out_put_module;
}
phy = phy_provider->of_xlate(phy_provider->dev, &args);
out_put_module:
module_put(phy_provider->owner);
err0:
out_unlock:
mutex_unlock(&phy_provider_mutex);
of_node_put(args.np);
......@@ -622,6 +630,38 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
}
EXPORT_SYMBOL_GPL(devm_of_phy_get);
/**
* devm_of_phy_get_by_index() - lookup and obtain a reference to a phy by index.
* @dev: device that requests this phy
* @np: node containing the phy
* @index: index of the phy
*
* Gets the phy using _of_phy_get(), and associates a device with it using
* devres. On driver detach, release function is invoked on the devres data,
* then, devres data is freed.
*
*/
struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
int index)
{
struct phy **ptr, *phy;
ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
phy = _of_phy_get(np, index);
if (!IS_ERR(phy)) {
*ptr = phy;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return phy;
}
EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy
......@@ -651,16 +691,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
goto free_phy;
}
/* phy-supply */
phy->pwr = regulator_get_optional(dev, "phy");
if (IS_ERR(phy->pwr)) {
if (PTR_ERR(phy->pwr) == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto free_ida;
}
phy->pwr = NULL;
}
device_initialize(&phy->dev);
mutex_init(&phy->mutex);
......@@ -674,6 +704,16 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
if (ret)
goto put_dev;
/* phy-supply */
phy->pwr = regulator_get_optional(&phy->dev, "phy");
if (IS_ERR(phy->pwr)) {
ret = PTR_ERR(phy->pwr);
if (ret == -EPROBE_DEFER)
goto put_dev;
phy->pwr = NULL;
}
ret = device_add(&phy->dev);
if (ret)
goto put_dev;
......@@ -689,9 +729,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
put_device(&phy->dev); /* calls phy_release() which frees resources */
return ERR_PTR(ret);
free_ida:
ida_simple_remove(&phy_ida, phy->id);
free_phy:
kfree(phy);
return ERR_PTR(ret);
......
......@@ -367,7 +367,7 @@ static struct miphy28lp_pll_gen pcie_pll_gen[] = {
static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy)
{
void *base = miphy_phy->base;
void __iomem *base = miphy_phy->base;
u8 val;
/* Putting Macro in reset */
......@@ -391,7 +391,7 @@ static inline void miphy28lp_set_reset(struct miphy28lp_phy *miphy_phy)
static inline void miphy28lp_pll_calibration(struct miphy28lp_phy *miphy_phy,
struct pll_ratio *pll_ratio)
{
void *base = miphy_phy->base;
void __iomem *base = miphy_phy->base;
u8 val;
/* Applying PLL Settings */
......@@ -1107,11 +1107,6 @@ static struct phy *miphy28lp_xlate(struct device *dev,
struct device_node *phynode = args->np;
int ret, index = 0;
if (!of_device_is_available(phynode)) {
dev_warn(dev, "Requested PHY is disabled\n");
return ERR_PTR(-ENODEV);
}
if (args->args_count != 1) {
dev_err(dev, "Invalid number of cells in 'phy' property\n");
return ERR_PTR(-EINVAL);
......
......@@ -441,8 +441,8 @@ static int miphy365x_init(struct phy *phy)
return ret;
}
int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
int index)
static int miphy365x_get_addr(struct device *dev,
struct miphy365x_phy *miphy_phy, int index)
{
struct device_node *phynode = miphy_phy->phy->dev.of_node;
const char *name;
......@@ -476,11 +476,6 @@ static struct phy *miphy365x_xlate(struct device *dev,
struct device_node *phynode = args->np;
int ret, index;
if (!of_device_is_available(phynode)) {
dev_warn(dev, "Requested PHY is disabled\n");
return ERR_PTR(-ENODEV);
}
if (args->args_count != 1) {
dev_err(dev, "Invalid number of cells in 'phy' property\n");
return ERR_PTR(-EINVAL);
......
/*
* Copyright (C) 2015 Linaro, Ltd.
* Rob Herring <robh@kernel.org>
*
* Based on vendor driver:
* Copyright (C) 2013 Marvell Inc.
* Author: Chao Xie <xiechao.mail@gmail.com>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#define PHY_28NM_HSIC_CTRL 0x08
#define PHY_28NM_HSIC_IMPCAL_CAL 0x18
#define PHY_28NM_HSIC_PLL_CTRL01 0x1c
#define PHY_28NM_HSIC_PLL_CTRL2 0x20
#define PHY_28NM_HSIC_INT 0x28
#define PHY_28NM_HSIC_PLL_SELLPFR_SHIFT 26
#define PHY_28NM_HSIC_PLL_FBDIV_SHIFT 0
#define PHY_28NM_HSIC_PLL_REFDIV_SHIFT 9
#define PHY_28NM_HSIC_S2H_PU_PLL BIT(10)
#define PHY_28NM_HSIC_H2S_PLL_LOCK BIT(15)
#define PHY_28NM_HSIC_S2H_HSIC_EN BIT(7)
#define S2H_DRV_SE0_4RESUME BIT(14)
#define PHY_28NM_HSIC_H2S_IMPCAL_DONE BIT(27)
#define PHY_28NM_HSIC_CONNECT_INT BIT(1)
#define PHY_28NM_HSIC_HS_READY_INT BIT(2)
struct mv_hsic_phy {
struct phy *phy;
struct platform_device *pdev;
void __iomem *base;
struct clk *clk;
};
static bool wait_for_reg(void __iomem *reg, u32 mask, unsigned long timeout)
{
timeout += jiffies;
while (time_is_after_eq_jiffies(timeout)) {
if ((readl(reg) & mask) == mask)
return true;
msleep(1);
}
return false;
}
static int mv_hsic_phy_init(struct phy *phy)
{
struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
struct platform_device *pdev = mv_phy->pdev;
void __iomem *base = mv_phy->base;
clk_prepare_enable(mv_phy->clk);
/* Set reference clock */
writel(0x1 << PHY_28NM_HSIC_PLL_SELLPFR_SHIFT |
0xf0 << PHY_28NM_HSIC_PLL_FBDIV_SHIFT |
0xd << PHY_28NM_HSIC_PLL_REFDIV_SHIFT,
base + PHY_28NM_HSIC_PLL_CTRL01);
/* Turn on PLL */
writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) |
PHY_28NM_HSIC_S2H_PU_PLL,
base + PHY_28NM_HSIC_PLL_CTRL2);
/* Make sure PHY PLL is locked */
if (!wait_for_reg(base + PHY_28NM_HSIC_PLL_CTRL2,
PHY_28NM_HSIC_H2S_PLL_LOCK, HZ / 10)) {
dev_err(&pdev->dev, "HSIC PHY PLL not locked after 100mS.");
clk_disable_unprepare(mv_phy->clk);
return -ETIMEDOUT;
}
return 0;
}
static int mv_hsic_phy_power_on(struct phy *phy)
{
struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
struct platform_device *pdev = mv_phy->pdev;
void __iomem *base = mv_phy->base;
u32 reg;
reg = readl(base + PHY_28NM_HSIC_CTRL);
/* Avoid SE0 state when resume for some device will take it as reset */
reg &= ~S2H_DRV_SE0_4RESUME;
reg |= PHY_28NM_HSIC_S2H_HSIC_EN; /* Enable HSIC PHY */
writel(reg, base + PHY_28NM_HSIC_CTRL);
/*
* Calibration Timing
* ____________________________
* CAL START ___|
* ____________________
* CAL_DONE ___________|
* | 400us |
*/
/* Make sure PHY Calibration is ready */
if (!wait_for_reg(base + PHY_28NM_HSIC_IMPCAL_CAL,
PHY_28NM_HSIC_H2S_IMPCAL_DONE, HZ / 10)) {
dev_warn(&pdev->dev, "HSIC PHY READY not set after 100mS.");
return -ETIMEDOUT;
}
/* Waiting for HSIC connect int*/
if (!wait_for_reg(base + PHY_28NM_HSIC_INT,
PHY_28NM_HSIC_CONNECT_INT, HZ / 5)) {
dev_warn(&pdev->dev, "HSIC wait for connect interrupt timeout.");
return -ETIMEDOUT;
}
return 0;
}
static int mv_hsic_phy_power_off(struct phy *phy)
{
struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
void __iomem *base = mv_phy->base;
writel(readl(base + PHY_28NM_HSIC_CTRL) & ~PHY_28NM_HSIC_S2H_HSIC_EN,
base + PHY_28NM_HSIC_CTRL);
return 0;
}
static int mv_hsic_phy_exit(struct phy *phy)
{
struct mv_hsic_phy *mv_phy = phy_get_drvdata(phy);
void __iomem *base = mv_phy->base;
/* Turn off PLL */
writel(readl(base + PHY_28NM_HSIC_PLL_CTRL2) &
~PHY_28NM_HSIC_S2H_PU_PLL,
base + PHY_28NM_HSIC_PLL_CTRL2);
clk_disable_unprepare(mv_phy->clk);
return 0;
}
static const struct phy_ops hsic_ops = {
.init = mv_hsic_phy_init,
.power_on = mv_hsic_phy_power_on,
.power_off = mv_hsic_phy_power_off,
.exit = mv_hsic_phy_exit,
.owner = THIS_MODULE,
};
static int mv_hsic_phy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct mv_hsic_phy *mv_phy;
struct resource *r;
mv_phy = devm_kzalloc(&pdev->dev, sizeof(*mv_phy), GFP_KERNEL);
if (!mv_phy)
return -ENOMEM;
mv_phy->pdev = pdev;
mv_phy->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(mv_phy->clk)) {
dev_err(&pdev->dev, "failed to get clock.\n");
return PTR_ERR(mv_phy->clk);
}
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mv_phy->base = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(mv_phy->base))
return PTR_ERR(mv_phy->base);
mv_phy->phy = devm_phy_create(&pdev->dev, pdev->dev.of_node, &hsic_ops);
if (IS_ERR(mv_phy->phy))
return PTR_ERR(mv_phy->phy);
phy_set_drvdata(mv_phy->phy, mv_phy);
phy_provider = devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id mv_hsic_phy_dt_match[] = {
{ .compatible = "marvell,pxa1928-hsic-phy", },
{},
};
MODULE_DEVICE_TABLE(of, mv_hsic_phy_dt_match);
static struct platform_driver mv_hsic_phy_driver = {
.probe = mv_hsic_phy_probe,
.driver = {
.name = "mv-hsic-phy",
.of_match_table = of_match_ptr(mv_hsic_phy_dt_match),
},
};
module_platform_driver(mv_hsic_phy_driver);
MODULE_AUTHOR("Rob Herring <robh@kernel.org>");
MODULE_DESCRIPTION("Marvell HSIC phy driver");
MODULE_LICENSE("GPL v2");
This diff is collapsed.
......@@ -195,6 +195,7 @@ static struct phy_ops rcar_gen2_phy_ops = {
static const struct of_device_id rcar_gen2_phy_match_table[] = {
{ .compatible = "renesas,usb-phy-r8a7790" },
{ .compatible = "renesas,usb-phy-r8a7791" },
{ .compatible = "renesas,usb-phy-r8a7794" },
{ }
};
MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table);
......@@ -206,11 +207,6 @@ static struct phy *rcar_gen2_phy_xlate(struct device *dev,
struct device_node *np = args->np;
int i;
if (!of_device_is_available(np)) {
dev_warn(dev, "Requested PHY is disabled\n");
return ERR_PTR(-ENODEV);
}
drv = dev_get_drvdata(dev);
if (!drv)
return ERR_PTR(-EINVAL);
......
......@@ -30,6 +30,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/phy/phy-sun4i-usb.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
......@@ -58,6 +59,7 @@
#define PHY_OTG_FUNC_EN 0x28
#define PHY_VBUS_DET_EN 0x29
#define PHY_DISCON_TH_SEL 0x2a
#define PHY_SQUELCH_DETECT 0x3c
#define MAX_PHYS 3
......@@ -204,6 +206,13 @@ static int sun4i_usb_phy_power_off(struct phy *_phy)
return 0;
}
void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
{
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
sun4i_usb_phy_write(phy, PHY_SQUELCH_DETECT, enabled ? 0 : 2, 2);
}
static struct phy_ops sun4i_usb_phy_ops = {
.init = sun4i_usb_phy_init,
.exit = sun4i_usb_phy_exit,
......
/**
* tusb1210.c - TUSB1210 USB ULPI PHY driver
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/ulpi/driver.h>
#include <linux/gpio/consumer.h>
#include "ulpi_phy.h"
#define TUSB1210_VENDOR_SPECIFIC2 0x80
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4
#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6
struct tusb1210 {
struct ulpi *ulpi;
struct phy *phy;
struct gpio_desc *gpio_reset;
struct gpio_desc *gpio_cs;
u8 vendor_specific2;
};
static int tusb1210_power_on(struct phy *phy)
{
struct tusb1210 *tusb = phy_get_drvdata(phy);
gpiod_set_value_cansleep(tusb->gpio_reset, 1);
gpiod_set_value_cansleep(tusb->gpio_cs, 1);
/* Restore the optional eye diagram optimization value */
if (tusb->vendor_specific2)
ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
tusb->vendor_specific2);
return 0;
}
static int tusb1210_power_off(struct phy *phy)
{
struct tusb1210 *tusb = phy_get_drvdata(phy);
gpiod_set_value_cansleep(tusb->gpio_reset, 0);
gpiod_set_value_cansleep(tusb->gpio_cs, 0);
return 0;
}
static struct phy_ops phy_ops = {
.power_on = tusb1210_power_on,
.power_off = tusb1210_power_off,
.owner = THIS_MODULE,
};
static int tusb1210_probe(struct ulpi *ulpi)
{
struct gpio_desc *gpio;
struct tusb1210 *tusb;
u8 val, reg;
int ret;
tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
if (!tusb)
return -ENOMEM;
gpio = devm_gpiod_get(&ulpi->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpiod_set_value_cansleep(gpio, 1);
tusb->gpio_reset = gpio;
}
gpio = devm_gpiod_get(&ulpi->dev, "cs");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
return ret;
gpiod_set_value_cansleep(gpio, 1);
tusb->gpio_cs = gpio;
}
/*
* VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
* diagram optimization and DP/DM swap.
*/
/* High speed output drive strength configuration */
device_property_read_u8(&ulpi->dev, "ihstx", &val);
reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
/* High speed output impedance configuration */
device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
/* DP/DM swap control */
device_property_read_u8(&ulpi->dev, "datapolarity", &val);
reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
if (reg) {
ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
tusb->vendor_specific2 = reg;
}
tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
if (IS_ERR(tusb->phy))
return PTR_ERR(tusb->phy);
tusb->ulpi = ulpi;
phy_set_drvdata(tusb->phy, tusb);
ulpi_set_drvdata(ulpi, tusb);
return 0;
}
static void tusb1210_remove(struct ulpi *ulpi)
{
struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
ulpi_phy_destroy(ulpi, tusb->phy);
}
#define TI_VENDOR_ID 0x0451
static const struct ulpi_device_id tusb1210_ulpi_id[] = {
{ TI_VENDOR_ID, 0x1507, },
{ },
};
MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
static struct ulpi_driver tusb1210_driver = {
.id_table = tusb1210_ulpi_id,
.probe = tusb1210_probe,
.remove = tusb1210_remove,
.driver = {
.name = "tusb1210",
.owner = THIS_MODULE,
},
};
module_ulpi_driver(tusb1210_driver);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
......@@ -144,6 +144,16 @@
#define PMBR1 0x0D
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
/*
* If VBUS is valid or ID is ground, then we know a
* cable is present and we need to be runtime-enabled
*/
static inline bool cable_present(enum omap_musb_vbus_id_status stat)
{
return stat == OMAP_MUSB_VBUS_VALID ||
stat == OMAP_MUSB_ID_GROUND;
}
struct twl4030_usb {
struct usb_phy phy;
struct device *dev;
......@@ -386,8 +396,6 @@ static int twl4030_usb_runtime_suspend(struct device *dev)
struct twl4030_usb *twl = dev_get_drvdata(dev);
dev_dbg(twl->dev, "%s\n", __func__);
if (pm_runtime_suspended(dev))
return 0;
__twl4030_phy_power(twl, 0);
regulator_disable(twl->usb1v5);
......@@ -403,8 +411,6 @@ static int twl4030_usb_runtime_resume(struct device *dev)
int res;
dev_dbg(twl->dev, "%s\n", __func__);
if (pm_runtime_active(dev))
return 0;
res = regulator_enable(twl->usb3v1);
if (res)
......@@ -536,8 +542,10 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
mutex_lock(&twl->lock);
if (status >= 0 && status != twl->linkstat) {
status_changed =
cable_present(twl->linkstat) !=
cable_present(status);
twl->linkstat = status;
status_changed = true;
}
mutex_unlock(&twl->lock);
......@@ -553,15 +561,11 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
* USB_LINK_VBUS state. musb_hdrc won't care until it
* starts to handle softconnect right.
*/
if ((status == OMAP_MUSB_VBUS_VALID) ||
(status == OMAP_MUSB_ID_GROUND)) {
if (pm_runtime_suspended(twl->dev))
pm_runtime_get_sync(twl->dev);
if (cable_present(status)) {
pm_runtime_get_sync(twl->dev);
} else {
if (pm_runtime_active(twl->dev)) {
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
}
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put_autosuspend(twl->dev);
}
omap_musb_mailbox(status);
}
......@@ -711,7 +715,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 2000);
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
/* Our job is to use irqs and status from the power module
* to keep the transceiver disabled when nothing's connected.
......@@ -767,6 +770,9 @@ static int twl4030_usb_remove(struct platform_device *pdev)
/* disable complete OTG block */
twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
if (cable_present(twl->linkstat))
pm_runtime_put_noidle(twl->dev);
pm_runtime_mark_last_busy(twl->dev);
pm_runtime_put(twl->dev);
......
#include <linux/phy/phy.h>
/**
* Helper that registers PHY for a ULPI device and adds a lookup for binding it
* and it's controller, which is always the parent.
*/
static inline struct phy
*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops)
{
struct phy *phy;
int ret;
phy = phy_create(&ulpi->dev, NULL, ops);
if (IS_ERR(phy))
return phy;
ret = phy_create_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
if (ret) {
phy_destroy(phy);
return ERR_PTR(ret);
}
return phy;
}
/* Remove a PHY that was created with ulpi_phy_create() and it's lookup. */
static inline void ulpi_phy_destroy(struct ulpi *ulpi, struct phy *phy)
{
phy_remove_lookup(phy, "usb2-phy", dev_name(ulpi->dev.parent));
phy_destroy(phy);
}
......@@ -638,10 +638,15 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
INIT_WORK(&bci->work, twl4030_bci_usb_work);
bci->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
if (!IS_ERR_OR_NULL(bci->transceiver)) {
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
usb_register_notifier(bci->transceiver, &bci->usb_nb);
bci->usb_nb.notifier_call = twl4030_bci_usb_ncb;
if (bci->dev->of_node) {
struct device_node *phynode;
phynode = of_find_compatible_node(bci->dev->of_node->parent,
NULL, "ti,twl4030-usb");
if (phynode)
bci->transceiver = devm_usb_get_phy_by_node(
bci->dev, phynode, &bci->usb_nb);
}
/* Enable interrupts now. */
......@@ -671,10 +676,6 @@ static int __init twl4030_bci_probe(struct platform_device *pdev)
return 0;
fail_unmask_interrupts:
if (!IS_ERR_OR_NULL(bci->transceiver)) {
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_phy(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
fail_bci_irq:
free_irq(bci->irq_chg, bci);
......@@ -703,10 +704,6 @@ static int __exit twl4030_bci_remove(struct platform_device *pdev)
twl_i2c_write_u8(TWL4030_MODULE_INTERRUPTS, 0xff,
TWL4030_INTERRUPTS_BCIIMR2A);
if (!IS_ERR_OR_NULL(bci->transceiver)) {
usb_unregister_notifier(bci->transceiver, &bci->usb_nb);
usb_put_phy(bci->transceiver);
}
free_irq(bci->irq_bci, bci);
free_irq(bci->irq_chg, bci);
power_supply_unregister(bci->usb);
......
......@@ -255,7 +255,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
usb_dbg(usbatm, "%s entered\n", __func__);
if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
buffer = (unsigned char *)__get_free_page(GFP_KERNEL);
if (!buffer) {
ret = -ENOMEM;
usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
goto out;
......@@ -638,7 +639,8 @@ static void speedtch_handle_int(struct urb *int_urb)
goto fail;
}
if ((int_urb = instance->int_urb)) {
int_urb = instance->int_urb;
if (int_urb) {
ret = usb_submit_urb(int_urb, GFP_ATOMIC);
schedule_work(&instance->status_check_work);
if (ret < 0) {
......@@ -650,7 +652,8 @@ static void speedtch_handle_int(struct urb *int_urb)
return;
fail:
if ((int_urb = instance->int_urb))
int_urb = instance->int_urb;
if (int_urb)
mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
}
......@@ -759,11 +762,13 @@ static void speedtch_release_interfaces(struct usb_device *usb_dev,
struct usb_interface *cur_intf;
int i;
for (i = 0; i < num_interfaces; i++)
if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
for (i = 0; i < num_interfaces; i++) {
cur_intf = usb_ifnum_to_if(usb_dev, i);
if (cur_intf) {
usb_set_intfdata(cur_intf, NULL);
usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
}
}
}
static int speedtch_bind(struct usbatm_data *usbatm,
......@@ -787,7 +792,8 @@ static int speedtch_bind(struct usbatm_data *usbatm,
return -ENODEV;
}
if (!(data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA))) {
data_intf = usb_ifnum_to_if(usb_dev, INTERFACE_DATA);
if (!data_intf) {
usb_err(usbatm, "%s: data interface not found!\n", __func__);
return -ENODEV;
}
......
......@@ -382,7 +382,8 @@ static void usbatm_extract_one_cell(struct usbatm_data *instance, unsigned char
"%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)",
__func__, length, pdu_length, vcc);
if (!(skb = dev_alloc_skb(length))) {
skb = dev_alloc_skb(length);
if (!skb) {
if (printk_ratelimit())
atm_err(instance, "%s: no memory for skb (length: %u)!\n",
__func__, length);
......@@ -816,7 +817,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc)
goto fail;
}
if (!(new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
new = kzalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL);
if (!new) {
atm_err(instance, "%s: no memory for vcc_data!\n", __func__);
ret = -ENOMEM;
goto fail;
......
......@@ -73,7 +73,8 @@ static int xusbatm_capture_intf(struct usbatm_data *usbatm, struct usb_device *u
usb_err(usbatm, "%s: failed to claim interface %2d (%d)!\n", __func__, ifnum, ret);
return ret;
}
if ((ret = usb_set_interface(usb_dev, ifnum, altsetting))) {
ret = usb_set_interface(usb_dev, ifnum, altsetting);
if (ret) {
usb_err(usbatm, "%s: altsetting %2d for interface %2d failed (%d)!\n", __func__, altsetting, ifnum, ret);
return ret;
}
......@@ -128,7 +129,8 @@ static int xusbatm_bind(struct usbatm_data *usbatm,
rx_intf->altsetting->desc.bInterfaceNumber,
tx_intf->altsetting->desc.bInterfaceNumber);
if ((ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf)))
ret = xusbatm_capture_intf(usbatm, usb_dev, rx_intf, rx_alt, rx_intf != intf);
if (ret)
return ret;
if ((tx_intf != rx_intf) && (ret = xusbatm_capture_intf(usbatm, usb_dev, tx_intf, tx_alt, tx_intf != intf))) {
......
......@@ -25,7 +25,7 @@ struct ci_hdrc_usb2_priv {
struct clk *clk;
};
static struct ci_hdrc_platform_data ci_default_pdata = {
static const struct ci_hdrc_platform_data ci_default_pdata = {
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_DISABLE_STREAMING,
};
......@@ -37,8 +37,10 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
int ret;
if (!ci_pdata)
ci_pdata = &ci_default_pdata;
if (!ci_pdata) {
ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL);
*ci_pdata = ci_default_pdata; /* struct copy */
}
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
......
......@@ -37,12 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
struct ehci_ci_priv {
struct regulator *reg_vbus;
struct ci_hdrc *ci;
};
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
struct ci_hdrc *ci = priv->ci;
struct device *dev = hcd->self.controller;
int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params);
......@@ -64,6 +66,15 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
return ret;
}
}
if (enable && (ci->platdata->phy_mode == USBPHY_INTERFACE_MODE_HSIC)) {
/*
* Marvell 28nm HSIC PHY requires forcing the port to HS mode.
* As HSIC is always HS, this should be safe for others.
*/
hw_port_test_set(ci, 5);
hw_port_test_set(ci, 0);
}
return 0;
};
......@@ -112,6 +123,7 @@ static int host_start(struct ci_hdrc *ci)
priv = (struct ehci_ci_priv *)ehci->priv;
priv->reg_vbus = NULL;
priv->ci = ci;
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
......
......@@ -160,7 +160,7 @@ static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
break;
default:
return -EINVAL;
};
}
spin_lock_irqsave(&usbmisc->lock, flags);
if (data->disable_oc)
......
......@@ -46,6 +46,7 @@
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <linux/idr.h>
#include <linux/list.h>
#include "cdc-acm.h"
......@@ -56,27 +57,27 @@
static struct usb_driver acm_driver;
static struct tty_driver *acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS];
static DEFINE_MUTEX(acm_table_lock);
static DEFINE_IDR(acm_minors);
static DEFINE_MUTEX(acm_minors_lock);
static void acm_tty_set_termios(struct tty_struct *tty,
struct ktermios *termios_old);
/*
* acm_table accessors
* acm_minors accessors
*/
/*
* Look up an ACM structure by index. If found and not disconnected, increment
* Look up an ACM structure by minor. If found and not disconnected, increment
* its refcount and return it with its mutex held.
*/
static struct acm *acm_get_by_index(unsigned index)
static struct acm *acm_get_by_minor(unsigned int minor)
{
struct acm *acm;
mutex_lock(&acm_table_lock);
acm = acm_table[index];
mutex_lock(&acm_minors_lock);
acm = idr_find(&acm_minors, minor);
if (acm) {
mutex_lock(&acm->mutex);
if (acm->disconnected) {
......@@ -87,7 +88,7 @@ static struct acm *acm_get_by_index(unsigned index)
mutex_unlock(&acm->mutex);
}
}
mutex_unlock(&acm_table_lock);
mutex_unlock(&acm_minors_lock);
return acm;
}
......@@ -98,14 +99,9 @@ static int acm_alloc_minor(struct acm *acm)
{
int minor;
mutex_lock(&acm_table_lock);
for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
if (!acm_table[minor]) {
acm_table[minor] = acm;
break;
}
}
mutex_unlock(&acm_table_lock);
mutex_lock(&acm_minors_lock);
minor = idr_alloc(&acm_minors, acm, 0, ACM_TTY_MINORS, GFP_KERNEL);
mutex_unlock(&acm_minors_lock);
return minor;
}
......@@ -113,9 +109,9 @@ static int acm_alloc_minor(struct acm *acm)
/* Release the minor number associated with 'acm'. */
static void acm_release_minor(struct acm *acm)
{
mutex_lock(&acm_table_lock);
acm_table[acm->minor] = NULL;
mutex_unlock(&acm_table_lock);
mutex_lock(&acm_minors_lock);
idr_remove(&acm_minors, acm->minor);
mutex_unlock(&acm_minors_lock);
}
/*
......@@ -497,7 +493,7 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
dev_dbg(tty->dev, "%s\n", __func__);
acm = acm_get_by_index(tty->index);
acm = acm_get_by_minor(tty->index);
if (!acm)
return -ENODEV;
......@@ -1267,12 +1263,9 @@ static int acm_probe(struct usb_interface *intf,
!= CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass
== CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
dev_dbg(&intf->dev,
"Your device has switched interfaces.\n");
t = control_interface;
control_interface = data_interface;
data_interface = t;
swap(control_interface, data_interface);
} else {
return -EINVAL;
}
......@@ -1301,12 +1294,9 @@ static int acm_probe(struct usb_interface *intf,
/* workaround for switched endpoints */
if (!usb_endpoint_dir_in(epread)) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
dev_dbg(&intf->dev,
"The data interface has switched endpoints\n");
t = epread;
epread = epwrite;
epwrite = t;
swap(epread, epwrite);
}
made_compressed_probe:
dev_dbg(&intf->dev, "interfaces are valid\n");
......@@ -1316,7 +1306,7 @@ static int acm_probe(struct usb_interface *intf,
goto alloc_fail;
minor = acm_alloc_minor(acm);
if (minor == ACM_TTY_MINORS) {
if (minor < 0) {
dev_err(&intf->dev, "no more free acm devices\n");
kfree(acm);
return -ENODEV;
......@@ -1477,6 +1467,11 @@ static int acm_probe(struct usb_interface *intf,
goto alloc_fail8;
}
if (quirks & CLEAR_HALT_CONDITIONS) {
usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress));
usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress));
}
return 0;
alloc_fail8:
if (acm->country_codes) {
......@@ -1756,6 +1751,10 @@ static const struct usb_device_id acm_ids[] = {
.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
},
{ USB_DEVICE(0x2912, 0x0001), /* ATOL FPrint */
.driver_info = CLEAR_HALT_CONDITIONS,
},
/* Nokia S60 phones expose two ACM channels. The first is
* a modem and is picked up by the standard AT-command
* information below. The second is 'vendor-specific' but
......
......@@ -19,7 +19,7 @@
*/
#define ACM_TTY_MAJOR 166
#define ACM_TTY_MINORS 32
#define ACM_TTY_MINORS 256
/*
* Requests.
......@@ -133,3 +133,4 @@ struct acm {
#define NO_DATA_INTERFACE BIT(4)
#define IGNORE_DEVICE BIT(5)
#define QUIRK_CONTROL_LINE_STATE BIT(6)
#define CLEAR_HALT_CONDITIONS BIT(7)
......@@ -660,7 +660,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case LPGETSTATUS:
if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
retval = usblp_read_status(usblp, usblp->statusbuf);
if (retval) {
printk_ratelimited(KERN_ERR "usblp%d:"
"failed reading printer status (%d)\n",
usblp->minor, retval);
......@@ -693,9 +694,11 @@ static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
struct urb *urb;
char *writebuf;
if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
writebuf = kmalloc(transfer_length, GFP_KERNEL);
if (writebuf == NULL)
return NULL;
if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL) {
kfree(writebuf);
return NULL;
}
......@@ -732,7 +735,8 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
transfer_length = USBLP_BUF_SIZE;
rv = -ENOMEM;
if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL)
writeurb = usblp_new_writeurb(usblp, transfer_length);
if (writeurb == NULL)
goto raise_urb;
usb_anchor_urb(writeurb, &usblp->urbs);
......@@ -980,7 +984,8 @@ static int usblp_submit_read(struct usblp *usblp)
int rc;
rc = -ENOMEM;
if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
urb = usb_alloc_urb(0, GFP_KERNEL);
if (urb == NULL)
goto raise_urb;
usb_fill_bulk_urb(urb, usblp->dev,
......
......@@ -109,6 +109,7 @@ struct usbtmc_ID_rigol_quirk {
static const struct usbtmc_ID_rigol_quirk usbtmc_id_quirk[] = {
{ 0x1ab1, 0x0588 },
{ 0x1ab1, 0x04b0 },
{ 0, 0 }
};
......
......@@ -7,3 +7,4 @@ usb-common-y += common.o
usb-common-$(CONFIG_USB_LED_TRIG) += led.o
obj-$(CONFIG_USB_OTG_FSM) += usb-otg-fsm.o
obj-$(CONFIG_USB_ULPI_BUS) += ulpi.o
/**
* ulpi.c - USB ULPI PHY bus
*
* Copyright (C) 2015 Intel Corporation
*
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/ulpi/interface.h>
#include <linux/ulpi/driver.h>
#include <linux/ulpi/regs.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/acpi.h>
/* -------------------------------------------------------------------------- */
int ulpi_read(struct ulpi *ulpi, u8 addr)
{
return ulpi->ops->read(ulpi->ops, addr);
}
EXPORT_SYMBOL_GPL(ulpi_read);
int ulpi_write(struct ulpi *ulpi, u8 addr, u8 val)
{
return ulpi->ops->write(ulpi->ops, addr, val);
}
EXPORT_SYMBOL_GPL(ulpi_write);
/* -------------------------------------------------------------------------- */
static int ulpi_match(struct device *dev, struct device_driver *driver)
{
struct ulpi_driver *drv = to_ulpi_driver(driver);
struct ulpi *ulpi = to_ulpi_dev(dev);
const struct ulpi_device_id *id;
for (id = drv->id_table; id->vendor; id++)
if (id->vendor == ulpi->id.vendor &&
id->product == ulpi->id.product)
return 1;
return 0;
}
static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct ulpi *ulpi = to_ulpi_dev(dev);
if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x",
ulpi->id.vendor, ulpi->id.product))
return -ENOMEM;
return 0;
}
static int ulpi_probe(struct device *dev)
{
struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
return drv->probe(to_ulpi_dev(dev));
}
static int ulpi_remove(struct device *dev)
{
struct ulpi_driver *drv = to_ulpi_driver(dev->driver);
if (drv->remove)
drv->remove(to_ulpi_dev(dev));
return 0;
}
static struct bus_type ulpi_bus = {
.name = "ulpi",
.match = ulpi_match,
.uevent = ulpi_uevent,
.probe = ulpi_probe,
.remove = ulpi_remove,
};
/* -------------------------------------------------------------------------- */
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct ulpi *ulpi = to_ulpi_dev(dev);
return sprintf(buf, "ulpi:v%04xp%04x\n",
ulpi->id.vendor, ulpi->id.product);
}
static DEVICE_ATTR_RO(modalias);
static struct attribute *ulpi_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL
};
static struct attribute_group ulpi_dev_attr_group = {
.attrs = ulpi_dev_attrs,
};
static const struct attribute_group *ulpi_dev_attr_groups[] = {
&ulpi_dev_attr_group,
NULL
};
static void ulpi_dev_release(struct device *dev)
{
kfree(to_ulpi_dev(dev));
}
static struct device_type ulpi_dev_type = {
.name = "ulpi_device",
.groups = ulpi_dev_attr_groups,
.release = ulpi_dev_release,
};
/* -------------------------------------------------------------------------- */
/**
* ulpi_register_driver - register a driver with the ULPI bus
* @drv: driver being registered
*
* Registers a driver with the ULPI bus.
*/
int ulpi_register_driver(struct ulpi_driver *drv)
{
if (!drv->probe)
return -EINVAL;
drv->driver.bus = &ulpi_bus;
return driver_register(&drv->driver);
}
EXPORT_SYMBOL_GPL(ulpi_register_driver);
/**
* ulpi_unregister_driver - unregister a driver with the ULPI bus
* @drv: driver to unregister
*
* Unregisters a driver with the ULPI bus.
*/
void ulpi_unregister_driver(struct ulpi_driver *drv)
{
driver_unregister(&drv->driver);
}
EXPORT_SYMBOL_GPL(ulpi_unregister_driver);
/* -------------------------------------------------------------------------- */
static int ulpi_register(struct device *dev, struct ulpi *ulpi)
{
int ret;
/* Test the interface */
ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa);
if (ret < 0)
return ret;
ret = ulpi_read(ulpi, ULPI_SCRATCH);
if (ret < 0)
return ret;
if (ret != 0xaa)
return -ENODEV;
ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW);
ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8;
ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW);
ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8;
ulpi->dev.parent = dev;
ulpi->dev.bus = &ulpi_bus;
ulpi->dev.type = &ulpi_dev_type;
dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev));
ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev));
request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product);
ret = device_register(&ulpi->dev);
if (ret)
return ret;
dev_dbg(&ulpi->dev, "registered ULPI PHY: vendor %04x, product %04x\n",
ulpi->id.vendor, ulpi->id.product);
return 0;
}
/**
* ulpi_register_interface - instantiate new ULPI device
* @dev: USB controller's device interface
* @ops: ULPI register access
*
* Allocates and registers a ULPI device and an interface for it. Called from
* the USB controller that provides the ULPI interface.
*/
struct ulpi *ulpi_register_interface(struct device *dev, struct ulpi_ops *ops)
{
struct ulpi *ulpi;
int ret;
ulpi = kzalloc(sizeof(*ulpi), GFP_KERNEL);
if (!ulpi)
return ERR_PTR(-ENOMEM);
ulpi->ops = ops;
ops->dev = dev;
ret = ulpi_register(dev, ulpi);
if (ret) {
kfree(ulpi);
return ERR_PTR(ret);
}
return ulpi;
}
EXPORT_SYMBOL_GPL(ulpi_register_interface);
/**
* ulpi_unregister_interface - unregister ULPI interface
* @intrf: struct ulpi_interface
*
* Unregisters a ULPI device and it's interface that was created with
* ulpi_create_interface().
*/
void ulpi_unregister_interface(struct ulpi *ulpi)
{
device_unregister(&ulpi->dev);
}
EXPORT_SYMBOL_GPL(ulpi_unregister_interface);
/* -------------------------------------------------------------------------- */
static int __init ulpi_init(void)
{
return bus_register(&ulpi_bus);
}
module_init(ulpi_init);
static void __exit ulpi_exit(void)
{
bus_unregister(&ulpi_bus);
}
module_exit(ulpi_exit);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("USB ULPI PHY bus");
......@@ -84,3 +84,23 @@ config USB_OTG_FSM
Implements OTG Finite State Machine as specified in On-The-Go
and Embedded Host Supplement to the USB Revision 2.0 Specification.
config USB_ULPI_BUS
tristate "USB ULPI PHY interface support"
depends on USB_SUPPORT
help
UTMI+ Low Pin Interface (ULPI) is specification for a commonly used
USB 2.0 PHY interface. The ULPI specification defines a standard set
of registers that can be used to detect the vendor and product which
allows ULPI to be handled as a bus. This module is the driver for that
bus.
The ULPI interfaces (the buses) are registered by the drivers for USB
controllers which support ULPI register access and have ULPI PHY
attached to them. The ULPI PHY drivers themselves are normal PHY
drivers.
ULPI PHYs provide often functions such as ADP sensing/probing (OTG
protocol) and USB charger detection.
To compile this driver as a module, choose M here: the module will
be called ulpi.
......@@ -70,7 +70,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
size = pool_max[i];
if (!size)
continue;
snprintf(name, sizeof name, "buffer-%d", size);
snprintf(name, sizeof(name), "buffer-%d", size);
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
size, size, 0);
if (!hcd->pool[i]) {
......@@ -95,6 +95,7 @@ void hcd_buffer_destroy(struct usb_hcd *hcd)
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
struct dma_pool *pool = hcd->pool[i];
if (pool) {
dma_pool_destroy(pool);
hcd->pool[i] = NULL;
......
......@@ -513,7 +513,7 @@ static void async_completed(struct urb *urb)
snoop(&urb->dev->dev, "urb complete\n");
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
as->status, COMPLETE, NULL, 0);
if ((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_IN)
if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
snoop_urb_data(urb, urb->actual_length);
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
......
......@@ -2691,7 +2691,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
if ((retval = usb_register_bus(&hcd->self)) < 0)
goto err_register_bus;
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
if (rhdev == NULL) {
dev_err(hcd->self.controller, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
......
......@@ -127,7 +127,7 @@ static int usb_device_supports_lpm(struct usb_device *udev)
/* USB 2.1 (and greater) devices indicate LPM support through
* their USB 2.0 Extended Capabilities BOS descriptor.
*/
if (udev->speed == USB_SPEED_HIGH) {
if (udev->speed == USB_SPEED_HIGH || udev->speed == USB_SPEED_FULL) {
if (udev->bos->ext_cap &&
(USB_LPM_SUPPORT &
le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
......@@ -795,7 +795,8 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
* since each TT has "at least two" buffers that can need it (and
* there can be many TTs per hub). even if they're uncommon.
*/
if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) {
clear = kmalloc(sizeof *clear, GFP_ATOMIC);
if (clear == NULL) {
dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
/* FIXME recover somehow ... RESET_TT? */
return -ENOMEM;
......@@ -2350,6 +2351,26 @@ static void set_usb_port_removable(struct usb_device *udev)
hub = usb_hub_to_struct_hub(udev->parent);
/*
* If the platform firmware has provided information about a port,
* use that to determine whether it's removable.
*/
switch (hub->ports[udev->portnum - 1]->connect_type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
udev->removable = USB_DEVICE_REMOVABLE;
return;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
case USB_PORT_NOT_USED:
udev->removable = USB_DEVICE_FIXED;
return;
default:
break;
}
/*
* Otherwise, check whether the hub knows whether a port is removable
* or not
*/
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
......@@ -2369,21 +2390,6 @@ static void set_usb_port_removable(struct usb_device *udev)
else
udev->removable = USB_DEVICE_FIXED;
/*
* Platform firmware may have populated an alternative value for
* removable. If the parent port has a known connect_type use
* that instead.
*/
switch (hub->ports[udev->portnum - 1]->connect_type) {
case USB_PORT_CONNECT_TYPE_HOT_PLUG:
udev->removable = USB_DEVICE_REMOVABLE;
break;
case USB_PORT_CONNECT_TYPE_HARD_WIRED:
udev->removable = USB_DEVICE_FIXED;
break;
default: /* use what was set above */
break;
}
}
/**
......@@ -2616,9 +2622,6 @@ static bool use_new_scheme(struct usb_device *udev, int retry)
return USE_NEW_SCHEME(retry);
}
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm);
/* Is a USB 3.0 port in the Inactive or Compliance Mode state?
* Port worm reset is required to recover
*/
......@@ -2706,44 +2709,6 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
return 0;
}
static void hub_port_finish_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, int *status)
{
switch (*status) {
case 0:
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
if (udev) {
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
update_devnum(udev, 0);
/* The xHC may think the device is already reset,
* so ignore the status.
*/
if (hcd->driver->reset_device)
hcd->driver->reset_device(hcd, udev);
}
/* FALL THROUGH */
case -ENOTCONN:
case -ENODEV:
usb_clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_C_RESET);
if (hub_is_superspeed(hub->hdev)) {
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_BH_PORT_RESET);
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE);
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
}
if (udev)
usb_set_device_state(udev, *status
? USB_STATE_NOTATTACHED
: USB_STATE_DEFAULT);
break;
}
}
/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
static int hub_port_reset(struct usb_hub *hub, int port1,
struct usb_device *udev, unsigned int delay, bool warm)
......@@ -2767,13 +2732,10 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
* If the caller hasn't explicitly requested a warm reset,
* double check and see if one is needed.
*/
status = hub_port_status(hub, port1,
&portstatus, &portchange);
if (status < 0)
goto done;
if (hub_port_warm_reset_required(hub, port1, portstatus))
warm = true;
if (hub_port_status(hub, port1, &portstatus, &portchange) == 0)
if (hub_port_warm_reset_required(hub, port1,
portstatus))
warm = true;
}
clear_bit(port1, hub->warm_reset_bits);
......@@ -2799,11 +2761,19 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
/* Check for disconnect or reset */
if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
hub_port_finish_reset(hub, port1, udev, &status);
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_RESET);
if (!hub_is_superspeed(hub->hdev))
goto done;
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_BH_PORT_RESET);
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_PORT_LINK_STATE);
usb_clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_CONNECTION);
/*
* If a USB 3.0 device migrates from reset to an error
* state, re-issue the warm reset.
......@@ -2836,6 +2806,26 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
dev_err(&port_dev->dev, "Cannot enable. Maybe the USB cable is bad?\n");
done:
if (status == 0) {
/* TRSTRCY = 10 ms; plus some extra */
msleep(10 + 40);
if (udev) {
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
update_devnum(udev, 0);
/* The xHC may think the device is already reset,
* so ignore the status.
*/
if (hcd->driver->reset_device)
hcd->driver->reset_device(hcd, udev);
usb_set_device_state(udev, USB_STATE_DEFAULT);
}
} else {
if (udev)
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
}
if (!hub_is_superspeed(hub->hdev))
up_read(&ehci_cf_port_reset_rwsem);
......
......@@ -50,18 +50,10 @@ config USB_DWC2_DUAL_ROLE
option requires USB_GADGET to be enabled.
endchoice
config USB_DWC2_PLATFORM
tristate "DWC2 Platform"
default USB_DWC2_HOST || USB_DWC2_PERIPHERAL
help
The Designware USB2.0 platform interface module for
controllers directly connected to the CPU.
config USB_DWC2_PCI
tristate "DWC2 PCI"
depends on PCI
default n
select USB_DWC2_PLATFORM
select NOP_USB_XCEIV
help
The Designware USB2.0 PCI interface module for controllers
......
......@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o
dwc2-y := core.o core_intr.o platform.o
ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += hcd.o hcd_intr.o
......@@ -13,6 +13,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += gadget.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
dwc2-y += debugfs.o
endif
# NOTE: The previous s3c-hsotg peripheral mode only driver has been moved to
# this location and renamed gadget.c. When building for dynamically linked
# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
......@@ -21,6 +25,3 @@ endif
obj-$(CONFIG_USB_DWC2_PCI) += dwc2_pci.o
dwc2_pci-y := pci.o
obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o
dwc2_platform-y := platform.o
This diff is collapsed.
......@@ -331,6 +331,17 @@ enum dwc2_ep0_state {
* by the driver and are ignored in this
* configuration value.
* @uframe_sched: True to enable the microframe scheduler
* @external_id_pin_ctl: Specifies whether ID pin is handled externally.
* Disable CONIDSTSCHNG controller interrupt in such
* case.
* 0 - No (default)
* 1 - Yes
* @hibernation: Specifies whether the controller support hibernation.
* If hibernation is enabled, the controller will enter
* hibernation in both peripheral and host mode when
* needed.
* 0 - No (default)
* 1 - Yes
*
* The following parameters may be specified when starting the module. These
* parameters define how the DWC_otg controller should be configured. A
......@@ -368,6 +379,8 @@ struct dwc2_core_params {
int reload_ctl;
int ahbcfg;
int uframe_sched;
int external_id_pin_ctl;
int hibernation;
};
/**
......@@ -451,6 +464,82 @@ struct dwc2_hw_params {
/* Size of control and EP0 buffers */
#define DWC2_CTRL_BUFF_SIZE 8
/**
* struct dwc2_gregs_backup - Holds global registers state before entering partial
* power down
* @gotgctl: Backup of GOTGCTL register
* @gintmsk: Backup of GINTMSK register
* @gahbcfg: Backup of GAHBCFG register
* @gusbcfg: Backup of GUSBCFG register
* @grxfsiz: Backup of GRXFSIZ register
* @gnptxfsiz: Backup of GNPTXFSIZ register
* @gi2cctl: Backup of GI2CCTL register
* @hptxfsiz: Backup of HPTXFSIZ register
* @gdfifocfg: Backup of GDFIFOCFG register
* @dtxfsiz: Backup of DTXFSIZ registers for each endpoint
* @gpwrdn: Backup of GPWRDN register
*/
struct dwc2_gregs_backup {
u32 gotgctl;
u32 gintmsk;
u32 gahbcfg;
u32 gusbcfg;
u32 grxfsiz;
u32 gnptxfsiz;
u32 gi2cctl;
u32 hptxfsiz;
u32 pcgcctl;
u32 gdfifocfg;
u32 dtxfsiz[MAX_EPS_CHANNELS];
u32 gpwrdn;
};
/**
* struct dwc2_dregs_backup - Holds device registers state before entering partial
* power down
* @dcfg: Backup of DCFG register
* @dctl: Backup of DCTL register
* @daintmsk: Backup of DAINTMSK register
* @diepmsk: Backup of DIEPMSK register
* @doepmsk: Backup of DOEPMSK register
* @diepctl: Backup of DIEPCTL register
* @dieptsiz: Backup of DIEPTSIZ register
* @diepdma: Backup of DIEPDMA register
* @doepctl: Backup of DOEPCTL register
* @doeptsiz: Backup of DOEPTSIZ register
* @doepdma: Backup of DOEPDMA register
*/
struct dwc2_dregs_backup {
u32 dcfg;
u32 dctl;
u32 daintmsk;
u32 diepmsk;
u32 doepmsk;
u32 diepctl[MAX_EPS_CHANNELS];
u32 dieptsiz[MAX_EPS_CHANNELS];
u32 diepdma[MAX_EPS_CHANNELS];
u32 doepctl[MAX_EPS_CHANNELS];
u32 doeptsiz[MAX_EPS_CHANNELS];
u32 doepdma[MAX_EPS_CHANNELS];
};
/**
* struct dwc2_hregs_backup - Holds host registers state before entering partial
* power down
* @hcfg: Backup of HCFG register
* @haintmsk: Backup of HAINTMSK register
* @hcintmsk: Backup of HCINTMSK register
* @hptr0: Backup of HPTR0 register
* @hfir: Backup of HFIR register
*/
struct dwc2_hregs_backup {
u32 hcfg;
u32 haintmsk;
u32 hcintmsk[MAX_EPS_CHANNELS];
u32 hprt0;
u32 hfir;
};
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
......@@ -481,6 +570,9 @@ struct dwc2_hw_params {
* interrupt
* @wkp_timer: Timer object for handling Wakeup Detected interrupt
* @lx_state: Lx state of connected device
* @gregs_backup: Backup of global registers during suspend
* @dregs_backup: Backup of device registers during suspend
* @hregs_backup: Backup of host registers during suspend
*
* These are for host mode:
*
......@@ -613,11 +705,12 @@ struct dwc2_hsotg {
struct work_struct wf_otg;
struct timer_list wkp_timer;
enum dwc2_lx_state lx_state;
struct dwc2_gregs_backup *gr_backup;
struct dwc2_dregs_backup *dr_backup;
struct dwc2_hregs_backup *hr_backup;
struct dentry *debug_root;
struct dentry *debug_file;
struct dentry *debug_testmode;
struct dentry *debug_fifo;
struct debugfs_regset32 *regset;
/* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a
......@@ -751,6 +844,8 @@ enum dwc2_halt_status {
* and the DWC_otg controller
*/
extern void dwc2_core_host_init(struct dwc2_hsotg *hsotg);
extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg);
extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore);
/*
* Host core Functions.
......@@ -983,6 +1078,15 @@ extern void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val);
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
/*
* Dump core registers and SPRAM
*/
......@@ -1005,6 +1109,8 @@ extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset);
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
#define dwc2_is_device_connected(hsotg) (hsotg->connected)
#else
static inline int s3c_hsotg_remove(struct dwc2_hsotg *dwc2)
{ return 0; }
......@@ -1018,6 +1124,10 @@ static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset) {}
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
static inline int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg,
int testmode)
{ return 0; }
#define dwc2_is_device_connected(hsotg) (0)
#endif
#if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
......@@ -1025,14 +1135,12 @@ extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
#else
static inline void dwc2_set_all_params(struct dwc2_core_params *params, int value) {}
static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {}
static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {}
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params)
static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
#endif
......
......@@ -334,6 +334,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
*/
static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
{
int ret;
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
......@@ -345,6 +346,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
/* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG;
writel(dctl, hsotg->regs + DCTL);
ret = dwc2_exit_hibernation(hsotg, true);
if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit hibernation failed\n");
call_gadget(hsotg, resume);
}
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
......@@ -397,6 +403,7 @@ static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
{
u32 dsts;
int ret;
dev_dbg(hsotg->dev, "USB SUSPEND\n");
......@@ -411,10 +418,43 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d\n",
!!(dsts & DSTS_SUSPSTS),
hsotg->hw_params.power_optimized);
if ((dsts & DSTS_SUSPSTS) && hsotg->hw_params.power_optimized) {
/* Ignore suspend request before enumeration */
if (!dwc2_is_device_connected(hsotg)) {
dev_dbg(hsotg->dev,
"ignore suspend request before enumeration\n");
goto clear_int;
}
ret = dwc2_enter_hibernation(hsotg);
if (ret) {
if (ret != -ENOTSUPP)
dev_err(hsotg->dev,
"enter hibernation failed\n");
goto skip_power_saving;
}
udelay(100);
/* Ask phy to be suspended */
if (!IS_ERR_OR_NULL(hsotg->uphy))
usb_phy_set_suspend(hsotg->uphy, true);
skip_power_saving:
/*
* Change to L2 (suspend) state before releasing
* spinlock
*/
hsotg->lx_state = DWC2_L2;
/* Call gadget suspend callback */
call_gadget(hsotg, suspend);
}
} else {
if (hsotg->op_state == OTG_STATE_A_PERIPHERAL) {
dev_dbg(hsotg->dev, "a_peripheral->a_host\n");
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
/* Clear the a_peripheral flag, back to a_host */
spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg);
......@@ -423,9 +463,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
}
}
/* Change to L2 (suspend) state */
hsotg->lx_state = DWC2_L2;
clear_int:
/* Clear interrupt */
writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
}
......@@ -522,4 +560,3 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
spin_unlock(&hsotg->lock);
return retval;
}
EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
/**
* debug.h - Designware USB2 DRD controller debug header
*
* Copyright (C) 2015 Intel Corporation
* Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "core.h"
#ifdef CONFIG_DEBUG_FS
extern int dwc2_debugfs_init(struct dwc2_hsotg *);
extern void dwc2_debugfs_exit(struct dwc2_hsotg *);
#else
static inline int dwc2_debugfs_init(struct dwc2_hsotg *hsotg)
{ return 0; }
static inline void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg)
{ }
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -357,12 +357,12 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
writel(0, hsotg->regs + HPRT0);
}
/* Caller must hold driver lock */
static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
struct dwc2_hcd_urb *urb, void **ep_handle,
gfp_t mem_flags)
{
struct dwc2_qtd *qtd;
unsigned long flags;
u32 intr_mask;
int retval;
int dev_speed;
......@@ -413,11 +413,9 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
*/
return 0;
spin_lock_irqsave(&hsotg->lock, flags);
tr_type = dwc2_hcd_select_transactions(hsotg);
if (tr_type != DWC2_TRANSACTION_NONE)
dwc2_hcd_queue_transactions(hsotg, tr_type);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
return 0;
......@@ -721,9 +719,7 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
/* 3072 = 3 max-size Isoc packets */
buf_size = 3072;
qh->dw_align_buf = dma_alloc_coherent(hsotg->dev, buf_size,
&qh->dw_align_buf_dma,
GFP_ATOMIC);
qh->dw_align_buf = kmalloc(buf_size, GFP_ATOMIC | GFP_DMA);
if (!qh->dw_align_buf)
return -ENOMEM;
qh->dw_align_buf_size = buf_size;
......@@ -748,6 +744,15 @@ static int dwc2_hc_setup_align_buf(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
}
}
qh->dw_align_buf_dma = dma_map_single(hsotg->dev,
qh->dw_align_buf, qh->dw_align_buf_size,
chan->ep_is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (dma_mapping_error(hsotg->dev, qh->dw_align_buf_dma)) {
dev_err(hsotg->dev, "can't map align_buf\n");
chan->align_buf = 0;
return -EINVAL;
}
chan->align_buf = qh->dw_align_buf_dma;
return 0;
}
......@@ -1774,6 +1779,15 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
/* Not supported */
break;
case USB_PORT_FEAT_TEST:
hprt0 = dwc2_read_hprt0(hsotg);
dev_dbg(hsotg->dev,
"SetPortFeature - USB_PORT_FEAT_TEST\n");
hprt0 &= ~HPRT0_TSTCTL_MASK;
hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
writel(hprt0, hsotg->regs + HPRT0);
break;
default:
retval = -EINVAL;
dev_err(hsotg->dev,
......@@ -2313,6 +2327,22 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
usleep_range(1000, 3000);
}
static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
hsotg->lx_state = DWC2_L2;
return 0;
}
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
hsotg->lx_state = DWC2_L0;
return 0;
}
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
......@@ -2468,7 +2498,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
"%s: unaligned transfer with no transfer_buffer",
__func__);
retval = -EINVAL;
goto fail1;
goto fail0;
}
}
......@@ -2496,7 +2526,6 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
spin_lock_irqsave(&hsotg->lock, flags);
retval = usb_hcd_link_urb_to_ep(hcd, urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
if (retval)
goto fail1;
......@@ -2505,22 +2534,22 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
goto fail2;
if (alloc_bandwidth) {
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_allocate_bus_bandwidth(hcd,
dwc2_hcd_get_ep_bandwidth(hsotg, ep),
urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
fail2:
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_urb->priv = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&hsotg->lock, flags);
fail1:
spin_unlock_irqrestore(&hsotg->lock, flags);
urb->hcpriv = NULL;
fail0:
kfree(dwc2_urb);
return retval;
......@@ -2683,6 +2712,9 @@ static struct hc_driver dwc2_hc_driver = {
.hub_status_data = _dwc2_hcd_hub_status_data,
.hub_control = _dwc2_hcd_hub_control,
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
.bus_suspend = _dwc2_hcd_suspend,
.bus_resume = _dwc2_hcd_resume,
};
/*
......@@ -2748,8 +2780,6 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
destroy_workqueue(hsotg->wq_otg);
}
kfree(hsotg->core_params);
hsotg->core_params = NULL;
del_timer(&hsotg->wkp_timer);
}
......@@ -2761,30 +2791,13 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg)
dwc2_hcd_free(hsotg);
}
/*
* Sets all parameters to the given value.
*
* Assumes that the dwc2_core_params struct contains only integers.
*/
void dwc2_set_all_params(struct dwc2_core_params *params, int value)
{
int *p = (int *)params;
size_t size = sizeof(*params) / sizeof(*p);
int i;
for (i = 0; i < size; i++)
p[i] = value;
}
EXPORT_SYMBOL_GPL(dwc2_set_all_params);
/*
* Initializes the HCD. This function allocates memory for and initializes the
* static parts of the usb_hcd and dwc2_hsotg structures. It also registers the
* USB bus with the core and calls the hc_driver->start() function. It returns
* a negative error on failure.
*/
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params)
int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
{
struct usb_hcd *hcd;
struct dwc2_host_chan *channel;
......@@ -2797,12 +2810,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
/* Detect config values from hardware */
retval = dwc2_get_hwparams(hsotg);
if (retval)
return retval;
retval = -ENOMEM;
hcfg = readl(hsotg->regs + HCFG);
......@@ -2821,15 +2828,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
hsotg->last_frame_num = HFNUM_MAX_FRNUM;
#endif
hsotg->core_params = kzalloc(sizeof(*hsotg->core_params), GFP_KERNEL);
if (!hsotg->core_params)
goto error1;
dwc2_set_all_params(hsotg->core_params, -1);
/* Validate parameter values */
dwc2_set_parameters(hsotg, params);
/* Check if the bus driver or platform code has setup a dma_mask */
if (hsotg->core_params->dma_enable > 0 &&
hsotg->dev->dma_mask == NULL) {
......@@ -2947,6 +2945,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
/* Don't support SG list at this point */
hcd->self.sg_tablesize = 0;
if (!IS_ERR_OR_NULL(hsotg->uphy))
otg_set_host(hsotg->uphy->otg, &hcd->self);
/*
* Finish generic HCD initialization and start the HCD. This function
* allocates the DMA buffer pool, registers the USB bus, requests the
......@@ -2979,7 +2980,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
dev_err(hsotg->dev, "%s() FAILED, returning %d\n", __func__, retval);
return retval;
}
EXPORT_SYMBOL_GPL(dwc2_hcd_init);
/*
* Removes the HCD.
......@@ -3000,6 +3000,9 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
return;
}
if (!IS_ERR_OR_NULL(hsotg->uphy))
otg_set_host(hsotg->uphy->otg, NULL);
usb_remove_hcd(hcd);
hsotg->priv = NULL;
dwc2_hcd_release(hsotg);
......@@ -3010,4 +3013,3 @@ void dwc2_hcd_remove(struct dwc2_hsotg *hsotg)
kfree(hsotg->frame_num_array);
#endif
}
EXPORT_SYMBOL_GPL(dwc2_hcd_remove);
......@@ -451,13 +451,8 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe)
return !dwc2_hcd_is_pipe_in(pipe);
}
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
const struct dwc2_core_params *params);
extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq);
extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg);
extern void dwc2_set_parameters(struct dwc2_hsotg *hsotg,
const struct dwc2_core_params *params);
extern void dwc2_set_all_params(struct dwc2_core_params *params, int value);
extern int dwc2_get_hwparams(struct dwc2_hsotg *hsotg);
/* Transaction Execution Functions */
extern enum dwc2_transaction_type dwc2_hcd_select_transactions(
......
This diff is collapsed.
......@@ -229,11 +229,13 @@ static struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg,
*/
void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
{
if (hsotg->core_params->dma_desc_enable > 0)
if (hsotg->core_params->dma_desc_enable > 0) {
dwc2_hcd_qh_free_ddma(hsotg, qh);
else if (qh->dw_align_buf)
dma_free_coherent(hsotg->dev, qh->dw_align_buf_size,
qh->dw_align_buf, qh->dw_align_buf_dma);
} else {
/* kfree(NULL) is safe */
kfree(qh->dw_align_buf);
qh->dw_align_buf_dma = (dma_addr_t)0;
}
kfree(qh);
}
......@@ -761,6 +763,7 @@ void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb)
/**
* dwc2_hcd_qtd_add() - Adds a QTD to the QTD-list of a QH
* Caller must hold driver lock.
*
* @hsotg: The DWC HCD structure
* @qtd: The QTD to add
......@@ -777,7 +780,6 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
struct dwc2_qh **qh, gfp_t mem_flags)
{
struct dwc2_hcd_urb *urb = qtd->urb;
unsigned long flags;
int allocated = 0;
int retval;
......@@ -792,15 +794,12 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
allocated = 1;
}
spin_lock_irqsave(&hsotg->lock, flags);
retval = dwc2_hcd_qh_add(hsotg, *qh);
if (retval)
goto fail;
qtd->qh = *qh;
list_add_tail(&qtd->qtd_list_entry, &(*qh)->qtd_list);
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
......@@ -817,10 +816,7 @@ int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd,
qtd_list_entry)
dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh_tmp);
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hcd_qh_free(hsotg, qh_tmp);
} else {
spin_unlock_irqrestore(&hsotg->lock, flags);
}
return retval;
......
This diff is collapsed.
......@@ -11,6 +11,13 @@ config USB_DWC3
if USB_DWC3
config USB_DWC3_ULPI
bool "Register ULPI PHY Interface"
depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_DWC3
help
Select this if you have ULPI type PHY attached to your DWC3
controller.
choice
bool "DWC3 Mode Selection"
default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET)
......
......@@ -15,6 +15,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += gadget.o ep0.o
endif
ifneq ($(CONFIG_USB_DWC3_ULPI),)
dwc3-y += ulpi.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
dwc3-y += debugfs.o
endif
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -45,4 +45,6 @@ struct dwc3_platform_data {
unsigned tx_de_emphasis_quirk:1;
unsigned tx_de_emphasis:2;
const char *hsphy_interface;
};
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -39,8 +39,6 @@ struct f_rndis_opts {
int refcnt;
};
int rndis_init(void);
void rndis_exit(void);
void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net);
#endif /* U_RNDIS_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment