usb: patches for v3.20 merge window

Here's the big pull request for Gadgets and PHYs. It's
 a total of 217 non-merge commits with pretty much everything
 being touched.
 
 The most important bits are a ton of new documentation for
 almost all usb gadget functions, a new isp1760 UDC driver,
 several improvements to the old net2280 UDC driver, and
 some minor tracepoint improvements to dwc3.
 
 Other than that, a big list of minor cleanups, smaller bugfixes
 and new features all over the place.
 
 Signed-off-by: Felipe Balbi <balbi@ti.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJU0lRFAAoJEIaOsuA1yqRE17sP/R4iPwrPQGVQBaqg5AOHZGEe
 dKf9GqZZIPzNIs4146Ua5W/9d4U6zQKndy+fRQaNEVc2SR3Tm0IwOSokvSaC3FYr
 NEGHMoRnTWd/JWSVB/6sy0qn8rKRMbkxR7u9lG9M/JACUymn3NJfH4D0jq85ewPR
 0Tjv4g5wGnv3YEmnWgR5ieFgn0OxgUBiGUF7QufgMp7G3F2hjmeligBD0jt3w6tD
 G4oMHp+pRfPCcm8mcdiHoP3aXOtNJ824rI+b1EZkKBKeo7FxRDIe48Vl107XOpOB
 yUFnQVGZazh1Oi6Vxmh9O1mmjpNOir/4dni7gZfh1uGC7cJ7tSkOfbN4jH4Ycsay
 Ckt8XQkmf/z9VWTONsAkDwfPhnMbxCafz8Fi/UdOXsoR69YV1MKnt1zRN5dzgNq9
 7EIqDwPPJi6qwLACoqxVYknSmXQqhW8B0IMPpMqEByvR1mnIOWomlFot63AufMaQ
 +uS7JGJguUmMvkyP1FJRKcPsd9u4PYll5JzymPsvSB6xtDisVFqYb3BbfieZHpBn
 +/ZFqltT71pQ3TxIx2ZiTk1e91PiKJUbEQikV6TBiLhgtkpn2J8obHtF50K4+xHh
 wXOU3VHFd2ZONN+WB5F5EoVtZiwsd3pARr8QJRcVhdXltTWElJ2qsA4Z1+5QVhAy
 mqXYcwsvBe9C+5p2pYwR
 =bGMq
 -----END PGP SIGNATURE-----

Merge tag 'usb-for-v3.20' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

Felipe writes:

usb: patches for v3.20 merge window

Here's the big pull request for Gadgets and PHYs. It's
a total of 217 non-merge commits with pretty much everything
being touched.

The most important bits are a ton of new documentation for
almost all usb gadget functions, a new isp1760 UDC driver,
several improvements to the old net2280 UDC driver, and
some minor tracepoint improvements to dwc3.

Other than that, a big list of minor cleanups, smaller bugfixes
and new features all over the place.

Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Greg Kroah-Hartman 2015-02-04 11:03:20 -08:00
commit 4d4bac4499
102 changed files with 8135 additions and 2238 deletions

View file

@ -0,0 +1,265 @@
What: /config/usb-gadget/gadget/functions/uvc.name
Date: Dec 2014
KernelVersion: 3.20
Description: UVC function directory
streaming_maxburst - 0..15 (ss only)
streaming_maxpacket - 1..1023 (fs), 1..3072 (hs/ss)
streaming_interval - 1..16
What: /config/usb-gadget/gadget/functions/uvc.name/control
Date: Dec 2014
KernelVersion: 3.20
Description: Control descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class
Date: Dec 2014
KernelVersion: 3.20
Description: Class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/ss
Date: Dec 2014
KernelVersion: 3.20
Description: Super speed control class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/class/fs
Date: Dec 2014
KernelVersion: 3.20
Description: Full speed control class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal
Date: Dec 2014
KernelVersion: 3.20
Description: Terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output
Date: Dec 2014
KernelVersion: 3.20
Description: Output terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/output/default
Date: Dec 2014
KernelVersion: 3.20
Description: Default output terminal descriptors
All attributes read only:
iTerminal - index of string descriptor
bSourceID - id of the terminal to which this terminal
is connected
bAssocTerminal - id of the input terminal to which this output
terminal is associated
wTerminalType - terminal type
bTerminalID - a non-zero id of this terminal
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera
Date: Dec 2014
KernelVersion: 3.20
Description: Camera terminal descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/terminal/camera/default
Date: Dec 2014
KernelVersion: 3.20
Description: Default camera terminal descriptors
All attributes read only:
bmControls - bitmap specifying which controls are
supported for the video stream
wOcularFocalLength - the value of Locular
wObjectiveFocalLengthMax- the value of Lmin
wObjectiveFocalLengthMin- the value of Lmax
iTerminal - index of string descriptor
bAssocTerminal - id of the output terminal to which
this terminal is connected
wTerminalType - terminal type
bTerminalID - a non-zero id of this terminal
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing
Date: Dec 2014
KernelVersion: 3.20
Description: Processing unit descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/processing/default
Date: Dec 2014
KernelVersion: 3.20
Description: Default processing unit descriptors
All attributes read only:
iProcessing - index of string descriptor
bmControls - bitmap specifying which controls are
supported for the video stream
wMaxMultiplier - maximum digital magnification x100
bSourceID - id of the terminal to which this unit is
connected
bUnitID - a non-zero id of this unit
What: /config/usb-gadget/gadget/functions/uvc.name/control/header
Date: Dec 2014
KernelVersion: 3.20
Description: Control header descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/control/header/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific control header descriptors
dwClockFrequency
bcdUVC
What: /config/usb-gadget/gadget/functions/uvc.name/streaming
Date: Dec 2014
KernelVersion: 3.20
Description: Streaming descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class
Date: Dec 2014
KernelVersion: 3.20
Description: Streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/ss
Date: Dec 2014
KernelVersion: 3.20
Description: Super speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/hs
Date: Dec 2014
KernelVersion: 3.20
Description: High speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/class/fs
Date: Dec 2014
KernelVersion: 3.20
Description: Full speed streaming class descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching
Date: Dec 2014
KernelVersion: 3.20
Description: Color matching descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/color_matching/default
Date: Dec 2014
KernelVersion: 3.20
Description: Default color matching descriptors
All attributes read only:
bMatrixCoefficients - matrix used to compute luma and
chroma values from the color primaries
bTransferCharacteristics- optoelectronic transfer
characteristic of the source picutre,
also called the gamma function
bColorPrimaries - color primaries and the reference
white
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg
Date: Dec 2014
KernelVersion: 3.20
Description: MJPEG format descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific MJPEG format descriptors
All attributes read only,
except bmaControls and bDefaultFrameIndex:
bmaControls - this format's data for bmaControls in
the streaming header
bmInterfaceFlags - specifies interlace information,
read-only
bAspectRatioY - the X dimension of the picture aspect
ratio, read-only
bAspectRatioX - the Y dimension of the picture aspect
ratio, read-only
bmFlags - characteristics of this format,
read-only
bDefaultFrameIndex - optimum frame index for this stream
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/mjpeg/name/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific MJPEG frame descriptors
dwFrameInterval - indicates how frame interval can be
programmed; a number of values
separated by newline can be specified
dwDefaultFrameInterval - the frame interval the device would
like to use as default
dwMaxVideoFrameBufferSize- the maximum number of bytes the
compressor will produce for a video
frame or still image
dwMaxBitRate - the maximum bit rate at the shortest
frame interval in bps
dwMinBitRate - the minimum bit rate at the longest
frame interval in bps
wHeight - height of decoded bitmap frame in px
wWidth - width of decoded bitmam frame in px
bmCapabilities - still image support, fixed frame-rate
support
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed
Date: Dec 2014
KernelVersion: 3.20
Description: Uncompressed format descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific uncompressed format descriptors
bmaControls - this format's data for bmaControls in
the streaming header
bmInterfaceFlags - specifies interlace information,
read-only
bAspectRatioY - the X dimension of the picture aspect
ratio, read-only
bAspectRatioX - the Y dimension of the picture aspect
ratio, read-only
bDefaultFrameIndex - optimum frame index for this stream
bBitsPerPixel - number of bits per pixel used to
specify color in the decoded video
frame
guidFormat - globally unique id used to identify
stream-encoding format
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/uncompressed/name/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific uncompressed frame descriptors
dwFrameInterval - indicates how frame interval can be
programmed; a number of values
separated by newline can be specified
dwDefaultFrameInterval - the frame interval the device would
like to use as default
dwMaxVideoFrameBufferSize- the maximum number of bytes the
compressor will produce for a video
frame or still image
dwMaxBitRate - the maximum bit rate at the shortest
frame interval in bps
dwMinBitRate - the minimum bit rate at the longest
frame interval in bps
wHeight - height of decoded bitmap frame in px
wWidth - width of decoded bitmam frame in px
bmCapabilities - still image support, fixed frame-rate
support
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header
Date: Dec 2014
KernelVersion: 3.20
Description: Streaming header descriptors
What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header/name
Date: Dec 2014
KernelVersion: 3.20
Description: Specific streaming header descriptors
All attributes read only:
bTriggerUsage - how the host software will respond to
a hardware trigger interrupt event
bTriggerSupport - flag specifying if hardware
triggering is supported
bStillCaptureMethod - method of still image caputre
supported
bTerminalLink - id of the output terminal to which
the video endpoint of this interface
is connected
bmInfo - capabilities of this video streaming
interface

View file

@ -51,7 +51,10 @@ usb1: gadget@fffa4000 {
Atmel High-Speed USB device controller
Required properties:
- compatible: Should be "atmel,at91sam9rl-udc"
- compatible: Should be one of the following
"at91sam9rl-udc"
"at91sam9g45-udc"
"sama5d3-udc"
- reg: Address and length of the register set for the device
- interrupts: Should contain usba interrupt
- ep childnode: To specify the number of endpoints and their properties.

View file

@ -20,6 +20,10 @@ Optional properties:
Refer to phy/phy-bindings.txt for generic phy consumer properties
- dr_mode: shall be one of "host", "peripheral" and "otg"
Refer to usb/generic.txt
- g-use-dma: enable dma usage in gadget driver.
- g-rx-fifo-size: size of rx fifo size in gadget mode.
- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode.
- g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode.
Example:

View file

@ -14,6 +14,8 @@ Optional properties:
function should be enabled
- phys: phandle + phy specifier pair
- phy-names: must be "usb"
- dmas: Must contain a list of references to DMA specifiers.
- dma-names : Must contain a list of DMA names, "tx" or "rx".
Example:
usbhs: usb@e6590000 {

View file

@ -13,10 +13,15 @@ Optional properties:
- clock-frequency: the clock frequency (in Hz) that the PHY clock must
be configured to.
- vcc-supply: phandle to the regulator that provides RESET to the PHY.
- vcc-supply: phandle to the regulator that provides power to the PHY.
- reset-gpios: Should specify the GPIO for reset.
- vbus-detect-gpio: should specify the GPIO detecting a VBus insertion
(see Documentation/devicetree/bindings/gpio/gpio.txt)
- vbus-regulator : should specifiy the regulator supplying current drawn from
the VBus line (see Documentation/devicetree/bindings/regulator/regulator.txt).
Example:
hsusb1_phy {
@ -26,8 +31,11 @@ Example:
clock-names = "main_clk";
vcc-supply = <&hsusb1_vcc_regulator>;
reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
vbus-detect-gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>;
vbus-regulator = <&vbus_regulator>;
};
hsusb1_phy is a NOP USB PHY device that gets its clock from an oscillator
and expects that clock to be configured to 19.2MHz by the NOP PHY driver.
hsusb1_vcc_regulator provides power to the PHY and GPIO 7 controls RESET.
GPIO 13 detects VBus insertion, and accordingly notifies the vbus-regulator.

View file

@ -0,0 +1,728 @@
This file summarizes information on basic testing of USB functions
provided by gadgets.
1. ACM function
2. ECM function
3. ECM subset function
4. EEM function
5. FFS function
6. HID function
7. LOOPBACK function
8. MASS STORAGE function
9. MIDI function
10. NCM function
11. OBEX function
12. PHONET function
13. RNDIS function
14. SERIAL function
15. SOURCESINK function
16. UAC1 function
17. UAC2 function
18. UVC function
1. ACM function
===============
The function is provided by usb_f_acm.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "acm".
The ACM function provides just one attribute in its function directory:
port_num
The attribute is read-only.
There can be at most 4 ACM/generic serial/OBEX ports in the system.
Testing the ACM function
------------------------
On the host: cat > /dev/ttyACM<X>
On the device : cat /dev/ttyGS<Y>
then the other way round
On the device: cat > /dev/ttyGS<Y>
On the host: cat /dev/ttyACM<X>
2. ECM function
===============
The function is provided by usb_f_ecm.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "ecm".
The ECM function provides these attributes in its function directory:
ifname - network device interface name associated with this
function instance
qmult - queue length multiplier for high and super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
and after creating the functions/ecm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
Testing the ECM function
------------------------
Configure IP addresses of the device and the host. Then:
On the device: ping <host's IP>
On the host: ping <device's IP>
3. ECM subset function
======================
The function is provided by usb_f_ecm_subset.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "geth".
The ECM subset function provides these attributes in its function directory:
ifname - network device interface name associated with this
function instance
qmult - queue length multiplier for high and super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
and after creating the functions/ecm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
Testing the ECM subset function
-------------------------------
Configure IP addresses of the device and the host. Then:
On the device: ping <host's IP>
On the host: ping <device's IP>
4. EEM function
===============
The function is provided by usb_f_eem.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "eem".
The EEM function provides these attributes in its function directory:
ifname - network device interface name associated with this
function instance
qmult - queue length multiplier for high and super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
and after creating the functions/eem.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
Testing the EEM function
------------------------
Configure IP addresses of the device and the host. Then:
On the device: ping <host's IP>
On the host: ping <device's IP>
5. FFS function
===============
The function is provided by usb_f_fs.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "ffs".
The function directory is intentionally empty and not modifiable.
After creating the directory there is a new instance (a "device") of FunctionFS
available in the system. Once a "device" is available, the user should follow
the standard procedure for using FunctionFS (mount it, run the userspace
process which implements the function proper). The gadget should be enabled
by writing a suitable string to usb_gadget/<gadget>/UDC.
Testing the FFS function
------------------------
On the device: start the function's userspace daemon, enable the gadget
On the host: use the USB function provided by the device
6. HID function
===============
The function is provided by usb_f_hid.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "hid".
The HID function provides these attributes in its function directory:
protocol - HID protocol to use
report_desc - data to be used in HID reports, except data
passed with /dev/hidg<X>
report_length - HID report length
subclass - HID subclass to use
For a keyboard the protocol and the subclass are 1, the report_length is 8,
while the report_desc is:
$ hd my_report_desc
00000000 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 |..........)...%.|
00000010 75 01 95 08 81 02 95 01 75 08 81 03 95 05 75 01 |u.......u.....u.|
00000020 05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 06 |....).....u.....|
00000030 75 08 15 00 25 65 05 07 19 00 29 65 81 00 c0 |u...%e....)e...|
0000003f
Such a sequence of bytes can be stored to the attribute with echo:
$ echo -ne \\x05\\x01\\x09\\x06\\xa1.....
Testing the HID function
------------------------
Device:
- create the gadget
- connect the gadget to a host, preferably not the one used
to control the gadget
- run a program which writes to /dev/hidg<N>, e.g.
a userspace program found in Documentation/usb/gadget_hid.txt:
$ ./hid_gadget_test /dev/hidg0 keyboard
Host:
- observe the keystrokes from the gadget
7. LOOPBACK function
====================
The function is provided by usb_f_ss_lb.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "Loopback".
The LOOPBACK function provides these attributes in its function directory:
qlen - depth of loopback queue
bulk_buflen - buffer length
Testing the LOOPBACK function
-----------------------------
device: run the gadget
host: test-usb
http://www.linux-usb.org/usbtest/testusb.c
8. MASS STORAGE function
========================
The function is provided by usb_f_mass_storage.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "mass_storage".
The MASS STORAGE function provides these attributes in its directory:
files:
stall - Set to permit function to halt bulk endpoints.
Disabled on some USB devices known not to work
correctly. You should set it to true.
num_buffers - Number of pipeline buffers. Valid numbers
are 2..4. Available only if
CONFIG_USB_GADGET_DEBUG_FILES is set.
and a default lun.0 directory corresponding to SCSI LUN #0.
A new lun can be added with mkdir:
$ mkdir functions/mass_storage.0/partition.5
Lun numbering does not have to be continuous, except for lun #0 which is
created by default. A maximum of 8 luns can be specified and they all must be
named following the <name>.<number> scheme. The numbers can be 0..8.
Probably a good convention is to name the luns "lun.<number>",
although it is not mandatory.
In each lun directory there are the following attribute files:
file - The path to the backing file for the LUN.
Required if LUN is not marked as removable.
ro - Flag specifying access to the LUN shall be
read-only. This is implied if CD-ROM emulation
is enabled as well as when it was impossible
to open "filename" in R/W mode.
removable - Flag specifying that LUN shall be indicated as
being removable.
cdrom - Flag specifying that LUN shall be reported as
being a CD-ROM.
nofua - Flag specifying that FUA flag
in SCSI WRITE(10,12)
Testing the MASS STORAGE function
---------------------------------
device: connect the gadget, enable it
host: dmesg, see the USB drives appear (if system configured to automatically
mount)
9. MIDI function
================
The function is provided by usb_f_midi.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "midi".
The MIDI function provides these attributes in its function directory:
buflen - MIDI buffer length
id - ID string for the USB MIDI adapter
in_ports - number of MIDI input ports
index - index value for the USB MIDI adapter
out_ports - number of MIDI output ports
qlen - USB read request queue length
Testing the MIDI function
-------------------------
There are two cases: playing a mid from the gadget to
the host and playing a mid from the host to the gadget.
1) Playing a mid from the gadget to the host
host)
$ arecordmidi -l
Port Client name Port name
14:0 Midi Through Midi Through Port-0
24:0 MIDI Gadget MIDI Gadget MIDI 1
$ arecordmidi -p 24:0 from_gadget.mid
gadget)
$ aplaymidi -l
Port Client name Port name
20:0 f_midi f_midi
$ aplaymidi -p 20:0 to_host.mid
2) Playing a mid from the host to the gadget
gadget)
$ arecordmidi -l
Port Client name Port name
20:0 f_midi f_midi
$ arecordmidi -p 20:0 from_host.mid
host)
$ aplaymidi -l
Port Client name Port name
14:0 Midi Through Midi Through Port-0
24:0 MIDI Gadget MIDI Gadget MIDI 1
$ aplaymidi -p24:0 to_gadget.mid
The from_gadget.mid should sound identical to the to_host.mid.
The from_host.id should sound identical to the to_gadget.mid.
MIDI files can be played to speakers/headphones with e.g. timidity installed
$ aplaymidi -l
Port Client name Port name
14:0 Midi Through Midi Through Port-0
24:0 MIDI Gadget MIDI Gadget MIDI 1
128:0 TiMidity TiMidity port 0
128:1 TiMidity TiMidity port 1
128:2 TiMidity TiMidity port 2
128:3 TiMidity TiMidity port 3
$ aplaymidi -p 128:0 file.mid
MIDI ports can be logically connected using the aconnect utility, e.g.:
$ aconnect 24:0 128:0 # try it on the host
After the gadget's MIDI port is connected to timidity's MIDI port,
whatever is played at the gadget side with aplaymidi -l is audible
in host's speakers/headphones.
10. NCM function
================
The function is provided by usb_f_ncm.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "ncm".
The NCM function provides these attributes in its function directory:
ifname - network device interface name associated with this
function instance
qmult - queue length multiplier for high and super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
and after creating the functions/ncm.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
Testing the NCM function
------------------------
Configure IP addresses of the device and the host. Then:
On the device: ping <host's IP>
On the host: ping <device's IP>
11. OBEX function
=================
The function is provided by usb_f_obex.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "obex".
The OBEX function provides just one attribute in its function directory:
port_num
The attribute is read-only.
There can be at most 4 ACM/generic serial/OBEX ports in the system.
Testing the OBEX function
-------------------------
On device: seriald -f /dev/ttyGS<Y> -s 1024
On host: serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \
-t<out endpoint addr> -r<in endpoint addr>
where seriald and serialc are Felipe's utilities found here:
https://git.gitorious.org/usb/usb-tools.git master
12. PHONET function
===================
The function is provided by usb_f_phonet.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "phonet".
The PHONET function provides just one attribute in its function directory:
ifname - network device interface name associated with this
function instance
Testing the PHONET function
---------------------------
It is not possible to test the SOCK_STREAM protocol without a specific piece
of hardware, so only SOCK_DGRAM has been tested. For the latter to work,
in the past I had to apply the patch mentioned here:
http://www.spinics.net/lists/linux-usb/msg85689.html
These tools are required:
git://git.gitorious.org/meego-cellular/phonet-utils.git
On the host:
$ ./phonet -a 0x10 -i usbpn0
$ ./pnroute add 0x6c usbpn0
$./pnroute add 0x10 usbpn0
$ ifconfig usbpn0 up
On the device:
$ ./phonet -a 0x6c -i upnlink0
$ ./pnroute add 0x10 upnlink0
$ ifconfig upnlink0 up
Then a test program can be used:
http://www.spinics.net/lists/linux-usb/msg85690.html
On the device:
$ ./pnxmit -a 0x6c -r
On the host:
$ ./pnxmit -a 0x10 -s 0x6c
As a result some data should be sent from host to device.
Then the other way round:
On the host:
$ ./pnxmit -a 0x10 -r
On the device:
$ ./pnxmit -a 0x6c -s 0x10
13. RNDIS function
==================
The function is provided by usb_f_rndis.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "rndis".
The RNDIS function provides these attributes in its function directory:
ifname - network device interface name associated with this
function instance
qmult - queue length multiplier for high and super speed
host_addr - MAC address of host's end of this
Ethernet over USB link
dev_addr - MAC address of device's end of this
Ethernet over USB link
and after creating the functions/rndis.<instance name> they contain default
values: qmult is 5, dev_addr and host_addr are randomly selected.
Except for ifname they can be written to until the function is linked to a
configuration. The ifname is read-only and contains the name of the interface
which was assigned by the net core, e. g. usb0.
By default there can be only 1 RNDIS interface in the system.
Testing the RNDIS function
--------------------------
Configure IP addresses of the device and the host. Then:
On the device: ping <host's IP>
On the host: ping <device's IP>
14. SERIAL function
===================
The function is provided by usb_f_gser.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "gser".
The SERIAL function provides just one attribute in its function directory:
port_num
The attribute is read-only.
There can be at most 4 ACM/generic serial/OBEX ports in the system.
Testing the SERIAL function
---------------------------
On host: insmod usbserial
echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id
On host: cat > /dev/ttyUSB<X>
On target: cat /dev/ttyGS<Y>
then the other way round
On target: cat > /dev/ttyGS<Y>
On host: cat /dev/ttyUSB<X>
15. SOURCESINK function
=======================
The function is provided by usb_f_ss_lb.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "SourceSink".
The SOURCESINK function provides these attributes in its function directory:
pattern - 0 (all zeros), 1 (mod63), 2 (none)
isoc_interval - 1..16
isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss)
isoc_mult - 0..2 (hs/ss only)
isoc_maxburst - 0..15 (ss only)
bulk_buflen - buffer length
Testing the SOURCESINK function
-------------------------------
device: run the gadget
host: test-usb
http://www.linux-usb.org/usbtest/testusb.c
16. UAC1 function
=================
The function is provided by usb_f_uac1.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "uac1".
The uac1 function provides these attributes in its function directory:
audio_buf_size - audio buffer size
fn_cap - capture pcm device file name
fn_cntl - control device file name
fn_play - playback pcm device file name
req_buf_size - ISO OUT endpoint request buffer size
req_count - ISO OUT endpoint request count
The attributes have sane default values.
Testing the UAC1 function
-------------------------
device: run the gadget
host: aplay -l # should list our USB Audio Gadget
17. UAC2 function
=================
The function is provided by usb_f_uac2.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "uac2".
The uac2 function provides these attributes in its function directory:
chmask - capture channel mask
c_srate - capture sampling rate
c_ssize - capture sample size (bytes)
p_chmask - playback channel mask
p_srate - playback sampling rate
p_ssize - playback sample size (bytes)
The attributes have sane default values.
Testing the UAC2 function
-------------------------
device: run the gadget
host: aplay -l # should list our USB Audio Gadget
This function does not require real hardware support, it just
sends a stream of audio data to/from the host. In order to
actually hear something at the device side, a command similar
to this must be used at the device side:
$ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 &
e.g.:
$ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \
aplay -D default:CARD=OdroidU3
18. UVC function
================
The function is provided by usb_f_uvc.ko module.
Function-specific configfs interface
------------------------------------
The function name to use when creating the function directory is "uvc".
The uvc function provides these attributes in its function directory:
streaming_interval - interval for polling endpoint for data transfers
streaming_maxburst - bMaxBurst for super speed companion descriptor
streaming_maxpacket - maximum packet size this endpoint is capable of
sending or receiving when this configuration is
selected
There are also "control" and "streaming" subdirectories, each of which contain
a number of their subdirectories. There are some sane defaults provided, but
the user must provide the following:
control header - create in control/header, link from control/class/fs
and/or control/class/ss
streaming header - create in streaming/header, link from
streaming/class/fs and/or streaming/class/hs and/or
streaming/class/ss
format description - create in streaming/mjpeg and/or
streaming/uncompressed
frame description - create in streaming/mjpeg/<format> and/or in
streaming/uncompressed/<format>
Each frame description contains frame interval specification, and each
such specification consists of a number of lines with an inverval value
in each line. The rules stated above are best illustrated with an example:
# mkdir functions/uvc.usb0/control/header/h
# cd functions/uvc.usb0/control/header/h
# ln -s header/h class/fs
# ln -s header/h class/ss
# mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p
# cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval
666666
1000000
5000000
EOF
# cd $GADGET_CONFIGFS_ROOT
# mkdir functions/uvc.usb0/streaming/header/h
# cd functions/uvc.usb0/streaming/header/h
# ln -s ../../uncompressed/u
# cd ../../class/fs
# ln -s ../../header/h
# cd ../../class/hs
# ln -s ../../header/h
# cd ../../class/ss
# ln -s ../../header/h
Testing the UVC function
------------------------
device: run the gadget, modprobe vivid
# uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #>
where uvc-gadget is this program:
http://git.ideasonboard.org/uvc-gadget.git
with these patches:
http://www.spinics.net/lists/linux-usb/msg99220.html
host: luvcview -f yuv

