提交 e7cf773d 编写于 作者: L Linus Torvalds

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

Pull USB updates from Greg KH:
 "Here's the big set of USB and PHY patches for 3.19-rc1.

  The normal churn in the USB gadget area is in here, as well as xhci
  and other individual USB driver updates.  The PHY tree is also in
  here, as there were dependancies on the USB tree.

  All of these have been in linux-next"

* tag 'usb-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (351 commits)
  arm: omap3: twl: remove usb phy init data
  usbip: fix error handling in stub_probe()
  usb: gadget: udc: missing curly braces
  USB: mos7720: delete some unneeded code
  wusb: replace memset by memzero_explicit
  usbip: remove unneeded structure
  usb: xhci: fix comment for PORT_DEV_REMOVE
  xhci: don't use the same variable for stopped and halted rings current TD
  xhci: clear extra bits from slot context when setting max exit latency
  xhci: cleanup finish_td function
  USB: adutux: NULL dereferences on disconnect
  usb: chipidea: fix platform_no_drv_owner.cocci warnings
  usb: chipidea: Fixed a few typos in comments
  Documentation: bindings: add doc for the USB2 ChipIdea USB driver
  usb: chipidea: add a usb2 driver for ci13xxx
  usb: chipidea: fix phy handling
  usb: chipidea: remove duplicate dev_set_drvdata for host_start
  usb: chipidea: parameter 'mode' isn't needed for hw_device_reset
  usb: chipidea: add controller reset API
  usb: chipidea: remove flag CI_HDRC_REQUIRE_TRANSCEIVER
  ...