View file

@ -236,8 +236,12 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial
E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms
You must explicitly load the usbserial driver with parameters to
configure it to recognize the gadget serial device, like this:
You must load the usbserial driver and explicitly set its parameters
to configure it to recognize the gadget serial device, like this:
echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id
The legacy way is to use module parameters:
modprobe usbserial vendor=0x0525 product=0xA4A6

View file

@ -3033,7 +3033,7 @@ S: Maintained
F: drivers/platform/x86/dell-wmi.c
DESIGNWARE USB2 DRD IP DRIVER
M: Paul Zimmerman <paulz@synopsys.com>
M: John Youn <johnyoun@synopsys.com>
L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
S: Maintained

View file

@ -1608,7 +1608,7 @@ static int std_req_get_status(struct nbu2ss_udc *udc)
switch (recipient) {
case USB_RECIP_DEVICE:
if (udc->ctrl.wIndex == 0x0000) {
if (udc->self_powered)
if (udc->gadget.is_selfpowered)
status_data |= (1 << USB_DEVICE_SELF_POWERED);
if (udc->remote_wakeup)
@ -3117,7 +3117,7 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
int is_selfpowered)
{
struct nbu2ss_udc *udc;
struct nbu2ss_udc *udc;
unsigned long flags;
/* INFO("=== %s()\n", __func__); */
@ -3130,7 +3130,7 @@ static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
udc->self_powered = (is_selfpowered != 0);
pgadget->is_selfpowered = (is_selfpowered != 0);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
@ -3308,7 +3308,7 @@ static int __init nbu2ss_drv_contest_init(
spin_lock_init(&udc->lock);
udc->dev = &pdev->dev;
udc->self_powered = 1;
udc->gadget.is_selfpowered = 1;
udc->devstate = USB_STATE_NOTATTACHED;
udc->pdev = pdev;
udc->mA = 0;

View file

@ -624,7 +624,6 @@ struct nbu2ss_udc {
unsigned linux_suspended:1;
unsigned linux_resume:1;
unsigned usb_suspended:1;
unsigned self_powered:1;
unsigned remote_wakeup:1;
unsigned udc_enabled:1;

View file

@ -104,6 +104,8 @@ source "drivers/usb/dwc2/Kconfig"
source "drivers/usb/chipidea/Kconfig"
source "drivers/usb/isp1760/Kconfig"
comment "USB port drivers"
if USB

View file

@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/
obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_MON) += mon/
@ -23,7 +24,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
obj-$(CONFIG_USB_FUSBH200_HCD) += host/

View file

@ -819,8 +819,8 @@ __acquires(hwep->lock)
}
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Assume that device is bus powered for now. */
*(u16 *)req->buf = ci->remote_wakeup << 1;
*(u16 *)req->buf = (ci->remote_wakeup << 1) |
ci->gadget.is_selfpowered;
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@ -1520,6 +1520,19 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
return -ENOTSUPP;
}
static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
{
struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
struct ci_hw_ep *hwep = ci->ep0in;
unsigned long flags;
spin_lock_irqsave(hwep->lock, flags);
_gadget->is_selfpowered = (is_on != 0);
spin_unlock_irqrestore(hwep->lock, flags);
return 0;
}
/* Change Data+ pullup status
* this func is used by usb_gadget_connect/disconnet
*/
@ -1549,6 +1562,7 @@ static int ci_udc_stop(struct usb_gadget *gadget);
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci_udc_vbus_session,
.wakeup = ci_udc_wakeup,
.set_selfpowered = ci_udc_selfpowered,
.pullup = ci_udc_pullup,
.vbus_draw = ci_udc_vbus_draw,
.udc_start = ci_udc_start,

View file

@ -23,7 +23,7 @@ choice
config USB_DWC2_HOST
bool "Host only mode"
depends on USB
depends on USB=y || (USB_DWC2=m && USB)
help
The Designware USB2.0 high-speed host controller
integrated into many SoCs. Select this option if you want the
@ -42,7 +42,7 @@ config USB_DWC2_PERIPHERAL
config USB_DWC2_DUAL_ROLE
bool "Dual Role mode"
depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
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

View file

@ -462,7 +462,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
dwc2_enable_common_interrupts(hsotg);
/*
* Do device or host intialization based on mode during PCD and
* Do device or host initialization based on mode during PCD and
* HCD initialization
*/
if (dwc2_is_host_mode(hsotg)) {

View file

@ -108,7 +108,7 @@ struct s3c_hsotg_req;
* @halted: Set if the endpoint has been halted.
* @periodic: Set if this is a periodic ep, such as Interrupt
* @isochronous: Set if this is a isochronous ep
* @sent_zlp: Set if we've sent a zero-length packet.
* @send_zlp: Set if we need to send a zero-length packet.
* @total_data: The total number of data bytes done.
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
* @fifo_load: The amount of data loaded into the FIFO (periodic IN)
@ -149,7 +149,7 @@ struct s3c_hsotg_ep {
unsigned int halted:1;
unsigned int periodic:1;
unsigned int isochronous:1;
unsigned int sent_zlp:1;
unsigned int send_zlp:1;
char name[10];
};
@ -158,14 +158,12 @@ struct s3c_hsotg_ep {
* struct s3c_hsotg_req - data transfer request
* @req: The USB gadget request
* @queue: The list of requests for the endpoint this is queued for.
* @in_progress: Has already had size/packets written to core
* @mapped: DMA buffer for this request has been mapped via dma_map_single().
* @saved_req_buf: variable to save req.buf when bounce buffers are used.
*/
struct s3c_hsotg_req {
struct usb_request req;
struct list_head queue;
unsigned char in_progress;
unsigned char mapped;
void *saved_req_buf;
};
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@ -193,6 +191,22 @@ enum dwc2_lx_state {
DWC2_L3, /* Off state */
};
/*
* Gadget periodic tx fifo sizes as used by legacy driver
* EP0 is not included
*/
#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
768, 0, 0, 0, 0, 0, 0, 0}
/* Gadget ep0 states */
enum dwc2_ep0_state {
DWC2_EP0_SETUP,
DWC2_EP0_DATA_IN,
DWC2_EP0_DATA_OUT,
DWC2_EP0_STATUS_IN,
DWC2_EP0_STATUS_OUT,
};
/**
* struct dwc2_core_params - Parameters for configuring the core
*
@ -381,7 +395,7 @@ struct dwc2_core_params {
* @power_optimized Are power optimizations enabled?
* @num_dev_ep Number of device endpoints available
* @num_dev_perio_in_ep Number of device periodic IN endpoints
* avaialable
* available
* @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
* Depth
* 0 to 30
@ -434,6 +448,9 @@ struct dwc2_hw_params {
u32 snpsid;
};
/* Size of control and EP0 buffers */
#define DWC2_CTRL_BUFF_SIZE 8
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
@ -552,14 +569,20 @@ struct dwc2_hw_params {
* @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: Root directrory for debugfs.
* @debug_file: Main status file for debugfs.
* @debug_testmode: Testmode status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
* @ep0_reply: Request used for ep0 reply.
* @ep0_buff: Buffer for EP0 reply data, if needed.
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
* @setup: NAK management for EP0 SETUP
* @ep0_state: EP0 control transfers state
* @test_mode: USB test mode requested by the host
* @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
* @g_using_dma: Indicate if dma usage is enabled
* @g_rx_fifo_sz: Contains rx fifo size value
* @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
* @g_tx_fifo_sz: Contains tx fifo size value per endpoints
*/
struct dwc2_hsotg {
struct device *dev;
@ -591,6 +614,7 @@ struct dwc2_hsotg {
struct dentry *debug_root;
struct dentry *debug_file;
struct dentry *debug_testmode;
struct dentry *debug_fifo;
/* DWC OTG HW Release versions */
@ -684,15 +708,21 @@ struct dwc2_hsotg {
struct usb_request *ep0_reply;
struct usb_request *ctrl_req;
u8 ep0_buff[8];
u8 ctrl_buff[8];
void *ep0_buff;
void *ctrl_buff;
enum dwc2_ep0_state ep0_state;
u8 test_mode;
struct usb_gadget gadget;
unsigned int enabled:1;
unsigned int connected:1;
unsigned int setup:1;
unsigned long last_rst;
struct s3c_hsotg_ep *eps;
struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
u32 g_using_dma;
u32 g_rx_fifo_sz;
u32 g_np_g_tx_fifo_sz;
u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
};
@ -969,7 +999,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset);
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
#else
@ -981,7 +1012,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset) {}
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
#endif

File diff suppressed because it is too large Load diff

View file

@ -316,10 +316,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
*/
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
{
if (hsotg->lx_state == DWC2_L2)
if (hsotg->lx_state == DWC2_L2) {
hsotg->flags.b.port_suspend_change = 1;
else
usb_hcd_resume_root_hub(hsotg->priv);
} else {
hsotg->flags.b.port_l1_change = 1;
}
}
/**
@ -1371,7 +1373,7 @@ 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_init_disconnected(hsotg, false);
s3c_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
@ -1473,30 +1475,6 @@ 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)
@ -1542,7 +1520,17 @@ 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");
dwc2_port_resume(hsotg);
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);
break;
case USB_PORT_FEAT_POWER:
@ -2317,55 +2305,6 @@ 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)
{
@ -2736,9 +2675,6 @@ 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,
};
/*

View file

@ -294,6 +294,7 @@
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
#define GHWCFG4_DED_FIFO_EN (1 << 25)
#define GHWCFG4_DED_FIFO_SHIFT 25
#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
@ -541,6 +542,7 @@
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
#define DXEPINT_SETUP_RCVD (1 << 15)
#define DXEPINT_INEPNAKEFF (1 << 6)
#define DXEPINT_BACK2BACKSETUP (1 << 6)
#define DXEPINT_INTKNEPMIS (1 << 5)

View file

@ -155,6 +155,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
struct dwc2_core_params defparams;
struct dwc2_hsotg *hsotg;
struct resource *res;
struct phy *phy;
struct usb_phy *uphy;
int retval;
int irq;
@ -212,6 +214,24 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
/*
* Attempt to find a generic PHY, then look for an old style
* USB PHY
*/
phy = devm_phy_get(&dev->dev, "usb2-phy");
if (IS_ERR(phy)) {
hsotg->phy = NULL;
uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
if (IS_ERR(uphy))
hsotg->uphy = NULL;
else
hsotg->uphy = uphy;
} else {
hsotg->phy = phy;
phy_power_on(hsotg->phy);
phy_init(hsotg->phy);
}
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
retval = dwc2_gadget_init(hsotg, irq);
@ -231,8 +251,15 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
if (dwc2_is_device_mode(dwc2))
if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_suspend(dwc2);
} else {
if (dwc2->lx_state == DWC2_L0)
return 0;
phy_exit(dwc2->phy);
phy_power_off(dwc2->phy);
}
return ret;
}
@ -241,8 +268,13 @@ static int __maybe_unused dwc2_resume(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
if (dwc2_is_device_mode(dwc2))
if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_resume(dwc2);
} else {
phy_power_on(dwc2->phy);
phy_init(dwc2->phy);
}
return ret;
}

View file

@ -104,12 +104,6 @@ config USB_DWC3_DEBUG
help
Say Y here to enable debugging messages on DWC3 Driver.
config USB_DWC3_VERBOSE
bool "Enable Verbose Debugging Messages"
depends on USB_DWC3_DEBUG
help
Say Y here to enable verbose debugging messages on DWC3 Driver.
config DWC3_HOST_USB3_LPM_ENABLE
bool "Enable USB3 LPM Capability"
depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y

View file

@ -2,7 +2,6 @@
CFLAGS_trace.o := -I$(src)
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o

View file

@ -345,7 +345,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
dwc->num_in_eps, dwc->num_out_eps);
}

View file

@ -431,7 +431,6 @@ struct dwc3_event_buffer {
* @dwc: pointer to DWC controller
* @saved_state: ep state saved during hibernation
* @flags: endpoint flags (wedged, stalled, ...)
* @current_trb: index of current used trb
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
@ -464,8 +463,6 @@ struct dwc3_ep {
/* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31)
unsigned current_trb;
u8 number;
u8 type;
u8 resource_index;
@ -685,7 +682,6 @@ struct dwc3_scratchpad_array {
* @is_utmi_l1_suspend: the core asserts output signal
* 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n
* @is_selfpowered: true when we are selfpowered
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
@ -809,7 +805,6 @@ struct dwc3 {
unsigned has_hibernation:1;
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
unsigned is_selfpowered:1;
unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;

View file

@ -22,9 +22,6 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
#include "platform_data.h"
/* FIXME define these in <linux/pci_ids.h> */
@ -36,66 +33,41 @@
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
struct dwc3_pci {
struct device *dev;
struct platform_device *dwc3;
struct platform_device *usb2_phy;
struct platform_device *usb3_phy;
};
static int dwc3_pci_register_phys(struct dwc3_pci *glue)
static int dwc3_pci_quirks(struct pci_dev *pdev)
{
struct usb_phy_generic_platform_data pdata;
struct platform_device *pdev;
int ret;
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
struct dwc3_platform_data pdata;
memset(&pdata, 0x00, sizeof(pdata));
memset(&pdata, 0, sizeof(pdata));
pdev = platform_device_alloc("usb_phy_generic", 0);
if (!pdev)
return -ENOMEM;
pdata.has_lpm_erratum = true;
pdata.lpm_nyet_threshold = 0xf;
glue->usb2_phy = pdev;
pdata.type = USB_PHY_TYPE_USB2;
pdata.gpio_reset = -1;
pdata.u2exit_lfps_quirk = true;
pdata.u2ss_inp3_quirk = true;
pdata.req_p1p2p3_quirk = true;
pdata.del_p1p2p3_quirk = true;
pdata.del_phy_power_chg_quirk = true;
pdata.lfps_filter_quirk = true;
pdata.rx_detect_poll_quirk = true;
ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
if (ret)
goto err1;
pdata.tx_de_emphasis_quirk = true;
pdata.tx_de_emphasis = 1;
pdev = platform_device_alloc("usb_phy_generic", 1);
if (!pdev) {
ret = -ENOMEM;
goto err1;
/*
* FIXME these quirks should be removed when AMD NL
* taps out
*/
pdata.disable_scramble_quirk = true;
pdata.dis_u3_susphy_quirk = true;
pdata.dis_u2_susphy_quirk = true;
return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
sizeof(pdata));
}
glue->usb3_phy = pdev;
pdata.type = USB_PHY_TYPE_USB3;
ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
if (ret)
goto err2;
ret = platform_device_add(glue->usb2_phy);
if (ret)
goto err2;
ret = platform_device_add(glue->usb3_phy);
if (ret)
goto err3;
return 0;
err3:
platform_device_del(glue->usb2_phy);
err2:
platform_device_put(glue->usb3_phy);
err1:
platform_device_put(glue->usb2_phy);
return ret;
}
static int dwc3_pci_probe(struct pci_dev *pci,
@ -103,18 +75,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
{
struct resource res[2];
struct platform_device *dwc3;
struct dwc3_pci *glue;
int ret;
struct device *dev = &pci->dev;
struct dwc3_platform_data dwc3_pdata;
memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
if (!glue)
return -ENOMEM;
glue->dev = dev;
ret = pcim_enable_device(pci);
if (ret) {
@ -124,12 +86,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
pci_set_master(pci);
ret = dwc3_pci_register_phys(glue);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
return ret;
}
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
@ -147,70 +103,34 @@ static int dwc3_pci_probe(struct pci_dev *pci,
res[1].name = "dwc_usb3";
res[1].flags = IORESOURCE_IRQ;
if (pci->vendor == PCI_VENDOR_ID_AMD &&
pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
dwc3_pdata.has_lpm_erratum = true;
dwc3_pdata.lpm_nyet_threshold = 0xf;
dwc3_pdata.u2exit_lfps_quirk = true;
dwc3_pdata.u2ss_inp3_quirk = true;
dwc3_pdata.req_p1p2p3_quirk = true;
dwc3_pdata.del_p1p2p3_quirk = true;
dwc3_pdata.del_phy_power_chg_quirk = true;
dwc3_pdata.lfps_filter_quirk = true;
dwc3_pdata.rx_detect_poll_quirk = true;
dwc3_pdata.tx_de_emphasis_quirk = true;
dwc3_pdata.tx_de_emphasis = 1;
/*
* FIXME these quirks should be removed when AMD NL
* taps out
*/
dwc3_pdata.disable_scramble_quirk = true;
dwc3_pdata.dis_u3_susphy_quirk = true;
dwc3_pdata.dis_u2_susphy_quirk = true;
}
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
return ret;
}
pci_set_drvdata(pci, glue);
ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
pci_set_drvdata(pci, dwc3);
ret = dwc3_pci_quirks(pci);
if (ret)
goto err3;
goto err;
dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
dwc3->dev.dma_mask = dev->dma_mask;
dwc3->dev.dma_parms = dev->dma_parms;
dwc3->dev.parent = dev;
glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(dev, "failed to register dwc3 device\n");
goto err3;
goto err;
}
return 0;
err3:
err:
platform_device_put(dwc3);
return ret;
}
static void dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *glue = pci_get_drvdata(pci);
platform_device_unregister(glue->dwc3);
platform_device_unregister(glue->usb2_phy);
platform_device_unregister(glue->usb3_phy);
platform_device_unregister(pci_get_drvdata(pci));
}
static const struct pci_device_id dwc3_pci_id_table[] = {
@ -228,45 +148,11 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
#ifdef CONFIG_PM_SLEEP
static int dwc3_pci_suspend(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
pci_disable_device(pci);
return 0;
}
static int dwc3_pci_resume(struct device *dev)
{
struct pci_dev *pci = to_pci_dev(dev);
int ret;
ret = pci_enable_device(pci);
if (ret) {
dev_err(dev, "can't re-enable device --> %d\n", ret);
return ret;
}
pci_set_master(pci);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
};
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
.driver = {
.pm = &dwc3_pci_dev_pm_ops,
},
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");

View file

@ -344,7 +344,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
/*
* LTM will be set once we know how to set this in HW.
*/
usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
usb_status |= dwc->gadget.is_selfpowered;
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);

View file

@ -139,7 +139,8 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
udelay(5);
}
dev_vdbg(dwc->dev, "link state change request timed out\n");
dwc3_trace(trace_dwc3_gadget,
"link state change request timed out");
return -ETIMEDOUT;
}
@ -219,7 +220,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
fifo_size |= (last_fifo_depth << 16);
dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
dep->name, last_fifo_depth, fifo_size & 0xffff);
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
@ -287,7 +288,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DGCMD_STATUS(reg));
return 0;
}
@ -297,8 +299,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
* interrupt context.
*/
timeout--;
if (!timeout)
if (!timeout) {
dwc3_trace(trace_dwc3_gadget,
"Command Timed Out");
return -ETIMEDOUT;
}
udelay(1);
} while (1);
}
@ -320,7 +325,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
do {
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
if (!(reg & DWC3_DEPCMD_CMDACT)) {
dev_vdbg(dwc->dev, "Command Complete --> %d\n",
dwc3_trace(trace_dwc3_gadget,
"Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
return 0;
}
@ -330,8 +336,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
* interrupt context.
*/
timeout--;
if (!timeout)
if (!timeout) {
dwc3_trace(trace_dwc3_gadget,
"Command Timed Out");
return -ETIMEDOUT;
}
udelay(1);
} while (1);
@ -352,9 +361,6 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
if (dep->trb_pool)
return 0;
if (dep->number == 0 || dep->number == 1)
return 0;
dep->trb_pool = dma_alloc_coherent(dwc->dev,
sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
&dep->trb_pool_dma, GFP_KERNEL);
@ -492,7 +498,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
u32 reg;
int ret;
dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_start_config(dwc, dep);
@ -729,10 +735,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain, unsigned node)
{
struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
dep->name, req, (unsigned long long) dma,
length, last ? " last" : "",
chain ? " chain" : "");
@ -934,7 +939,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
u32 cmd;
if (start_new && (dep->flags & DWC3_EP_BUSY)) {
dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
return -EBUSY;
}
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
@ -1005,8 +1010,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
u32 uf;
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
dep->name);
dwc3_trace(trace_dwc3_gadget,
"ISOC ep %s run out for requests",
dep->name);
dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
}
@ -1113,15 +1119,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* handled.
*/
if (dep->stream_capable) {
int ret;
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
}
}
return 0;
@ -1152,8 +1153,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
goto out;
}
dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
request, ep->name, request->length);
trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
@ -1416,7 +1415,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->is_selfpowered = !!is_selfpowered;
g->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@ -1468,7 +1467,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
udelay(1);
} while (1);
dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
dwc->gadget_driver
? dwc->gadget_driver->function : "no-function",
is_on ? "connect" : "disconnect");
@ -1688,7 +1687,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
dep->endpoint.name = dep->name;
dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
if (epnum == 0 || epnum == 1) {
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
@ -1725,13 +1724,15 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
dwc3_trace(trace_dwc3_gadget,
"failed to allocate OUT endpoints");
return ret;
}
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
if (ret < 0) {
dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
dwc3_trace(trace_dwc3_gadget,
"failed to allocate IN endpoints");
return ret;
}
@ -1977,7 +1978,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
} else {
int ret;
dev_vdbg(dwc->dev, "%s: reason %s\n",
dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
dep->name, event->status &
DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
@ -2001,7 +2002,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
switch (event->status) {
case DEPEVT_STREAMEVT_FOUND:
dev_vdbg(dwc->dev, "Stream %d found and started\n",
dwc3_trace(trace_dwc3_gadget,
"Stream %d found and started",
event->parameters);
break;
@ -2015,7 +2017,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
break;
case DWC3_DEPEVT_EPCMDCMPLT:
dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
break;
}
}
@ -2043,6 +2045,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(&dwc->gadget);
spin_lock(&dwc->lock);
}
}
@ -2079,7 +2082,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
* We have discussed this with the IP Provider and it was
* suggested to giveback all requests here, but give HW some
* extra time to synchronize with the interconnect. We're using
* an arbitraty 100us delay for that.
* an arbitrary 100us delay for that.
*
* Note also that a similar handling was tested by Synopsys
* (thanks a lot Paul) and nothing bad has come out of it.
@ -2389,7 +2392,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
dwc3_trace(trace_dwc3_gadget,
"ignoring transition U3 -> Resume");
return;
}
}
@ -2511,22 +2515,22 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_EOPF:
dev_vdbg(dwc->dev, "End of Periodic Frame\n");
dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_SOF:
dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
dev_vdbg(dwc->dev, "Erratic Error\n");
dwc3_trace(trace_dwc3_gadget, "Erratic Error");
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
dev_vdbg(dwc->dev, "Command Complete\n");
dwc3_trace(trace_dwc3_gadget, "Command Complete");
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
dev_vdbg(dwc->dev, "Overflow\n");
dwc3_trace(trace_dwc3_gadget, "Overflow");
break;
default:
dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
}

View file

@ -47,6 +47,16 @@ DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_core,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
);
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)

View file

@ -423,6 +423,17 @@ config USB_CONFIGFS_F_HID
For more information, see Documentation/usb/gadget_hid.txt.
config USB_CONFIGFS_F_UVC
bool "USB Webcam function"
depends on USB_CONFIGFS
depends on VIDEO_DEV
select VIDEOBUF2_VMALLOC
select USB_F_UVC
help
The Webcam function acts as a composite USB Audio and Video Class
device. It provides a userspace API to process UVC control requests
and stream video data to the host.
source "drivers/usb/gadget/legacy/Kconfig"
endchoice

View file

@ -1655,7 +1655,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
* OS descriptors handling
*/
if (cdev->use_os_string && cdev->os_desc_config &&
(ctrl->bRequest & USB_TYPE_VENDOR) &&
(ctrl->bRequestType & USB_TYPE_VENDOR) &&
ctrl->bRequest == cdev->b_vendor_code) {
struct usb_request *req;
struct usb_configuration *os_desc_cfg;

View file

@ -36,7 +36,7 @@ usb_f_uac1-y := f_uac1.o u_uac1.o
obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o
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
usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.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

View file

@ -31,6 +31,7 @@
#include <linux/aio.h>
#include <linux/mmu_context.h>
#include <linux/poll.h>
#include <linux/eventfd.h>
#include "u_fs.h"
#include "u_f.h"
@ -153,6 +154,8 @@ struct ffs_io_data {
struct usb_ep *ep;
struct usb_request *req;
struct ffs_data *ffs;
};
struct ffs_desc_helper {
@ -390,17 +393,20 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
return ret;
}
/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
{
/*
* We are holding ffs->ev.waitq.lock and ffs->mutex and we need
* to release them.
* n cannot be bigger than ffs->ev.count, which cannot be bigger than
* size of ffs->ev.types array (which is four) so that's how much space
* we reserve.
*/
struct usb_functionfs_event events[n];
struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
const size_t size = n * sizeof *events;
unsigned i = 0;
memset(events, 0, sizeof events);
memset(events, 0, size);
do {
events[i].type = ffs->ev.types[i];
@ -410,19 +416,15 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
}
} while (++i < n);
if (n < ffs->ev.count) {
ffs->ev.count -= n;
ffs->ev.count -= n;
if (ffs->ev.count)
memmove(ffs->ev.types, ffs->ev.types + n,
ffs->ev.count * sizeof *ffs->ev.types);
} else {
ffs->ev.count = 0;
}
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
return unlikely(__copy_to_user(buf, events, sizeof events))
? -EFAULT : sizeof events;
return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@ -606,6 +608,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
}
case FFS_CLOSING:
break;
case FFS_DEACTIVATED:
break;
}
mutex_unlock(&ffs->mutex);
@ -673,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
aio_complete(io_data->kiocb, ret, ret);
if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
eventfd_signal(io_data->ffs->ffs_eventfd, 1);
usb_ep_free_request(io_data->ep, io_data->req);
io_data->kiocb->private = NULL;
@ -826,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
io_data->buf = data;
io_data->ep = ep->ep;
io_data->req = req;
io_data->ffs = epfile->ffs;
req->context = io_data;
req->complete = ffs_epfile_async_io_complete;
@ -1180,6 +1188,7 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
bool no_disconnect;
struct ffs_data *ffs_data;
};
@ -1250,6 +1259,12 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
/* Interpret option */
switch (eq - opts) {
case 13:
if (!memcmp(opts, "no_disconnect", 13))
data->no_disconnect = !!value;
else
goto invalid;
break;
case 5:
if (!memcmp(opts, "rmode", 5))
data->root_mode = (value & 0555) | S_IFDIR;
@ -1314,6 +1329,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
.gid = GLOBAL_ROOT_GID,
},
.root_mode = S_IFDIR | 0500,
.no_disconnect = false,
};
struct dentry *rv;
int ret;
@ -1330,6 +1346,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
if (unlikely(!ffs))
return ERR_PTR(-ENOMEM);
ffs->file_perms = data.perms;
ffs->no_disconnect = data.no_disconnect;
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
if (unlikely(!ffs->dev_name)) {
@ -1361,6 +1378,7 @@ ffs_fs_kill_sb(struct super_block *sb)
kill_litter_super(sb);
if (sb->s_fs_info) {
ffs_release_dev(sb->s_fs_info);
ffs_data_closed(sb->s_fs_info);
ffs_data_put(sb->s_fs_info);
}
}
@ -1417,7 +1435,11 @@ static void ffs_data_opened(struct ffs_data *ffs)
ENTER();
atomic_inc(&ffs->ref);
atomic_inc(&ffs->opened);
if (atomic_add_return(1, &ffs->opened) == 1 &&
ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
}
static void ffs_data_put(struct ffs_data *ffs)
@ -1439,6 +1461,21 @@ static void ffs_data_closed(struct ffs_data *ffs)
ENTER();
if (atomic_dec_and_test(&ffs->opened)) {
if (ffs->no_disconnect) {
ffs->state = FFS_DEACTIVATED;
if (ffs->epfiles) {
ffs_epfiles_destroy(ffs->epfiles,
ffs->eps_count);
ffs->epfiles = NULL;
}
if (ffs->setup_state == FFS_SETUP_PENDING)
__ffs_ep0_stall(ffs);
} else {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
}
if (atomic_read(&ffs->opened) < 0) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
@ -1480,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
if (ffs->ffs_eventfd)
eventfd_ctx_put(ffs->ffs_eventfd);
kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
@ -1581,10 +1621,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
mutex_init(&epfile->mutex);
init_waitqueue_head(&epfile->wait);
if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
sprintf(epfiles->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
sprintf(epfile->name, "ep%u", i);
epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
if (unlikely(!epfile->dentry)) {
@ -1616,7 +1656,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
kfree(epfiles);
}
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
@ -1629,10 +1668,12 @@ static void ffs_func_eps_disable(struct ffs_function *func)
/* pending requests get nuked */
if (likely(ep->ep))
usb_ep_disable(ep->ep);
epfile->ep = NULL;
++ep;
++epfile;
if (epfile) {
epfile->ep = NULL;
++epfile;
}
} while (--count);
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
}
@ -2138,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC |
FUNCTIONFS_HAS_MS_OS_DESC |
FUNCTIONFS_VIRTUAL_ADDR)) {
FUNCTIONFS_VIRTUAL_ADDR |
FUNCTIONFS_EVENTFD)) {
ret = -ENOSYS;
goto error;
}
@ -2149,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto error;
}
if (flags & FUNCTIONFS_EVENTFD) {
if (len < 4)
goto error;
ffs->ffs_eventfd =
eventfd_ctx_fdget((int)get_unaligned_le32(data));
if (IS_ERR(ffs->ffs_eventfd)) {
ret = PTR_ERR(ffs->ffs_eventfd);
ffs->ffs_eventfd = NULL;
goto error;
}
data += 4;
len -= 4;
}
/* Read fs_count, hs_count and ss_count (if present) */
for (i = 0; i < 3; ++i) {
if (!(flags & (1 << i))) {
@ -2377,6 +2433,13 @@ static void __ffs_event_add(struct ffs_data *ffs,
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELLED;
/*
* Logic of this function guarantees that there are at most four pending
* evens on ffs->ev.types queue. This is important because the queue
* has space for four elements only and __ffs_ep0_read_events function
* depends on that limit as well. If more event types are added, those
* limits have to be revisited or guaranteed to still hold.
*/
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
@ -2416,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
if (ffs->ffs_eventfd)
eventfd_signal(ffs->ffs_eventfd, 1);
}
static void ffs_event_add(struct ffs_data *ffs,
@ -2888,6 +2953,13 @@ static int ffs_func_bind(struct usb_configuration *c,
/* Other USB function hooks *************************************************/
static void ffs_reset_work(struct work_struct *work)
{
struct ffs_data *ffs = container_of(work,
struct ffs_data, reset_work);
ffs_data_reset(ffs);
}
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
@ -2904,6 +2976,13 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func)
ffs_func_eps_disable(ffs->func);
if (ffs->state == FFS_DEACTIVATED) {
ffs->state = FFS_CLOSING;
INIT_WORK(&ffs->reset_work, ffs_reset_work);
schedule_work(&ffs->reset_work);
return -ENODEV;
}
if (ffs->state != FFS_ACTIVE)
return -ENODEV;

View file

@ -759,7 +759,7 @@ static struct f_hid_opts_attribute f_hid_opts_##name = \
F_HID_OPT(subclass, 8, 255);
F_HID_OPT(protocol, 8, 255);
F_HID_OPT(report_length, 16, 65536);
F_HID_OPT(report_length, 16, 65535);
static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
{

View file

@ -1214,7 +1214,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->pattern);
result = sprintf(page, "%u", opts->pattern);
mutex_unlock(&opts->lock);
return result;
@ -1258,7 +1258,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_interval);
result = sprintf(page, "%u", opts->isoc_interval);
mutex_unlock(&opts->lock);
return result;
@ -1302,7 +1302,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_maxpacket);
result = sprintf(page, "%u", opts->isoc_maxpacket);
mutex_unlock(&opts->lock);
return result;
@ -1346,7 +1346,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_mult);
result = sprintf(page, "%u", opts->isoc_mult);
mutex_unlock(&opts->lock);
return result;
@ -1390,7 +1390,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->isoc_maxburst);
result = sprintf(page, "%u", opts->isoc_maxburst);
mutex_unlock(&opts->lock);
return result;
@ -1434,7 +1434,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->bulk_buflen);
result = sprintf(page, "%u", opts->bulk_buflen);
mutex_unlock(&opts->lock);
return result;
@ -1473,7 +1473,7 @@ static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_interval);
result = sprintf(page, "%u", opts->int_interval);
mutex_unlock(&opts->lock);
return result;
@ -1517,7 +1517,7 @@ static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_maxpacket);
result = sprintf(page, "%u", opts->int_maxpacket);
mutex_unlock(&opts->lock);
return result;
@ -1561,7 +1561,7 @@ static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_mult);
result = sprintf(page, "%u", opts->int_mult);
mutex_unlock(&opts->lock);
return result;
@ -1605,7 +1605,7 @@ static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
result = sprintf(page, "%d", opts->int_maxburst);
result = sprintf(page, "%u", opts->int_maxburst);
mutex_unlock(&opts->lock);
return result;

View file