What: /sys/class/udc/<udc>/a_alt_hnp_support
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates if an OTG A-Host supports HNP at an alternate port.
Users:
What: /sys/class/udc/<udc>/a_hnp_support
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates if an OTG A-Host supports HNP at this port.
Users:
What: /sys/class/udc/<udc>/b_hnp_enable
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates if an OTG A-Host enabled HNP support.
Users:
What: /sys/class/udc/<udc>/current_speed
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates the current negotiated speed at this port.
Users:
What: /sys/class/udc/<udc>/is_a_peripheral
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates that this port is the default Host on an OTG session
but HNP was used to switch roles.
Users:
What: /sys/class/udc/<udc>/is_otg
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates that this port support OTG.
Users:
What: /sys/class/udc/<udc>/maximum_speed
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates the maximum USB speed supported by this port.
Users:
What: /sys/class/udc/<udc>/maximum_speed
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates the maximum USB speed supported by this port.
Users:
What: /sys/class/udc/<udc>/soft_connect
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Allows users to disconnect data pullup resistors thus causing a
logical disconnection from the USB Host.
Users:
What: /sys/class/udc/<udc>/srp
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Allows users to manually start Session Request Protocol.
Users:
What: /sys/class/udc/<udc>/state
Date: June 2011
KernelVersion: 3.1
Contact: Felipe Balbi <balbi@kernel.org>
Description:
Indicates current state of the USB Device Controller. Valid
states are: 'not-attached', 'attached', 'powered',
'reconnecting', 'unauthenticated', 'default', 'addressed',
'configured', and 'suspended'; however not all USB Device
Controllers support reporting all states.
Users:
What: /config/usb-gadget/gadget/functions/hid.name
Date: Nov 2014
KernelVersion: 3.19
Description:
The attributes:
protocol - HID protocol to use
report_desc - blob corresponding to HID report descriptors
except the data passed through /dev/hidg<N>
report_length - HID report length
subclass - HID device subclass to use
What: /config/usb-gadget/gadget/functions/midi.name
Date: Nov 2014
KernelVersion: 3.19
Description:
The attributes:
index - index value for the USB MIDI adapter
id - ID string for the USB MIDI adapter
buflen - MIDI buffer length
qlen - USB read request queue length
in_ports - number of MIDI input ports
out_ports - number of MIDI output ports
......@@ -6,11 +6,17 @@ Required Properties:
- interrupts : Interrupt controller is using
- nr-ports : Number of SATA ports in use.
Optional Properties:
- phys : List of phandles to sata phys
- phy-names : Should be "0", "1", etc, one number per phandle
Example:
sata@80000 {
compatible = "marvell,orion-sata";
reg = <0x80000 0x5000>;
interrupts = <21>;
phys = <&sata_phy0>, <&sata_phy1>;
phy-names = "0", "1";
nr-ports = <2>;
}
......@@ -2,7 +2,9 @@ Berlin SATA PHY
---------------
Required properties:
- compatible: should be "marvell,berlin2q-sata-phy"
- compatible: should be one of
"marvell,berlin2-sata-phy"
"marvell,berlin2q-sata-phy"
- address-cells: should be 1
- size-cells: should be 0
- phy-cells: from the generic PHY bindings, must be 1
......
* Marvell Berlin USB PHY
Required properties:
- compatible: "marvell,berlin2-usb-phy" or "marvell,berlin2cd-usb-phy"
- reg: base address and length of the registers
- #phys-cells: should be 0
- resets: reference to the reset controller
Example:
usb-phy@f774000 {
compatible = "marvell,berlin2-usb-phy";
reg = <0xf774000 0x128>;
#phy-cells = <0>;
resets = <&chip 0x104 14>;
};
STMicroelectronics STi MIPHY28LP PHY binding
============================================
This binding describes a miphy device that is used to control PHY hardware
for SATA, PCIe or USB3.
Required properties (controller (parent) node):
- compatible : Should be "st,miphy28lp-phy".
- st,syscfg : Should be a phandle of the system configuration register group
which contain the SATA, PCIe or USB3 mode setting bits.
Required nodes : A sub-node is required for each channel the controller
provides. Address range information including the usual
'reg' and 'reg-names' properties are used inside these
nodes to describe the controller's topology. These nodes
are translated by the driver's .xlate() function.
Required properties (port (child) node):
- #phy-cells : Should be 1 (See second example)
Cell after port phandle is device type from:
- PHY_TYPE_SATA
- PHY_TYPE_PCI
- PHY_TYPE_USB3
- reg : Address and length of the register set for the device.
- reg-names : The names of the register addresses corresponding to the registers
filled in "reg". It can also contain the offset of the system configuration
registers used as glue-logic to setup the device for SATA/PCIe or USB3
devices.
- resets : phandle to the parent reset controller.
- reset-names : Associated name must be "miphy-sw-rst".
Optional properties (port (child) node):
- st,osc-rdy : to check the MIPHY0_OSC_RDY status in the glue-logic. This
is not available in all the MiPHY. For example, for STiH407, only the
MiPHY0 has this bit.
- st,osc-force-ext : to select the external oscillator. This can change from
different MiPHY inside the same SoC.
- st,sata_gen : to select which SATA_SPDMODE has to be set in the SATA system config
register.
- st,px_rx_pol_inv : to invert polarity of RXn/RXp (respectively negative line and positive
line).
- st,scc-on : enable ssc to reduce effects of EMI (only for sata or PCIe).
- st,tx-impedance-comp : to compensate tx impedance avoiding out of range values.
example:
miphy28lp_phy: miphy28lp@9b22000 {
compatible = "st,miphy28lp-phy";
st,syscfg = <&syscfg_core>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
phy_port0: port@9b22000 {
reg = <0x9b22000 0xff>,
<0x9b09000 0xff>,
<0x9b04000 0xff>,
<0x114 0x4>, /* sysctrl MiPHY cntrl */
<0x818 0x4>, /* sysctrl MiPHY status*/
<0xe0 0x4>, /* sysctrl PCIe */
<0xec 0x4>; /* sysctrl SATA */
reg-names = "sata-up",
"pcie-up",
"pipew",
"miphy-ctrl-glue",
"miphy-status-glue",
"pcie-glue",
"sata-glue";
#phy-cells = <1>;
st,osc-rdy;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY0_SOFTRESET>;
};
phy_port1: port@9b2a000 {
reg = <0x9b2a000 0xff>,
<0x9b19000 0xff>,
<0x9b14000 0xff>,
<0x118 0x4>,
<0x81c 0x4>,
<0xe4 0x4>,
<0xf0 0x4>;
reg-names = "sata-up",
"pcie-up",
"pipew",
"miphy-ctrl-glue",
"miphy-status-glue",
"pcie-glue",
"sata-glue";
#phy-cells = <1>;
st,osc-force-ext;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY1_SOFTRESET>;
};
phy_port2: port@8f95000 {
reg = <0x8f95000 0xff>,
<0x8f90000 0xff>,
<0x11c 0x4>,
<0x820 0x4>;
reg-names = "pipew",
"usb3-up",
"miphy-ctrl-glue",
"miphy-status-glue";
#phy-cells = <1>;
reset-names = "miphy-sw-rst";
resets = <&softreset STIH407_MIPHY2_SOFTRESET>;
};
};
Specifying phy control of devices
=================================
Device nodes should specify the configuration required in their "phys"
property, containing a phandle to the miphy device node and an index
specifying which configuration to use, as described in phy-bindings.txt.
example:
sata0: sata@9b20000 {
...
phys = <&phy_port0 PHY_TYPE_SATA>;
...
};
Macro definitions for the supported miphy configuration can be found in:
include/dt-bindings/phy/phy-miphy28lp.h
* Marvell MVEBU SATA PHY
Power control for the SATA phy found on Marvell MVEBU SoCs.
This document extends the binding described in phy-bindings.txt
Required properties :
- reg : Offset and length of the register set for the SATA device
- compatible : Should be "marvell,mvebu-sata-phy"
- clocks : phandle of clock and specifier that supplies the device
- clock-names : Should be "sata"
Example:
sata-phy@84000 {
compatible = "marvell,mvebu-sata-phy";
reg = <0x84000 0x0334>;
clocks = <&gate_clk 15>;
clock-names = "sata";
#phy-cells = <0>;
status = "ok";
};
Armada 375 USB cluster
----------------------
Armada 375 comes with an USB2 host and device controller and an USB3
controller. The USB cluster control register allows to manage common
features of both USB controllers.
Required properties:
- compatible: "marvell,armada-375-usb-cluster"
- reg: Should contain usb cluster register location and length.
- #phy-cells : from the generic phy bindings, must be 1. Possible
values are 1 (USB2), 2 (USB3).
Example:
usbcluster: usb-cluster@18400 {
compatible = "marvell,armada-375-usb-cluster";
reg = <0x18400 0x4>;
#phy-cells = <1>
};
......@@ -128,6 +128,7 @@ Required properties:
- compatible : Should be set to one of the following supported values:
- "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC,
- "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC.
- "samsung,exynos7-usbdrd-phy" - for exynos7 SoC.
- reg : Register offset and length of USB DRD PHY register set;
- clocks: Clock IDs array as required by the controller
- clock-names: names of clocks correseponding to IDs in the clock property;
......@@ -138,6 +139,11 @@ Required properties:
PHY operations, associated by phy name. It is used to
determine bit values for clock settings register.
For Exynos5420 this is given as 'sclk_usbphy30' in CMU.
- optional clocks: Exynos7 SoC has now following additional
gate clocks available:
- phy_pipe: for PIPE3 phy
- phy_utmi: for UTMI+ phy
- itp: for ITP generation
- samsung,pmu-syscon: phandle for PMU system controller interface, used to
control pmu registers for power isolation.
- #phy-cells : from the generic PHY bindings, must be 1;
......
* USB2 ChipIdea USB controller for ci13xxx
Required properties:
- compatible: should be "chipidea,usb2"
- reg: base address and length of the registers
- interrupts: interrupt for the USB controller
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
Example:
usb@f7ed0000 {
compatible = "chipidea,usb2";
reg = <0xf7ed0000 0x10000>;
interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&chip CLKID_USB0>;
phys = <&usb_phy0>;
phy-names = "usb-phy";
vbus-supply = <&reg_usb0_vbus>;
};
......@@ -14,6 +14,29 @@ Optional properties:
- phys: from the *Generic PHY* bindings
- phy-names: from the *Generic PHY* bindings
- tx-fifo-resize: determines if the FIFO *has* to be reallocated.
- snps,disable_scramble_quirk: true when SW should disable data scrambling.
Only really useful for FPGA builds.
- snps,has-lpm-erratum: true when DWC3 was configured with LPM Erratum enabled
- snps,lpm-nyet-threshold: LPM NYET threshold
- snps,u2exit_lfps_quirk: set if we want to enable u2exit lfps quirk
- snps,u2ss_inp3_quirk: set if we enable P3 OK for U2/SS Inactive quirk
- snps,req_p1p2p3_quirk: when set, the core will always request for
P1/P2/P3 transition sequence.
- snps,del_p1p2p3_quirk: when set core will delay P1/P2/P3 until a certain
amount of 8B10B errors occur.
- snps,del_phy_power_chg_quirk: when set core will delay PHY power change
from P0 to P1/P2/P3.
- snps,lfps_filter_quirk: when set core will filter LFPS reception.
- snps,rx_detect_poll_quirk: when set core will disable a 400us delay to start
Polling LFPS after RX.Detect.
- snps,tx_de_emphasis_quirk: when set core will set Tx de-emphasis value.
- snps,tx_de_emphasis: the value driven to the PHY is controlled by the
LTSSM during USB3 Compliance mode.
- snps,dis_u3_susphy_quirk: when set core will disable USB3 suspend phy.
- snps,dis_u2_susphy_quirk: when set core will disable USB2 suspend phy.
- 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
This is usually a subnode to DWC3 glue to which it is connected.
......
......@@ -82,8 +82,10 @@ Example:
DWC3
Required properties:
- compatible: should be "samsung,exynos5250-dwusb3" for USB 3.0 DWC3
controller.
- compatible: should be one of the following -
"samsung,exynos5250-dwusb3": for USB 3.0 DWC3 controller on
Exynos5250/5420.
"samsung,exynos7-dwusb3": for USB 3.0 DWC3 controller on Exynos7.
- #address-cells, #size-cells : should be '1' if the device has sub-nodes
with 'reg' property.
- ranges: allows valid 1:1 translation between child's address space and
......
......@@ -29,3 +29,25 @@ Example:
marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
};
UDC
Required properties:
- compatible: Should be "marvell,pxa270-udc" for USB controllers
used in device mode.
- reg: usb device MMIO address space
- interrupts: single interrupt generated by the UDC IP
- clocks: input clock of the UDC IP (see clock-bindings.txt)
Optional properties:
- gpios:
- gpio activated to control the USB D+ pullup (see gpio.txt)
Example:
pxa27x_udc: udc@40600000 {
compatible = "marvell,pxa270-udc";
reg = <0x40600000 0x10000>;
interrupts = <11>;
clocks = <&pxa2xx_clks 11>;
gpios = <&gpio 22 GPIO_ACTIVE_LOW>;
};
......@@ -9,6 +9,8 @@ Optional properties:
- big-endian-regs : boolean, set this for hcds with big-endian registers
- big-endian-desc : boolean, set this for hcds with big-endian descriptors
- big-endian : boolean, for hcds with big-endian-regs + big-endian-desc
- no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA
- num-ports : u32, to override the detected port count
- clocks : a list of phandle + clock specifier pairs
- phys : phandle + phy specifier pair
- phy-names : "usb"
......
......@@ -54,18 +54,14 @@ The PHY driver should create the PHY in order for other peripheral controllers
to make use of it. The PHY framework provides 2 APIs to create the PHY.
struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data);
const struct phy_ops *ops);
struct phy *devm_phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data);
const struct phy_ops *ops);
The PHY drivers can use one of the above 2 APIs to create the PHY by passing
the device pointer, phy ops and init_data.
the device pointer and phy ops.
phy_ops is a set of function pointers for performing PHY operations such as
init, exit, power_on and power_off. *init_data* is mandatory to get a reference
to the PHY in the case of non-dt boot. See section *Board File Initialization*
on how init_data should be used.
init, exit, power_on and power_off.
Inorder to dereference the private data (in phy_ops), the phy provider driver
can use phy_set_drvdata() after creating the PHY and use phy_get_drvdata() in
......@@ -137,42 +133,18 @@ There are exported APIs like phy_pm_runtime_get, phy_pm_runtime_get_sync,
phy_pm_runtime_put, phy_pm_runtime_put_sync, phy_pm_runtime_allow and
phy_pm_runtime_forbid for performing PM operations.
8. Board File Initialization
Certain board file initialization is necessary in order to get a reference
to the PHY in the case of non-dt boot.
Say we have a single device that implements 3 PHYs that of USB, SATA and PCIe,
then in the board file the following initialization should be done.
struct phy_consumer consumers[] = {
PHY_CONSUMER("dwc3.0", "usb"),
PHY_CONSUMER("pcie.0", "pcie"),
PHY_CONSUMER("sata.0", "sata"),
};
PHY_CONSUMER takes 2 parameters, first is the device name of the controller
(PHY consumer) and second is the port name.
struct phy_init_data init_data = {
.consumers = consumers,
.num_consumers = ARRAY_SIZE(consumers),
};
static const struct platform_device pipe3_phy_dev = {
.name = "pipe3-phy",
.id = -1,
.dev = {
.platform_data = {
.init_data = &init_data,
},
},
};
then, while doing phy_create, the PHY driver should pass this init_data
phy_create(dev, ops, pdata->init_data);
and the controller driver (phy consumer) should pass the port name along with
the device to get a reference to the PHY
phy_get(dev, "pcie");
8. PHY Mappings
In order to get reference to a PHY without help from DeviceTree, the framework
offers lookups which can be compared to clkdev that allow clk structures to be
bound to devices. A lookup can be made be made during runtime when a handle to
the struct phy already exists.
The framework offers the following API for registering and unregistering the
lookups.
int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
9. DeviceTree Binding
......
......@@ -74,6 +74,13 @@ static struct platform_device my_hid = {
You can add as many HID functions as you want, only limited by
the amount of interrupt endpoints your gadget driver supports.
Configuration with configfs
Instead of adding fake platform devices and drivers in order to pass
some data to the kernel, if HID is a part of a gadget composed with
configfs the hidg_func_descriptor.report_desc is passed to the kernel
by writing the appropriate stream of bytes to a configfs attribute.
Send and receive HID reports
HID reports can be sent/received using read/write on the
......
......@@ -145,7 +145,7 @@ Keyspan PDA Serial Adapter
Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly
sold in Macintosh catalogs, comes in a translucent white/green dongle).
Fairly simple device. Firmware is homebrew.
This driver also works for the Xircom/Entrgra single port serial adapter.
This driver also works for the Xircom/Entrega single port serial adapter.
Current status:
Things that work:
......
......@@ -843,6 +843,8 @@
maximum-speed = "high-speed";
dr_mode = "otg";
status = "disabled";
snps,dis_u3_susphy_quirk;
snps,dis_u2_susphy_quirk;
};
};
......@@ -865,6 +867,8 @@
maximum-speed = "high-speed";
dr_mode = "otg";
status = "disabled";
snps,dis_u3_susphy_quirk;
snps,dis_u2_susphy_quirk;
};
};
......
......@@ -91,18 +91,8 @@ void __init omap_pmic_late_init(void)
}
#if defined(CONFIG_ARCH_OMAP3)
struct phy_consumer consumers[] = {
PHY_CONSUMER("musb-hdrc.0", "usb"),
};
struct phy_init_data init_data = {
.consumers = consumers,
.num_consumers = ARRAY_SIZE(consumers),
};
static struct twl4030_usb_data omap3_usb_pdata = {
.usb_mode = T2_USB_MODE_ULPI,
.init_data = &init_data,
.usb_mode = T2_USB_MODE_ULPI,
};
static int omap3_batt_table[] = {
......
......@@ -7,22 +7,27 @@
* Copyright (C) 2008 Wind River Systems
*/
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/i2c.h>
#include <linux/usb.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/of_platform.h>
#include <linux/of_fdt.h>
#include <linux/libfdt.h>
#include <linux/usb/ehci_pdriver.h>
#include <linux/usb/ohci_pdriver.h>
#include <asm/octeon/octeon.h>
#include <asm/octeon/cvmx-rnm-defs.h>
#include <asm/octeon/cvmx-helper.h>
#include <asm/octeon/cvmx-helper-board.h>
#include <asm/octeon/cvmx-uctlx-defs.h>
/* Octeon Random Number Generator. */
static int __init octeon_rng_device_init(void)
......@@ -68,6 +73,229 @@ device_initcall(octeon_rng_device_init);
#ifdef CONFIG_USB
static DEFINE_MUTEX(octeon2_usb_clocks_mutex);
static int octeon2_usb_clock_start_cnt;
static void octeon2_usb_clocks_start(void)
{
u64 div;
union cvmx_uctlx_if_ena if_ena;
union cvmx_uctlx_clk_rst_ctl clk_rst_ctl;
union cvmx_uctlx_uphy_ctl_status uphy_ctl_status;
union cvmx_uctlx_uphy_portx_ctl_status port_ctl_status;
int i;
unsigned long io_clk_64_to_ns;
mutex_lock(&octeon2_usb_clocks_mutex);
octeon2_usb_clock_start_cnt++;
if (octeon2_usb_clock_start_cnt != 1)
goto exit;
io_clk_64_to_ns = 64000000000ull / octeon_get_io_clock_rate();
/*
* Step 1: Wait for voltages stable. That surely happened
* before starting the kernel.
*
* Step 2: Enable SCLK of UCTL by writing UCTL0_IF_ENA[EN] = 1
*/
if_ena.u64 = 0;
if_ena.s.en = 1;
cvmx_write_csr(CVMX_UCTLX_IF_ENA(0), if_ena.u64);
/* Step 3: Configure the reference clock, PHY, and HCLK */
clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
/*
* If the UCTL looks like it has already been started, skip
* the initialization, otherwise bus errors are obtained.
*/
if (clk_rst_ctl.s.hrst)
goto end_clock;
/* 3a */
clk_rst_ctl.s.p_por = 1;
clk_rst_ctl.s.hrst = 0;
clk_rst_ctl.s.p_prst = 0;
clk_rst_ctl.s.h_clkdiv_rst = 0;
clk_rst_ctl.s.o_clkdiv_rst = 0;
clk_rst_ctl.s.h_clkdiv_en = 0;
clk_rst_ctl.s.o_clkdiv_en = 0;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 3b */
/* 12MHz crystal. */
clk_rst_ctl.s.p_refclk_sel = 0;
clk_rst_ctl.s.p_refclk_div = 0;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 3c */
div = octeon_get_io_clock_rate() / 130000000ull;
switch (div) {
case 0:
div = 1;
break;
case 1:
case 2:
case 3:
case 4:
break;
case 5:
div = 4;
break;
case 6:
case 7:
div = 6;
break;
case 8:
case 9:
case 10:
case 11:
div = 8;
break;
default:
div = 12;
break;
}
clk_rst_ctl.s.h_div = div;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* Read it back, */
clk_rst_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_CLK_RST_CTL(0));
clk_rst_ctl.s.h_clkdiv_en = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 3d */
clk_rst_ctl.s.h_clkdiv_rst = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 3e: delay 64 io clocks */
ndelay(io_clk_64_to_ns);
/*
* Step 4: Program the power-on reset field in the UCTL
* clock-reset-control register.
*/
clk_rst_ctl.s.p_por = 0;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* Step 5: Wait 1 ms for the PHY clock to start. */
mdelay(1);
/*
* Step 6: Program the reset input from automatic test
* equipment field in the UPHY CSR
*/
uphy_ctl_status.u64 = cvmx_read_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0));
uphy_ctl_status.s.ate_reset = 1;
cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
/* Step 7: Wait for at least 10ns. */
ndelay(10);
/* Step 8: Clear the ATE_RESET field in the UPHY CSR. */
uphy_ctl_status.s.ate_reset = 0;
cvmx_write_csr(CVMX_UCTLX_UPHY_CTL_STATUS(0), uphy_ctl_status.u64);
/*
* Step 9: Wait for at least 20ns for UPHY to output PHY clock
* signals and OHCI_CLK48
*/
ndelay(20);
/* Step 10: Configure the OHCI_CLK48 and OHCI_CLK12 clocks. */
/* 10a */
clk_rst_ctl.s.o_clkdiv_rst = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 10b */
clk_rst_ctl.s.o_clkdiv_en = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* 10c */
ndelay(io_clk_64_to_ns);
/*
* Step 11: Program the PHY reset field:
* UCTL0_CLK_RST_CTL[P_PRST] = 1
*/
clk_rst_ctl.s.p_prst = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
/* Step 12: Wait 1 uS. */
udelay(1);
/* Step 13: Program the HRESET_N field: UCTL0_CLK_RST_CTL[HRST] = 1 */
clk_rst_ctl.s.hrst = 1;
cvmx_write_csr(CVMX_UCTLX_CLK_RST_CTL(0), clk_rst_ctl.u64);
end_clock:
/* Now we can set some other registers. */
for (i = 0; i <= 1; i++) {
port_ctl_status.u64 =
cvmx_read_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0));
/* Set txvreftune to 15 to obtain compliant 'eye' diagram. */
port_ctl_status.s.txvreftune = 15;
port_ctl_status.s.txrisetune = 1;
port_ctl_status.s.txpreemphasistune = 1;
cvmx_write_csr(CVMX_UCTLX_UPHY_PORTX_CTL_STATUS(i, 0),
port_ctl_status.u64);
}
/* Set uSOF cycle period to 60,000 bits. */
cvmx_write_csr(CVMX_UCTLX_EHCI_FLA(0), 0x20ull);
exit:
mutex_unlock(&octeon2_usb_clocks_mutex);
}
static void octeon2_usb_clocks_stop(void)
{
mutex_lock(&octeon2_usb_clocks_mutex);
octeon2_usb_clock_start_cnt--;
mutex_unlock(&octeon2_usb_clocks_mutex);
}
static int octeon_ehci_power_on(struct platform_device *pdev)
{
octeon2_usb_clocks_start();
return 0;
}
static void octeon_ehci_power_off(struct platform_device *pdev)
{
octeon2_usb_clocks_stop();
}
static struct usb_ehci_pdata octeon_ehci_pdata = {
/* Octeon EHCI matches CPU endianness. */
#ifdef __BIG_ENDIAN
.big_endian_mmio = 1,
#endif
.power_on = octeon_ehci_power_on,
.power_off = octeon_ehci_power_off,
};
static void __init octeon_ehci_hw_start(void)
{
union cvmx_uctlx_ehci_ctl ehci_ctl;
octeon2_usb_clocks_start();
ehci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_EHCI_CTL(0));
/* Use 64-bit addressing. */
ehci_ctl.s.ehci_64b_addr_en = 1;
ehci_ctl.s.l2c_addr_msb = 0;
ehci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
ehci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
cvmx_write_csr(CVMX_UCTLX_EHCI_CTL(0), ehci_ctl.u64);
octeon2_usb_clocks_stop();
}
static u64 octeon_ehci_dma_mask = DMA_BIT_MASK(64);
static int __init octeon_ehci_device_init(void)
{
struct platform_device *pd;
......@@ -88,7 +316,7 @@ static int __init octeon_ehci_device_init(void)
if (octeon_is_simulation() || usb_disabled())
return 0; /* No USB in the simulator. */
pd = platform_device_alloc("octeon-ehci", 0);
pd = platform_device_alloc("ehci-platform", 0);
if (!pd) {
ret = -ENOMEM;
goto out;
......@@ -105,6 +333,10 @@ static int __init octeon_ehci_device_init(void)
if (ret)
goto fail;
pd->dev.dma_mask = &octeon_ehci_dma_mask;
pd->dev.platform_data = &octeon_ehci_pdata;
octeon_ehci_hw_start();
ret = platform_device_add(pd);
if (ret)
goto fail;
......@@ -117,6 +349,41 @@ static int __init octeon_ehci_device_init(void)
}
device_initcall(octeon_ehci_device_init);
static int octeon_ohci_power_on(struct platform_device *pdev)
{
octeon2_usb_clocks_start();
return 0;
}
static void octeon_ohci_power_off(struct platform_device *pdev)
{
octeon2_usb_clocks_stop();
}
static struct usb_ohci_pdata octeon_ohci_pdata = {
/* Octeon OHCI matches CPU endianness. */
#ifdef __BIG_ENDIAN
.big_endian_mmio = 1,
#endif
.power_on = octeon_ohci_power_on,
.power_off = octeon_ohci_power_off,
};
static void __init octeon_ohci_hw_start(void)
{
union cvmx_uctlx_ohci_ctl ohci_ctl;
octeon2_usb_clocks_start();
ohci_ctl.u64 = cvmx_read_csr(CVMX_UCTLX_OHCI_CTL(0));
ohci_ctl.s.l2c_addr_msb = 0;
ohci_ctl.s.l2c_buff_emod = 1; /* Byte swapped. */
ohci_ctl.s.l2c_desc_emod = 1; /* Byte swapped. */
cvmx_write_csr(CVMX_UCTLX_OHCI_CTL(0), ohci_ctl.u64);
octeon2_usb_clocks_stop();
}
static int __init octeon_ohci_device_init(void)
{
struct platform_device *pd;
......@@ -137,7 +404,7 @@ static int __init octeon_ohci_device_init(void)
if (octeon_is_simulation() || usb_disabled())
return 0; /* No USB in the simulator. */
pd = platform_device_alloc("octeon-ohci", 0);
pd = platform_device_alloc("ohci-platform", 0);
if (!pd) {
ret = -ENOMEM;
goto out;
......@@ -154,6 +421,9 @@ static int __init octeon_ohci_device_init(void)
if (ret)
goto fail;
pd->dev.platform_data = &octeon_ohci_pdata;
octeon_ohci_hw_start();
ret = platform_device_add(pd);
if (ret)
goto fail;
......
......@@ -120,6 +120,9 @@ CONFIG_SPI_OCTEON=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
# CONFIG_USB_SUPPORT is not set
CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_STAGING=y
......
......@@ -378,6 +378,26 @@ static void quirk_ati_exploding_mce(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RS100, quirk_ati_exploding_mce);
/*
* In the AMD NL platform, this device ([1022:7912]) has a class code of
* PCI_CLASS_SERIAL_USB_XHCI (0x0c0330), which means the xhci driver will
* claim it.
* But the dwc3 driver is a more specific driver for this device, and we'd
* prefer to use it instead of xhci. To prevent xhci from claiming the
* device, change the class code to 0x0c03fe, which the PCI r3.0 spec
* defines as "USB device (not host controller)". The dwc3 driver can then
* claim it based on its Vendor and Device ID.
*/
static void quirk_amd_nl_class(struct pci_dev *pdev)
{
/*
* Use 'USB Device' (0x0c03fe) instead of PCI header provided
*/
pdev->class = 0x0c03fe;
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB,
quirk_amd_nl_class);
/*
* Let's make the southbridge information explicit instead
* of having to worry about people probing the ACPI areas,
......
......@@ -15,6 +15,13 @@ config GENERIC_PHY
phy users can obtain reference to the PHY. All the users of this
framework should select this config.
config PHY_BERLIN_USB
tristate "Marvell Berlin USB PHY Driver"
depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF
select GENERIC_PHY
help
Enable this to support the USB PHY on Marvell Berlin SoCs.
config PHY_BERLIN_SATA
tristate "Marvell Berlin SATA PHY driver"
depends on ARCH_BERLIN && HAS_IOMEM && OF
......@@ -22,6 +29,12 @@ config PHY_BERLIN_SATA
help
Enable this to support the SATA PHY on Marvell Berlin SoCs.
config ARMADA375_USBCLUSTER_PHY
def_bool y
depends on MACH_ARMADA_375 || COMPILE_TEST
depends on OF
select GENERIC_PHY
config PHY_EXYNOS_MIPI_VIDEO
tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver"
depends on HAS_IOMEM
......@@ -38,6 +51,14 @@ config PHY_MVEBU_SATA
depends on OF
select GENERIC_PHY
config PHY_MIPHY28LP
tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407"
depends on ARCH_STI
select GENERIC_PHY
help
Enable this to support the miphy transceiver (for SATA/PCIE/USB3)
that is part of STMicroelectronics STiH407 SoC.
config PHY_MIPHY365X
tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series"
depends on ARCH_STI
......@@ -193,7 +214,7 @@ config PHY_EXYNOS5250_USB2
config PHY_EXYNOS5_USBDRD
tristate "Exynos5 SoC series USB DRD PHY driver"
depends on ARCH_EXYNOS5 && OF
depends on ARCH_EXYNOS && OF
depends on HAS_IOMEM
depends on USB_DWC3_EXYNOS
select GENERIC_PHY
......
......@@ -3,11 +3,14 @@
#
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
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_MVEBU_SATA) += phy-mvebu-sata.o
obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_MIPHY365X) += phy-miphy365x.o
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o
......
/*
* USB cluster support for Armada 375 platform.
*
* Copyright (C) 2014 Marvell
*
* Gregory CLEMENT <gregory.clement@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2 or later. This program is licensed "as is"
* without any warranty of any kind, whether express or implied.
*
* Armada 375 comes with an USB2 host and device controller and an
* USB3 controller. The USB cluster control register allows to manage
* common features of both USB controllers.
*/
#include <dt-bindings/phy/phy.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#define USB2_PHY_CONFIG_DISABLE BIT(0)
struct armada375_cluster_phy {
struct phy *phy;
void __iomem *reg;
bool use_usb3;
int phy_provided;
};
static int armada375_usb_phy_init(struct phy *phy)
{
struct armada375_cluster_phy *cluster_phy;
u32 reg;
cluster_phy = dev_get_drvdata(phy->dev.parent);
if (!cluster_phy)
return -ENODEV;
reg = readl(cluster_phy->reg);
if (cluster_phy->use_usb3)
reg |= USB2_PHY_CONFIG_DISABLE;
else
reg &= ~USB2_PHY_CONFIG_DISABLE;
writel(reg, cluster_phy->reg);
return 0;
}
static struct phy_ops armada375_usb_phy_ops = {
.init = armada375_usb_phy_init,
.owner = THIS_MODULE,
};
/*
* Only one controller can use this PHY. We shouldn't have the case
* when two controllers want to use this PHY. But if this case occurs
* then we provide a phy to the first one and return an error for the
* next one. This error has also to be an error returned by
* devm_phy_optional_get() so different from ENODEV for USB2. In the
* USB3 case it still optional and we use ENODEV.
*/
static struct phy *armada375_usb_phy_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct armada375_cluster_phy *cluster_phy = dev_get_drvdata(dev);
if (!cluster_phy)
return ERR_PTR(-ENODEV);
/*
* Either the phy had never been requested and then the first
* usb claiming it can get it, or it had already been
* requested in this case, we only allow to use it with the
* same configuration.
*/
if (WARN_ON((cluster_phy->phy_provided != PHY_NONE) &&
(cluster_phy->phy_provided != args->args[0]))) {
dev_err(dev, "This PHY has already been provided!\n");
dev_err(dev, "Check your device tree, only one controller can use it\n.");
if (args->args[0] == PHY_TYPE_USB2)
return ERR_PTR(-EBUSY);
else
return ERR_PTR(-ENODEV);
}
if (args->args[0] == PHY_TYPE_USB2)
cluster_phy->use_usb3 = false;
else if (args->args[0] == PHY_TYPE_USB3)
cluster_phy->use_usb3 = true;
else {
dev_err(dev, "Invalid PHY mode\n");
return ERR_PTR(-ENODEV);
}
/* Store which phy mode is used for next test */
cluster_phy->phy_provided = args->args[0];
return cluster_phy->phy;
}
static int armada375_usb_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *usb_cluster_base;
struct resource *res;
struct armada375_cluster_phy *cluster_phy;
cluster_phy = devm_kzalloc(dev, sizeof(*cluster_phy), GFP_KERNEL);
if (!cluster_phy)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
if (!usb_cluster_base)
return -ENOMEM;
phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy);
}
cluster_phy->phy = phy;
cluster_phy->reg = usb_cluster_base;
dev_set_drvdata(dev, cluster_phy);
phy_provider = devm_of_phy_provider_register(&pdev->dev,
armada375_usb_phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id of_usb_cluster_table[] = {
{ .compatible = "marvell,armada-375-usb-cluster", },
{ /* end of list */ },
};
MODULE_DEVICE_TABLE(of, of_usb_cluster_table);
static struct platform_driver armada375_usb_phy_driver = {
.probe = armada375_usb_phy_probe,
.driver = {
.of_match_table = of_usb_cluster_table,
.name = "armada-375-usb-cluster",
.owner = THIS_MODULE,
}
};
module_platform_driver(armada375_usb_phy_driver);
MODULE_DESCRIPTION("Armada 375 USB cluster driver");
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
MODULE_LICENSE("GPL");
......@@ -117,7 +117,7 @@ static int bcm_kona_usb2_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
gphy = devm_phy_create(dev, NULL, &ops, NULL);
gphy = devm_phy_create(dev, NULL, &ops);
if (IS_ERR(gphy))
return PTR_ERR(gphy);
......
......@@ -30,7 +30,8 @@
#define MBUS_WRITE_REQUEST_SIZE_128 (BIT(2) << 16)
#define MBUS_READ_REQUEST_SIZE_128 (BIT(2) << 19)
#define PHY_BASE 0x200
#define BG2_PHY_BASE 0x080
#define BG2Q_PHY_BASE 0x200
/* register 0x01 */
#define REF_FREF_SEL_25 BIT(0)
......@@ -61,15 +62,16 @@ struct phy_berlin_priv {
struct clk *clk;
struct phy_berlin_desc **phys;
unsigned nphys;
u32 phy_base;
};
static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg, u32 reg,
u32 mask, u32 val)
static inline void phy_berlin_sata_reg_setbits(void __iomem *ctrl_reg,
u32 phy_base, u32 reg, u32 mask, u32 val)
{
u32 regval;
/* select register */
writel(PHY_BASE + reg, ctrl_reg + PORT_VSR_ADDR);
writel(phy_base + reg, ctrl_reg + PORT_VSR_ADDR);
/* set bits */
regval = readl(ctrl_reg + PORT_VSR_DATA);
......@@ -103,17 +105,20 @@ static int phy_berlin_sata_power_on(struct phy *phy)
writel(regval, priv->base + HOST_VSA_DATA);
/* set PHY mode and ref freq to 25 MHz */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x1, 0xff,
REF_FREF_SEL_25 | PHY_MODE_SATA);
phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x01,
0x00ff, REF_FREF_SEL_25 | PHY_MODE_SATA);
/* set PHY up to 6 Gbps */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x25, 0xc00, PHY_GEN_MAX_6_0);
phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x25,
0x0c00, PHY_GEN_MAX_6_0);
/* set 40 bits width */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x23, 0xc00, DATA_BIT_WIDTH_40);
phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x23,
0x0c00, DATA_BIT_WIDTH_40);
/* use max pll rate */
phy_berlin_sata_reg_setbits(ctrl_reg, 0x2, 0x0, USE_MAX_PLL_RATE);
phy_berlin_sata_reg_setbits(ctrl_reg, priv->phy_base, 0x02,
0x0000, USE_MAX_PLL_RATE);
/* set Gen3 controller speed */
regval = readl(ctrl_reg + PORT_SCR_CTL);
......@@ -218,6 +223,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!priv->phys)
return -ENOMEM;
if (of_device_is_compatible(dev->of_node, "marvell,berlin2-sata-phy"))
priv->phy_base = BG2_PHY_BASE;
else
priv->phy_base = BG2Q_PHY_BASE;
dev_set_drvdata(dev, priv);
spin_lock_init(&priv->lock);
......@@ -239,7 +249,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (!phy_desc)
return -ENOMEM;
phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops, NULL);
phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", phy_id);
return PTR_ERR(phy);
......@@ -258,13 +268,11 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
phy_provider =
devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
return 0;
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_berlin_sata_of_match[] = {
{ .compatible = "marvell,berlin2-sata-phy" },
{ .compatible = "marvell,berlin2q-sata-phy" },
{ },
};
......
/*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Tenart <antoine.tenart@free-electrons.com>
* Jisheng Zhang <jszhang@marvell.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#define USB_PHY_PLL 0x04
#define USB_PHY_PLL_CONTROL 0x08
#define USB_PHY_TX_CTRL0 0x10
#define USB_PHY_TX_CTRL1 0x14
#define USB_PHY_TX_CTRL2 0x18
#define USB_PHY_RX_CTRL 0x20
#define USB_PHY_ANALOG 0x34
/* USB_PHY_PLL */
#define CLK_REF_DIV(x) ((x) << 4)
#define FEEDBACK_CLK_DIV(x) ((x) << 8)
/* USB_PHY_PLL_CONTROL */
#define CLK_STABLE BIT(0)
#define PLL_CTRL_PIN BIT(1)
#define PLL_CTRL_REG BIT(2)
#define PLL_ON BIT(3)
#define PHASE_OFF_TOL_125 (0x0 << 5)
#define PHASE_OFF_TOL_250 BIT(5)
#define KVC0_CALIB (0x0 << 9)
#define KVC0_REG_CTRL BIT(9)
#define KVC0_HIGH (0x0 << 10)
#define KVC0_LOW (0x3 << 10)
#define CLK_BLK_EN BIT(13)
/* USB_PHY_TX_CTRL0 */
#define EXT_HS_RCAL_EN BIT(3)
#define EXT_FS_RCAL_EN BIT(4)
#define IMPCAL_VTH_DIV(x) ((x) << 5)
#define EXT_RS_RCAL_DIV(x) ((x) << 8)
#define EXT_FS_RCAL_DIV(x) ((x) << 12)
/* USB_PHY_TX_CTRL1 */
#define TX_VDD15_14 (0x0 << 4)
#define TX_VDD15_15 BIT(4)
#define TX_VDD15_16 (0x2 << 4)
#define TX_VDD15_17 (0x3 << 4)
#define TX_VDD12_VDD (0x0 << 6)
#define TX_VDD12_11 BIT(6)
#define TX_VDD12_12 (0x2 << 6)
#define TX_VDD12_13 (0x3 << 6)
#define LOW_VDD_EN BIT(8)
#define TX_OUT_AMP(x) ((x) << 9)
/* USB_PHY_TX_CTRL2 */
#define TX_CHAN_CTRL_REG(x) ((x) << 0)
#define DRV_SLEWRATE(x) ((x) << 4)
#define IMP_CAL_FS_HS_DLY_0 (0x0 << 6)
#define IMP_CAL_FS_HS_DLY_1 BIT(6)
#define IMP_CAL_FS_HS_DLY_2 (0x2 << 6)
#define IMP_CAL_FS_HS_DLY_3 (0x3 << 6)
#define FS_DRV_EN_MASK(x) ((x) << 8)
#define HS_DRV_EN_MASK(x) ((x) << 12)
/* USB_PHY_RX_CTRL */
#define PHASE_FREEZE_DLY_2_CL (0x0 << 0)
#define PHASE_FREEZE_DLY_4_CL BIT(0)
#define ACK_LENGTH_8_CL (0x0 << 2)
#define ACK_LENGTH_12_CL BIT(2)
#define ACK_LENGTH_16_CL (0x2 << 2)
#define ACK_LENGTH_20_CL (0x3 << 2)
#define SQ_LENGTH_3 (0x0 << 4)
#define SQ_LENGTH_6 BIT(4)
#define SQ_LENGTH_9 (0x2 << 4)
#define SQ_LENGTH_12 (0x3 << 4)
#define DISCON_THRESHOLD_260 (0x0 << 6)
#define DISCON_THRESHOLD_270 BIT(6)
#define DISCON_THRESHOLD_280 (0x2 << 6)
#define DISCON_THRESHOLD_290 (0x3 << 6)
#define SQ_THRESHOLD(x) ((x) << 8)
#define LPF_COEF(x) ((x) << 12)
#define INTPL_CUR_10 (0x0 << 14)
#define INTPL_CUR_20 BIT(14)
#define INTPL_CUR_30 (0x2 << 14)
#define INTPL_CUR_40 (0x3 << 14)
/* USB_PHY_ANALOG */
#define ANA_PWR_UP BIT(1)
#define ANA_PWR_DOWN BIT(2)
#define V2I_VCO_RATIO(x) ((x) << 7)
#define R_ROTATE_90 (0x0 << 10)
#define R_ROTATE_0 BIT(10)
#define MODE_TEST_EN BIT(11)
#define ANA_TEST_DC_CTRL(x) ((x) << 12)
#define to_phy_berlin_usb_priv(p) \
container_of((p), struct phy_berlin_usb_priv, phy)
static const u32 phy_berlin_pll_dividers[] = {
/* Berlin 2 */
CLK_REF_DIV(0xc) | FEEDBACK_CLK_DIV(0x54),
/* Berlin 2CD */
CLK_REF_DIV(0x6) | FEEDBACK_CLK_DIV(0x55),
};
struct phy_berlin_usb_priv {
void __iomem *base;
struct phy *phy;
struct reset_control *rst_ctrl;
u32 pll_divider;
};
static int phy_berlin_usb_power_on(struct phy *phy)
{
struct phy_berlin_usb_priv *priv = dev_get_drvdata(phy->dev.parent);
reset_control_reset(priv->rst_ctrl);
writel(priv->pll_divider,
priv->base + USB_PHY_PLL);
writel(CLK_STABLE | PLL_CTRL_REG | PHASE_OFF_TOL_250 | KVC0_REG_CTRL |
CLK_BLK_EN, priv->base + USB_PHY_PLL_CONTROL);
writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5),
priv->base + USB_PHY_ANALOG);
writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 |
DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL);
writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
priv->base + USB_PHY_TX_CTRL0);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4) |
EXT_FS_RCAL_DIV(0x2), priv->base + USB_PHY_TX_CTRL0);
writel(EXT_HS_RCAL_EN | IMPCAL_VTH_DIV(0x3) | EXT_RS_RCAL_DIV(0x4),
priv->base + USB_PHY_TX_CTRL0);
writel(TX_CHAN_CTRL_REG(0xf) | DRV_SLEWRATE(0x3) | IMP_CAL_FS_HS_DLY_3 |
FS_DRV_EN_MASK(0xd), priv->base + USB_PHY_TX_CTRL2);
return 0;
}
static struct phy_ops phy_berlin_usb_ops = {
.power_on = phy_berlin_usb_power_on,
.owner = THIS_MODULE,
};
static const struct of_device_id phy_berlin_sata_of_match[] = {
{
.compatible = "marvell,berlin2-usb-phy",
.data = &phy_berlin_pll_dividers[0],
},
{
.compatible = "marvell,berlin2cd-usb-phy",
.data = &phy_berlin_pll_dividers[1],
},
{ },
};
MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
static int phy_berlin_usb_probe(struct platform_device *pdev)
{
const struct of_device_id *match =
of_match_device(phy_berlin_sata_of_match, &pdev->dev);
struct phy_berlin_usb_priv *priv;
struct resource *res;
struct phy_provider *phy_provider;
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
priv->rst_ctrl = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(priv->rst_ctrl))
return PTR_ERR(priv->rst_ctrl);
priv->pll_divider = *((u32 *)match->data);
priv->phy = devm_phy_create(&pdev->dev, NULL, &phy_berlin_usb_ops);
if (IS_ERR(priv->phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(priv->phy);
}
platform_set_drvdata(pdev, priv);
phy_provider =
devm_of_phy_provider_register(&pdev->dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
return 0;
}
static struct platform_driver phy_berlin_usb_driver = {
.probe = phy_berlin_usb_probe,
.driver = {
.name = "phy-berlin-usb",
.owner = THIS_MODULE,
.of_match_table = phy_berlin_sata_of_match,
},
};
module_platform_driver(phy_berlin_usb_driver);
MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
MODULE_DESCRIPTION("Marvell Berlin PHY driver for USB");
MODULE_LICENSE("GPL");
......@@ -26,6 +26,7 @@
static struct class *phy_class;
static DEFINE_MUTEX(phy_provider_mutex);
static LIST_HEAD(phy_provider_list);
static LIST_HEAD(phys);
static DEFINE_IDA(phy_ida);
static void devm_phy_release(struct device *dev, void *res)
......@@ -54,34 +55,79 @@ static int devm_phy_match(struct device *dev, void *res, void *match_data)
return res == match_data;
}
static struct phy *phy_lookup(struct device *device, const char *port)
/**
* phy_create_lookup() - allocate and register PHY/device association
* @phy: the phy of the association
* @con_id: connection ID string on device
* @dev_id: the device of the association
*
* Creates and registers phy_lookup entry.
*/
int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{
unsigned int count;
struct phy *phy;
struct device *dev;
struct phy_consumer *consumers;
struct class_dev_iter iter;
struct phy_lookup *pl;
class_dev_iter_init(&iter, phy_class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) {
phy = to_phy(dev);
if (!phy || !dev_id || !con_id)
return -EINVAL;
if (!phy->init_data)
continue;
count = phy->init_data->num_consumers;
consumers = phy->init_data->consumers;
while (count--) {
if (!strcmp(consumers->dev_name, dev_name(device)) &&
!strcmp(consumers->port, port)) {
class_dev_iter_exit(&iter);
return phy;
}
consumers++;
pl = kzalloc(sizeof(*pl), GFP_KERNEL);
if (!pl)
return -ENOMEM;
pl->dev_id = dev_id;
pl->con_id = con_id;
pl->phy = phy;
mutex_lock(&phy_provider_mutex);
list_add_tail(&pl->node, &phys);
mutex_unlock(&phy_provider_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(phy_create_lookup);
/**
* phy_remove_lookup() - find and remove PHY/device association
* @phy: the phy of the association
* @con_id: connection ID string on device
* @dev_id: the device of the association
*
* Finds and unregisters phy_lookup entry that was created with
* phy_create_lookup().
*/
void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id)
{
struct phy_lookup *pl;
if (!phy || !dev_id || !con_id)
return;
mutex_lock(&phy_provider_mutex);
list_for_each_entry(pl, &phys, node)
if (pl->phy == phy && !strcmp(pl->dev_id, dev_id) &&
!strcmp(pl->con_id, con_id)) {
list_del(&pl->node);
kfree(pl);
break;
}
}
mutex_unlock(&phy_provider_mutex);
}
EXPORT_SYMBOL_GPL(phy_remove_lookup);
class_dev_iter_exit(&iter);
return ERR_PTR(-ENODEV);
static struct phy *phy_find(struct device *dev, const char *con_id)
{
const char *dev_id = dev_name(dev);
struct phy_lookup *p, *pl = NULL;
mutex_lock(&phy_provider_mutex);
list_for_each_entry(p, &phys, node)
if (!strcmp(p->dev_id, dev_id) && !strcmp(p->con_id, con_id)) {
pl = p;
break;
}
mutex_unlock(&phy_provider_mutex);
return pl ? pl->phy : ERR_PTR(-ENODEV);
}
static struct phy_provider *of_phy_provider_lookup(struct device_node *node)
......@@ -414,21 +460,13 @@ struct phy *of_phy_simple_xlate(struct device *dev, struct of_phandle_args
{
struct phy *phy;
struct class_dev_iter iter;
struct device_node *node = dev->of_node;
struct device_node *child;
class_dev_iter_init(&iter, phy_class, NULL, NULL);
while ((dev = class_dev_iter_next(&iter))) {
phy = to_phy(dev);
if (node != phy->dev.of_node) {
for_each_child_of_node(node, child) {
if (child == phy->dev.of_node)
goto phy_found;
}
if (args->np != phy->dev.of_node)
continue;
}
phy_found:
class_dev_iter_exit(&iter);
return phy;
}
......@@ -463,7 +501,7 @@ struct phy *phy_get(struct device *dev, const char *string)
string);
phy = _of_phy_get(dev->of_node, index);
} else {
phy = phy_lookup(dev, string);
phy = phy_find(dev, string);
}
if (IS_ERR(phy))
return phy;
......@@ -588,13 +626,11 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
* @init_data: contains the list of PHY consumers or NULL
*
* Called to create a phy using phy framework.
*/
struct phy *phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data)
const struct phy_ops *ops)
{
int ret;
int id;
......@@ -632,7 +668,6 @@ struct phy *phy_create(struct device *dev, struct device_node *node,
phy->dev.of_node = node ?: dev->of_node;
phy->id = id;
phy->ops = ops;
phy->init_data = init_data;
ret = dev_set_name(&phy->dev, "phy-%s.%d", dev_name(dev), id);
if (ret)
......@@ -667,7 +702,6 @@ EXPORT_SYMBOL_GPL(phy_create);
* @dev: device that is creating the new phy
* @node: device node of the phy
* @ops: function pointers for performing phy operations
* @init_data: contains the list of PHY consumers or NULL
*
* Creates a new PHY device adding it to the PHY class.
* While at that, it also associates the device with the phy using devres.
......@@ -675,8 +709,7 @@ EXPORT_SYMBOL_GPL(phy_create);
* then, devres data is freed.
*/
struct phy *devm_phy_create(struct device *dev, struct device_node *node,
const struct phy_ops *ops,
struct phy_init_data *init_data)
const struct phy_ops *ops)
{
struct phy **ptr, *phy;
......@@ -684,7 +717,7 @@ struct phy *devm_phy_create(struct device *dev, struct device_node *node,
if (!ptr)
return ERR_PTR(-ENOMEM);
phy = phy_create(dev, node, ops, init_data);
phy = phy_create(dev, node, ops);
if (!IS_ERR(phy)) {
*ptr = phy;
devres_add(dev, ptr);
......
......@@ -112,7 +112,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)
match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node);
state->drvdata = match->data;
phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops, NULL);
phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy);
......
......@@ -137,7 +137,7 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
&exynos_mipi_video_phy_ops, NULL);
&exynos_mipi_video_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy);
......
......@@ -141,6 +141,7 @@ struct exynos5_usbdrd_phy_drvdata {
const struct exynos5_usbdrd_phy_config *phy_cfg;
u32 pmu_offset_usbdrd0_phy;
u32 pmu_offset_usbdrd1_phy;
bool has_common_clk_gate;
};
/**
......@@ -148,6 +149,9 @@ struct exynos5_usbdrd_phy_drvdata {
* @dev: pointer to device instance of this platform device
* @reg_phy: usb phy controller register memory base
* @clk: phy clock for register access
* @pipeclk: clock for pipe3 phy
* @utmiclk: clock for utmi+ phy
* @itpclk: clock for ITP generation
* @drv_data: pointer to SoC level driver data structure
* @phys[]: array for 'EXYNOS5_DRDPHYS_NUM' number of PHY
* instances each with its 'phy' and 'phy_cfg'.
......@@ -155,12 +159,16 @@ struct exynos5_usbdrd_phy_drvdata {
* reference clocks' for SS and HS operations
* @ref_clk: reference clock to PHY block from which PHY's
* operational clocks are derived
* @ref_rate: rate of above reference clock
* vbus: VBUS regulator for phy
* vbus_boost: Boost regulator for VBUS present on few Exynos boards
*/
struct exynos5_usbdrd_phy {
struct device *dev;
void __iomem *reg_phy;
struct clk *clk;
struct clk *pipeclk;
struct clk *utmiclk;
struct clk *itpclk;
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct phy_usb_instance {
struct phy *phy;
......@@ -172,6 +180,7 @@ struct exynos5_usbdrd_phy {
u32 extrefclk;
struct clk *ref_clk;
struct regulator *vbus;
struct regulator *vbus_boost;
};
static inline
......@@ -447,13 +456,27 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
dev_dbg(phy_drd->dev, "Request to power_on usbdrd_phy phy\n");
clk_prepare_enable(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_prepare_enable(phy_drd->pipeclk);
clk_prepare_enable(phy_drd->utmiclk);
clk_prepare_enable(phy_drd->itpclk);
}
/* Enable VBUS supply */
if (phy_drd->vbus_boost) {
ret = regulator_enable(phy_drd->vbus_boost);
if (ret) {
dev_err(phy_drd->dev,
"Failed to enable VBUS boost supply\n");
goto fail_vbus;
}
}
if (phy_drd->vbus) {
ret = regulator_enable(phy_drd->vbus);
if (ret) {
dev_err(phy_drd->dev, "Failed to enable VBUS supply\n");
goto fail_vbus;
goto fail_vbus_boost;
}
}
......@@ -462,8 +485,17 @@ static int exynos5_usbdrd_phy_power_on(struct phy *phy)
return 0;
fail_vbus_boost:
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
fail_vbus:
clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->utmiclk);
clk_disable_unprepare(phy_drd->pipeclk);
}
return ret;
}
......@@ -481,8 +513,15 @@ static int exynos5_usbdrd_phy_power_off(struct phy *phy)
/* Disable VBUS supply */
if (phy_drd->vbus)
regulator_disable(phy_drd->vbus);
if (phy_drd->vbus_boost)
regulator_disable(phy_drd->vbus_boost);
clk_disable_unprepare(phy_drd->ref_clk);
if (!phy_drd->drv_data->has_common_clk_gate) {
clk_disable_unprepare(phy_drd->itpclk);
clk_disable_unprepare(phy_drd->pipeclk);
clk_disable_unprepare(phy_drd->utmiclk);
}
return 0;
}
......@@ -506,6 +545,57 @@ static struct phy_ops exynos5_usbdrd_phy_ops = {
.owner = THIS_MODULE,
};
static int exynos5_usbdrd_phy_clk_handle(struct exynos5_usbdrd_phy *phy_drd)
{
unsigned long ref_rate;
int ret;
phy_drd->clk = devm_clk_get(phy_drd->dev, "phy");
if (IS_ERR(phy_drd->clk)) {
dev_err(phy_drd->dev, "Failed to get phy clock\n");
return PTR_ERR(phy_drd->clk);
}
phy_drd->ref_clk = devm_clk_get(phy_drd->dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {
dev_err(phy_drd->dev, "Failed to get phy reference clock\n");
return PTR_ERR(phy_drd->ref_clk);
}
ref_rate = clk_get_rate(phy_drd->ref_clk);
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
if (ret) {
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
ref_rate);
return ret;
}
if (!phy_drd->drv_data->has_common_clk_gate) {
phy_drd->pipeclk = devm_clk_get(phy_drd->dev, "phy_pipe");
if (IS_ERR(phy_drd->pipeclk)) {
dev_info(phy_drd->dev,
"PIPE3 phy operational clock not specified\n");
phy_drd->pipeclk = NULL;
}
phy_drd->utmiclk = devm_clk_get(phy_drd->dev, "phy_utmi");
if (IS_ERR(phy_drd->utmiclk)) {
dev_info(phy_drd->dev,
"UTMI phy operational clock not specified\n");
phy_drd->utmiclk = NULL;
}
phy_drd->itpclk = devm_clk_get(phy_drd->dev, "itp");
if (IS_ERR(phy_drd->itpclk)) {
dev_info(phy_drd->dev,
"ITP clock from main OSC not specified\n");
phy_drd->itpclk = NULL;
}
}
return 0;
}
static const struct exynos5_usbdrd_phy_config phy_cfg_exynos5[] = {
{
.id = EXYNOS5_DRDPHY_UTMI,
......@@ -525,11 +615,19 @@ static const struct exynos5_usbdrd_phy_drvdata exynos5420_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.pmu_offset_usbdrd1_phy = EXYNOS5420_USBDRD1_PHY_CONTROL,
.has_common_clk_gate = true,
};
static const struct exynos5_usbdrd_phy_drvdata exynos5250_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = true,
};
static const struct exynos5_usbdrd_phy_drvdata exynos7_usbdrd_phy = {
.phy_cfg = phy_cfg_exynos5,
.pmu_offset_usbdrd0_phy = EXYNOS5_USBDRD_PHY_CONTROL,
.has_common_clk_gate = false,
};
static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
......@@ -539,6 +637,9 @@ static const struct of_device_id exynos5_usbdrd_phy_of_match[] = {
}, {
.compatible = "samsung,exynos5420-usbdrd-phy",
.data = &exynos5420_usbdrd_phy
}, {
.compatible = "samsung,exynos7-usbdrd-phy",
.data = &exynos7_usbdrd_phy
},
{ },
};
......@@ -555,7 +656,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
const struct exynos5_usbdrd_phy_drvdata *drv_data;
struct regmap *reg_pmu;
u32 pmu_offset;
unsigned long ref_rate;
int i, ret;
int channel;
......@@ -576,23 +676,9 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
drv_data = match->data;
phy_drd->drv_data = drv_data;
phy_drd->clk = devm_clk_get(dev, "phy");
if (IS_ERR(phy_drd->clk)) {
dev_err(dev, "Failed to get clock of phy controller\n");
return PTR_ERR(phy_drd->clk);
}
phy_drd->ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(phy_drd->ref_clk)) {
dev_err(dev, "Failed to get reference clock of usbdrd phy\n");
return PTR_ERR(phy_drd->ref_clk);
}
ref_rate = clk_get_rate(phy_drd->ref_clk);
ret = exynos5_rate_to_clk(ref_rate, &phy_drd->extrefclk);
ret = exynos5_usbdrd_phy_clk_handle(phy_drd);
if (ret) {
dev_err(phy_drd->dev, "Clock rate (%ld) not supported\n",
ref_rate);
dev_err(dev, "Failed to initialize clocks\n");
return ret;
}
......@@ -622,7 +708,7 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
break;
}
/* Get Vbus regulator */
/* Get Vbus regulators */
phy_drd->vbus = devm_regulator_get(dev, "vbus");
if (IS_ERR(phy_drd->vbus)) {
ret = PTR_ERR(phy_drd->vbus);
......@@ -633,12 +719,21 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)
phy_drd->vbus = NULL;
}
phy_drd->vbus_boost = devm_regulator_get(dev, "vbus-boost");
if (IS_ERR(phy_drd->vbus_boost)) {
ret = PTR_ERR(phy_drd->vbus_boost);
if (ret == -EPROBE_DEFER)
return ret;
dev_warn(dev, "Failed to get VBUS boost supply regulator\n");
phy_drd->vbus_boost = NULL;
}
dev_vdbg(dev, "Creating usbdrd_phy phy\n");
for (i = 0; i < EXYNOS5_DRDPHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
&exynos5_usbdrd_phy_ops,
NULL);
&exynos5_usbdrd_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "Failed to create usbdrd_phy phy\n");
return PTR_ERR(phy);
......
......@@ -210,7 +210,7 @@ static int exynos_sata_phy_probe(struct platform_device *pdev)
return ret;
}
sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops, NULL);
sata_phy->phy = devm_phy_create(dev, NULL, &exynos_sata_phy_ops);
if (IS_ERR(sata_phy->phy)) {
clk_disable_unprepare(sata_phy->phyclk);
dev_err(dev, "failed to create PHY\n");
......
......@@ -156,7 +156,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(priv->peri_ctrl))
priv->peri_ctrl = NULL;
phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops, NULL);
phy = devm_phy_create(dev, NULL, &hix5hd2_sata_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n");
return PTR_ERR(phy);
......@@ -164,10 +164,7 @@ static int hix5hd2_sata_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
return 0;
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id hix5hd2_sata_phy_of_match[] = {
......
此差异已折叠。
......@@ -593,7 +593,7 @@ static int miphy365x_probe(struct platform_device *pdev)
miphy_dev->phys[port] = miphy_phy;
phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops, NULL);
phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
return PTR_ERR(phy);
......@@ -610,10 +610,7 @@ static int miphy365x_probe(struct platform_device *pdev)
}
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
if (IS_ERR(provider))
return PTR_ERR(provider);
return 0;
return PTR_ERR_OR_ZERO(provider);
}
static const struct of_device_id miphy365x_of_match[] = {
......
......@@ -101,7 +101,7 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev)
if (IS_ERR(priv->clk))
return PTR_ERR(priv->clk);
phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops, NULL);
phy = devm_phy_create(&pdev->dev, NULL, &phy_mvebu_sata_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
......
......@@ -60,7 +60,7 @@ EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
{
struct omap_usb *phy = phy_to_omapusb(otg->phy);
struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
if (!phy->comparator)
return -ENODEV;
......@@ -70,7 +70,7 @@ static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
static int omap_usb_start_srp(struct usb_otg *otg)
{
struct omap_usb *phy = phy_to_omapusb(otg->phy);
struct omap_usb *phy = phy_to_omapusb(otg->usb_phy);
if (!phy->comparator)
return -ENODEV;
......@@ -80,11 +80,9 @@ static int omap_usb_start_srp(struct usb_otg *otg)
static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
{
struct usb_phy *phy = otg->phy;
otg->host = host;
if (!host)
phy->state = OTG_STATE_UNDEFINED;
otg->state = OTG_STATE_UNDEFINED;
return 0;
}
......@@ -92,11 +90,9 @@ static int omap_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
static int omap_usb_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
struct usb_phy *phy = otg->phy;
otg->gadget = gadget;
if (!gadget)
phy->state = OTG_STATE_UNDEFINED;
otg->state = OTG_STATE_UNDEFINED;
return 0;
}
......@@ -255,12 +251,12 @@ static int omap_usb2_probe(struct platform_device *pdev)
otg->set_vbus = omap_usb_set_vbus;
if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
otg->start_srp = omap_usb_start_srp;
otg->phy = &phy->phy;
otg->usb_phy = &phy->phy;
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL);
generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy)) {
pm_runtime_disable(phy->dev);
return PTR_ERR(generic_phy);
......
......@@ -228,8 +228,7 @@ static int qcom_apq8064_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio);
generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops,
NULL);
generic_phy = devm_phy_create(dev, NULL, &qcom_apq8064_sata_phy_ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy);
......
......@@ -150,8 +150,7 @@ static int qcom_ipq806x_sata_phy_probe(struct platform_device *pdev)
if (IS_ERR(phy->mmio))
return PTR_ERR(phy->mmio);
generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops,
NULL);
generic_phy = devm_phy_create(dev, NULL, &qcom_ipq806x_sata_phy_ops);
if (IS_ERR(generic_phy)) {
dev_err(dev, "%s: failed to create phy\n", __func__);
return PTR_ERR(generic_phy);
......
......@@ -304,7 +304,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev)
phy->select_value = select_value[channel_num][n];
phy->phy = devm_phy_create(dev, NULL,
&rcar_gen2_phy_ops, NULL);
&rcar_gen2_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "Failed to create PHY\n");
return PTR_ERR(phy->phy);
......
......@@ -202,8 +202,7 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)
struct samsung_usb2_phy_instance *p = &drv->instances[i];
dev_dbg(dev, "Creating phy \"%s\"\n", label);
p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops,
NULL);
p->phy = devm_phy_create(dev, NULL, &samsung_usb2_phy_ops);
if (IS_ERR(p->phy)) {
dev_err(drv->dev, "Failed to create usb2_phy \"%s\"\n",
label);
......
......@@ -227,7 +227,7 @@ static int spear1310_miphy_probe(struct platform_device *pdev)
return -EINVAL;
}
priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops, NULL);
priv->phy = devm_phy_create(dev, NULL, &spear1310_miphy_ops);
if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy);
......
......@@ -259,7 +259,7 @@ static int spear1340_miphy_probe(struct platform_device *pdev)
return PTR_ERR(priv->misc);
}
priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops, NULL);
priv->phy = devm_phy_create(dev, NULL, &spear1340_miphy_ops);
if (IS_ERR(priv->phy)) {
dev_err(dev, "failed to create SATA PCIe PHY\n");
return PTR_ERR(priv->phy);
......
......@@ -137,7 +137,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
}
phy_dev->param = res->start;
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data, NULL);
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create Display Port PHY\n");
return PTR_ERR(phy);
......
......@@ -148,7 +148,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy_dev->clk);
}
phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops, NULL);
phy = devm_phy_create(dev, NULL, &stih41x_usb_phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
......@@ -160,10 +160,7 @@ static int stih41x_usb_phy_probe(struct platform_device *pdev)
phy_set_drvdata(phy, phy_dev);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
if (IS_ERR(phy_provider))
return PTR_ERR(phy_provider);
return 0;
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id stih41x_usb_phy_of_match[] = {
......
......@@ -157,6 +157,10 @@ static int sun4i_usb_phy_init(struct phy *_phy)
return ret;
}
/* Enable USB 45 Ohm resistor calibration */
if (phy->index == 0)
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
/* Adjust PHY's magnitude and rate */
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
......@@ -213,7 +217,7 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
{
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
if (WARN_ON(args->args[0] == 0 || args->args[0] >= data->num_phys))
if (args->args[0] >= data->num_phys)
return ERR_PTR(-ENODEV);
return data->phys[args->args[0]].phy;
......@@ -255,8 +259,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
/* Skip 0, 0 is the phy for otg which is not yet supported. */
for (i = 1; i < data->num_phys; i++) {
for (i = 0; i < data->num_phys; i++) {
struct sun4i_usb_phy *phy = data->phys + i;
char name[16];
......@@ -295,7 +298,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
return PTR_ERR(phy->pmu);
}
phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops, NULL);
phy->phy = devm_phy_create(dev, NULL, &sun4i_usb_phy_ops);
if (IS_ERR(phy->phy)) {
dev_err(dev, "failed to create PHY %d\n", i);
return PTR_ERR(phy->phy);
......
......@@ -399,7 +399,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, phy);
pm_runtime_enable(phy->dev);
generic_phy = devm_phy_create(phy->dev, NULL, &ops, NULL);
generic_phy = devm_phy_create(phy->dev, NULL, &ops);
if (IS_ERR(generic_phy))
return PTR_ERR(generic_phy);
......
......@@ -606,7 +606,7 @@ static int twl4030_set_peripheral(struct usb_otg *otg,
otg->gadget = gadget;
if (!gadget)
otg->phy->state = OTG_STATE_UNDEFINED;
otg->state = OTG_STATE_UNDEFINED;
return 0;
}
......@@ -618,7 +618,7 @@ static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
otg->host = host;
if (!host)
otg->phy->state = OTG_STATE_UNDEFINED;
otg->state = OTG_STATE_UNDEFINED;
return 0;
}
......@@ -644,7 +644,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
struct usb_otg *otg;
struct device_node *np = pdev->dev.of_node;
struct phy_provider *phy_provider;
struct phy_init_data *init_data = NULL;
twl = devm_kzalloc(&pdev->dev, sizeof(*twl), GFP_KERNEL);
if (!twl)
......@@ -655,7 +654,6 @@ static int twl4030_usb_probe(struct platform_device *pdev)
(enum twl4030_usb_mode *)&twl->usb_mode);
else if (pdata) {
twl->usb_mode = pdata->usb_mode;
init_data = pdata->init_data;
} else {
dev_err(&pdev->dev, "twl4030 initialized without pdata\n");
return -EINVAL;
......@@ -676,11 +674,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
twl->phy.otg = otg;
twl->phy.type = USB_PHY_TYPE_USB2;
otg->phy = &twl->phy;
otg->usb_phy = &twl->phy;
otg->set_host = twl4030_set_host;
otg->set_peripheral = twl4030_set_peripheral;
phy = devm_phy_create(twl->dev, NULL, &ops, init_data);
phy = devm_phy_create(twl->dev, NULL, &ops);
if (IS_ERR(phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
return PTR_ERR(phy);
......@@ -733,6 +731,11 @@ static int twl4030_usb_probe(struct platform_device *pdev)
return status;
}
if (pdata)
err = phy_create_lookup(phy, "usb", "musb-hdrc.0");
if (err)
return err;
pm_runtime_mark_last_busy(&pdev->dev);
pm_runtime_put_autosuspend(twl->dev);
......
......@@ -1707,7 +1707,7 @@ static int xgene_phy_probe(struct platform_device *pdev)
ctx->dev = &pdev->dev;
platform_set_drvdata(pdev, ctx);
ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops, NULL);
ctx->phy = devm_phy_create(ctx->dev, NULL, &xgene_phy_ops);
if (IS_ERR(ctx->phy)) {
dev_dbg(&pdev->dev, "Failed to create PHY\n");
rc = PTR_ERR(ctx->phy);
......
......@@ -915,7 +915,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
goto reset;
}
phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops, NULL);
phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
......@@ -924,7 +924,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev)
padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
phy_set_drvdata(phy, padctl);
phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops, NULL);
phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops);
if (IS_ERR(phy)) {
err = PTR_ERR(phy);
goto unregister;
......
......@@ -10,6 +10,7 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o
# Glue/Bridge layers go here
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_usb2.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_msm.o
obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc_zevio.o
......
......@@ -161,7 +161,8 @@ struct hw_bank {
* @test_mode: the selected test mode
* @platdata: platform specific information supplied by parent device
* @vbus_active: is VBUS active
* @transceiver: pointer to USB PHY, if any
* @phy: pointer to PHY, if any
* @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework
* @hcd: pointer to usb_hcd for ehci host driver
* @debugfs: root dentry for this controller in debugfs
* @id_event: indicates there is an id event, and handled at ci_otg_work
......@@ -177,6 +178,7 @@ struct ci_hdrc {
struct ci_role_driver *roles[CI_ROLE_END];
enum ci_role role;
bool is_otg;
struct usb_otg otg;
struct otg_fsm fsm;
struct ci_otg_fsm_timer_list *fsm_timer;
struct work_struct work;
......@@ -201,7 +203,9 @@ struct ci_hdrc {
struct ci_hdrc_platform_data *platdata;
int vbus_active;
struct usb_phy *transceiver;
struct phy *phy;
/* old usb_phy interface */
struct usb_phy *usb_phy;
struct usb_hcd *hcd;
struct dentry *debugfs;
bool id_event;
......@@ -348,7 +352,7 @@ u32 hw_read_intr_enable(struct ci_hdrc *ci);
u32 hw_read_intr_status(struct ci_hdrc *ci);
int hw_device_reset(struct ci_hdrc *ci, u32 mode);
int hw_device_reset(struct ci_hdrc *ci);
int hw_port_test_set(struct ci_hdrc *ci, u8 mode);
......
......@@ -106,8 +106,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
struct ci_hdrc_platform_data pdata = {
.name = dev_name(&pdev->dev),
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_DISABLE_STREAMING,
.flags = CI_HDRC_DISABLE_STREAMING,
};
int ret;
const struct of_device_id *of_id =
......@@ -115,10 +114,8 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev, "Failed to allocate ci_hdrc-imx data!\n");
if (!data)
return -ENOMEM;
}
data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
if (IS_ERR(data->usbmisc_data))
......@@ -147,7 +144,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto err_clk;
}
pdata.phy = data->phy;
pdata.usb_phy = data->phy;
if (imx_platform_flag->flags & CI_HDRC_IMX_IMX28_WRITE_FIX)
pdata.flags |= CI_HDRC_IMX28_WRITE_FIX;
......@@ -210,6 +207,41 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int imx_controller_suspend(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
dev_dbg(dev, "at %s\n", __func__);
clk_disable_unprepare(data->clk);
return 0;
}
static int imx_controller_resume(struct device *dev)
{
struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
dev_dbg(dev, "at %s\n", __func__);
return clk_prepare_enable(data->clk);
}
static int ci_hdrc_imx_suspend(struct device *dev)
{
return imx_controller_suspend(dev);
}
static int ci_hdrc_imx_resume(struct device *dev)
{
return imx_controller_resume(dev);
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
};
static struct platform_driver ci_hdrc_imx_driver = {
.probe = ci_hdrc_imx_probe,
.remove = ci_hdrc_imx_remove,
......@@ -217,6 +249,7 @@ static struct platform_driver ci_hdrc_imx_driver = {
.name = "imx_usb",
.owner = THIS_MODULE,
.of_match_table = ci_hdrc_imx_dt_ids,
.pm = &ci_hdrc_imx_pm_ops,
},
};
......
......@@ -26,15 +26,15 @@ static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
writel(0, USB_AHBBURST);
writel(0, USB_AHBMODE);
usb_phy_init(ci->transceiver);
usb_phy_init(ci->usb_phy);
break;
case CI_HDRC_CONTROLLER_STOPPED_EVENT:
dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
/*
* Put the transceiver in non-driving mode. Otherwise host
* Put the phy in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
usb_phy_notify_disconnect(ci->transceiver, USB_SPEED_UNKNOWN);
usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN);
break;
default:
dev_dbg(dev, "unknown ci_hdrc event\n");
......@@ -46,7 +46,6 @@ static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = {
.name = "ci_hdrc_msm",
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_REGS_SHARED |
CI_HDRC_REQUIRE_TRANSCEIVER |
CI_HDRC_DISABLE_STREAMING,
.notify_event = ci_hdrc_msm_notify_event,
......@@ -68,7 +67,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)
if (IS_ERR(phy))
return PTR_ERR(phy);
ci_hdrc_msm_platdata.phy = phy;
ci_hdrc_msm_platdata.usb_phy = phy;
plat_ci = ci_hdrc_add_device(&pdev->dev,
pdev->resource, pdev->num_resources,
......
/*
* Copyright (C) 2014 Marvell Technology Group Ltd.
*
* Antoine Tenart <antoine.tenart@free-electrons.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/usb/chipidea.h>
#include <linux/usb/hcd.h>
#include <linux/usb/ulpi.h>
#include "ci.h"
struct ci_hdrc_usb2_priv {
struct platform_device *ci_pdev;
struct clk *clk;
};
static struct ci_hdrc_platform_data ci_default_pdata = {
.capoffset = DEF_CAPOFFSET,
.flags = CI_HDRC_DISABLE_STREAMING,
};
static int ci_hdrc_usb2_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ci_hdrc_usb2_priv *priv;
struct ci_hdrc_platform_data *ci_pdata = dev_get_platdata(dev);
int ret;
if (!ci_pdata)
ci_pdata = &ci_default_pdata;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(priv->clk)) {
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "failed to enable the clock: %d\n", ret);
return ret;
}
}
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret)
goto clk_err;
ci_pdata->name = dev_name(dev);
priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource,
pdev->num_resources, ci_pdata);
if (IS_ERR(priv->ci_pdev)) {
ret = PTR_ERR(priv->ci_pdev);
if (ret != -EPROBE_DEFER)
dev_err(dev,
"failed to register ci_hdrc platform device: %d\n",
ret);
goto clk_err;
}
platform_set_drvdata(pdev, priv);
pm_runtime_no_callbacks(dev);
pm_runtime_enable(dev);
return 0;
clk_err:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
return ret;
}
static int ci_hdrc_usb2_remove(struct platform_device *pdev)
{
struct ci_hdrc_usb2_priv *priv = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
ci_hdrc_remove_device(priv->ci_pdev);
clk_disable_unprepare(priv->clk);
return 0;
}
static const struct of_device_id ci_hdrc_usb2_of_match[] = {
{ .compatible = "chipidea,usb2" },
{ }
};
MODULE_DEVICE_TABLE(of, ci_hdrc_usb2_of_match);
static struct platform_driver ci_hdrc_usb2_driver = {
.probe = ci_hdrc_usb2_probe,
.remove = ci_hdrc_usb2_remove,
.driver = {
.name = "chipidea-usb2",
.of_match_table = of_match_ptr(ci_hdrc_usb2_of_match),
},
};
module_platform_driver(ci_hdrc_usb2_driver);
MODULE_DESCRIPTION("ChipIdea HDRC USB2 binding for ci13xxx");
MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
MODULE_LICENSE("GPL");
......@@ -47,6 +47,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/idr.h>
......@@ -189,24 +190,29 @@ u8 hw_port_test_get(struct ci_hdrc *ci)
return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> __ffs(PORTSC_PTC);
}
static void hw_wait_phy_stable(void)
{
/*
* The phy needs some delay to output the stable status from low
* power mode. And for OTGSC, the status inputs are debounced
* using a 1 ms time constant, so, delay 2ms for controller to get
* the stable status, like vbus and id when the phy leaves low power.
*/
usleep_range(2000, 2500);
}
/* The PHY enters/leaves low power mode */
static void ci_hdrc_enter_lpm(struct ci_hdrc *ci, bool enable)
{
enum ci_hw_regs reg = ci->hw_bank.lpm ? OP_DEVLC : OP_PORTSC;
bool lpm = !!(hw_read(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm)));
if (enable && !lpm) {
if (enable && !lpm)
hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
PORTSC_PHCD(ci->hw_bank.lpm));
} else if (!enable && lpm) {
else if (!enable && lpm)
hw_write(ci, reg, PORTSC_PHCD(ci->hw_bank.lpm),
0);
/*
* the PHY needs some time (less
* than 1ms) to leave low power mode.
*/
usleep_range(1000, 1100);
}
}
static int hw_device_init(struct ci_hdrc *ci, void __iomem *base)
......@@ -298,6 +304,49 @@ static void hw_phymode_configure(struct ci_hdrc *ci)
}
}
/**
* _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy
* interfaces
* @ci: the controller
*
* This function returns an error code if the phy failed to init
*/
static int _ci_usb_phy_init(struct ci_hdrc *ci)
{
int ret;
if (ci->phy) {
ret = phy_init(ci->phy);
if (ret)
return ret;
ret = phy_power_on(ci->phy);
if (ret) {
phy_exit(ci->phy);
return ret;
}
} else {
ret = usb_phy_init(ci->usb_phy);
}
return ret;
}
/**
* _ci_usb_phy_exit: deinitialize phy taking in account both phy and usb_phy
* interfaces
* @ci: the controller
*/
static void ci_usb_phy_exit(struct ci_hdrc *ci)
{
if (ci->phy) {
phy_power_off(ci->phy);
phy_exit(ci->phy);
} else {
usb_phy_shutdown(ci->usb_phy);
}
}
/**
* ci_usb_phy_init: initialize phy according to different phy type
* @ci: the controller
......@@ -312,40 +361,68 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
case USBPHY_INTERFACE_MODE_UTMI:
case USBPHY_INTERFACE_MODE_UTMIW:
case USBPHY_INTERFACE_MODE_HSIC:
ret = usb_phy_init(ci->transceiver);
if (ret)
ret = _ci_usb_phy_init(ci);
if (!ret)
hw_wait_phy_stable();
else
return ret;
hw_phymode_configure(ci);
break;
case USBPHY_INTERFACE_MODE_ULPI:
case USBPHY_INTERFACE_MODE_SERIAL:
hw_phymode_configure(ci);
ret = usb_phy_init(ci->transceiver);
ret = _ci_usb_phy_init(ci);
if (ret)
return ret;
break;
default:
ret = usb_phy_init(ci->transceiver);
ret = _ci_usb_phy_init(ci);
if (!ret)
hw_wait_phy_stable();
}
return ret;
}
/**
* hw_device_reset: resets chip (execute without interruption)
* hw_controller_reset: do controller reset
* @ci: the controller
*
* This function returns an error code
*/
int hw_device_reset(struct ci_hdrc *ci, u32 mode)
static int hw_controller_reset(struct ci_hdrc *ci)
{
int count = 0;
hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
while (hw_read(ci, OP_USBCMD, USBCMD_RST)) {
udelay(10);
if (count++ > 1000)
return -ETIMEDOUT;
}
return 0;
}
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
*
* This function returns an error code
*/
int hw_device_reset(struct ci_hdrc *ci)
{
int ret;
/* should flush & stop before reset */
hw_write(ci, OP_ENDPTFLUSH, ~0, ~0);
hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST);
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
ret = hw_controller_reset(ci);
if (ret) {
dev_err(ci->dev, "error resetting controller, ret=%d\n", ret);
return ret;
}
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
......@@ -363,12 +440,12 @@ int hw_device_reset(struct ci_hdrc *ci, u32 mode)
/* USBMODE should be configured step by step */
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
hw_write(ci, OP_USBMODE, USBMODE_CM, mode);
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
/* HW >= 2.3 */
hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM);
if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) {
pr_err("cannot enter in %s mode", ci_role(ci)->name);
if (hw_read(ci, OP_USBMODE, USBMODE_CM) != USBMODE_CM_DC) {
pr_err("cannot enter in %s device mode", ci_role(ci)->name);
pr_err("lpm = %i", ci->hw_bank.lpm);
return -ENODEV;
}
......@@ -472,7 +549,7 @@ static int ci_get_platdata(struct device *dev,
if (PTR_ERR(platdata->reg_vbus) == -EPROBE_DEFER) {
return -EPROBE_DEFER;
} else if (PTR_ERR(platdata->reg_vbus) == -ENODEV) {
/* no vbus regualator is needed */
/* no vbus regulator is needed */
platdata->reg_vbus = NULL;
} else if (IS_ERR(platdata->reg_vbus)) {
dev_err(dev, "Getting regulator error: %ld\n",
......@@ -589,11 +666,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return PTR_ERR(base);
ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL);
if (!ci) {
dev_err(dev, "can't allocate device\n");
if (!ci)
return -ENOMEM;
}
platform_set_drvdata(pdev, ci);
ci->dev = dev;
ci->platdata = dev_get_platdata(dev);
ci->imx28_write_fix = !!(ci->platdata->flags &
......@@ -605,36 +681,32 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
if (ci->platdata->phy)
ci->transceiver = ci->platdata->phy;
else
ci->transceiver = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
if (IS_ERR(ci->transceiver)) {
ret = PTR_ERR(ci->transceiver);
/*
* if -ENXIO is returned, it means PHY layer wasn't
* enabled, so it makes no sense to return -EPROBE_DEFER
* in that case, since no PHY driver will ever probe.
*/
if (ret == -ENXIO)
return ret;
if (ci->platdata->phy) {
ci->phy = ci->platdata->phy;
} else if (ci->platdata->usb_phy) {
ci->usb_phy = ci->platdata->usb_phy;
} else {
ci->phy = devm_phy_get(dev->parent, "usb-phy");
ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2);
/* if both generic PHY and USB PHY layers aren't enabled */
if (PTR_ERR(ci->phy) == -ENOSYS &&
PTR_ERR(ci->usb_phy) == -ENXIO)
return -ENXIO;
if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy))
return -EPROBE_DEFER;
dev_err(dev, "no usb2 phy configured\n");
return -EPROBE_DEFER;
if (IS_ERR(ci->phy))
ci->phy = NULL;
else if (IS_ERR(ci->usb_phy))
ci->usb_phy = NULL;
}
ret = ci_usb_phy_init(ci);
if (ret) {
dev_err(dev, "unable to init phy: %d\n", ret);
return ret;
} else {
/*
* The delay to sync PHY's status, the maximum delay is
* 2ms since the otgsc uses 1ms timer to debounce the
* PHY's input
*/
usleep_range(2000, 2500);
}
ci->hw_bank.phys = res->start;
......@@ -711,9 +783,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
}
}
platform_set_drvdata(pdev, ci);
ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
ci);
ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED,
ci->platdata->name, ci);
if (ret)
goto stop;
......@@ -724,11 +795,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
if (!ret)
return 0;
free_irq(ci->irq, ci);
stop:
ci_role_destroy(ci);
deinit_phy:
usb_phy_shutdown(ci->transceiver);
ci_usb_phy_exit(ci);
return ret;
}
......@@ -738,19 +808,66 @@ static int ci_hdrc_remove(struct platform_device *pdev)
struct ci_hdrc *ci = platform_get_drvdata(pdev);
dbg_remove_files(ci);
free_irq(ci->irq, ci);
ci_role_destroy(ci);
ci_hdrc_enter_lpm(ci, true);
usb_phy_shutdown(ci->transceiver);
ci_usb_phy_exit(ci);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static void ci_controller_suspend(struct ci_hdrc *ci)
{
ci_hdrc_enter_lpm(ci, true);
if (ci->usb_phy)
usb_phy_set_suspend(ci->usb_phy, 1);
}
static int ci_controller_resume(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
dev_dbg(dev, "at %s\n", __func__);
ci_hdrc_enter_lpm(ci, false);
if (ci->usb_phy) {
usb_phy_set_suspend(ci->usb_phy, 0);
usb_phy_set_wakeup(ci->usb_phy, false);
hw_wait_phy_stable();
}
return 0;
}
static int ci_suspend(struct device *dev)
{
struct ci_hdrc *ci = dev_get_drvdata(dev);
if (ci->wq)
flush_workqueue(ci->wq);
ci_controller_suspend(ci);
return 0;
}
static int ci_resume(struct device *dev)
{
return ci_controller_resume(dev);
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops ci_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ci_suspend, ci_resume)
};
static struct platform_driver ci_hdrc_driver = {
.probe = ci_hdrc_probe,
.remove = ci_hdrc_remove,
.driver = {
.name = "ci_hdrc",
.pm = &ci_pm_ops,
.owner = THIS_MODULE,
},
};
......
......@@ -220,7 +220,7 @@ static int ci_otg_show(struct seq_file *s, void *unused)
/* ------ State ----- */
seq_printf(s, "OTG state: %s\n\n",
usb_otg_state_string(ci->transceiver->state));
usb_otg_state_string(ci->otg.state));
/* ------ State Machine Variables ----- */
seq_printf(s, "a_bus_drop: %d\n", fsm->a_bus_drop);
......
......@@ -34,6 +34,44 @@
static struct hc_driver __read_mostly ci_ehci_hc_driver;
struct ehci_ci_priv {
struct regulator *reg_vbus;
};
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 device *dev = hcd->self.controller;
struct ci_hdrc *ci = dev_get_drvdata(dev);
int ret = 0;
int port = HCS_N_PORTS(ehci->hcs_params);
if (priv->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
if (port > 1) {
dev_warn(dev,
"Not support multi-port regulator control\n");
return 0;
}
if (enable)
ret = regulator_enable(priv->reg_vbus);
else
ret = regulator_disable(priv->reg_vbus);
if (ret) {
dev_err(dev,
"Failed to %s vbus regulator, ret=%d\n",
enable ? "enable" : "disable", ret);
return ret;
}
}
return 0;
};
static const struct ehci_driver_overrides ehci_ci_overrides = {
.extra_priv_size = sizeof(struct ehci_ci_priv),
.port_power = ehci_ci_portpower,
};
static irqreturn_t host_irq(struct ci_hdrc *ci)
{
return usb_hcd_irq(ci->irq, ci->hcd);
......@@ -43,6 +81,7 @@ static int host_start(struct ci_hdrc *ci)
{
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct ehci_ci_priv *priv;
int ret;
if (usb_disabled())
......@@ -52,15 +91,17 @@ static int host_start(struct ci_hdrc *ci)
if (!hcd)
return -ENOMEM;
dev_set_drvdata(ci->dev, ci);
hcd->rsrc_start = ci->hw_bank.phys;
hcd->rsrc_len = ci->hw_bank.size;
hcd->regs = ci->hw_bank.abs;
hcd->has_tt = 1;
hcd->power_budget = ci->platdata->power_budget;
hcd->usb_phy = ci->transceiver;
hcd->tpl_support = ci->platdata->tpl_support;
if (ci->phy)
hcd->phy = ci->phy;
else
hcd->usb_phy = ci->usb_phy;
ehci = hcd_to_ehci(hcd);
ehci->caps = ci->hw_bank.cap;
......@@ -68,28 +109,21 @@ static int host_start(struct ci_hdrc *ci)
ehci->has_tdi_phy_lpm = ci->hw_bank.lpm;
ehci->imx28_write_fix = ci->imx28_write_fix;
/*
* vbus is always on if host is not in OTG FSM mode,
* otherwise should be controlled by OTG FSM
*/
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
ret = regulator_enable(ci->platdata->reg_vbus);
if (ret) {
dev_err(ci->dev,
"Failed to enable vbus regulator, ret=%d\n",
ret);
goto put_hcd;
}
}
priv = (struct ehci_ci_priv *)ehci->priv;
priv->reg_vbus = NULL;
if (ci->platdata->reg_vbus)
priv->reg_vbus = ci->platdata->reg_vbus;
ret = usb_add_hcd(hcd, 0, 0);
if (ret) {
goto disable_reg;
goto put_hcd;
} else {
struct usb_otg *otg = ci->transceiver->otg;
struct usb_otg *otg = &ci->otg;
ci->hcd = hcd;
if (otg) {
if (ci_otg_is_fsm_mode(ci)) {
otg->host = &hcd->self;
hcd->self.otg_port = 1;
}
......@@ -100,10 +134,6 @@ static int host_start(struct ci_hdrc *ci)
return ret;
disable_reg:
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
regulator_disable(ci->platdata->reg_vbus);
put_hcd:
usb_put_hcd(hcd);
......@@ -117,8 +147,6 @@ static void host_stop(struct ci_hdrc *ci)
if (hcd) {
usb_remove_hcd(hcd);
usb_put_hcd(hcd);
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci))
regulator_disable(ci->platdata->reg_vbus);
}
}
......@@ -146,7 +174,7 @@ int ci_hdrc_host_init(struct ci_hdrc *ci)
rdrv->name = "host";
ci->roles[CI_ROLE_HOST] = rdrv;
ehci_init_driver(&ci_ehci_hc_driver, NULL);
ehci_init_driver(&ci_ehci_hc_driver, &ehci_ci_overrides);
return 0;
}
......@@ -303,7 +303,7 @@ static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
/* Disable port power */
hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0);
/* Clear exsiting DP irq */
/* Clear existing DP irq */
hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS);
/* Enable data pulse irq */
hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE);
......@@ -328,7 +328,7 @@ static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator)
set_tmout(ci, indicator);
/* only vbus fall below B_sess_vld in b_idle state */
if (ci->transceiver->state == OTG_STATE_B_IDLE)
if (ci->fsm.otg->state == OTG_STATE_B_IDLE)
ci_otg_queue_work(ci);
}
......@@ -543,7 +543,7 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
ci_role_start(ci, CI_ROLE_HOST);
} else {
ci_role_stop(ci);
hw_device_reset(ci, USBMODE_CM_DC);
hw_device_reset(ci);
ci_role_start(ci, CI_ROLE_GADGET);
}
mutex_lock(&fsm->lock);
......@@ -582,11 +582,11 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
* when there is no gadget class driver
*/
if (ci->fsm.id && !(ci->driver) &&
ci->transceiver->state < OTG_STATE_A_IDLE)
ci->fsm.otg->state < OTG_STATE_A_IDLE)
return 0;
if (otg_statemachine(&ci->fsm)) {
if (ci->transceiver->state == OTG_STATE_A_IDLE) {
if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
/*
* Further state change for cases:
* a_idle to b_idle; or
......@@ -600,7 +600,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
ci_otg_queue_work(ci);
if (ci->id_event)
ci->id_event = false;
} else if (ci->transceiver->state == OTG_STATE_B_IDLE) {
} else if (ci->fsm.otg->state == OTG_STATE_B_IDLE) {
if (ci->fsm.b_sess_vld) {
ci->fsm.power_up = 0;
/*
......@@ -627,7 +627,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
otg_bsess_vld = hw_read_otgsc(ci, OTGSC_BSV);
port_conn = hw_read(ci, OP_PORTSC, PORTSC_CCS);
switch (ci->transceiver->state) {
switch (ci->fsm.otg->state) {
case OTG_STATE_A_WAIT_BCON:
if (port_conn) {
fsm->b_conn = 1;
......@@ -663,7 +663,7 @@ static void ci_otg_fsm_event(struct ci_hdrc *ci)
fsm->b_bus_suspend = 1;
/*
* Init a timer to know how long this suspend
* will contine, if time out, indicates B no longer
* will continue, if time out, indicates B no longer
* wants to be host role
*/
ci_otg_add_timer(ci, A_BIDL_ADIS);
......@@ -778,34 +778,25 @@ void ci_hdrc_otg_fsm_start(struct ci_hdrc *ci)
int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci)
{
int retval = 0;
struct usb_otg *otg;
otg = devm_kzalloc(ci->dev,
sizeof(struct usb_otg), GFP_KERNEL);
if (!otg) {
dev_err(ci->dev,
"Failed to allocate usb_otg structure for ci hdrc otg!\n");
return -ENOMEM;
}
if (ci->phy)
ci->otg.phy = ci->phy;
else
ci->otg.usb_phy = ci->usb_phy;
otg->phy = ci->transceiver;
otg->gadget = &ci->gadget;
ci->fsm.otg = otg;
ci->transceiver->otg = ci->fsm.otg;
ci->otg.gadget = &ci->gadget;
ci->fsm.otg = &ci->otg;
ci->fsm.power_up = 1;
ci->fsm.id = hw_read_otgsc(ci, OTGSC_ID) ? 1 : 0;
ci->transceiver->state = OTG_STATE_UNDEFINED;
ci->fsm.otg->state = OTG_STATE_UNDEFINED;
ci->fsm.ops = &ci_otg_ops;
mutex_init(&ci->fsm.lock);
ci->fsm_timer = devm_kzalloc(ci->dev,
sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL);
if (!ci->fsm_timer) {
dev_err(ci->dev,
"Failed to allocate timer structure for ci hdrc otg!\n");
if (!ci->fsm_timer)
return -ENOMEM;
}
INIT_LIST_HEAD(&ci->fsm_timer->active_timers);
retval = ci_otg_init_timers(ci);
......
......@@ -692,10 +692,8 @@ __acquires(ci->lock)
int retval;
spin_unlock(&ci->lock);
if (ci->gadget.speed != USB_SPEED_UNKNOWN) {
if (ci->driver)
ci->driver->disconnect(&ci->gadget);
}
if (ci->gadget.speed != USB_SPEED_UNKNOWN)
usb_gadget_udc_reset(&ci->gadget, ci->driver);
retval = _gadget_stop_activity(&ci->gadget);
if (retval)
......@@ -709,8 +707,6 @@ __acquires(ci->lock)
if (ci->status == NULL)
retval = -ENOMEM;
usb_gadget_set_state(&ci->gadget, USB_STATE_DEFAULT);
done:
spin_lock(&ci->lock);
......@@ -1475,7 +1471,7 @@ static int ci_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
if (gadget_ready) {
if (is_active) {
pm_runtime_get_sync(&_gadget->dev);
hw_device_reset(ci, USBMODE_CM_DC);
hw_device_reset(ci);
hw_device_state(ci, ci->ep0out->qh.dma);
usb_gadget_set_state(_gadget, USB_STATE_POWERED);
} else {
......@@ -1519,8 +1515,8 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
if (ci->transceiver)
return usb_phy_set_power(ci->transceiver, ma);
if (ci->usb_phy)
return usb_phy_set_power(ci->usb_phy, ma);
return -ENOTSUPP;
}
......@@ -1544,8 +1540,7 @@ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on)
static int ci_udc_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int ci_udc_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int ci_udc_stop(struct usb_gadget *gadget);
/**
* Device operations part of the API to the USB controller hardware,
* which don't involve endpoints (or i/o)
......@@ -1665,7 +1660,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
pm_runtime_get_sync(&ci->gadget.dev);
if (ci->vbus_active) {
spin_lock_irqsave(&ci->lock, flags);
hw_device_reset(ci, USBMODE_CM_DC);
hw_device_reset(ci);
} else {
pm_runtime_put_sync(&ci->gadget.dev);
return retval;
......@@ -1682,8 +1677,7 @@ static int ci_udc_start(struct usb_gadget *gadget,
/**
* ci_udc_stop: unregister a gadget driver
*/
static int ci_udc_stop(struct usb_gadget *gadget,
struct usb_gadget_driver *driver)
static int ci_udc_stop(struct usb_gadget *gadget)
{
struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget);
unsigned long flags;
......
......@@ -117,10 +117,9 @@ static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
if (data->index > 2)
return -EINVAL;
reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
if (data->evdo) {
spin_lock_irqsave(&usbmisc->lock, flags);
reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
val = readl(reg);
writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
spin_unlock_irqrestore(&usbmisc->lock, flags);
......@@ -172,8 +171,7 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
return -EINVAL;
/* Select a 24 MHz reference clock for the PHY */
reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
val = readl(reg);
val = readl(usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
val |= MX53_USB_PLL_DIV_24_MHZ;
writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
......
......@@ -1157,8 +1157,6 @@ static int acm_probe(struct usb_interface *intf,
case USB_CDC_CALL_MANAGEMENT_TYPE:
call_management_function = buffer[3];
call_interface_num = buffer[4];
if ((quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
break;
default:
/* there are LOTS more CDC descriptors that
......@@ -1197,10 +1195,11 @@ static int acm_probe(struct usb_interface *intf,
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = union_header->bSlaveInterface0));
if (!control_interface || !data_interface) {
dev_dbg(&intf->dev, "no interfaces\n");
return -ENODEV;
}
}
if (!control_interface || !data_interface) {
dev_dbg(&intf->dev, "no interfaces\n");
return -ENODEV;
}
if (data_interface_num != call_interface_num)
......@@ -1475,6 +1474,7 @@ static int acm_probe(struct usb_interface *intf,
&dev_attr_wCountryCodes);
device_remove_file(&acm->control->dev,
&dev_attr_iCountryCodeRelDate);
kfree(acm->country_codes);
}
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7:
......@@ -1813,11 +1813,6 @@ static const struct usb_device_id acm_ids[] = {
/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
/* Support Lego NXT using pbLua firmware */
{ USB_DEVICE(0x0694, 0xff00),
.driver_info = NOT_A_MODEM,
},
/* Support for Droids MuIn LCD */
{ USB_DEVICE(0x04d8, 0x000b),
.driver_info = NO_DATA_INTERFACE,
......
......@@ -130,7 +130,6 @@ struct acm {
#define NO_UNION_NORMAL BIT(0)
#define SINGLE_RX_URB BIT(1)
#define NO_CAP_LINE BIT(2)
#define NOT_A_MODEM BIT(3)
#define NO_DATA_INTERFACE BIT(4)
#define IGNORE_DEVICE BIT(5)
#define QUIRK_CONTROL_LINE_STATE BIT(6)
......@@ -1104,10 +1104,8 @@ static int usbtmc_probe(struct usb_interface *intf,
dev_dbg(&intf->dev, "%s called\n", __func__);
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&intf->dev, "Unable to allocate kernel memory\n");
if (!data)
return -ENOMEM;
}
data->intf = intf;
data->id = id;
......
......@@ -124,10 +124,10 @@ static void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
state_changed = 1;
if (fsm->otg->phy->state == new_state)
if (fsm->otg->state == new_state)
return 0;
VDBG("Set state: %s\n", usb_otg_state_string(new_state));
otg_leave_state(fsm, fsm->otg->phy->state);
otg_leave_state(fsm, fsm->otg->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
otg_drv_vbus(fsm, 0);
......@@ -236,7 +236,7 @@ static int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
break;
}
fsm->otg->phy->state = new_state;
fsm->otg->state = new_state;
return 0;
}
......@@ -247,7 +247,7 @@ int otg_statemachine(struct otg_fsm *fsm)
mutex_lock(&fsm->lock);
state = fsm->otg->phy->state;
state = fsm->otg->state;
state_changed = 0;
/* State machine state change judgement */
......
......@@ -2646,7 +2646,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
}
if (IS_ENABLED(CONFIG_GENERIC_PHY)) {
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
struct phy *phy = phy_get(hcd->self.controller, "usb");
if (IS_ERR(phy)) {
......@@ -2666,6 +2666,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
goto err_phy;
}
hcd->phy = phy;
hcd->remove_phy = 1;
}
}
......@@ -2812,7 +2813,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
err_register_bus:
hcd_buffer_destroy(hcd);
err_create_buf:
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
......@@ -2896,7 +2897,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_deregister_bus(&hcd->self);
hcd_buffer_destroy(hcd);
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->phy) {
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
phy_power_off(hcd->phy);
phy_exit(hcd->phy);
phy_put(hcd->phy);
......
......@@ -2543,11 +2543,14 @@ int usb_authorize_device(struct usb_device *usb_dev)
"can't autoresume for authorization: %d\n", result);
goto error_autoresume;
}
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
if (result < 0) {
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
"authorization: %d\n", result);
goto error_device_descriptor;
if (usb_dev->wusb) {
result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
if (result < 0) {
dev_err(&usb_dev->dev, "can't re-read device descriptor for "
"authorization: %d\n", result);
goto error_device_descriptor;
}
}
usb_dev->authorized = 1;
......@@ -3907,14 +3910,9 @@ static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev,
enum usb3_link_state state)
{
int feature;
switch (state) {
case USB3_LPM_U1:
feature = USB_PORT_FEAT_U1_TIMEOUT;
break;
case USB3_LPM_U2:
feature = USB_PORT_FEAT_U2_TIMEOUT;
break;
default:
dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n",
......
config USB_DWC2
bool "DesignWare USB2 DRD Core Support"
depends on USB
tristate "DesignWare USB2 DRD Core Support"
depends on USB || USB_GADGET
help
Say Y here if your system has a Dual Role Hi-Speed USB
controller based on the DesignWare HSOTG IP Core.
......@@ -10,49 +10,61 @@ config USB_DWC2
bus interface module (if you have a PCI bus system) will be
called dwc2_pci.ko, and the platform interface module (for
controllers directly connected to the CPU) will be called
dwc2_platform.ko. For gadget mode, there will be a single
module called dwc2_gadget.ko.
NOTE: The s3c-hsotg driver is now renamed to dwc2_gadget. The
host and gadget drivers are still currently separate drivers.
There are plans to merge the dwc2_gadget driver with the dwc2
host driver in the near future to create a dual-role driver.
dwc2_platform.ko. For all modes(host, gadget and dual-role), there
will be an additional module named dwc2.ko.
if USB_DWC2
choice
bool "DWC2 Mode Selection"
default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET)
default USB_DWC2_HOST if (USB && !USB_GADGET)
default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET)
config USB_DWC2_HOST
tristate "Host only mode"
bool "Host only mode"
depends on USB
help
The Designware USB2.0 high-speed host controller
integrated into many SoCs.
integrated into many SoCs. Select this option if you want the
driver to operate in Host-only mode.
config USB_DWC2_PLATFORM
bool "DWC2 Platform"
depends on USB_DWC2_HOST
default USB_DWC2_HOST
comment "Gadget/Dual-role mode requires USB Gadget support to be enabled"
config USB_DWC2_PERIPHERAL
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_DWC2
help
The Designware USB2.0 platform interface module for
controllers directly connected to the CPU. This is only
used for host mode.
The Designware USB2.0 high-speed gadget controller
integrated into many SoCs. Select this option if you want the
driver to operate in Peripheral-only mode. This option requires
USB_GADGET to be enabled.
config USB_DWC2_DUAL_ROLE
bool "Dual Role mode"
depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
help
Select this option if you want the driver to work in a dual-role
mode. In this mode both host and gadget features are enabled, and
the role will be determined by the cable that gets plugged-in. This
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
bool "DWC2 PCI"
tristate "DWC2 PCI"
depends on USB_DWC2_HOST && PCI
default USB_DWC2_HOST
help
The Designware USB2.0 PCI interface module for controllers
connected to a PCI bus. This is only used for host mode.
comment "Gadget mode requires USB Gadget support to be enabled"
config USB_DWC2_PERIPHERAL
tristate "Gadget only mode"
depends on USB_GADGET
help
The Designware USB2.0 high-speed gadget controller
integrated into many SoCs.
config USB_DWC2_DEBUG
bool "Enable Debugging Messages"
help
......
ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC2_HOST) += dwc2.o
obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o
dwc2-y += hcd.o hcd_intr.o
dwc2-y += hcd_queue.o hcd_ddma.o
ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += hcd.o hcd_intr.o
dwc2-y += hcd_queue.o hcd_ddma.o
endif
ifneq ($(filter y,$(CONFIG_USB_DWC2_PERIPHERAL) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
dwc2-y += gadget.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_gadget.ko will get built for peripheral mode. For host mode,
# the core module will be dwc2.ko, the PCI bus interface module will called
# dwc2_pci.ko and the platform interface module will be called dwc2_platform.ko.
# At present the host and gadget driver will be separate drivers, but there
# are plans in the near future to create a dual-role driver.
# modules, dwc2.ko will get built for host mode, peripheral mode, and dual-role
# mode. The PCI bus interface module will called dwc2_pci.ko and the platform
# interface module will be called dwc2_platform.ko.
ifneq ($(CONFIG_USB_DWC2_PCI),)
obj-$(CONFIG_USB_DWC2_HOST) += dwc2_pci.o
obj-$(CONFIG_USB_DWC2) += dwc2_pci.o
dwc2_pci-y := pci.o
endif
ifneq ($(CONFIG_USB_DWC2_PLATFORM),)
obj-$(CONFIG_USB_DWC2_HOST) += dwc2_platform.o
dwc2_platform-y := platform.o
endif
obj-$(CONFIG_USB_DWC2_PERIPHERAL) += dwc2_gadget.o
dwc2_gadget-y := gadget.o
obj-$(CONFIG_USB_DWC2_PLATFORM) += dwc2_platform.o
dwc2_platform-y := platform.o
......@@ -458,16 +458,6 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
/* Clear the SRP success bit for FS-I2c */
hsotg->srp_success = 0;
if (irq >= 0) {
dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
irq);
retval = devm_request_irq(hsotg->dev, irq,
dwc2_handle_common_intr, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (retval)
return retval;
}
/* Enable common interrupts */
dwc2_enable_common_interrupts(hsotg);
......
此差异已折叠。
......@@ -128,6 +128,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dwc2_op_state_str(hsotg));
gotgctl = readl(hsotg->regs + GOTGCTL);
if (dwc2_is_device_mode(hsotg))
s3c_hsotg_disconnect(hsotg);
if (hsotg->op_state == OTG_STATE_B_HOST) {
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
} else {
......@@ -287,9 +290,11 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
* Release lock before scheduling workq as it holds spinlock during
* scheduling.
*/
spin_unlock(&hsotg->lock);
queue_work(hsotg->wq_otg, &hsotg->wf_otg);
spin_lock(&hsotg->lock);
if (hsotg->wq_otg) {
spin_unlock(&hsotg->lock);
queue_work(hsotg->wq_otg, &hsotg->wf_otg);
spin_lock(&hsotg->lock);
}
/* Clear interrupt */
writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
......@@ -312,6 +317,12 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
/* Clear interrupt */
writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
/*
* Report disconnect if there is any previous session established
*/
if (dwc2_is_device_mode(hsotg))
s3c_hsotg_disconnect(hsotg);
}
/*
......
此差异已折叠。
......@@ -1371,6 +1371,8 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_core_init(hsotg, false, -1);
dwc2_enable_global_interrupts(hsotg);
s3c_hsotg_core_init_disconnected(hsotg);
s3c_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
dev_dbg(hsotg->dev, "connId A\n");
......@@ -1471,6 +1473,30 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
}
}
static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
{
u32 hprt0;
/* After clear the Stop PHY clock bit, we should wait for a moment
* for PLL work stable with clock output.
*/
writel(0, hsotg->regs + PCGCTL);
usleep_range(2000, 4000);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hprt0 &= ~HPRT0_SUSP;
/* according to USB2.0 Spec 7.1.7.7, the host must send the resume
* signal for at least 20ms
*/
usleep_range(20000, 25000);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hsotg->lx_state = DWC2_L0;
}
/* Handles hub class-specific requests */
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u16 wvalue, u16 windex, char *buf, u16 wlength)
......@@ -1516,17 +1542,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
case USB_PORT_FEAT_SUSPEND:
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
writel(0, hsotg->regs + PCGCTL);
usleep_range(20000, 40000);
hprt0 = dwc2_read_hprt0(hsotg);
hprt0 |= HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
hprt0 &= ~HPRT0_SUSP;
usleep_range(100000, 150000);
hprt0 &= ~HPRT0_RES;
writel(hprt0, hsotg->regs + HPRT0);
dwc2_port_resume(hsotg);
break;
case USB_PORT_FEAT_POWER:
......@@ -2299,6 +2315,55 @@ 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);
u32 hprt0;
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
(hsotg->op_state == OTG_STATE_A_HOST)))
return 0;
/* TODO: We get into suspend from 'on' state, maybe we need to do
* something if we get here from DWC2_L1(LPM sleep) state one day.
*/
if (hsotg->lx_state != DWC2_L0)
return 0;
hprt0 = dwc2_read_hprt0(hsotg);
if (hprt0 & HPRT0_CONNSTS) {
dwc2_port_suspend(hsotg, 1);
} else {
u32 pcgctl = readl(hsotg->regs + PCGCTL);
pcgctl |= PCGCTL_STOPPCLK;
writel(pcgctl, hsotg->regs + PCGCTL);
}
return 0;
}
static int _dwc2_hcd_resume(struct usb_hcd *hcd)
{
struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
u32 hprt0;
if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
(hsotg->op_state == OTG_STATE_A_HOST)))
return 0;
if (hsotg->lx_state != DWC2_L2)
return 0;
hprt0 = dwc2_read_hprt0(hsotg);
if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
dwc2_port_resume(hsotg);
else
writel(0, hsotg->regs + PCGCTL);
return 0;
}
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
......@@ -2669,6 +2734,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,
};
/*
......@@ -2778,6 +2846,9 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
int i, num_channels;
int retval;
if (usb_disabled())
return -ENODEV;
dev_dbg(hsotg->dev, "DWC OTG HCD INIT\n");
/* Detect config values from hardware */
......@@ -2839,7 +2910,6 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq,
hcd->has_tt = 1;
spin_lock_init(&hsotg->lock);
((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg;
hsotg->priv = hcd;
......
......@@ -668,9 +668,6 @@ extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg);
*/
extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg);
extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host,
* and 0 otherwise
......@@ -679,13 +676,6 @@ extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg);
*/
extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_get_frame_number() - Returns current frame number
*
* @hsotg: The DWC2 HCD
*/
extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg);
/**
* dwc2_hcd_dump_state() - Dumps hsotg state
*
......
......@@ -141,6 +141,13 @@ static int dwc2_driver_probe(struct pci_dev *dev,
pci_set_master(dev);
retval = devm_request_irq(hsotg->dev, dev->irq,
dwc2_handle_common_intr, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (retval)
return retval;
spin_lock_init(&hsotg->lock);
retval = dwc2_hcd_init(hsotg, dev->irq, &dwc2_module_params);
if (retval) {
pci_disable_device(dev);
......
此差异已折叠。
......@@ -55,7 +55,7 @@ config USB_DWC3_OMAP
config USB_DWC3_EXYNOS
tristate "Samsung Exynos Platform"
depends on ARCH_EXYNOS || COMPILE_TEST
depends on ARCH_EXYNOS && OF || COMPILE_TEST
default USB_DWC3
help
Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -243,7 +243,7 @@ static int st_dwc3_probe(struct platform_device *pdev)
dwc3_data->rstc_rst = devm_reset_control_get(dev, "softreset");
if (IS_ERR(dwc3_data->rstc_rst)) {
dev_err(&pdev->dev, "could not get reset controller\n");
ret = PTR_ERR(dwc3_data->rstc_pwrdn);
ret = PTR_ERR(dwc3_data->rstc_rst);
goto undo_powerdown;
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -38,3 +38,7 @@ usb_f_uac2-y := f_uac2.o
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
usb_f_midi-y := f_midi.o
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
usb_f_hid-y := f_hid.o
obj-$(CONFIG_USB_F_HID) += usb_f_hid.o
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册