@ -31,7 +31,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
*/
#define F_AUDIO_AC_INTERFACE 0
#define F_AUDIO_AS_INTERFACE 1
#define F_AUDIO_NUM_INTERFACES 2
#define F_AUDIO_NUM_INTERFACES 1
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc = {
@ -42,14 +42,18 @@ static struct usb_interface_descriptor ac_interface_desc = {
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
/*
* The number of AudioStreaming and MIDIStreaming interfaces
* in the Audio Interface Collection
*/
DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
/* 1 input terminal, 1 output terminal and 1 feature unit */
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct uac1_ac_header_descriptor_2 ac_header_desc = {
static struct uac1_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@ -57,8 +61,8 @@ static struct uac1_ac_header_descriptor_2 ac_header_desc = {
.wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
.bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE,
[1] = F_AUDIO_AS_INTERFACE,
/* Interface number of the first AudioStream interface */
[0] = 1,
}
};
@ -584,6 +588,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (intf == 1) {
if (alt == 1) {
config_ep_by_speed(cdev->gadget, f, out_ep);
usb_ep_enable(out_ep);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
@ -669,7 +674,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
audio->card.gadget = c->cdev->gadget;
audio_opts->card = &audio->card;
/* set up ASLA audio devices */
if (!audio_opts->bound) {
status = gaudio_setup(&audio->card);

View file

@ -27,10 +27,11 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
#include "u_uvc.h"
#include "uvc.h"
#include "uvc_configfs.h"
#include "uvc_v4l2.h"
#include "uvc_video.h"
#include "u_uvc.h"
unsigned int uvc_gadget_trace_param;
@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
break;
}
if (!uvc_control_desc || !uvc_streaming_cls)
return ERR_PTR(-ENODEV);
/* Descriptors layout
*
* uvc_iad
@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
INFO(cdev, "uvc_function_bind\n");
opts = to_f_uvc_opts(f->fi);
opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
*/
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
if (gadget_is_dualspeed(cdev->gadget))
if (IS_ERR(f->fs_descriptors)) {
ret = PTR_ERR(f->fs_descriptors);
f->fs_descriptors = NULL;
goto error;
}
if (gadget_is_dualspeed(cdev->gadget)) {
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
if (gadget_is_superspeed(c->cdev->gadget))
if (IS_ERR(f->hs_descriptors)) {
ret = PTR_ERR(f->hs_descriptors);
f->hs_descriptors = NULL;
goto error;
}
}
if (gadget_is_superspeed(c->cdev->gadget)) {
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
if (IS_ERR(f->ss_descriptors)) {
ret = PTR_ERR(f->ss_descriptors);
f->ss_descriptors = NULL;
goto error;
}
}
/* Preallocate control endpoint request. */
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@ -766,27 +787,106 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
static void uvc_free_inst(struct usb_function_instance *f)
{
struct f_uvc_opts *opts = to_f_uvc_opts(f);
struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
mutex_destroy(&opts->lock);
kfree(opts);
}
static struct usb_function_instance *uvc_alloc_inst(void)
{
struct f_uvc_opts *opts;
struct uvc_camera_terminal_descriptor *cd;
struct uvc_processing_unit_descriptor *pd;
struct uvc_output_terminal_descriptor *od;
struct uvc_color_matching_descriptor *md;
struct uvc_descriptor_header **ctl_cls;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = uvc_free_inst;
mutex_init(&opts->lock);
cd = &opts->uvc_camera_terminal;
cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3);
cd->bDescriptorType = USB_DT_CS_INTERFACE;
cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL;
cd->bTerminalID = 1;
cd->wTerminalType = cpu_to_le16(0x0201);
cd->bAssocTerminal = 0;
cd->iTerminal = 0;
cd->wObjectiveFocalLengthMin = cpu_to_le16(0);
cd->wObjectiveFocalLengthMax = cpu_to_le16(0);
cd->wOcularFocalLength = cpu_to_le16(0);
cd->bControlSize = 3;
cd->bmControls[0] = 2;
cd->bmControls[1] = 0;
cd->bmControls[2] = 0;
pd = &opts->uvc_processing;
pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2);
pd->bDescriptorType = USB_DT_CS_INTERFACE;
pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT;
pd->bUnitID = 2;
pd->bSourceID = 1;
pd->wMaxMultiplier = cpu_to_le16(16*1024);
pd->bControlSize = 2;
pd->bmControls[0] = 1;
pd->bmControls[1] = 0;
pd->iProcessing = 0;
od = &opts->uvc_output_terminal;
od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
od->bDescriptorType = USB_DT_CS_INTERFACE;
od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL;
od->bTerminalID = 3;
od->wTerminalType = cpu_to_le16(0x0101);
od->bAssocTerminal = 0;
od->bSourceID = 2;
od->iTerminal = 0;
md = &opts->uvc_color_matching;
md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
md->bDescriptorType = USB_DT_CS_INTERFACE;
md->bDescriptorSubType = UVC_VS_COLORFORMAT;
md->bColorPrimaries = 1;
md->bTransferCharacteristics = 1;
md->bMatrixCoefficients = 4;
/* Prepare fs control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_fs_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
ctl_cls[3] = (struct uvc_descriptor_header *)od;
ctl_cls[4] = NULL; /* NULL-terminate */
opts->fs_control =
(const struct uvc_descriptor_header * const *)ctl_cls;
/* Prepare hs control class descriptors for configfs-based gadgets */
ctl_cls = opts->uvc_ss_control_cls;
ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
ctl_cls[1] = (struct uvc_descriptor_header *)cd;
ctl_cls[2] = (struct uvc_descriptor_header *)pd;
ctl_cls[3] = (struct uvc_descriptor_header *)od;
ctl_cls[4] = NULL; /* NULL-terminate */
opts->ss_control =
(const struct uvc_descriptor_header * const *)ctl_cls;
opts->streaming_interval = 1;
opts->streaming_maxpacket = 1024;
uvcg_attach_configfs(opts);
return &opts->func_inst;
}
static void uvc_free(struct usb_function *f)
{
struct uvc_device *uvc = to_uvc(f);
struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
func_inst);
--opts->refcnt;
kfree(uvc);
}
@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
{
struct uvc_device *uvc;
struct f_uvc_opts *opts;
struct uvc_descriptor_header **strm_cls;
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
if (uvc == NULL)
return ERR_PTR(-ENOMEM);
uvc->state = UVC_STATE_DISCONNECTED;
opts = to_f_uvc_opts(fi);
opts = fi_to_f_uvc_opts(fi);
mutex_lock(&opts->lock);
if (opts->uvc_fs_streaming_cls) {
strm_cls = opts->uvc_fs_streaming_cls;
opts->fs_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
if (opts->uvc_hs_streaming_cls) {
strm_cls = opts->uvc_hs_streaming_cls;
opts->hs_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
if (opts->uvc_ss_streaming_cls) {
strm_cls = opts->uvc_ss_streaming_cls;
opts->ss_streaming =
(const struct uvc_descriptor_header * const *)strm_cls;
}
uvc->desc.fs_control = opts->fs_control;
uvc->desc.ss_control = opts->ss_control;
uvc->desc.fs_streaming = opts->fs_streaming;
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
++opts->refcnt;
mutex_unlock(&opts->lock);
/* Register the function. */
uvc->func.name = "uvc";

View file

@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
if (len < 18)
return -EINVAL;
snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
dev_addr[0], dev_addr[1], dev_addr[2],
dev_addr[3], dev_addr[4], dev_addr[5]);
snprintf(str, len, "%pM", dev_addr);
return 18;
}

View file

@ -19,6 +19,7 @@
#include <linux/usb/composite.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#ifdef VERBOSE_DEBUG
#ifndef pr_vdebug
@ -92,6 +93,26 @@ enum ffs_state {
*/
FFS_ACTIVE,
/*
* Function is visible to host, but it's not functional. All
* setup requests are stalled and transfers on another endpoints
* are refused. All epfiles, except ep0, are deleted so there
* is no way to perform any operations on them.
*
* This state is set after closing all functionfs files, when
* mount parameter "no_disconnect=1" has been set. Function will
* remain in deactivated state until filesystem is umounted or
* ep0 is opened again. In the second case functionfs state will
* be reset, and it will be ready for descriptors and strings
* writing.
*
* This is useful only when functionfs is composed to gadget
* with another function which can perform some critical
* operations, and it's strongly desired to have this operations
* completed, even after functionfs files closure.
*/
FFS_DEACTIVATED,
/*
* All endpoints have been closed. This state is also set if
* we encounter an unrecoverable error. The only
@ -251,6 +272,10 @@ struct ffs_data {
kgid_t gid;
} file_perms;
struct eventfd_ctx *ffs_eventfd;
bool no_disconnect;
struct work_struct reset_work;
/*
* The endpoint files, filled by ffs_epfiles_create(),
* destroyed by ffs_epfiles_destroy().

View file

@ -308,8 +308,7 @@ int gaudio_setup(struct gaudio *card)
*/
void gaudio_cleanup(struct gaudio *the_card)
{
if (the_card) {
if (the_card)
gaudio_close_snd_dev(the_card);
}
}

View file

@ -70,7 +70,6 @@ struct f_uac1_opts {
unsigned fn_play_alloc:1;
unsigned fn_cap_alloc:1;
unsigned fn_cntl_alloc:1;
struct gaudio *card;
struct mutex lock;
int refcnt;
};

View file

@ -17,8 +17,9 @@
#define U_UVC_H
#include <linux/usb/composite.h>
#include <linux/usb/video.h>
#define to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
#define fi_to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
struct f_uvc_opts {
struct usb_function_instance func_inst;
@ -26,11 +27,60 @@ struct f_uvc_opts {
unsigned int streaming_interval;
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;
/*
* Control descriptors array pointers for full-/high-speed and
* super-speed. They point by default to the uvc_fs_control_cls and
* uvc_ss_control_cls arrays respectively. Legacy gadgets must
* override them in their gadget bind callback.
*/
const struct uvc_descriptor_header * const *fs_control;
const struct uvc_descriptor_header * const *ss_control;
/*
* Streaming descriptors array pointers for full-speed, high-speed and
* super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
* for configfs-based gadgets. Legacy gadgets must initialize them in
* their gadget bind callback.
*/
const struct uvc_descriptor_header * const *fs_streaming;
const struct uvc_descriptor_header * const *hs_streaming;
const struct uvc_descriptor_header * const *ss_streaming;
/* Default control descriptors for configfs-based gadgets. */
struct uvc_camera_terminal_descriptor uvc_camera_terminal;
struct uvc_processing_unit_descriptor uvc_processing;
struct uvc_output_terminal_descriptor uvc_output_terminal;
struct uvc_color_matching_descriptor uvc_color_matching;
/*
* Control descriptors pointers arrays for full-/high-speed and
* super-speed. The first element is a configurable control header
* descriptor, the other elements point to the fixed default control
* descriptors. Used by configfs only, must not be touched by legacy
* gadgets.
*/
struct uvc_descriptor_header *uvc_fs_control_cls[5];
struct uvc_descriptor_header *uvc_ss_control_cls[5];
/*
* Streaming descriptors for full-speed, high-speed and super-speed.
* Used by configfs only, must not be touched by legacy gadgets. The
* arrays are allocated at runtime as the number of descriptors isn't
* known in advance.
*/
struct uvc_descriptor_header **uvc_fs_streaming_cls;
struct uvc_descriptor_header **uvc_hs_streaming_cls;
struct uvc_descriptor_header **uvc_ss_streaming_cls;
/*
* Read/write access to configfs attributes is handled by configfs.
*
* This lock protects the descriptors from concurrent access by
* read/write and symlink creation/removal.
*/
struct mutex lock;
int refcnt;
};
void uvc_set_trace_param(unsigned int trace);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
/*
* uvc_configfs.h
*
* Configfs support for the uvc function.
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef UVC_CONFIGFS_H
#define UVC_CONFIGFS_H
struct f_uvc_opts;
int uvcg_attach_configfs(struct f_uvc_opts *opts);
#endif /* UVC_CONFIGFS_H */

View file

@ -176,7 +176,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->enabled
? (udc->vbus ? "active" : "enabled")
: "disabled",
udc->selfpowered ? "self" : "VBUS",
udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@ -1000,7 +1000,7 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
udc->selfpowered = (is_on != 0);
gadget->is_selfpowered = (is_on != 0);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@ -1149,7 +1149,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_STATUS:
tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
PACKET("get device status\n");
@ -1653,7 +1653,7 @@ static int at91_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1;
udc->selfpowered = 1;
udc->gadget.is_selfpowered = 1;
return 0;
}

View file

@ -122,7 +122,6 @@ struct at91_udc {
unsigned req_pending:1;
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
unsigned selfpowered:1;
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;

View file

@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/clk/at91_pmc.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@ -315,6 +316,17 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
}
#endif
static inline u32 usba_int_enb_get(struct usba_udc *udc)
{
return udc->int_enb_cache;
}
static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
{
usba_writel(udc, INT_ENB, val);
udc->int_enb_cache = val;
}
static int vbus_is_present(struct usba_udc *udc)
{
if (gpio_is_valid(udc->vbus_pin))
@ -324,27 +336,22 @@ static int vbus_is_present(struct usba_udc *udc)
return 1;
}
#if defined(CONFIG_ARCH_AT91SAM9RL)
#include <linux/clk/at91_pmc.h>
static void toggle_bias(int is_on)
static void toggle_bias(struct usba_udc *udc, int is_on)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
if (is_on)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
if (udc->errata && udc->errata->toggle_bias)
udc->errata->toggle_bias(udc, is_on);
}
#else
static void toggle_bias(int is_on)
static void generate_bias_pulse(struct usba_udc *udc)
{
}
if (!udc->bias_pulse_needed)
return;
#endif /* CONFIG_ARCH_AT91SAM9RL */
if (udc->errata && udc->errata->pulse_bias)
udc->errata->pulse_bias(udc);
udc->bias_pulse_needed = false;
}
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
{
@ -601,16 +608,14 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (ep->can_dma) {
u32 ctrl;
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1 << ep->index)
| USBA_BF(DMA_INT, 1 << ep->index)));
usba_int_enb_set(udc, usba_int_enb_get(udc) |
USBA_BF(EPT_INT, 1 << ep->index) |
USBA_BF(DMA_INT, 1 << ep->index));
ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
usba_ep_writel(ep, CTL_ENB, ctrl);
} else {
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1 << ep->index)));
usba_int_enb_set(udc, usba_int_enb_get(udc) |
USBA_BF(EPT_INT, 1 << ep->index));
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -618,7 +623,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
(unsigned long)usba_ep_readl(ep, CFG));
DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
(unsigned long)usba_readl(udc, INT_ENB));
(unsigned long)usba_int_enb_get(udc));
return 0;
}
@ -654,9 +659,8 @@ static int usba_ep_disable(struct usb_ep *_ep)
usba_dma_readl(ep, STATUS);
}
usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
usba_writel(udc, INT_ENB,
usba_readl(udc, INT_ENB)
& ~USBA_BF(EPT_INT, 1 << ep->index));
usba_int_enb_set(udc, usba_int_enb_get(udc) &
~USBA_BF(EPT_INT, 1 << ep->index));
request_complete_list(ep, &req_list, -ESHUTDOWN);
@ -985,6 +989,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
struct usba_udc *udc = to_usba_udc(gadget);
unsigned long flags;
gadget->is_selfpowered = (is_selfpowered != 0);
spin_lock_irqsave(&udc->lock, flags);
if (is_selfpowered)
udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
@ -1619,18 +1624,21 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
static irqreturn_t usba_udc_irq(int irq, void *devid)
{
struct usba_udc *udc = devid;
u32 status;
u32 status, int_enb;
u32 dma_status;
u32 ep_status;
spin_lock(&udc->lock);
status = usba_readl(udc, INT_STA);
int_enb = usba_int_enb_get(udc);
status = usba_readl(udc, INT_STA) & int_enb;
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
udc->bias_pulse_needed = true;
DBG(DBG_BUS, "Suspend detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->suspend) {
@ -1641,13 +1649,15 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
}
if (status & USBA_WAKE_UP) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, INT_CLR, USBA_WAKE_UP);
usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
DBG(DBG_BUS, "Wake Up CPU detected\n");
}
if (status & USBA_END_OF_RESUME) {
usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
generate_bias_pulse(udc);
DBG(DBG_BUS, "Resume detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->resume) {
@ -1683,6 +1693,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
struct usba_ep *ep0;
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
generate_bias_pulse(udc);
reset_all_endpoints(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
@ -1708,11 +1719,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
usba_ep_writel(ep0, CTL_ENB,
USBA_EPT_ENABLE | USBA_RX_SETUP);
usba_writel(udc, INT_ENB,
(usba_readl(udc, INT_ENB)
| USBA_BF(EPT_INT, 1)
| USBA_DET_SUSPEND
| USBA_END_OF_RESUME));
usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
USBA_DET_SUSPEND | USBA_END_OF_RESUME);
/*
* Unclear why we hit this irregularly, e.g. in usbtest,
@ -1745,13 +1753,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
usba_int_enb_set(udc, USBA_END_OF_RESET);
} else {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
if (udc->driver->disconnect) {
spin_unlock(&udc->lock);
@ -1797,9 +1805,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
/* If Vbus is present, enable the controller and wait for reset */
spin_lock_irqsave(&udc->lock, flags);
if (vbus_is_present(udc) && udc->vbus_prev == 0) {
toggle_bias(1);
toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
usba_int_enb_set(udc, USBA_END_OF_RESET);
}
spin_unlock_irqrestore(&udc->lock, flags);
@ -1820,7 +1828,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
spin_unlock_irqrestore(&udc->lock, flags);
/* This will also disable the DP pullup */
toggle_bias(0);
toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(udc->hclk);
@ -1832,6 +1840,41 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
}
#ifdef CONFIG_OF
static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
if (is_on)
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
}
static void at91sam9g45_pulse_bias(struct usba_udc *udc)
{
unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
}
static const struct usba_udc_errata at91sam9rl_errata = {
.toggle_bias = at91sam9rl_toggle_bias,
};
static const struct usba_udc_errata at91sam9g45_errata = {
.pulse_bias = at91sam9g45_pulse_bias,
};
static const struct of_device_id atmel_udc_dt_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
{ .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
{ .compatible = "atmel,sama5d3-udc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
struct usba_udc *udc)
{
@ -1839,10 +1882,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
const char *name;
enum of_gpio_flags flags;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
struct device_node *pp;
int i, ret;
struct usba_ep *eps, *ep;
match = of_match_node(atmel_udc_dt_ids, np);
if (!match)
return ERR_PTR(-EINVAL);
udc->errata = match->data;
udc->num_ep = 0;
udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
@ -2033,7 +2083,7 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
return ret;
}
toggle_bias(0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(pclk);
@ -2042,6 +2092,8 @@ static int usba_udc_probe(struct platform_device *pdev)
else
udc->usba_ep = usba_udc_pdata(pdev, udc);
toggle_bias(udc, 0);
if (IS_ERR(udc->usba_ep))
return PTR_ERR(udc->usba_ep);
@ -2101,15 +2153,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
return 0;
}
#if defined(CONFIG_OF)
static const struct of_device_id atmel_udc_dt_ids[] = {
{ .compatible = "atmel,at91sam9rl-udc" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
#endif
static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {

View file

@ -304,6 +304,11 @@ struct usba_request {
unsigned int mapped:1;
};
struct usba_udc_errata {
void (*toggle_bias)(struct usba_udc *udc, int is_on);
void (*pulse_bias)(struct usba_udc *udc);
};
struct usba_udc {
/* Protect hw registers from concurrent modifications */
spinlock_t lock;
@ -314,6 +319,7 @@ struct usba_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct platform_device *pdev;
const struct usba_udc_errata *errata;
int irq;
int vbus_pin;
int vbus_pin_inverted;
@ -321,12 +327,15 @@ struct usba_udc {
struct clk *pclk;
struct clk *hclk;
struct usba_ep *usba_ep;
bool bias_pulse_needed;
u16 devstatus;
u16 test_mode;
int vbus_prev;
u32 int_enb_cache;
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
struct dentry *debugfs_regs;

View file

@ -718,7 +718,7 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
struct bdc *bdc;
int ret = 0;
if (!req || !ep || !ep->usb_ep.desc)
if (!req || !ep->usb_ep.desc)
return -EINVAL;
bdc = ep->bdc;
@ -882,8 +882,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
ret = bdc_ep_set_stall(bdc, ep->ep_num);
if (ret)
dev_err(bdc->dev, "failed to %s STALL on %s\n",
value ? "set" : "clear", ep->name);
dev_err(bdc->dev, "failed to set STALL on %s\n",
ep->name);
else
ep->flags |= BDC_EP_STALL;
} else {
@ -891,8 +891,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
dev_dbg(bdc->dev, "Before Clear\n");
ret = bdc_ep_clear_stall(bdc, ep->ep_num);
if (ret)
dev_err(bdc->dev, "failed to %s STALL on %s\n",
value ? "set" : "clear", ep->name);
dev_err(bdc->dev, "failed to clear STALL on %s\n",
ep->name);
else
ep->flags &= ~BDC_EP_STALL;
dev_dbg(bdc->dev, "After Clear\n");

View file

@ -454,6 +454,7 @@ static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
unsigned long flags;
dev_dbg(bdc->dev, "%s()\n", __func__);
gadget->is_selfpowered = (is_self != 0);
spin_lock_irqsave(&bdc->lock, flags);
if (!is_self)
bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;

View file

@ -802,6 +802,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
_gadget->is_selfpowered = (value != 0);
dum = gadget_to_dummy_hcd(_gadget)->dum;
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);

View file

@ -2630,7 +2630,7 @@ static int qe_udc_remove(struct platform_device *ofdev)
struct qe_udc *udc = platform_get_drvdata(ofdev);
struct qe_ep *ep;
unsigned int size;
DECLARE_COMPLETION(done);
DECLARE_COMPLETION_ONSTACK(done);
usb_del_gadget_udc(&udc->gadget);

View file

@ -1337,7 +1337,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Get device status */
tmp = 1 << USB_DEVICE_SELF_POWERED;
tmp = udc->gadget.is_selfpowered;
tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
/* Get interface status */
@ -1948,6 +1948,7 @@ static int fsl_udc_start(struct usb_gadget *g,
/* hook up the driver */
udc_controller->driver = driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
g->is_selfpowered = 1;
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
/* Suspend the controller until OTG enable it */
@ -2529,7 +2530,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
DECLARE_COMPLETION(done);
DECLARE_COMPLETION_ONSTACK(done);
if (!udc_controller)
return -ENODEV;

View file

@ -191,7 +191,6 @@ struct lpc32xx_udc {
bool enabled;
bool clocked;
bool suspended;
bool selfpowered;
int ep0state;
atomic_t enabled_ep_cnt;
wait_queue_head_t ep_disable_wait_queue;
@ -547,7 +546,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->vbus ? "present" : "off",
udc->enabled ? (udc->vbus ? "active" : "enabled") :
"disabled",
udc->selfpowered ? "self" : "VBUS",
udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@ -2212,7 +2211,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
break; /* Not supported */
case USB_RECIP_DEVICE:
ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
ep0buff = udc->gadget.is_selfpowered;
if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
break;
@ -2498,10 +2497,7 @@ static int lpc32xx_wakeup(struct usb_gadget *gadget)
static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
{
struct lpc32xx_udc *udc = to_udc(gadget);
/* Always self-powered */
udc->selfpowered = (is_on != 0);
gadget->is_selfpowered = (is_on != 0);
return 0;
}
@ -2946,7 +2942,7 @@ static int lpc32xx_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1;
udc->selfpowered = 1;
udc->gadget.is_selfpowered = 1;
udc->vbus = 0;
/* Force VBUS process once to check for cable insertion */

View file

@ -1378,9 +1378,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
}
}
/* pullup is always on */
mv_udc_pullup(&udc->gadget, 1);
/* When boot with cable attached, there will be no vbus irq occurred */
if (udc->qwork)
queue_work(udc->qwork, &udc->vbus_work);

View file

@ -1132,13 +1132,10 @@ net2272_wakeup(struct usb_gadget *_gadget)
static int
net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct net2272 *dev;
if (!_gadget)
return -ENODEV;
dev = container_of(_gadget, struct net2272, gadget);
dev->is_selfpowered = value;
_gadget->is_selfpowered = (value != 0);
return 0;
}
@ -1844,7 +1841,7 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
case USB_RECIP_DEVICE:
if (u.r.wLength > 2)
goto do_stall;
if (dev->is_selfpowered)
if (dev->gadget.is_selfpowered)
status = (1 << USB_DEVICE_SELF_POWERED);
/* don't bother with a request object! */

View file

@ -458,7 +458,6 @@ struct net2272 {
struct usb_gadget_driver *driver;
unsigned protocol_stall:1,
softconnect:1,
is_selfpowered:1,
wakeup:1,
dma_eot_polarity:1,
dma_dack_polarity:1,

View file

@ -12,11 +12,7 @@
* the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
* as well as Gadget Zero and Gadgetfs.
*
* DMA is enabled by default. Drivers using transfer queues might use
* DMA chaining to remove IRQ latencies between transfers. (Except when
* short OUT transfers happen.) Drivers can use the req->no_interrupt
* hint to completely eliminate some IRQs, if a later IRQ is guaranteed
* and DMA chaining is enabled.
* DMA is enabled by default.
*
* MSI is enabled by default. The legacy IRQ is used if MSI couldn't
* be enabled.
@ -84,23 +80,6 @@ static const char *const ep_name[] = {
"ep-e", "ep-f", "ep-g", "ep-h",
};
/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
* use_dma_chaining -- dma descriptor queueing gives even more irq reduction
*
* The net2280 DMA engines are not tightly integrated with their FIFOs;
* not all cases are (yet) handled well in this driver or the silicon.
* Some gadget drivers work better with the dma support here than others.
* These two parameters let you use PIO or more aggressive DMA.
*/
static bool use_dma = true;
static bool use_dma_chaining;
static bool use_msi = true;
/* "modprobe net2280 use_dma=n" etc */
module_param(use_dma, bool, 0444);
module_param(use_dma_chaining, bool, 0444);
module_param(use_msi, bool, 0444);
/* mode 0 == ep-{a,b,c,d} 1K fifo each
* mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
* mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
@ -120,11 +99,6 @@ static bool enable_suspend;
/* "modprobe net2280 enable_suspend=1" etc */
module_param(enable_suspend, bool, 0444);
/* force full-speed operation */
static bool full_speed;
module_param(full_speed, bool, 0444);
MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
static char *type_string(u8 bmAttributes)
@ -202,15 +176,6 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* set speed-dependent max packet; may kick in high bandwidth */
set_max_speed(ep, max);
/* FIFO lines can't go to different packets. PIO is ok, so
* use it instead of troublesome (non-bulk) multi-packet DMA.
*/
if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
ep->ep.name, ep->ep.maxpacket);
ep->dma = NULL;
}
/* set type, direction, address; reset fifo counters */
writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
@ -478,7 +443,7 @@ static int net2280_disable(struct usb_ep *_ep)
/* synch memory views with the device */
(void)readl(&ep->cfg->ep_cfg);
if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
if (!ep->dma && ep->num >= 1 && ep->num <= 4)
ep->dma = &ep->dev->dma[ep->num - 1];
spin_unlock_irqrestore(&ep->dev->lock, flags);
@ -610,9 +575,15 @@ static void out_flush(struct net2280_ep *ep)
u32 __iomem *statp;
u32 tmp;
ASSERT_OUT_NAKING(ep);
statp = &ep->regs->ep_stat;
tmp = readl(statp);
if (tmp & BIT(NAK_OUT_PACKETS)) {
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
ep->ep.name, __func__, tmp);
writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
}
writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
BIT(DATA_PACKET_RECEIVED_INTERRUPT),
statp);
@ -747,8 +718,7 @@ static void fill_dma_desc(struct net2280_ep *ep,
req->valid = valid;
if (valid)
dmacount |= BIT(VALID_BIT);
if (likely(!req->req.no_interrupt || !use_dma_chaining))
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
/* td->dmadesc = previously set by caller */
td->dmaaddr = cpu_to_le32 (req->req.dma);
@ -862,27 +832,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
req->td->dmadesc = cpu_to_le32 (ep->td_dma);
fill_dma_desc(ep, req, 1);
if (!use_dma_chaining)
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
start_queue(ep, tmp, req->td_dma);
}
static inline void resume_dma(struct net2280_ep *ep)
{
writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
ep->dma_started = true;
}
static inline void ep_stop_dma(struct net2280_ep *ep)
{
writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
spin_stop_dma(ep->dma);
ep->dma_started = false;
}
static inline void
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
{
@ -973,10 +927,8 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return ret;
}
#if 0
ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
_ep->name, _req, _req->length, _req->buf);
#endif
spin_lock_irqsave(&dev->lock, flags);
@ -984,24 +936,12 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
_req->actual = 0;
/* kickstart this i/o queue? */
if (list_empty(&ep->queue) && !ep->stopped) {
/* DMA request while EP halted */
if (ep->dma &&
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
(dev->quirks & PLX_SUPERSPEED)) {
int valid = 1;
if (ep->is_in) {
int expect;
expect = likely(req->req.zero ||
((req->req.length %
ep->ep.maxpacket) != 0));
if (expect != ep->in_fifo_validate)
valid = 0;
}
queue_dma(ep, req, valid);
}
if (list_empty(&ep->queue) && !ep->stopped &&
!((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
(readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
/* use DMA if the endpoint supports it, else pio */
else if (ep->dma)
if (ep->dma)
start_dma(ep, req);
else {
/* maybe there's no control data, just status ack */
@ -1084,8 +1024,6 @@ dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount,
done(ep, req, status);
}
static void restart_dma(struct net2280_ep *ep);
static void scan_dma_completions(struct net2280_ep *ep)
{
/* only look at descriptors that were "naturally" retired,
@ -1117,9 +1055,8 @@ static void scan_dma_completions(struct net2280_ep *ep)
dma_done(ep, req, tmp, 0);
break;
} else if (!ep->is_in &&
(req->req.length % ep->ep.maxpacket) != 0) {
if (ep->dev->quirks & PLX_SUPERSPEED)
return dma_done(ep, req, tmp, 0);
(req->req.length % ep->ep.maxpacket) &&
!(ep->dev->quirks & PLX_SUPERSPEED)) {
tmp = readl(&ep->regs->ep_stat);
/* AVOID TROUBLE HERE by not issuing short reads from
@ -1150,67 +1087,15 @@ static void scan_dma_completions(struct net2280_ep *ep)
static void restart_dma(struct net2280_ep *ep)
{
struct net2280_request *req;
u32 dmactl = dmactl_default;
if (ep->stopped)
return;
req = list_entry(ep->queue.next, struct net2280_request, queue);
if (!use_dma_chaining) {
start_dma(ep, req);
return;
}
/* the 2280 will be processing the queue unless queue hiccups after
* the previous transfer:
* IN: wanted automagic zlp, head doesn't (or vice versa)
* DMA_FIFO_VALIDATE doesn't init from dma descriptors.
* OUT: was "usb-short", we must restart.
*/
if (ep->is_in && !req->valid) {
struct net2280_request *entry, *prev = NULL;
int reqmode, done = 0;
ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
ep->in_fifo_validate = likely(req->req.zero ||
(req->req.length % ep->ep.maxpacket) != 0);
if (ep->in_fifo_validate)
dmactl |= BIT(DMA_FIFO_VALIDATE);
list_for_each_entry(entry, &ep->queue, queue) {
__le32 dmacount;
if (entry == req)
continue;
dmacount = entry->td->dmacount;
if (!done) {
reqmode = likely(entry->req.zero ||
(entry->req.length % ep->ep.maxpacket));
if (reqmode == ep->in_fifo_validate) {
entry->valid = 1;
dmacount |= valid_bit;
entry->td->dmacount = dmacount;
prev = entry;
continue;
} else {
/* force a hiccup */
prev->td->dmacount |= dma_done_ie;
done = 1;
}
}
/* walk the rest of the queue so unlinks behave */
entry->valid = 0;
dmacount &= ~valid_bit;
entry->td->dmacount = dmacount;
prev = entry;
}
}
writel(0, &ep->dma->dmactl);
start_queue(ep, dmactl, req->td_dma);
start_dma(ep, req);
}
static void abort_dma_228x(struct net2280_ep *ep)
static void abort_dma(struct net2280_ep *ep)
{
/* abort the current transfer */
if (likely(!list_empty(&ep->queue))) {
@ -1222,19 +1107,6 @@ static void abort_dma_228x(struct net2280_ep *ep)
scan_dma_completions(ep);
}
static void abort_dma_338x(struct net2280_ep *ep)
{
writel(BIT(DMA_ABORT), &ep->dma->dmastat);
spin_stop_dma(ep->dma);
}
static void abort_dma(struct net2280_ep *ep)
{
if (ep->dev->quirks & PLX_LEGACY)
return abort_dma_228x(ep);
return abort_dma_338x(ep);
}
/* dequeue ALL requests */
static void nuke(struct net2280_ep *ep)
{
@ -1306,25 +1178,6 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req)
done(ep, req, -ECONNRESET);
}
req = NULL;
/* patch up hardware chaining data */
} else if (ep->dma && use_dma_chaining) {
if (req->queue.prev == ep->queue.next) {
writel(le32_to_cpu(req->td->dmadesc),
&ep->dma->dmadesc);
if (req->td->dmacount & dma_done_ie)
writel(readl(&ep->dma->dmacount) |
le32_to_cpu(dma_done_ie),
&ep->dma->dmacount);
} else {
struct net2280_request *prev;
prev = list_entry(req->queue.prev,
struct net2280_request, queue);
prev->td->dmadesc = req->td->dmadesc;
if (req->td->dmacount & dma_done_ie)
prev->td->dmacount |= dma_done_ie;
}
}
if (req)
@ -1512,10 +1365,10 @@ static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value)
tmp = readl(&dev->usb->usbctl);
if (value) {
tmp |= BIT(SELF_POWERED_STATUS);
dev->selfpowered = 1;
_gadget->is_selfpowered = 1;
} else {
tmp &= ~BIT(SELF_POWERED_STATUS);
dev->selfpowered = 0;
_gadget->is_selfpowered = 0;
}
writel(tmp, &dev->usb->usbctl);
spin_unlock_irqrestore(&dev->lock, flags);
@ -1604,14 +1457,11 @@ static ssize_t registers_show(struct device *_dev,
/* Main Control Registers */
t = scnprintf(next, size, "%s version " DRIVER_VERSION
", chiprev %04x, dma %s\n\n"
", chiprev %04x\n\n"
"devinit %03x fifoctl %08x gadget '%s'\n"
"pci irqenb0 %02x irqenb1 %08x "
"irqstat0 %04x irqstat1 %08x\n",
driver_name, dev->chiprev,
use_dma
? (use_dma_chaining ? "chaining" : "enabled")
: "disabled",
readl(&dev->regs->devinit),
readl(&dev->regs->fifoctl),
s,
@ -1913,76 +1763,73 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
static void defect7374_enable_data_eps_zero(struct net2280 *dev)
{
u32 tmp = 0, tmp_reg;
u32 fsmvalue, scratch;
u32 scratch;
int i;
unsigned char ep_sel;
scratch = get_idx_reg(dev->regs, SCRATCH);
fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
== DEFECT7374_FSM_SS_CONTROL_READ);
scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
/*See if firmware needs to set up for workaround*/
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
ep_warn(dev, "Operate Defect 7374 workaround soft this time");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
/*GPEPs:*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
((dev->enhanced_mode) ?
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
BIT(IN_ENDPOINT_ENABLE));
/*GPEPs:*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
(2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
((dev->enhanced_mode) ?
BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
BIT(IN_ENDPOINT_ENABLE));
for (i = 1; i < 5; i++)
writel(tmp, &dev->ep[i].cfg->ep_cfg);
for (i = 1; i < 5; i++)
writel(tmp, &dev->ep[i].cfg->ep_cfg);
/* CSRIN, PCIIN, STATIN, RCIN*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
writel(tmp, &dev->dep[1].dep_cfg);
writel(tmp, &dev->dep[3].dep_cfg);
writel(tmp, &dev->dep[4].dep_cfg);
writel(tmp, &dev->dep[5].dep_cfg);
/* CSRIN, PCIIN, STATIN, RCIN*/
tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
writel(tmp, &dev->dep[1].dep_cfg);
writel(tmp, &dev->dep[3].dep_cfg);
writel(tmp, &dev->dep[4].dep_cfg);
writel(tmp, &dev->dep[5].dep_cfg);
/*Implemented for development and debug.
* Can be refined/tuned later.*/
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
/* Select an endpoint for subsequent operations: */
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
writel(((tmp_reg & ~0x1f) | ep_sel),
&dev->plregs->pl_ep_ctrl);
/*Implemented for development and debug.
* Can be refined/tuned later.*/
for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
/* Select an endpoint for subsequent operations: */
tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
writel(((tmp_reg & ~0x1f) | ep_sel),
&dev->plregs->pl_ep_ctrl);
if (ep_sel == 1) {
tmp =
(readl(&dev->plregs->pl_ep_ctrl) |
BIT(CLEAR_ACK_ERROR_CODE) | 0);
writel(tmp, &dev->plregs->pl_ep_ctrl);
continue;
}
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
ep_sel == 18 || ep_sel == 20)
continue;
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
writel(tmp, &dev->plregs->pl_ep_cfg_4);
tmp = readl(&dev->plregs->pl_ep_ctrl) &
~BIT(EP_INITIALIZED);
if (ep_sel == 1) {
tmp =
(readl(&dev->plregs->pl_ep_ctrl) |
BIT(CLEAR_ACK_ERROR_CODE) | 0);
writel(tmp, &dev->plregs->pl_ep_ctrl);
continue;
}
/* Set FSM to focus on the first Control Read:
* - Tip: Connection speed is known upon the first
* setup request.*/
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
set_idx_reg(dev->regs, SCRATCH, scratch);
if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
ep_sel == 18 || ep_sel == 20)
continue;
tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
writel(tmp, &dev->plregs->pl_ep_cfg_4);
tmp = readl(&dev->plregs->pl_ep_ctrl) &
~BIT(EP_INITIALIZED);
writel(tmp, &dev->plregs->pl_ep_ctrl);
} else{
ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
ep_warn(dev, "It will operate on cold-reboot and SS connect");
}
/* Set FSM to focus on the first Control Read:
* - Tip: Connection speed is known upon the first
* setup request.*/
scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
set_idx_reg(dev->regs, SCRATCH, scratch);
}
/* keeping it simple:
@ -2033,21 +1880,13 @@ static void usb_reset_228x(struct net2280 *dev)
static void usb_reset_338x(struct net2280 *dev)
{
u32 tmp;
u32 fsmvalue;
dev->gadget.speed = USB_SPEED_UNKNOWN;
(void)readl(&dev->usb->usbctl);
net2280_led_init(dev);
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if firmware needs to set up for workaround: */
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
fsmvalue);
} else {
if (dev->bug7734_patched) {
/* disable automatic responses, and irqs */
writel(0, &dev->usb->stdrsp);
writel(0, &dev->regs->pciirqenb0);
@ -2064,7 +1903,7 @@ static void usb_reset_338x(struct net2280 *dev)
writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
if (dev->bug7734_patched) {
/* reset, and enable pci */
tmp = readl(&dev->regs->devinit) |
BIT(PCI_ENABLE) |
@ -2093,10 +1932,6 @@ static void usb_reset(struct net2280 *dev)
static void usb_reinit_228x(struct net2280 *dev)
{
u32 tmp;
int init_dma;
/* use_dma changes are ignored till next device re-init */
init_dma = use_dma;
/* basic endpoint init */
for (tmp = 0; tmp < 7; tmp++) {
@ -2108,8 +1943,7 @@ static void usb_reinit_228x(struct net2280 *dev)
if (tmp > 0 && tmp <= 4) {
ep->fifo_size = 1024;
if (init_dma)
ep->dma = &dev->dma[tmp - 1];
ep->dma = &dev->dma[tmp - 1];
} else
ep->fifo_size = 64;
ep->regs = &dev->epregs[tmp];
@ -2133,17 +1967,12 @@ static void usb_reinit_228x(struct net2280 *dev)
static void usb_reinit_338x(struct net2280 *dev)
{
int init_dma;
int i;
u32 tmp, val;
u32 fsmvalue;
static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
0x00, 0xC0, 0x00, 0xC0 };
/* use_dma changes are ignored till next device re-init */
init_dma = use_dma;
/* basic endpoint init */
for (i = 0; i < dev->n_ep; i++) {
struct net2280_ep *ep = &dev->ep[i];
@ -2152,7 +1981,7 @@ static void usb_reinit_338x(struct net2280 *dev)
ep->dev = dev;
ep->num = i;
if (i > 0 && i <= 4 && init_dma)
if (i > 0 && i <= 4)
ep->dma = &dev->dma[i - 1];
if (dev->enhanced_mode) {
@ -2177,14 +2006,7 @@ static void usb_reinit_338x(struct net2280 *dev)
dev->ep[0].stopped = 0;
/* Link layer set up */
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if driver needs to set up for workaround: */
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
__func__, fsmvalue);
else {
if (dev->bug7734_patched) {
tmp = readl(&dev->usb_ext->usbctl2) &
~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
writel(tmp, &dev->usb_ext->usbctl2);
@ -2291,15 +2113,8 @@ static void ep0_start_228x(struct net2280 *dev)
static void ep0_start_338x(struct net2280 *dev)
{
u32 fsmvalue;
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
fsmvalue);
else
if (dev->bug7734_patched)
writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
BIT(SET_EP_HIDE_STATUS_PHASE),
&dev->epregs[0].ep_rsp);
@ -2382,16 +2197,12 @@ static int net2280_start(struct usb_gadget *_gadget,
if (retval)
goto err_func;
/* Enable force-full-speed testing mode, if desired */
if (full_speed && (dev->quirks & PLX_LEGACY))
writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
/* ... then enable host detection and ep0; and we're ready
/* enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
*/
net2280_led_active(dev, 1);
if (dev->quirks & PLX_SUPERSPEED)
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_enable_data_eps_zero(dev);
ep0_start(dev);
@ -2444,10 +2255,6 @@ static int net2280_stop(struct usb_gadget *_gadget)
net2280_led_active(dev, 0);
/* Disable full-speed test mode */
if (dev->quirks & PLX_LEGACY)
writel(0, &dev->usb->xcvrdiag);
device_remove_file(&dev->pdev->dev, &dev_attr_function);
device_remove_file(&dev->pdev->dev, &dev_attr_queues);
@ -2478,10 +2285,10 @@ static void handle_ep_small(struct net2280_ep *ep)
/* ack all, and handle what we care about */
t = readl(&ep->regs->ep_stat);
ep->irqs++;
#if 0
ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
ep->ep.name, t, req ? &req->req : 0);
#endif
ep->ep.name, t, req ? &req->req : NULL);
if (!ep->is_in || (ep->dev->quirks & PLX_2280))
writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
else
@ -2717,6 +2524,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
* run after the next USB connection.
*/
scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
dev->bug7734_patched = 1;
goto restore_data_eps;
}
@ -2730,6 +2538,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
dev->bug7734_patched = 1;
break;
}
@ -2766,80 +2575,19 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
return;
}
static void ep_stall(struct net2280_ep *ep, int stall)
static void ep_clear_seqnum(struct net2280_ep *ep)
{
struct net2280 *dev = ep->dev;
u32 val;
static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
if (stall) {
writel(BIT(SET_ENDPOINT_HALT) |
/* BIT(SET_NAK_PACKETS) | */
BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
&ep->regs->ep_rsp);
ep->is_halt = 1;
} else {
if (dev->gadget.speed == USB_SPEED_SUPER) {
/*
* Workaround for SS SeqNum not cleared via
* Endpoint Halt (Clear) bit. select endpoint
*/
val = readl(&dev->plregs->pl_ep_ctrl);
val = (val & ~0x1f) | ep_pl[ep->num];
writel(val, &dev->plregs->pl_ep_ctrl);
val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
val |= ep_pl[ep->num];
writel(val, &dev->plregs->pl_ep_ctrl);
val |= BIT(SEQUENCE_NUMBER_RESET);
writel(val, &dev->plregs->pl_ep_ctrl);
val |= BIT(SEQUENCE_NUMBER_RESET);
writel(val, &dev->plregs->pl_ep_ctrl);
}
val = readl(&ep->regs->ep_rsp);
val |= BIT(CLEAR_ENDPOINT_HALT) |
BIT(CLEAR_ENDPOINT_TOGGLE);
writel(val,
/* | BIT(CLEAR_NAK_PACKETS),*/
&ep->regs->ep_rsp);
ep->is_halt = 0;
val = readl(&ep->regs->ep_rsp);
}
}
static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
{
/* set/clear, then synch memory views with the device */
if (value) {
ep->stopped = 1;
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else {
if (ep->dma)
ep_stop_dma(ep);
ep_stall(ep, true);
}
if (wedged)
ep->wedged = 1;
} else {
ep->stopped = 0;
ep->wedged = 0;
ep_stall(ep, false);
/* Flush the queue */
if (!list_empty(&ep->queue)) {
struct net2280_request *req =
list_entry(ep->queue.next, struct net2280_request,
queue);
if (ep->dma)
resume_dma(ep);
else {
if (ep->is_in)
write_fifo(ep, &req->req);
else {
if (read_fifo(ep, req))
done(ep, req, 0);
}
}
}
}
return;
}
static void handle_stat0_irqs_superspeed(struct net2280 *dev,
@ -2863,7 +2611,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
switch (r.bRequestType) {
case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
status = dev->wakeup_enable ? 0x02 : 0x00;
if (dev->selfpowered)
if (dev->gadget.is_selfpowered)
status |= BIT(0);
status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
dev->ltm_enable << 4);
@ -2940,7 +2688,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
if (w_value != USB_ENDPOINT_HALT)
goto do_stall3;
ep_vdbg(dev, "%s clear halt\n", e->ep.name);
ep_stall(e, false);
/*
* Workaround for SS SeqNum not cleared via
* Endpoint Halt (Clear) bit. select endpoint
*/
ep_clear_seqnum(e);
clear_halt(e);
if (!list_empty(&e->queue) && e->td_dma)
restart_dma(e);
allow_status(ep);
@ -2998,7 +2751,14 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
e = get_ep_by_addr(dev, w_index);
if (!e || (w_value != USB_ENDPOINT_HALT))
goto do_stall3;
ep_stdrsp(e, true, false);
ep->stopped = 1;
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else {
if (ep->dma)
abort_dma(ep);
set_halt(ep);
}
allow_status_338x(ep);
break;
@ -3026,7 +2786,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
r.bRequestType, r.bRequest, tmp);
dev->protocol_stall = 1;
/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
ep_stall(ep, true);
set_halt(ep);
}
next_endpoints3:
@ -3091,9 +2851,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
}
ep->stopped = 0;
dev->protocol_stall = 0;
if (dev->quirks & PLX_SUPERSPEED)
ep->is_halt = 0;
else{
if (!(dev->quirks & PLX_SUPERSPEED)) {
if (ep->dev->quirks & PLX_2280)
tmp = BIT(FIFO_OVERFLOW) |
BIT(FIFO_UNDERFLOW);
@ -3120,7 +2878,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
cpu_to_le32s(&u.raw[0]);
cpu_to_le32s(&u.raw[1]);
if (dev->quirks & PLX_SUPERSPEED)
if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_workaround(dev, u.r);
tmp = 0;
@ -3423,17 +3181,12 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
continue;
}
/* chaining should stop on abort, short OUT from fifo,
* or (stat0 codepath) short OUT transfer.
*/
if (!use_dma_chaining) {
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
ep_dbg(ep->dev, "%s no xact done? %08x\n",
ep->ep.name, tmp);
continue;
}
stop_dma(ep->dma);
if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
ep_dbg(ep->dev, "%s no xact done? %08x\n",
ep->ep.name, tmp);
continue;
}
stop_dma(ep->dma);
/* OUT transfers terminate when the data from the
* host is in our memory. Process whatever's done.
@ -3448,30 +3201,9 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
scan_dma_completions(ep);
/* disable dma on inactive queues; else maybe restart */
if (list_empty(&ep->queue)) {
if (use_dma_chaining)
stop_dma(ep->dma);
} else {
if (!list_empty(&ep->queue)) {
tmp = readl(&dma->dmactl);
if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
restart_dma(ep);
else if (ep->is_in && use_dma_chaining) {
struct net2280_request *req;
__le32 dmacount;
/* the descriptor at the head of the chain
* may still have VALID_BIT clear; that's
* used to trigger changing DMA_FIFO_VALIDATE
* (affects automagic zlp writes).
*/
req = list_entry(ep->queue.next,
struct net2280_request, queue);
dmacount = req->td->dmacount;
dmacount &= cpu_to_le32(BIT(VALID_BIT) |
DMA_BYTE_COUNT_MASK);
if (dmacount && (dmacount & valid_bit) == 0)
restart_dma(ep);
}
restart_dma(ep);
}
ep->irqs++;
}
@ -3556,7 +3288,7 @@ static void net2280_remove(struct pci_dev *pdev)
}
if (dev->got_irq)
free_irq(pdev->irq, dev);
if (use_msi && dev->quirks & PLX_SUPERSPEED)
if (dev->quirks & PLX_SUPERSPEED)
pci_disable_msi(pdev);
if (dev->regs)
iounmap(dev->regs);
@ -3581,9 +3313,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
void __iomem *base = NULL;
int retval, i;
if (!use_dma)
use_dma_chaining = 0;
/* alloc, and start init */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
@ -3663,9 +3392,12 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if firmware needs to set up for workaround: */
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
dev->bug7734_patched = 1;
writel(0, &dev->usb->usbctl);
} else{
} else
dev->bug7734_patched = 0;
} else {
dev->enhanced_mode = 0;
dev->n_ep = 7;
/* put into initial config, link up all endpoints */
@ -3682,7 +3414,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
if (use_msi && (dev->quirks & PLX_SUPERSPEED))
if (dev->quirks & PLX_SUPERSPEED)
if (pci_enable_msi(pdev))
ep_err(dev, "Failed to enable MSI mode\n");
@ -3741,9 +3473,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ep_info(dev, "%s\n", driver_desc);
ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
pdev->irq, base, dev->chiprev);
ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
use_dma ? (use_dma_chaining ? "chaining" : "enabled")
: "disabled",
ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
dev->enhanced_mode ? "enhanced mode" : "legacy mode");
retval = device_create_file(&pdev->dev, &dev_attr_registers);
if (retval)
@ -3776,9 +3506,6 @@ static void net2280_shutdown(struct pci_dev *pdev)
/* disable the pullup so the host will think we're gone */
writel(0, &dev->usb->usbctl);
/* Disable full-speed test mode */
if (dev->quirks & PLX_LEGACY)
writel(0, &dev->usb->xcvrdiag);
}

View file

@ -100,7 +100,6 @@ struct net2280_ep {
dma_addr_t td_dma; /* of dummy */
struct net2280 *dev;
unsigned long irqs;
unsigned is_halt:1, dma_started:1;
/* analogous to a host-side qh */
struct list_head queue;
@ -126,7 +125,7 @@ static inline void allow_status(struct net2280_ep *ep)
ep->stopped = 1;
}
static void allow_status_338x(struct net2280_ep *ep)
static inline void allow_status_338x(struct net2280_ep *ep)
{
/*
* Control Status Phase Handshake was set by the chip when the setup
@ -165,8 +164,8 @@ struct net2280 {
u2_enable:1,
ltm_enable:1,
wakeup_enable:1,
selfpowered:1,
addressed_state:1;
addressed_state:1,
bug7734_patched:1;
u16 chiprev;
int enhanced_mode;
int n_ep;
@ -356,23 +355,6 @@ static inline void start_out_naking(struct net2280_ep *ep)
readl(&ep->regs->ep_rsp);
}
#ifdef DEBUG
static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
{
u32 tmp = readl(&ep->regs->ep_stat);
if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
ep_dbg(ep->dev, "%s %s %08x !NAK\n",
ep->ep.name, where, tmp);
writel(BIT(SET_NAK_OUT_PACKETS),
&ep->regs->ep_rsp);
}
}
#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
#else
#define ASSERT_OUT_NAKING(ep) do {} while (0)
#endif
static inline void stop_out_naking(struct net2280_ep *ep)
{
u32 tmp;

View file

@ -1171,6 +1171,7 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
unsigned long flags;
u16 syscon1;
gadget->is_selfpowered = (is_selfpowered != 0);
udc = container_of(gadget, struct omap_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
syscon1 = omap_readw(UDC_SYSCON1);

View file

@ -1161,6 +1161,7 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
if (!gadget)
return -EINVAL;
gadget->is_selfpowered = (value != 0);
dev = container_of(gadget, struct pch_udc_dev, gadget);
if (value)
pch_udc_set_selfpowered(dev);

View file

@ -1272,7 +1272,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
goto bind_fail;
}
pullup(dev);
dump_state(dev);
return 0;
bind_fail:
@ -1339,7 +1338,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g)
local_irq_disable();
dev->pullup = 0;
pullup(dev);
stop_activity(dev, NULL);
local_irq_enable();

View file

@ -1809,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
udc->driver = driver;
dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) {
retval = otg_set_peripheral(udc->transceiver->otg,
@ -1862,7 +1861,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
stop_activity(udc, NULL);
udc_disable(udc);
dplus_pullup(udc, 0);
udc->driver = NULL;

View file

@ -1803,6 +1803,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
{
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
gadget->is_selfpowered = (is_self != 0);
if (is_self)
r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
else

View file

@ -238,14 +238,6 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
S3C2410_UDC_EP0_CSR_REG);
}
static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
{
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
| S3C2410_UDC_EP0_CSR_SSE),
S3C2410_UDC_EP0_CSR_REG);
}
static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
{
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
@ -291,18 +283,6 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
}
}
static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
{
unsigned i;
/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
* fifos, and pending transactions mustn't be continued in any case.
*/
for (i = 1; i < S3C2410_ENDPOINTS; i++)
s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
}
static inline int s3c2410_udc_fifo_count_out(void)
{
int tmp;
@ -1454,6 +1434,7 @@ static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
gadget->is_selfpowered = (value != 0);
if (value)
udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else

View file

@ -564,6 +564,7 @@ static USB_UDC_ATTR(is_a_peripheral);
static USB_UDC_ATTR(b_hnp_enable);
static USB_UDC_ATTR(a_hnp_support);
static USB_UDC_ATTR(a_alt_hnp_support);
static USB_UDC_ATTR(is_selfpowered);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
@ -577,6 +578,7 @@ static struct attribute *usb_udc_attrs[] = {
&dev_attr_b_hnp_enable.attr,
&dev_attr_a_hnp_support.attr,
&dev_attr_a_alt_hnp_support.attr,
&dev_attr_is_selfpowered.attr,
NULL,
};

View file

@ -331,20 +331,6 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
config USB_ISP1760_HCD
tristate "ISP 1760 HCD support"
---help---
The ISP1760 chip is a USB 2.0 host controller.
This driver does not support isochronous transfers or OTG.
This USB controller is usually attached to a non-DMA-Master
capable bus. NXP's eval kit brings this chip on PCI card
where the chip itself is behind a PLB to simulate such
a bus.
To compile this driver as a module, choose M here: the
module will be called isp1760.
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
---help---

View file

@ -5,8 +5,6 @@
# tell define_trace.h where to find the xhci trace header
CFLAGS_xhci-trace.o := -I$(src)
isp1760-y := isp1760-hcd.o isp1760-if.o
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
@ -69,7 +67,6 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o

View file

@ -1,208 +0,0 @@
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
/* exports for if */
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags);
int init_kmem_once(void);
void deinit_kmem_cache(void);
/* EHCI capability registers */
#define HC_CAPLENGTH 0x00
#define HC_HCSPARAMS 0x04
#define HC_HCCPARAMS 0x08
/* EHCI operational registers */
#define HC_USBCMD 0x20
#define HC_USBSTS 0x24
#define HC_FRINDEX 0x2c
#define HC_CONFIGFLAG 0x60
#define HC_PORTSC1 0x64
#define HC_ISO_PTD_DONEMAP_REG 0x130
#define HC_ISO_PTD_SKIPMAP_REG 0x134
#define HC_ISO_PTD_LASTPTD_REG 0x138
#define HC_INT_PTD_DONEMAP_REG 0x140
#define HC_INT_PTD_SKIPMAP_REG 0x144
#define HC_INT_PTD_LASTPTD_REG 0x148
#define HC_ATL_PTD_DONEMAP_REG 0x150
#define HC_ATL_PTD_SKIPMAP_REG 0x154
#define HC_ATL_PTD_LASTPTD_REG 0x158
/* Configuration Register */
#define HC_HW_MODE_CTRL 0x300
#define ALL_ATX_RESET (1 << 31)
#define HW_ANA_DIGI_OC (1 << 15)
#define HW_DATA_BUS_32BIT (1 << 8)
#define HW_DACK_POL_HIGH (1 << 6)
#define HW_DREQ_POL_HIGH (1 << 5)
#define HW_INTR_HIGH_ACT (1 << 2)
#define HW_INTR_EDGE_TRIG (1 << 1)
#define HW_GLOBAL_INTR_EN (1 << 0)
#define HC_CHIP_ID_REG 0x304
#define HC_SCRATCH_REG 0x308
#define HC_RESET_REG 0x30c
#define SW_RESET_RESET_HC (1 << 1)
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
#define ISO_BUF_FILL (1 << 2)
#define INT_BUF_FILL (1 << 1)
#define ATL_BUF_FILL (1 << 0)
#define HC_MEMORY_REG 0x33c
#define ISP_BANK(x) ((x) << 16)
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
#define PORT1_INIT2 (1 << 23)
#define HW_OTG_CTRL_SET 0x374
#define HW_OTG_CTRL_CLR 0x376
/* Interrupt Register */
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31C
#define HC_ATL_IRQ_MASK_OR_REG 0x320
#define HC_ISO_IRQ_MASK_AND_REG 0x324
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32C
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
/* Philips Proprietary Transfer Descriptor (PTD) */
typedef __u32 __bitwise __dw;
struct ptd {
__dw dw0;
__dw dw1;
__dw dw2;
__dw dw3;
__dw dw4;
__dw dw5;
__dw dw6;
__dw dw7;
};
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
struct slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
unsigned long timestamp;
};
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
/* chip memory management */
struct memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
/*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
#define BLOCK_1_NUM 32
#define BLOCK_2_NUM 20
#define BLOCK_3_NUM 4
#define BLOCK_1_SIZE 256
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
#define PAYLOAD_AREA_SIZE 0xf000
/* ATL */
/* DW0 */
#define DW0_VALID_BIT 1
#define FROM_DW0_VALID(x) ((x) & 0x01)
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
#define TO_DW0_MULTI(x) (((u32) x) << 29)
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
#define DW1_TRANS_BULK ((u32) 2 << 12)
#define DW1_TRANS_INT ((u32) 3 << 12)
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
/* DW2 */
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
#define TO_DW2_RL(x) ((x) << 25)
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
/* DW3 */
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
#define TO_DW3_CERR(x) ((x) << 23)
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
#define TO_DW3_PING(x) ((x) << 26)
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
#define DW3_ERROR_BIT (1 << 28)
#define DW3_BABBLE_BIT (1 << 29)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ACTIVE_BIT (1 << 31)
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
#endif /* _ISP1760_HCD_H_ */

View file

@ -1,477 +0,0 @@
/*
* Glue code for the ISP1760 driver and bus
* Currently there is support for
* - OpenFirmware
* - PCI
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
*
*/
#include <linux/usb.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
#include "isp1760-hcd.h"
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
struct isp1760 {
struct usb_hcd *hcd;
int rst_gpio;
};
static int of_isp1760_probe(struct platform_device *dev)
{
struct isp1760 *drvdata;
struct device_node *dp = dev->dev.of_node;
struct resource *res;
struct resource memory;
int virq;
resource_size_t res_len;
int ret;
unsigned int devflags = 0;
enum of_gpio_flags gpio_flags;
u32 bus_width = 0;
drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
if (!drvdata)
return -ENOMEM;
ret = of_address_to_resource(dp, 0, &memory);
if (ret) {
ret = -ENXIO;
goto free_data;
}
res_len = resource_size(&memory);
res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
if (!res) {
ret = -EBUSY;
goto free_data;
}
virq = irq_of_parse_and_map(dp, 0);
if (!virq) {
ret = -ENODEV;
goto release_reg;
}
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
/* Some systems wire up only 16 of the 32 data lines */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (of_get_property(dp, "port1-otg", NULL) != NULL)
devflags |= ISP1760_FLAG_OTG_EN;
if (of_get_property(dp, "analog-oc", NULL) != NULL)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (of_get_property(dp, "dack-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
if (gpio_is_valid(drvdata->rst_gpio)) {
ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
if (!ret) {
if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
gpio_direction_output(drvdata->rst_gpio, 0);
} else {
gpio_direction_output(drvdata->rst_gpio, 1);
}
} else {
drvdata->rst_gpio = ret;
}
}
drvdata->hcd = isp1760_register(memory.start, res_len, virq,
IRQF_SHARED, drvdata->rst_gpio,
&dev->dev, dev_name(&dev->dev),
devflags);
if (IS_ERR(drvdata->hcd)) {
ret = PTR_ERR(drvdata->hcd);
goto free_gpio;
}
platform_set_drvdata(dev, drvdata);
return ret;
free_gpio:
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
release_reg:
release_mem_region(memory.start, res_len);
free_data:
kfree(drvdata);
return ret;
}
static int of_isp1760_remove(struct platform_device *dev)
{
struct isp1760 *drvdata = platform_get_drvdata(dev);
usb_remove_hcd(drvdata->hcd);
iounmap(drvdata->hcd->regs);
release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
usb_put_hcd(drvdata->hcd);
if (gpio_is_valid(drvdata->rst_gpio))
gpio_free(drvdata->rst_gpio);
kfree(drvdata);
return 0;
}
static const struct of_device_id of_isp1760_match[] = {
{
.compatible = "nxp,usb-isp1760",
},
{
.compatible = "nxp,usb-isp1761",
},
{ },
};
MODULE_DEVICE_TABLE(of, of_isp1760_match);
static struct platform_driver isp1760_of_driver = {
.driver = {
.name = "nxp-isp1760",
.of_match_table = of_isp1760_match,
},
.probe = of_isp1760_probe,
.remove = of_isp1760_remove,
};
#endif
#ifdef CONFIG_PCI
static int isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
u8 latency, limit;
__u32 reg_data;
int retry_count;
struct usb_hcd *hcd;
unsigned int devflags = 0;
int ret_status = 0;
resource_size_t pci_mem_phy0;
resource_size_t memlength;
u8 __iomem *chip_addr;
u8 __iomem *iobase;
resource_size_t nxp_pci_io_base;
resource_size_t iolength;
if (usb_disabled())
return -ENODEV;
if (pci_enable_device(dev) < 0)
return -ENODEV;
if (!dev->irq)
return -ENODEV;
/* Grab the PLX PCI mem maped port start address we need */
nxp_pci_io_base = pci_resource_start(dev, 0);
iolength = pci_resource_len(dev, 0);
if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
printk(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap_nocache(nxp_pci_io_base, iolength);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
ret_status = -ENOMEM;
goto cleanup1;
}
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
pci_mem_phy0 = pci_resource_start(dev, 3);
memlength = pci_resource_len(dev, 3);
if (memlength < 0xffff) {
printk(KERN_ERR "memory length for this resource is wrong\n");
ret_status = -ENOMEM;
goto cleanup2;
}
if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
ret_status = -EBUSY;
goto cleanup2;
}
/* map available memory */
chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
if (!chip_addr) {
printk(KERN_ERR "Error ioremap failed\n");
ret_status = -ENOMEM;
goto cleanup3;
}
/* bad pci latencies can contribute to overruns */
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
}
/* Try to check whether we can access Scratch Register of
* Host Controller or not. The initial PCI access is retried until
* local init for the PCI bridge is completed
*/
retry_count = 20;
reg_data = 0;
while ((reg_data != 0xFACE) && retry_count) {
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
writel(0xface, chip_addr + HC_SCRATCH_REG);
udelay(100);
reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
retry_count--;
}
iounmap(chip_addr);
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
ret_status = -ENOMEM;
goto cleanup3;
}
pci_set_master(dev);
/* configure PLX PCI chip to pass interrupts */
#define PLX_INT_CSR_REG 0x68
reg_data = readl(iobase + PLX_INT_CSR_REG);
reg_data |= 0x900;
writel(reg_data, iobase + PLX_INT_CSR_REG);
dev->dev.dma_mask = NULL;
hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
devflags);
if (IS_ERR(hcd)) {
ret_status = -ENODEV;
goto cleanup3;
}
/* done with PLX IO access */
iounmap(iobase);
release_mem_region(nxp_pci_io_base, iolength);
pci_set_drvdata(dev, hcd);
return 0;
cleanup3:
release_mem_region(pci_mem_phy0, memlength);
cleanup2:
iounmap(iobase);
cleanup1:
release_mem_region(nxp_pci_io_base, iolength);
return ret_status;
}
static void isp1761_pci_remove(struct pci_dev *dev)
{
struct usb_hcd *hcd;
hcd = pci_get_drvdata(dev);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
pci_disable_device(dev);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
{
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx [] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x5406,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = 0x9054,
},
{ }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
static struct pci_driver isp1761_pci_driver = {
.name = "isp1760",
.id_table = isp1760_plx,
.probe = isp1761_pci_probe,
.remove = isp1761_pci_remove,
.shutdown = isp1761_pci_shutdown,
};
#endif
static int isp1760_plat_probe(struct platform_device *pdev)
{
int ret = 0;
struct usb_hcd *hcd;
struct resource *mem_res;
struct resource *irq_res;
resource_size_t mem_size;
struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
unsigned int devflags = 0;
unsigned long irqflags = IRQF_SHARED;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem_res) {
pr_warning("isp1760: Memory resource not available\n");
ret = -ENODEV;
goto out;
}
mem_size = resource_size(mem_res);
if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
pr_warning("isp1760: Cannot reserve the memory resource\n");
ret = -EBUSY;
goto out;
}
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
pr_warning("isp1760: IRQ resource not available\n");
ret = -ENODEV;
goto cleanup;
}
irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
if (priv) {
if (priv->is_isp1761)
devflags |= ISP1760_FLAG_ISP1761;
if (priv->bus_width_16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (priv->port1_otg)
devflags |= ISP1760_FLAG_OTG_EN;
if (priv->analog_oc)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (priv->dack_polarity_high)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (priv->dreq_polarity_high)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
}
hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
irqflags, -ENOENT,
&pdev->dev, dev_name(&pdev->dev), devflags);
platform_set_drvdata(pdev, hcd);
if (IS_ERR(hcd)) {
pr_warning("isp1760: Failed to register the HCD device\n");
ret = -ENODEV;
goto cleanup;
}
pr_info("ISP1760 USB device initialised\n");
return ret;
cleanup:
release_mem_region(mem_res->start, mem_size);
out:
return ret;
}
static int isp1760_plat_remove(struct platform_device *pdev)
{
struct resource *mem_res;
resource_size_t mem_size;
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
mem_size = resource_size(mem_res);
release_mem_region(mem_res->start, mem_size);
usb_put_hcd(hcd);
return 0;
}
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
.remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
},
};
static int __init isp1760_init(void)
{
int ret, any_ret = -ENODEV;
init_kmem_once();
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
ret = platform_driver_register(&isp1760_of_driver);
if (!ret)
any_ret = 0;
#endif
#ifdef CONFIG_PCI
ret = pci_register_driver(&isp1761_pci_driver);
if (!ret)
any_ret = 0;
#endif
if (any_ret)
deinit_kmem_cache();
return any_ret;
}
module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
platform_driver_unregister(&isp1760_of_driver);
#endif
#ifdef CONFIG_PCI
pci_unregister_driver(&isp1761_pci_driver);
#endif
deinit_kmem_cache();
}
module_exit(isp1760_exit);

View file

@ -0,0 +1,59 @@
config USB_ISP1760
tristate "NXP ISP 1760/1761 support"
depends on USB || USB_GADGET
help
Say Y or M here if your system as an ISP1760 USB host controller
or an ISP1761 USB dual-role controller.
This driver does not support isochronous transfers or OTG.
This USB controller is usually attached to a non-DMA-Master
capable bus. NXP's eval kit brings this chip on PCI card
where the chip itself is behind a PLB to simulate such
a bus.
To compile this driver as a module, choose M here: the
module will be called isp1760.
config USB_ISP1760_HCD
bool
config USB_ISP1761_UDC
bool
if USB_ISP1760
choice
bool "ISP1760 Mode Selection"
default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
config USB_ISP1760_HOST_ROLE
bool "Host only mode"
depends on USB=y || USB=USB_ISP1760
select USB_ISP1760_HCD
help
Select this if you want to use the ISP1760 in host mode only. The
gadget function will be disabled.
config USB_ISP1760_GADGET_ROLE
bool "Gadget only mode"
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in peripheral mode only.
The host function will be disabled.
config USB_ISP1760_DUAL_ROLE
bool "Dual Role mode"
depends on USB=y || USB=USB_ISP1760
depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
select USB_ISP1760_HCD
select USB_ISP1761_UDC
help
Select this if you want to use the ISP1760 in both host and
peripheral modes.
endchoice
endif

View file

@ -0,0 +1,5 @@
isp1760-y := isp1760-core.o isp1760-if.o
isp1760-$(CONFIG_USB_ISP1760_HCD) += isp1760-hcd.o
isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
obj-$(CONFIG_USB_ISP1760) += isp1760.o

View file

@ -0,0 +1,177 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
#include "isp1760-udc.h"
static void isp1760_init_core(struct isp1760_device *isp)
{
u32 otgctrl;
u32 hwmode;
/* Low-level chip reset */
if (isp->rst_gpio) {
gpiod_set_value_cansleep(isp->rst_gpio, 1);
mdelay(50);
gpiod_set_value_cansleep(isp->rst_gpio, 0);
}
/*
* Reset the host controller, including the CPU interface
* configuration.
*/
isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
msleep(100);
/* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT;
if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
hwmode &= ~HW_DATA_BUS_32BIT;
if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
hwmode |= HW_ANA_DIGI_OC;
if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
hwmode |= HW_DACK_POL_HIGH;
if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
hwmode |= HW_DREQ_POL_HIGH;
if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
hwmode |= HW_INTR_HIGH_ACT;
if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
hwmode |= HW_INTR_EDGE_TRIG;
/*
* The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
* IRQ line for both the host and device controllers. Hardcode IRQ
* sharing for now and disable the DC interrupts globally to avoid
* spurious interrupts during HCD registration.
*/
if (isp->devflags & ISP1760_FLAG_ISP1761) {
isp1760_write32(isp->regs, DC_MODE, 0);
hwmode |= HW_COMN_IRQ;
}
/*
* We have to set this first in case we're in 16-bit mode.
* Write it twice to ensure correct upper bits if switching
* to 16-bit mode.
*/
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
/*
* PORT 1 Control register of the ISP1760 is the OTG control register
* on ISP1761.
*
* TODO: Really support OTG. For now we configure port 1 in device mode
* when OTG is requested.
*/
if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
(isp->devflags & ISP1760_FLAG_OTG_EN))
otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
| HW_OTG_DISABLE;
else
otgctrl = (HW_SW_SEL_HC_DC << 16)
| (HW_VBUS_DRV | HW_SEL_CP_EXT);
isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
dev_info(isp->dev, "bus width: %u, oc: %s\n",
isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
}
void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
{
isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
}
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags)
{
struct isp1760_device *isp;
bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
int ret;
/*
* If neither the HCD not the UDC is enabled return an error, as no
* device would be registered.
*/
if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
(!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
return -ENODEV;
/* prevent usb-core allocating DMA pages */
dev->dma_mask = NULL;
isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
if (!isp)
return -ENOMEM;
isp->dev = dev;
isp->devflags = devflags;
isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
if (IS_ERR(isp->rst_gpio))
return PTR_ERR(isp->rst_gpio);
isp->regs = devm_ioremap_resource(dev, mem);
if (IS_ERR(isp->regs))
return PTR_ERR(isp->regs);
isp1760_init_core(isp);
if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
irqflags | IRQF_SHARED, dev);
if (ret < 0)
return ret;
}
if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
IRQF_DISABLED);
if (ret < 0) {
isp1760_hcd_unregister(&isp->hcd);
return ret;
}
}
dev_set_drvdata(dev, isp);
return 0;
}
void isp1760_unregister(struct device *dev)
{
struct isp1760_device *isp = dev_get_drvdata(dev);
isp1760_udc_unregister(isp);
isp1760_hcd_unregister(&isp->hcd);
}
MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,68 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_CORE_H_
#define _ISP1760_CORE_H_
#include <linux/ioport.h>
#include "isp1760-hcd.h"
#include "isp1760-udc.h"
struct device;
struct gpio_desc;
/*
* Device flags that can vary from board to board. All of these
* indicate the most "atypical" case, so that a devflags of 0 is
* a sane default configuration.
*/
#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
struct isp1760_device {
struct device *dev;
void __iomem *regs;
unsigned int devflags;
struct gpio_desc *rst_gpio;
struct isp1760_hcd hcd;
struct isp1760_udc udc;
};
int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
struct device *dev, unsigned int devflags);
void isp1760_unregister(struct device *dev);
void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
static inline u32 isp1760_read32(void __iomem *base, u32 reg)
{
return readl(base + reg);
}
static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
{
writel(val, base + reg);
}
#endif

View file

@ -11,6 +11,7 @@
* (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
*
*/
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@ -24,73 +25,96 @@
#include <linux/timer.h>
#include <asm/unaligned.h>
#include <asm/cacheflush.h>
#include <linux/gpio.h>
#include "isp1760-core.h"
#include "isp1760-hcd.h"
#include "isp1760-regs.h"
static struct kmem_cache *qtd_cachep;
static struct kmem_cache *qh_cachep;
static struct kmem_cache *urb_listitem_cachep;
enum queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
u32 hcs_params;
spinlock_t lock;
struct slotinfo atl_slots[32];
int atl_done_map;
struct slotinfo int_slots[32];
int int_done_map;
struct memory_chunk memory_pool[BLOCKS];
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
unsigned periodic_size;
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
unsigned int devflags;
int rst_gpio;
};
typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
struct isp1760_qtd *qtd);
static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
{
return (struct isp1760_hcd *) (hcd->hcd_priv);
return *(struct isp1760_hcd **)hcd->hcd_priv;
}
/* Section 2.2 Host Controller Capability Registers */
#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
/* urb state*/
#define DELETE_URB (0x0008)
#define NO_TRANSFER_ACTIVE (0xffffffff)
/* Section 2.3 Host Controller Operational Registers */
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
#define STS_PCD (1<<2) /* port change detect */
#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
/* Philips Proprietary Transfer Descriptor (PTD) */
typedef __u32 __bitwise __dw;
struct ptd {
__dw dw0;
__dw dw1;
__dw dw2;
__dw dw3;
__dw dw4;
__dw dw5;
__dw dw6;
__dw dw7;
};
#define PTD_OFFSET 0x0400
#define ISO_PTD_OFFSET 0x0400
#define INT_PTD_OFFSET 0x0800
#define ATL_PTD_OFFSET 0x0c00
#define PAYLOAD_OFFSET 0x1000
#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
#define PORT_POWER (1<<12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
#define PORT_RESET (1<<8) /* reset port */
#define PORT_SUSPEND (1<<7) /* suspend port */
#define PORT_RESUME (1<<6) /* resume it */
#define PORT_PE (1<<2) /* port enable */
#define PORT_CSC (1<<1) /* connect status change */
#define PORT_CONNECT (1<<0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC)
/* ATL */
/* DW0 */
#define DW0_VALID_BIT 1
#define FROM_DW0_VALID(x) ((x) & 0x01)
#define TO_DW0_LENGTH(x) (((u32) x) << 3)
#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
#define TO_DW0_MULTI(x) (((u32) x) << 29)
#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
/* DW1 */
#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
#define DW1_TRANS_BULK ((u32) 2 << 12)
#define DW1_TRANS_INT ((u32) 3 << 12)
#define DW1_TRANS_SPLIT ((u32) 1 << 14)
#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
/* DW2 */
#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
#define TO_DW2_RL(x) ((x) << 25)
#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
/* DW3 */
#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
#define TO_DW3_NAKCOUNT(x) ((x) << 19)
#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
#define TO_DW3_CERR(x) ((x) << 23)
#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
#define TO_DW3_PING(x) ((x) << 26)
#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
#define DW3_ERROR_BIT (1 << 28)
#define DW3_BABBLE_BIT (1 << 29)
#define DW3_HALT_BIT (1 << 30)
#define DW3_ACTIVE_BIT (1 << 31)
#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
#define INT_UNDERRUN (1 << 2)
#define INT_BABBLE (1 << 1)
#define INT_EXACT (1 << 0)
#define SETUP_PID (2)
#define IN_PID (1)
#define OUT_PID (0)
/* Errata 1 */
#define RL_COUNTER (0)
#define NAK_COUNTER (0)
#define ERR_COUNTER (2)
struct isp1760_qtd {
u8 packet_type;
@ -137,12 +161,12 @@ struct urb_listitem {
*/
static u32 reg_read32(void __iomem *base, u32 reg)
{
return readl(base + reg);
return isp1760_read32(base, reg);
}
static void reg_write32(void __iomem *base, u32 reg, u32 val)
{
writel(val, base + reg);
isp1760_write32(base, reg, val);
}
/*
@ -443,42 +467,6 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
int result;
u32 scratch, hwmode;
/* low-level chip reset */
if (gpio_is_valid(priv->rst_gpio)) {
unsigned int rst_lvl;
rst_lvl = (priv->devflags &
ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
gpio_set_value(priv->rst_gpio, rst_lvl);
mdelay(50);
gpio_set_value(priv->rst_gpio, !rst_lvl);
}
/* Setup HW Mode Control: This assumes a level active-low interrupt */
hwmode = HW_DATA_BUS_32BIT;
if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
hwmode &= ~HW_DATA_BUS_32BIT;
if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
hwmode |= HW_ANA_DIGI_OC;
if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
hwmode |= HW_DACK_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
hwmode |= HW_DREQ_POL_HIGH;
if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
hwmode |= HW_INTR_HIGH_ACT;
if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
hwmode |= HW_INTR_EDGE_TRIG;
/*
* We have to set this first in case we're in 16-bit mode.
* Write it twice to ensure correct upper bits if switching
* to 16-bit mode.
*/
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
/* Change bus pattern */
scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
@ -488,46 +476,33 @@ static int isp1760_hc_setup(struct usb_hcd *hcd)
return -ENODEV;
}
/* pre reset */
/*
* The RESET_HC bit in the SW_RESET register is supposed to reset the
* host controller without touching the CPU interface registers, but at
* least on the ISP1761 it seems to behave as the RESET_ALL bit and
* reset the whole device. We thus can't use it here, so let's reset
* the host controller through the EHCI USB Command register. The device
* has been reset in core code anyway, so this shouldn't matter.
*/
reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
/* reset */
reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
mdelay(100);
reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC);
mdelay(100);
result = ehci_reset(hcd);
if (result)
return result;
/* Step 11 passed */
dev_info(hcd->self.controller, "bus width: %d, oc: %s\n",
(priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
"analog" : "digital");
/* ATL reset */
hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
mdelay(10);
reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
/*
* PORT 1 Control register of the ISP1760 is the OTG control
* register on ISP1761. Since there is no OTG or device controller
* support in this driver, we use port 1 as a "normal" USB host port on
* both chips.
*/
reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
mdelay(10);
priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
return priv_init(hcd);
@ -743,8 +718,9 @@ static void qtd_free(struct isp1760_qtd *qtd)
}
static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
struct slotinfo *slots, struct isp1760_qtd *qtd,
struct isp1760_qh *qh, struct ptd *ptd)
struct isp1760_slotinfo *slots,
struct isp1760_qtd *qtd, struct isp1760_qh *qh,
struct ptd *ptd)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
int skip_map;
@ -857,7 +833,7 @@ static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
{
struct isp1760_hcd *priv = hcd_to_priv(hcd);
int ptd_offset;
struct slotinfo *slots;
struct isp1760_slotinfo *slots;
int curr_slot, free_slot;
int n;
struct ptd ptd;
@ -1097,7 +1073,7 @@ static void handle_done_ptds(struct usb_hcd *hcd)
struct isp1760_qh *qh;
int slot;
int state;
struct slotinfo *slots;
struct isp1760_slotinfo *slots;
u32 ptd_offset;
struct isp1760_qtd *qtd;
int modified;
@ -2161,7 +2137,7 @@ static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
static const struct hc_driver isp1760_hc_driver = {
.description = "isp1760-hcd",
.product_desc = "NXP ISP1760 USB Host Controller",
.hcd_priv_size = sizeof(struct isp1760_hcd),
.hcd_priv_size = sizeof(struct isp1760_hcd *),
.irq = isp1760_irq,
.flags = HCD_MEMORY | HCD_USB2,
.reset = isp1760_hc_setup,
@ -2177,7 +2153,7 @@ static const struct hc_driver isp1760_hc_driver = {
.clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
};
int __init init_kmem_once(void)
int __init isp1760_init_kmem_once(void)
{
urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
@ -2204,66 +2180,56 @@ int __init init_kmem_once(void)
return 0;
}
void deinit_kmem_cache(void)
void isp1760_deinit_kmem_cache(void)
{
kmem_cache_destroy(qtd_cachep);
kmem_cache_destroy(qh_cachep);
kmem_cache_destroy(urb_listitem_cachep);
}
struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
int irq, unsigned long irqflags,
int rst_gpio,
struct device *dev, const char *busname,
unsigned int devflags)
int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
struct resource *mem, int irq, unsigned long irqflags,
struct device *dev)
{
struct usb_hcd *hcd;
struct isp1760_hcd *priv;
int ret;
if (usb_disabled())
return ERR_PTR(-ENODEV);
/* prevent usb-core allocating DMA pages */
dev->dma_mask = NULL;
hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
if (!hcd)
return ERR_PTR(-ENOMEM);
return -ENOMEM;
*(struct isp1760_hcd **)hcd->hcd_priv = priv;
priv->hcd = hcd;
priv = hcd_to_priv(hcd);
priv->devflags = devflags;
priv->rst_gpio = rst_gpio;
init_memory(priv);
hcd->regs = ioremap(res_start, res_len);
if (!hcd->regs) {
ret = -EIO;
goto err_put;
}
hcd->irq = irq;
hcd->rsrc_start = res_start;
hcd->rsrc_len = res_len;
hcd->regs = regs;
hcd->rsrc_start = mem->start;
hcd->rsrc_len = resource_size(mem);
/* This driver doesn't support wakeup requests */
hcd->cant_recv_wakeups = 1;
ret = usb_add_hcd(hcd, irq, irqflags);
if (ret)
goto err_unmap;
goto error;
device_wakeup_enable(hcd->self.controller);
return hcd;
return 0;
err_unmap:
iounmap(hcd->regs);
err_put:
usb_put_hcd(hcd);
return ERR_PTR(ret);
error:
usb_put_hcd(hcd);
return ret;
}
MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
MODULE_LICENSE("GPL v2");
void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{
if (!priv->hcd)
return;
usb_remove_hcd(priv->hcd);
usb_put_hcd(priv->hcd);
}

View file

@ -0,0 +1,102 @@
#ifndef _ISP1760_HCD_H_
#define _ISP1760_HCD_H_
#include <linux/spinlock.h>
struct isp1760_qh;
struct isp1760_qtd;
struct resource;
struct usb_hcd;
/*
* 60kb divided in:
* - 32 blocks @ 256 bytes
* - 20 blocks @ 1024 bytes
* - 4 blocks @ 8192 bytes
*/
#define BLOCK_1_NUM 32
#define BLOCK_2_NUM 20
#define BLOCK_3_NUM 4
#define BLOCK_1_SIZE 256
#define BLOCK_2_SIZE 1024
#define BLOCK_3_SIZE 8192
#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
#define PAYLOAD_AREA_SIZE 0xf000
struct isp1760_slotinfo {
struct isp1760_qh *qh;
struct isp1760_qtd *qtd;
unsigned long timestamp;
};
/* chip memory management */
struct isp1760_memory_chunk {
unsigned int start;
unsigned int size;
unsigned int free;
};
enum isp1760_queue_head_types {
QH_CONTROL,
QH_BULK,
QH_INTERRUPT,
QH_END
};
struct isp1760_hcd {
#ifdef CONFIG_USB_ISP1760_HCD
struct usb_hcd *hcd;
u32 hcs_params;
spinlock_t lock;
struct isp1760_slotinfo atl_slots[32];
int atl_done_map;
struct isp1760_slotinfo int_slots[32];
int int_done_map;
struct isp1760_memory_chunk memory_pool[BLOCKS];
struct list_head qh_list[QH_END];
/* periodic schedule support */
#define DEFAULT_I_TDPS 1024
unsigned periodic_size;
unsigned i_thresh;
unsigned long reset_done;
unsigned long next_statechange;
#endif
};
#ifdef CONFIG_USB_ISP1760_HCD
int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
struct resource *mem, int irq, unsigned long irqflags,
struct device *dev);
void isp1760_hcd_unregister(struct isp1760_hcd *priv);
int isp1760_init_kmem_once(void);
void isp1760_deinit_kmem_cache(void);
#else
static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
void __iomem *regs, struct resource *mem,
int irq, unsigned long irqflags,
struct device *dev)
{
return 0;
}
static inline void isp1760_hcd_unregister(struct isp1760_hcd *priv)
{
}
static inline int isp1760_init_kmem_once(void)
{
return 0;
}
static inline void isp1760_deinit_kmem_cache(void)
{
}
#endif
#endif /* _ISP1760_HCD_H_ */

View file

@ -0,0 +1,309 @@
/*
* Glue code for the ISP1760 driver and bus
* Currently there is support for
* - OpenFirmware
* - PCI
* - PDEV (generic platform device centralized driver model)
*
* (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
*
*/
#include <linux/usb.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb/isp1760.h>
#include <linux/usb/hcd.h>
#include "isp1760-core.h"
#include "isp1760-regs.h"
#ifdef CONFIG_PCI
#include <linux/pci.h>
#endif
#ifdef CONFIG_PCI
static int isp1761_pci_init(struct pci_dev *dev)
{
resource_size_t mem_start;
resource_size_t mem_length;
u8 __iomem *iobase;
u8 latency, limit;
int retry_count;
u32 reg_data;
/* Grab the PLX PCI shared memory of the ISP 1761 we need */
mem_start = pci_resource_start(dev, 3);
mem_length = pci_resource_len(dev, 3);
if (mem_length < 0xffff) {
printk(KERN_ERR "memory length for this resource is wrong\n");
return -ENOMEM;
}
if (!request_mem_region(mem_start, mem_length, "ISP-PCI")) {
printk(KERN_ERR "host controller already in use\n");
return -EBUSY;
}
/* map available memory */
iobase = ioremap_nocache(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "Error ioremap failed\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* bad pci latencies can contribute to overruns */
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
if (latency) {
pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
if (limit && limit < latency)
pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
}
/* Try to check whether we can access Scratch Register of
* Host Controller or not. The initial PCI access is retried until
* local init for the PCI bridge is completed
*/
retry_count = 20;
reg_data = 0;
while ((reg_data != 0xFACE) && retry_count) {
/*by default host is in 16bit mode, so
* io operations at this stage must be 16 bit
* */
writel(0xface, iobase + HC_SCRATCH_REG);
udelay(100);
reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
retry_count--;
}
iounmap(iobase);
release_mem_region(mem_start, mem_length);
/* Host Controller presence is detected by writing to scratch register
* and reading back and checking the contents are same or not
*/
if (reg_data != 0xFACE) {
dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
return -ENOMEM;
}
/* Grab the PLX PCI mem maped port start address we need */
mem_start = pci_resource_start(dev, 0);
mem_length = pci_resource_len(dev, 0);
if (!request_mem_region(mem_start, mem_length, "ISP1761 IO MEM")) {
printk(KERN_ERR "request region #1\n");
return -EBUSY;
}
iobase = ioremap_nocache(mem_start, mem_length);
if (!iobase) {
printk(KERN_ERR "ioremap #1\n");
release_mem_region(mem_start, mem_length);
return -ENOMEM;
}
/* configure PLX PCI chip to pass interrupts */
#define PLX_INT_CSR_REG 0x68
reg_data = readl(iobase + PLX_INT_CSR_REG);
reg_data |= 0x900;
writel(reg_data, iobase + PLX_INT_CSR_REG);
/* done with PLX IO access */
iounmap(iobase);
release_mem_region(mem_start, mem_length);
return 0;
}
static int isp1761_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
unsigned int devflags = 0;
int ret;
if (!dev->irq)
return -ENODEV;
if (pci_enable_device(dev) < 0)
return -ENODEV;
ret = isp1761_pci_init(dev);
if (ret < 0)
goto error;
pci_set_master(dev);
dev->dev.dma_mask = NULL;
ret = isp1760_register(&dev->resource[3], dev->irq, 0, &dev->dev,
devflags);
if (ret < 0)
goto error;
return 0;
error:
pci_disable_device(dev);
return ret;
}
static void isp1761_pci_remove(struct pci_dev *dev)
{
isp1760_unregister(&dev->dev);
pci_disable_device(dev);
}
static void isp1761_pci_shutdown(struct pci_dev *dev)
{
printk(KERN_ERR "ips1761_pci_shutdown\n");
}
static const struct pci_device_id isp1760_plx [] = {
{
.class = PCI_CLASS_BRIDGE_OTHER << 8,
.class_mask = ~0,
.vendor = PCI_VENDOR_ID_PLX,
.device = 0x5406,
.subvendor = PCI_VENDOR_ID_PLX,
.subdevice = 0x9054,
},
{ }
};
MODULE_DEVICE_TABLE(pci, isp1760_plx);
static struct pci_driver isp1761_pci_driver = {
.name = "isp1760",
.id_table = isp1760_plx,
.probe = isp1761_pci_probe,
.remove = isp1761_pci_remove,
.shutdown = isp1761_pci_shutdown,
};
#endif
static int isp1760_plat_probe(struct platform_device *pdev)
{
unsigned long irqflags;
unsigned int devflags = 0;
struct resource *mem_res;
struct resource *irq_res;
int ret;
mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
pr_warning("isp1760: IRQ resource not available\n");
return -ENODEV;
}
irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
struct device_node *dp = pdev->dev.of_node;
u32 bus_width = 0;
if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
devflags |= ISP1760_FLAG_ISP1761;
/* Some systems wire up only 16 of the 32 data lines */
of_property_read_u32(dp, "bus-width", &bus_width);
if (bus_width == 16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (of_property_read_bool(dp, "port1-otg"))
devflags |= ISP1760_FLAG_OTG_EN;
if (of_property_read_bool(dp, "analog-oc"))
devflags |= ISP1760_FLAG_ANALOG_OC;
if (of_property_read_bool(dp, "dack-polarity"))
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (of_property_read_bool(dp, "dreq-polarity"))
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
} else if (dev_get_platdata(&pdev->dev)) {
struct isp1760_platform_data *pdata =
dev_get_platdata(&pdev->dev);
if (pdata->is_isp1761)
devflags |= ISP1760_FLAG_ISP1761;
if (pdata->bus_width_16)
devflags |= ISP1760_FLAG_BUS_WIDTH_16;
if (pdata->port1_otg)
devflags |= ISP1760_FLAG_OTG_EN;
if (pdata->analog_oc)
devflags |= ISP1760_FLAG_ANALOG_OC;
if (pdata->dack_polarity_high)
devflags |= ISP1760_FLAG_DACK_POL_HIGH;
if (pdata->dreq_polarity_high)
devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
}
ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
devflags);
if (ret < 0)
return ret;
pr_info("ISP1760 USB device initialised\n");
return 0;
}
static int isp1760_plat_remove(struct platform_device *pdev)
{
isp1760_unregister(&pdev->dev);
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id isp1760_of_match[] = {
{ .compatible = "nxp,usb-isp1760", },
{ .compatible = "nxp,usb-isp1761", },
{ },
};
MODULE_DEVICE_TABLE(of, isp1760_of_match);
#endif
static struct platform_driver isp1760_plat_driver = {
.probe = isp1760_plat_probe,
.remove = isp1760_plat_remove,
.driver = {
.name = "isp1760",
.of_match_table = of_match_ptr(isp1760_of_match),
},
};
static int __init isp1760_init(void)
{
int ret, any_ret = -ENODEV;
isp1760_init_kmem_once();
ret = platform_driver_register(&isp1760_plat_driver);
if (!ret)
any_ret = 0;
#ifdef CONFIG_PCI
ret = pci_register_driver(&isp1761_pci_driver);
if (!ret)
any_ret = 0;
#endif
if (any_ret)
isp1760_deinit_kmem_cache();
return any_ret;
}
module_init(isp1760_init);
static void __exit isp1760_exit(void)
{
platform_driver_unregister(&isp1760_plat_driver);
#ifdef CONFIG_PCI
pci_unregister_driver(&isp1761_pci_driver);
#endif
isp1760_deinit_kmem_cache();
}
module_exit(isp1760_exit);

View file

@ -0,0 +1,230 @@
/*
* Driver for the NXP ISP1760 chip
*
* Copyright 2014 Laurent Pinchart
* Copyright 2007 Sebastian Siewior
*
* Contacts:
* Sebastian Siewior <bigeasy@linutronix.de>
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_REGS_H_
#define _ISP1760_REGS_H_
/* -----------------------------------------------------------------------------
* Host Controller
*/
/* EHCI capability registers */
#define HC_CAPLENGTH 0x000
#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
#define HC_HCSPARAMS 0x004
#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
#define HC_HCCPARAMS 0x008
#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
/* EHCI operational registers */
#define HC_USBCMD 0x020
#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
#define CMD_RESET (1 << 1) /* reset HC not bus */
#define CMD_RUN (1 << 0) /* start/stop HC */
#define HC_USBSTS 0x024
#define STS_PCD (1 << 2) /* port change detect */
#define HC_FRINDEX 0x02c
#define HC_CONFIGFLAG 0x060
#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
#define HC_PORTSC1 0x064
#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
#define PORT_RESET (1 << 8) /* reset port */
#define PORT_SUSPEND (1 << 7) /* suspend port */
#define PORT_RESUME (1 << 6) /* resume it */
#define PORT_PE (1 << 2) /* port enable */
#define PORT_CSC (1 << 1) /* connect status change */
#define PORT_CONNECT (1 << 0) /* device connected */
#define PORT_RWC_BITS (PORT_CSC)
#define HC_ISO_PTD_DONEMAP_REG 0x130
#define HC_ISO_PTD_SKIPMAP_REG 0x134
#define HC_ISO_PTD_LASTPTD_REG 0x138
#define HC_INT_PTD_DONEMAP_REG 0x140
#define HC_INT_PTD_SKIPMAP_REG 0x144
#define HC_INT_PTD_LASTPTD_REG 0x148
#define HC_ATL_PTD_DONEMAP_REG 0x150
#define HC_ATL_PTD_SKIPMAP_REG 0x154
#define HC_ATL_PTD_LASTPTD_REG 0x158
/* Configuration Register */
#define HC_HW_MODE_CTRL 0x300
#define ALL_ATX_RESET (1 << 31)
#define HW_ANA_DIGI_OC (1 << 15)
#define HW_DEV_DMA (1 << 11)
#define HW_COMN_IRQ (1 << 10)
#define HW_COMN_DMA (1 << 9)
#define HW_DATA_BUS_32BIT (1 << 8)
#define HW_DACK_POL_HIGH (1 << 6)
#define HW_DREQ_POL_HIGH (1 << 5)
#define HW_INTR_HIGH_ACT (1 << 2)
#define HW_INTR_EDGE_TRIG (1 << 1)
#define HW_GLOBAL_INTR_EN (1 << 0)
#define HC_CHIP_ID_REG 0x304
#define HC_SCRATCH_REG 0x308
#define HC_RESET_REG 0x30c
#define SW_RESET_RESET_HC (1 << 1)
#define SW_RESET_RESET_ALL (1 << 0)
#define HC_BUFFER_STATUS_REG 0x334
#define ISO_BUF_FILL (1 << 2)
#define INT_BUF_FILL (1 << 1)
#define ATL_BUF_FILL (1 << 0)
#define HC_MEMORY_REG 0x33c
#define ISP_BANK(x) ((x) << 16)
#define HC_PORT1_CTRL 0x374
#define PORT1_POWER (3 << 3)
#define PORT1_INIT1 (1 << 7)
#define PORT1_INIT2 (1 << 23)
#define HW_OTG_CTRL_SET 0x374
#define HW_OTG_CTRL_CLR 0x376
#define HW_OTG_DISABLE (1 << 10)
#define HW_OTG_SE0_EN (1 << 9)
#define HW_BDIS_ACON_EN (1 << 8)
#define HW_SW_SEL_HC_DC (1 << 7)
#define HW_VBUS_CHRG (1 << 6)
#define HW_VBUS_DISCHRG (1 << 5)
#define HW_VBUS_DRV (1 << 4)
#define HW_SEL_CP_EXT (1 << 3)
#define HW_DM_PULLDOWN (1 << 2)
#define HW_DP_PULLDOWN (1 << 1)
#define HW_DP_PULLUP (1 << 0)
/* Interrupt Register */
#define HC_INTERRUPT_REG 0x310
#define HC_INTERRUPT_ENABLE 0x314
#define HC_ISO_INT (1 << 9)
#define HC_ATL_INT (1 << 8)
#define HC_INTL_INT (1 << 7)
#define HC_EOT_INT (1 << 3)
#define HC_SOT_INT (1 << 1)
#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
#define HC_ISO_IRQ_MASK_OR_REG 0x318
#define HC_INT_IRQ_MASK_OR_REG 0x31c
#define HC_ATL_IRQ_MASK_OR_REG 0x320
#define HC_ISO_IRQ_MASK_AND_REG 0x324
#define HC_INT_IRQ_MASK_AND_REG 0x328
#define HC_ATL_IRQ_MASK_AND_REG 0x32c
/* -----------------------------------------------------------------------------
* Peripheral Controller
*/
/* Initialization Registers */
#define DC_ADDRESS 0x0200
#define DC_DEVEN (1 << 7)
#define DC_MODE 0x020c
#define DC_DMACLKON (1 << 9)
#define DC_VBUSSTAT (1 << 8)
#define DC_CLKAON (1 << 7)
#define DC_SNDRSU (1 << 6)
#define DC_GOSUSP (1 << 5)
#define DC_SFRESET (1 << 4)
#define DC_GLINTENA (1 << 3)
#define DC_WKUPCS (1 << 2)
#define DC_INTCONF 0x0210
#define DC_CDBGMOD_ACK_NAK (0 << 6)
#define DC_CDBGMOD_ACK (1 << 6)
#define DC_CDBGMOD_ACK_1NAK (2 << 6)
#define DC_DDBGMODIN_ACK_NAK (0 << 4)
#define DC_DDBGMODIN_ACK (1 << 4)
#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
#define DC_INTLVL (1 << 1)
#define DC_INTPOL (1 << 0)
#define DC_DEBUG 0x0212
#define DC_INTENABLE 0x0214
#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
#define DC_IEP0SETUP (1 << 8)
#define DC_IEVBUS (1 << 7)
#define DC_IEDMA (1 << 6)
#define DC_IEHS_STA (1 << 5)
#define DC_IERESM (1 << 4)
#define DC_IESUSP (1 << 3)
#define DC_IEPSOF (1 << 2)
#define DC_IESOF (1 << 1)
#define DC_IEBRST (1 << 0)
/* Data Flow Registers */
#define DC_EPINDEX 0x022c
#define DC_EP0SETUP (1 << 5)
#define DC_ENDPIDX(n) ((n) << 1)
#define DC_EPDIR (1 << 0)
#define DC_CTRLFUNC 0x0228
#define DC_CLBUF (1 << 4)
#define DC_VENDP (1 << 3)
#define DC_DSEN (1 << 2)
#define DC_STATUS (1 << 1)
#define DC_STALL (1 << 0)
#define DC_DATAPORT 0x0220
#define DC_BUFLEN 0x021c
#define DC_DATACOUNT_MASK 0xffff
#define DC_BUFSTAT 0x021e
#define DC_EPMAXPKTSZ 0x0204
#define DC_EPTYPE 0x0208
#define DC_NOEMPKT (1 << 4)
#define DC_EPENABLE (1 << 3)
#define DC_DBLBUF (1 << 2)
#define DC_ENDPTYP_ISOC (1 << 0)
#define DC_ENDPTYP_BULK (2 << 0)
#define DC_ENDPTYP_INTERRUPT (3 << 0)
/* DMA Registers */
#define DC_DMACMD 0x0230
#define DC_DMATXCOUNT 0x0234
#define DC_DMACONF 0x0238
#define DC_DMAHW 0x023c
#define DC_DMAINTREASON 0x0250
#define DC_DMAINTEN 0x0254
#define DC_DMAEP 0x0258
#define DC_DMABURSTCOUNT 0x0264
/* General Registers */
#define DC_INTERRUPT 0x0218
#define DC_CHIPID 0x0270
#define DC_FRAMENUM 0x0274
#define DC_SCRATCH 0x0278
#define DC_UNLOCKDEV 0x027c
#define DC_INTPULSEWIDTH 0x0280
#define DC_TESTMODE 0x0284
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,106 @@
/*
* Driver for the NXP ISP1761 device controller
*
* Copyright 2014 Ideas on Board Oy
*
* Contacts:
* Laurent Pinchart <laurent.pinchart@ideasonboard.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#ifndef _ISP1760_UDC_H_
#define _ISP1760_UDC_H_
#include <linux/ioport.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/timer.h>
#include <linux/usb/gadget.h>
struct isp1760_device;
struct isp1760_udc;
enum isp1760_ctrl_state {
ISP1760_CTRL_SETUP, /* Waiting for a SETUP transaction */
ISP1760_CTRL_DATA_IN, /* Setup received, data IN stage */
ISP1760_CTRL_DATA_OUT, /* Setup received, data OUT stage */
ISP1760_CTRL_STATUS, /* 0-length request in status stage */
};
struct isp1760_ep {
struct isp1760_udc *udc;
struct usb_ep ep;
struct list_head queue;
unsigned int addr;
unsigned int maxpacket;
char name[7];
const struct usb_endpoint_descriptor *desc;
bool rx_pending;
bool halted;
bool wedged;
};
/**
* struct isp1760_udc - UDC state information
* irq: IRQ number
* irqname: IRQ name (as passed to request_irq)
* regs: Base address of the UDC registers
* driver: Gadget driver
* gadget: Gadget device
* lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
* ep: Array of endpoints
* ep0_state: Control request state for endpoint 0
* ep0_dir: Direction of the current control request
* ep0_length: Length of the current control request
* connected: Tracks gadget driver bus connection state
*/
struct isp1760_udc {
#ifdef CONFIG_USB_ISP1761_UDC
struct isp1760_device *isp;
int irq;
char *irqname;
void __iomem *regs;
struct usb_gadget_driver *driver;
struct usb_gadget gadget;
spinlock_t lock;
struct timer_list vbus_timer;
struct isp1760_ep ep[15];
enum isp1760_ctrl_state ep0_state;
u8 ep0_dir;
u16 ep0_length;
bool connected;
unsigned int devstatus;
#endif
};
#ifdef CONFIG_USB_ISP1761_UDC
int isp1760_udc_register(struct isp1760_device *isp, int irq,
unsigned long irqflags);
void isp1760_udc_unregister(struct isp1760_device *isp);
#else
static inline int isp1760_udc_register(struct isp1760_device *isp, int irq,
unsigned long irqflags)
{
return 0;
}
static inline void isp1760_udc_unregister(struct isp1760_device *isp)
{
}
#endif
#endif

View file

@ -63,11 +63,13 @@ comment "Platform Glue Layer"
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_TUSB6010
@ -77,12 +79,13 @@ config USB_MUSB_TUSB6010
config USB_MUSB_OMAP2PLUS
tristate "OMAP2430 and onwards"
depends on ARCH_OMAP2PLUS && USB
depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
select GENERIC_PHY
config USB_MUSB_AM35X
tristate "AM35x"
depends on ARCH_OMAP
depends on NOP_USB_XCEIV
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
@ -93,6 +96,7 @@ config USB_MUSB_DSPS
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
depends on NOP_USB_XCEIV
config USB_MUSB_UX500
tristate "Ux500 platforms"
@ -100,6 +104,7 @@ config USB_MUSB_UX500
config USB_MUSB_JZ4740
tristate "JZ4740"
depends on NOP_USB_XCEIV
depends on MACH_JZ4740 || COMPILE_TEST
depends on USB_MUSB_GADGET
depends on USB_OTG_BLACKLIST_HUB

View file

@ -608,7 +608,7 @@ static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume);
static struct platform_driver bfin_driver = {
.probe = bfin_probe,
.remove = __exit_p(bfin_remove),
.remove = bfin_remove,
.driver = {
.name = "musb-blackfin",
.pm = &bfin_pm_ops,

View file

@ -567,6 +567,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1;
musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@ -2500,6 +2501,12 @@ static int musb_runtime_resume(struct device *dev)
musb_restore_context(musb);
first = 0;
if (musb->need_finish_resume) {
musb->need_finish_resume = 0;
schedule_delayed_work(&musb->finish_resume_work,
msecs_to_jiffies(20));
}
return 0;
}

View file

@ -9,9 +9,9 @@
#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
#define EP_MODE_AUTOREG_NONE 0
#define EP_MODE_AUTOREG_ALL_NEOP 1
#define EP_MODE_AUTOREG_ALWAYS 3
#define EP_MODE_AUTOREQ_NONE 0
#define EP_MODE_AUTOREQ_ALL_NEOP 1
#define EP_MODE_AUTOREQ_ALWAYS 3
#define EP_MODE_DMA_TRANSPARENT 0
#define EP_MODE_DMA_RNDIS 1
@ -404,19 +404,19 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
/* auto req */
cppi41_set_autoreq_mode(cppi41_channel,
EP_MODE_AUTOREG_ALL_NEOP);
EP_MODE_AUTOREQ_ALL_NEOP);
} else {
musb_writel(musb->ctrl_base,
RNDIS_REG(cppi41_channel->port_num), 0);
cppi41_set_dma_mode(cppi41_channel,
EP_MODE_DMA_TRANSPARENT);
cppi41_set_autoreq_mode(cppi41_channel,
EP_MODE_AUTOREG_NONE);
EP_MODE_AUTOREQ_NONE);
}
} else {
/* fallback mode */
cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
len = min_t(u32, packet_sz, len);
}
cppi41_channel->prog_len = len;
@ -549,10 +549,15 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
csr &= ~MUSB_TXCSR_DMAENAB;
musb_writew(epio, MUSB_TXCSR, csr);
} else {
cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
csr = musb_readw(epio, MUSB_RXCSR);
csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
musb_writew(epio, MUSB_RXCSR, csr);
/* wait to drain cppi dma pipe line */
udelay(50);
csr = musb_readw(epio, MUSB_RXCSR);
if (csr & MUSB_RXCSR_RXPKTRDY) {
csr |= MUSB_RXCSR_FLUSHFIFO;
@ -566,13 +571,14 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
tdbit <<= 16;
do {
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
if (is_tx)
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
ret = dmaengine_terminate_all(cppi41_channel->dc);
} while (ret == -EAGAIN);
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
if (is_tx) {
musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY) {
csr |= MUSB_TXCSR_FLUSHFIFO;

View file

@ -196,7 +196,7 @@ static ssize_t musb_test_mode_write(struct file *file,
memset(buf, 0x00, sizeof(buf));
if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (strstarts(buf, "force host"))

View file

@ -1612,9 +1612,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
static int
musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
{
struct musb *musb = gadget_to_musb(gadget);
musb->is_self_powered = !!is_selfpowered;
gadget->is_selfpowered = !!is_selfpowered;
return 0;
}

View file

@ -85,7 +85,7 @@ static int service_tx_status_request(
switch (recip) {
case USB_RECIP_DEVICE:
result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] = musb->g.is_selfpowered << USB_DEVICE_SELF_POWERED;
result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
if (musb->g.is_otg) {
result[0] |= musb->g.b_hnp_enable

View file

@ -72,7 +72,6 @@ void musb_host_finish_resume(struct work_struct *work)
musb->xceiv->otg->state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&musb->lock, flags);
musb_host_resume_root_hub(musb);
}
void musb_port_suspend(struct musb *musb, bool do_suspend)
@ -349,8 +348,7 @@ int musb_hub_control(
desc->bDescriptorType = 0x29;
desc->bNbrPorts = 1;
desc->wHubCharacteristics = cpu_to_le16(
HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
| HUB_CHAR_NO_OCPM /* no overcurrent reporting */
);
desc->bPwrOn2PwrGood = 5; /* msec/2 */

View file

@ -107,19 +107,6 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
#define fsl_writel(val, addr) writel(val, addr)
#endif /* CONFIG_PPC32 */
/* Routines to access transceiver ULPI registers */
u8 view_ulpi(u8 addr)
{
u32 temp;
temp = 0x40000000 | (addr << 16);
fsl_writel(temp, &usb_dr_regs->ulpiview);
udelay(1000);
while (temp & 0x40)
temp = fsl_readl(&usb_dr_regs->ulpiview);
return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
}
int write_ulpi(u8 addr, u8 data)
{
u32 temp;
@ -460,28 +447,6 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
fsl_otg_del_timer(fsm, timer);
}
/*
* Reduce timer count by 1, and find timeout conditions.
* Called by fsl_otg 1ms timer interrupt
*/
int fsl_otg_tick_timer(void)
{
struct fsl_otg_timer *tmp_timer, *del_tmp;
int expired = 0;
list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
tmp_timer->count--;
/* check if timer expires */
if (!tmp_timer->count) {
list_del(&tmp_timer->list);
tmp_timer->function(tmp_timer->data);
expired = 1;
}
}
return expired;
}
/* Reset controller, not reset the bus */
void otg_reset_controller(void)
{

View file

@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
#include <linux/slab.h>
@ -39,6 +40,10 @@
#include "phy-generic.h"
#define VBUS_IRQ_FLAGS \
(IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
IRQF_ONESHOT)
struct platform_device *usb_phy_generic_register(void)
{
return platform_device_register_simple("usb_phy_generic",
@ -59,19 +64,79 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
static void nop_reset_set(struct usb_phy_generic *nop, int asserted)
{
int value;
if (!gpio_is_valid(nop->gpio_reset))
if (!nop->gpiod_reset)
return;
value = asserted;
if (nop->reset_active_low)
value = !value;
gpiod_direction_output(nop->gpiod_reset, !asserted);
usleep_range(10000, 20000);
gpiod_set_value(nop->gpiod_reset, asserted);
}
gpio_set_value_cansleep(nop->gpio_reset, value);
/* interface to regulator framework */
static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
{
struct regulator *vbus_draw = nop->vbus_draw;
int enabled;
int ret;
if (!asserted)
usleep_range(10000, 20000);
if (!vbus_draw)
return;
enabled = nop->vbus_draw_enabled;
if (mA) {
regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
if (!enabled) {
ret = regulator_enable(vbus_draw);
if (ret < 0)
return;
nop->vbus_draw_enabled = 1;
}
} else {
if (enabled) {
ret = regulator_disable(vbus_draw);
if (ret < 0)
return;
nop->vbus_draw_enabled = 0;
}
}
nop->mA = mA;
}
static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
{
struct usb_phy_generic *nop = data;
struct usb_otg *otg = nop->phy.otg;
int vbus, status;
vbus = gpiod_get_value(nop->gpiod_vbus);
if ((vbus ^ nop->vbus) == 0)
return IRQ_HANDLED;
nop->vbus = vbus;
if (vbus) {
status = USB_EVENT_VBUS;
otg->state = OTG_STATE_B_PERIPHERAL;
nop->phy.last_event = status;
usb_gadget_vbus_connect(otg->gadget);
/* drawing a "unit load" is *always* OK, except for OTG */
nop_set_vbus_draw(nop, 100);
atomic_notifier_call_chain(&nop->phy.notifier, status,
otg->gadget);
} else {
nop_set_vbus_draw(nop, 0);
usb_gadget_vbus_disconnect(otg->gadget);
status = USB_EVENT_NONE;
otg->state = OTG_STATE_B_IDLE;
nop->phy.last_event = status;
atomic_notifier_call_chain(&nop->phy.notifier, status,
otg->gadget);
}
return IRQ_HANDLED;
}
int usb_gen_phy_init(struct usb_phy *phy)
@ -143,37 +208,48 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
struct usb_phy_generic_platform_data *pdata)
{
enum usb_phy_type type = USB_PHY_TYPE_USB2;
int err;
int err = 0;
u32 clk_rate = 0;
bool needs_vcc = false;
nop->reset_active_low = true; /* default behaviour */
if (dev->of_node) {
struct device_node *node = dev->of_node;
enum of_gpio_flags flags = 0;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
0, &flags);
if (nop->gpio_reset == -EPROBE_DEFER)
return -EPROBE_DEFER;
nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
if (!err) {
nop->gpiod_vbus = devm_gpiod_get_optional(dev,
"vbus-detect");
err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
}
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc;
nop->gpio_reset = pdata->gpio_reset;
} else {
nop->gpio_reset = -1;
if (gpio_is_valid(pdata->gpio_reset)) {
err = devm_gpio_request_one(dev, pdata->gpio_reset, 0,
dev_name(dev));
if (!err)
nop->gpiod_reset =
gpio_to_desc(pdata->gpio_reset);
}
nop->gpiod_vbus = pdata->gpiod_vbus;
}
if (err == -EPROBE_DEFER)
return -EPROBE_DEFER;
if (err) {
dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
return err;
}
if (nop->gpiod_reset)
gpiod_direction_output(nop->gpiod_reset, 1);
nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
GFP_KERNEL);
if (!nop->phy.otg)
@ -201,24 +277,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
return -EPROBE_DEFER;
}
if (gpio_is_valid(nop->gpio_reset)) {
unsigned long gpio_flags;
/* Assert RESET */
if (nop->reset_active_low)
gpio_flags = GPIOF_OUT_INIT_LOW;
else
gpio_flags = GPIOF_OUT_INIT_HIGH;
err = devm_gpio_request_one(dev, nop->gpio_reset,
gpio_flags, dev_name(dev));
if (err) {
dev_err(dev, "Error requesting RESET GPIO %d\n",
nop->gpio_reset);
return err;
}
}
nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
@ -247,6 +305,18 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
if (err)
return err;
if (nop->gpiod_vbus) {
err = devm_request_threaded_irq(&pdev->dev,
gpiod_to_irq(nop->gpiod_vbus),
NULL, nop_gpio_vbus_thread,
VBUS_IRQ_FLAGS, "vbus_detect",
nop);
if (err) {
dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
gpiod_to_irq(nop->gpiod_vbus), err);
return err;
}
}
nop->phy.init = usb_gen_phy_init;
nop->phy.shutdown = usb_gen_phy_shutdown;

View file

@ -2,14 +2,20 @@
#define _PHY_GENERIC_H_
#include <linux/usb/usb_phy_generic.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
struct usb_phy_generic {
struct usb_phy phy;
struct device *dev;
struct clk *clk;
struct regulator *vcc;
int gpio_reset;
bool reset_active_low;
struct gpio_desc *gpiod_reset;
struct gpio_desc *gpiod_vbus;
struct regulator *vbus_draw;
bool vbus_draw_enabled;
unsigned long mA;
unsigned int vbus;
};
int usb_gen_phy_init(struct usb_phy *phy);

View file

@ -40,6 +40,7 @@
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
@ -69,6 +70,9 @@
#define ANADIG_USB2_LOOPBACK_SET 0x244
#define ANADIG_USB2_LOOPBACK_CLR 0x248
#define ANADIG_USB1_MISC 0x1f0
#define ANADIG_USB2_MISC 0x250
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
@ -80,6 +84,11 @@
#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
#define BM_ANADIG_USB1_MISC_RX_VPIN_FS BIT(29)
#define BM_ANADIG_USB1_MISC_RX_VMIN_FS BIT(28)
#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
@ -131,8 +140,7 @@ static const struct mxs_phy_data vf610_phy_data = {
};
static const struct mxs_phy_data imx6sx_phy_data = {
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
MXS_PHY_NEED_IP_FIX,
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
};
static const struct of_device_id mxs_phy_dt_ids[] = {
@ -256,6 +264,18 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
usleep_range(500, 1000);
}
static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
{
void __iomem *base = mxs_phy->phy.io_priv;
u32 phyctrl = readl(base + HW_USBPHY_CTRL);
if (IS_ENABLED(CONFIG_USB_OTG) &&
!(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
return true;
return false;
}
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
{
bool vbus_is_on = false;
@ -270,7 +290,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (on && !vbus_is_on)
if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
__mxs_phy_disconnect_line(mxs_phy, true);
else
__mxs_phy_disconnect_line(mxs_phy, false);
@ -293,6 +313,17 @@ static int mxs_phy_init(struct usb_phy *phy)
static void mxs_phy_shutdown(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
BM_USBPHY_CTRL_ENIDCHG_WKUP |
BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
writel(BM_USBPHY_CTRL_CLKGATE,
phy->io_priv + HW_USBPHY_CTRL_SET);
@ -300,13 +331,56 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
clk_disable_unprepare(mxs_phy->clk);
}
static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
{
unsigned int line_state;
/* bit definition is the same for all controllers */
unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
unsigned int reg = ANADIG_USB1_MISC;
/* If the SoCs don't have anatop, quit */
if (!mxs_phy->regmap_anatop)
return false;
if (mxs_phy->port_id == 0)
reg = ANADIG_USB1_MISC;
else if (mxs_phy->port_id == 1)
reg = ANADIG_USB2_MISC;
regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
if ((line_state & (dp_bit | dm_bit)) == dm_bit)
return true;
else
return false;
}
static int mxs_phy_suspend(struct usb_phy *x, int suspend)
{
int ret;
struct mxs_phy *mxs_phy = to_mxs_phy(x);
bool low_speed_connection, vbus_is_on;
low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (suspend) {
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
/*
* FIXME: Do not power down RXPWD1PT1 bit for low speed
* connect. The low speed connection will have problem at
* very rare cases during usb suspend and resume process.
*/
if (low_speed_connection & vbus_is_on) {
/*
* If value to be set as pwd value is not 0xffffffff,
* several 32Khz cycles are needed.
*/
mxs_phy_clock_switch_delay();
writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
} else {
writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
}
writel(BM_USBPHY_CTRL_CLKGATE,
x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
@ -359,7 +433,9 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
dev_dbg(phy->dev, "%s device has disconnected\n",
(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
if (speed == USB_SPEED_HIGH)
/* Sometimes, the speed is not high speed when the error occurs */
if (readl(phy->io_priv + HW_USBPHY_CTRL) &
BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
phy->io_priv + HW_USBPHY_CTRL_CLR);

View file

@ -363,6 +363,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
int id;
int enable;
int cable;
int ret;
/*
@ -376,6 +377,16 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
id = usbhs_platform_call(priv, get_id, pdev);
if (enable && !mod) {
if (priv->edev) {
cable = extcon_get_cable_state(priv->edev, "USB-HOST");
if ((cable > 0 && id != USBHS_HOST) ||
(!cable && id != USBHS_GADGET)) {
dev_info(&pdev->dev,
"USB cable plugged in doesn't match the selected role!\n");
return;
}
}
ret = usbhs_mod_change(priv, id);
if (ret < 0)
return;
@ -514,6 +525,12 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
if (IS_ERR(priv->edev))
return PTR_ERR(priv->edev);
}
/*
* care platform info
*/
@ -615,7 +632,7 @@ static int usbhs_probe(struct platform_device *pdev)
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
dev_err(&pdev->dev, "platform prove failed.\n");
dev_err(&pdev->dev, "platform init failed.\n");
goto probe_end_mod_exit;
}
@ -632,16 +649,12 @@ static int usbhs_probe(struct platform_device *pdev)
/*
* manual call notify_hotplug for cold plug
*/
ret = usbhsc_drvcllbck_notify_hotplug(pdev);
if (ret < 0)
goto probe_end_call_remove;
usbhsc_drvcllbck_notify_hotplug(pdev);
dev_info(&pdev->dev, "probed\n");
return ret;
probe_end_call_remove:
usbhs_platform_call(priv, hardware_exit, pdev);
probe_end_mod_exit:
usbhs_mod_remove(priv);
probe_end_fifo_exit:

View file

@ -17,6 +17,7 @@
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
#include <linux/extcon.h>
#include <linux/platform_device.h>
#include <linux/usb/renesas_usbhs.h>
@ -254,6 +255,8 @@ struct usbhs_priv {
struct delayed_work notify_hotplug_work;
struct platform_device *pdev;
struct extcon_dev *edev;
spinlock_t lock;
u32 flags;

View file

@ -1054,10 +1054,8 @@ static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo)
fifo->rx_chan = NULL;
}
static void usbhsf_dma_init(struct usbhs_priv *priv,
struct usbhs_fifo *fifo)
static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo)
{
struct device *dev = usbhs_priv_to_dev(priv);
dma_cap_mask_t mask;
dma_cap_zero(mask);
@ -1069,6 +1067,27 @@ static void usbhsf_dma_init(struct usbhs_priv *priv,
dma_cap_set(DMA_SLAVE, mask);
fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter,
&fifo->rx_slave);
}
static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo)
{
fifo->tx_chan = dma_request_slave_channel_reason(dev, "tx");
if (IS_ERR(fifo->tx_chan))
fifo->tx_chan = NULL;
fifo->rx_chan = dma_request_slave_channel_reason(dev, "rx");
if (IS_ERR(fifo->rx_chan))
fifo->rx_chan = NULL;
}
static void usbhsf_dma_init(struct usbhs_priv *priv,
struct usbhs_fifo *fifo)
{
struct device *dev = usbhs_priv_to_dev(priv);
if (dev->of_node)
usbhsf_dma_init_dt(dev, fifo);
else
usbhsf_dma_init_pdev(fifo);
if (fifo->tx_chan || fifo->rx_chan)
dev_dbg(dev, "enable DMAEngine (%s%s%s)\n",

View file

@ -926,6 +926,8 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
else
usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
gadget->is_selfpowered = (is_self != 0);
return 0;
}

View file

@ -523,6 +523,7 @@ struct usb_gadget_ops {
* enabled HNP support.
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
* MaxPacketSize.
* @is_selfpowered: if the gadget is self-powered.
*
* Gadgets have a mostly-portable "gadget driver" implementing device
* functions, handling all usb configurations and interfaces. Gadget
@ -563,6 +564,7 @@ struct usb_gadget {
unsigned a_hnp_support:1;
unsigned a_alt_hnp_support:1;
unsigned quirk_ep_out_aligned_size:1;
unsigned is_selfpowered:1;
};
#define work_to_gadget(w) (container_of((w), struct usb_gadget, work))

View file

@ -1,5 +1,5 @@
/* USB OTG (On The Go) defines */
/*
* USB PHY defines
*
* These APIs may be used between USB controllers. USB device drivers
* (for either host or peripheral roles) don't use these calls; they
@ -106,7 +106,7 @@ struct usb_phy {
int (*set_power)(struct usb_phy *x,
unsigned mA);
/* for non-OTG B devices: set transceiver into suspend mode */
/* Set transceiver into suspend mode */
int (*set_suspend)(struct usb_phy *x,
int suspend);

View file

@ -2,6 +2,7 @@
#define __LINUX_USB_NOP_XCEIV_H
#include <linux/usb/otg.h>
#include <linux/gpio/consumer.h>
struct usb_phy_generic_platform_data {
enum usb_phy_type type;
@ -11,6 +12,7 @@ struct usb_phy_generic_platform_data {
unsigned int needs_vcc:1;
unsigned int needs_reset:1; /* deprecated */
int gpio_reset;
struct gpio_desc *gpiod_vbus;
};
#if IS_ENABLED(CONFIG_NOP_USB_XCEIV)

View file

@ -20,6 +20,7 @@ enum functionfs_flags {
FUNCTIONFS_HAS_SS_DESC = 4,
FUNCTIONFS_HAS_MS_OS_DESC = 8,
FUNCTIONFS_VIRTUAL_ADDR = 16,
FUNCTIONFS_EVENTFD = 32,
};
/* Descriptor of an non-audio endpoint */

View file

@ -33,11 +33,6 @@
#define VENDOR 0x1d6b
#define PRODUCT 0x0105
/* endpoints indexes */
#define EP_BULK_IN (1 | LIBUSB_ENDPOINT_IN)
#define EP_BULK_OUT (2 | LIBUSB_ENDPOINT_OUT)
#define BUF_LEN 8192
/*
@ -159,14 +154,21 @@ void test_exit(struct test_state *state)
int main(void)
{
struct test_state state;
struct libusb_config_descriptor *conf;
struct libusb_interface_descriptor const *iface;
unsigned char addr;
if (test_init(&state))
return 1;
libusb_get_config_descriptor(state.found, 0, &conf);
iface = &conf->interface[0].altsetting[0];
addr = iface->endpoint[0].bEndpointAddress;
while (1) {
static unsigned char buffer[BUF_LEN];
int bytes;
libusb_bulk_transfer(state.handle, EP_BULK_IN, buffer, BUF_LEN,
libusb_bulk_transfer(state.handle, addr, buffer, BUF_LEN,
&bytes, 500);
}
test_exit(&state);

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