Commit ba7756d0 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

Felipe writes:

usb: changes for v4.12

With 51 non-merge commits, this is one of the smallest USB Gadget pull
requests. Apart from your expected set of non-critical fixes, and
other miscellaneous items, we have most of the changes in dwc3 (52.5%)
with all other UDCs following with 34.8%.

As for the actual changes, the most important of them are all the
recent changes to reduce memory footprint of dwc3, bare minimum
dual-role support on dwc3 and reworked endpoint count and
initialization routines.
parents a6308d70 48eab1f2
What: /sys/devices/platform/<renesas_usb3's name>/role
Date: March 2017
KernelVersion: 4.13
Contact: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Description:
This file can be read and write.
The file can show/change the drd mode of usb.
Write the following string to change the mode:
"host" - switching mode from peripheral to host.
"peripheral" - switching mode from host to peripheral.
Read the file, then it shows the following strings:
"host" - The mode is host now.
"peripheral" - The mode is peripheral now.
......@@ -31,6 +31,13 @@
#include <linux/usb/otg.h>
#include <linux/usb/otg-fsm.h>
#ifdef VERBOSE
#define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
__func__, ## args)
#else
#define VDBG(stuff...) do {} while (0)
#endif
/* Change USB protocol when there is a protocol change */
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
{
......
......@@ -423,6 +423,10 @@ enum dwc2_ep0_state {
* needed.
* 0 - No (default)
* 1 - Yes
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
* register.
* 0 - Deactivate the transceiver (default)
* 1 - Activate the transceiver
* @g_dma: Enables gadget dma usage (default: autodetect).
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
......@@ -477,6 +481,7 @@ struct dwc2_core_params {
bool uframe_sched;
bool external_id_pin_ctl;
bool hibernation;
bool activate_stm_fs_transceiver;
u16 max_packet_count;
u32 max_transfer_size;
u32 ahbcfg;
......
......@@ -121,7 +121,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
{
u32 usbcfg, i2cctl;
u32 usbcfg, ggpio, i2cctl;
int retval = 0;
/*
......@@ -145,6 +145,19 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
return retval;
}
}
if (hsotg->params.activate_stm_fs_transceiver) {
ggpio = dwc2_readl(hsotg->regs + GGPIO);
if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
dev_dbg(hsotg->dev, "Activating transceiver\n");
/*
* STM32F4x9 uses the GGPIO register as general
* core configuration register.
*/
ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
dwc2_writel(ggpio, hsotg->regs + GGPIO);
}
}
}
/*
......@@ -3264,6 +3277,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_disconnect(hsotg);
dwc2_hsotg_core_init_disconnected(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
dwc2_hsotg_core_connect(hsotg);
......
......@@ -225,6 +225,8 @@
#define GPVNDCTL HSOTG_REG(0x0034)
#define GGPIO HSOTG_REG(0x0038)
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
#define GUID HSOTG_REG(0x003c)
#define GSNPSID HSOTG_REG(0x0040)
#define GHWCFG1 HSOTG_REG(0x0044)
......
......@@ -120,6 +120,22 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
}
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->speed = DWC2_SPEED_PARAM_FULL;
p->host_rx_fifo_size = 128;
p->host_nperio_tx_fifo_size = 96;
p->host_perio_tx_fifo_size = 96;
p->max_packet_count = 256;
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
p->i2c_enable = false;
p->uframe_sched = false;
p->activate_stm_fs_transceiver = true;
}
const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
......@@ -133,6 +149,9 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "amlogic,meson-gxbb-usb",
.data = dwc2_set_amlogic_params },
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
{ .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" },
{},
};
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
......
......@@ -214,19 +214,10 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
if (IS_ERR(hsotg->reset)) {
ret = PTR_ERR(hsotg->reset);
switch (ret) {
case -ENOENT:
case -ENOTSUPP:
hsotg->reset = NULL;
break;
default:
dev_err(hsotg->dev, "error getting reset control %d\n",
ret);
dev_err(hsotg->dev, "error getting reset control %d\n", ret);
return ret;
}
}
if (hsotg->reset)
reset_control_deassert(hsotg->reset);
/* Set default UTMI width */
......@@ -326,7 +317,6 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg);
if (hsotg->reset)
reset_control_assert(hsotg->reset);
return 0;
......
......@@ -41,6 +41,7 @@ config USB_DWC3_GADGET
config USB_DWC3_DUAL_ROLE
bool "Dual Role mode"
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
depends on (EXTCON=y || EXTCON=USB_DWC3)
help
This is the default mode of working of DWC3 controller where
both host and gadget features are enabled.
......
......@@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
dwc3-y += gadget.o ep0.o
endif
ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
dwc3-y += drd.o
endif
ifneq ($(CONFIG_USB_DWC3_ULPI),)
dwc3-y += ulpi.o
endif
......
......@@ -100,7 +100,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
return 0;
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
static int dwc3_event_buffers_setup(struct dwc3 *dwc);
static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
{
u32 reg;
......@@ -110,6 +113,69 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
}
static void __dwc3_set_mode(struct work_struct *work)
{
struct dwc3 *dwc = work_to_dwc(work);
unsigned long flags;
int ret;
if (!dwc->desired_dr_role)
return;
if (dwc->desired_dr_role == dwc->current_dr_role)
return;
if (dwc->dr_mode != USB_DR_MODE_OTG)
return;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
dwc3_host_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_gadget_exit(dwc);
dwc3_event_buffers_cleanup(dwc);
break;
default:
break;
}
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
dwc->current_dr_role = dwc->desired_dr_role;
spin_unlock_irqrestore(&dwc->lock, flags);
switch (dwc->desired_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
ret = dwc3_host_init(dwc);
if (ret)
dev_err(dwc->dev, "failed to initialize host\n");
break;
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_event_buffers_setup(dwc);
ret = dwc3_gadget_init(dwc);
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");
break;
default:
break;
}
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
dwc->desired_dr_role = mode;
spin_unlock_irqrestore(&dwc->lock, flags);
queue_work(system_power_efficient_wq, &dwc->drd_work);
}
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
{
struct dwc3 *dwc = dep->dwc;
......@@ -397,8 +463,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
{
struct dwc3_hwparams *parms = &dwc->hwparams;
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
dwc->num_eps = DWC3_NUM_EPS(parms);
}
static void dwc3_cache_hwparams(struct dwc3 *dwc)
......@@ -431,6 +496,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
/*
* Make sure UX_EXIT_PX is cleared as that causes issues with some
* PHYs. Also, this bit is not supposed to be used in normal operation.
*/
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
/*
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
* to '0' during coreConsultant configuration. So default value
......@@ -714,21 +785,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
goto err4;
}
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
break;
case USB_DR_MODE_HOST:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
break;
case USB_DR_MODE_OTG:
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
break;
default:
dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
break;
}
/*
* ENDXFER polling is available on version 3.10a and later of
* the DWC_usb3 controller. It is NOT available in the
......@@ -846,6 +902,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
......@@ -854,6 +911,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_HOST:
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
......@@ -862,17 +920,11 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_OTG:
ret = dwc3_host_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize host\n");
return ret;
}
ret = dwc3_gadget_init(dwc);
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
ret = dwc3_drd_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize gadget\n");
dev_err(dev, "failed to initialize dual-role\n");
return ret;
}
break;
......@@ -894,8 +946,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
dwc3_host_exit(dwc);
dwc3_gadget_exit(dwc);
dwc3_drd_exit(dwc);
break;
default:
/* do nothing */
......
This diff is collapsed.
......@@ -124,6 +124,34 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
}
}
/**
* dwc3_trb_type_string - returns TRB type as a string
* @type: the type of the TRB
*/
static inline const char *dwc3_trb_type_string(unsigned int type)
{
switch (type) {
case DWC3_TRBCTL_NORMAL:
return "normal";
case DWC3_TRBCTL_CONTROL_SETUP:
return "setup";
case DWC3_TRBCTL_CONTROL_STATUS2:
return "status2";
case DWC3_TRBCTL_CONTROL_STATUS3:
return "status3";
case DWC3_TRBCTL_CONTROL_DATA:
return "data";
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
return "isoc-first";
case DWC3_TRBCTL_ISOCHRONOUS:
return "isoc";
case DWC3_TRBCTL_LINK_TRB:
return "link";
default:
return "UNKNOWN";
}
}
static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
{
switch (state) {
......
......@@ -300,7 +300,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
seq_printf(s, "device\n");
break;
case DWC3_GCTL_PRTCAP_OTG:
seq_printf(s, "OTG\n");
seq_printf(s, "otg\n");
break;
default:
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
......@@ -319,7 +319,6 @@ static ssize_t dwc3_mode_write(struct file *file,
{
struct seq_file *s = file->private_data;
struct dwc3 *dwc = s->private;
unsigned long flags;
u32 mode = 0;
char buf[32];
......@@ -327,19 +326,16 @@ static ssize_t dwc3_mode_write(struct file *file,
return -EFAULT;
if (!strncmp(buf, "host", 4))
mode |= DWC3_GCTL_PRTCAP_HOST;
mode = DWC3_GCTL_PRTCAP_HOST;
if (!strncmp(buf, "device", 6))
mode |= DWC3_GCTL_PRTCAP_DEVICE;
mode = DWC3_GCTL_PRTCAP_DEVICE;
if (!strncmp(buf, "otg", 3))
mode |= DWC3_GCTL_PRTCAP_OTG;
mode = DWC3_GCTL_PRTCAP_OTG;
if (mode) {
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_mode(dwc, mode);
spin_unlock_irqrestore(&dwc->lock, flags);
}
return count;
}
......@@ -446,52 +442,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
state = DWC3_DSTS_USBLNKST(reg);
spin_unlock_irqrestore(&dwc->lock, flags);
switch (state) {
case DWC3_LINK_STATE_U0:
seq_printf(s, "U0\n");
break;
case DWC3_LINK_STATE_U1:
seq_printf(s, "U1\n");
break;
case DWC3_LINK_STATE_U2:
seq_printf(s, "U2\n");
break;
case DWC3_LINK_STATE_U3:
seq_printf(s, "U3\n");
break;
case DWC3_LINK_STATE_SS_DIS:
seq_printf(s, "SS.Disabled\n");
break;
case DWC3_LINK_STATE_RX_DET:
seq_printf(s, "Rx.Detect\n");
break;
case DWC3_LINK_STATE_SS_INACT:
seq_printf(s, "SS.Inactive\n");
break;
case DWC3_LINK_STATE_POLL:
seq_printf(s, "Poll\n");
break;
case DWC3_LINK_STATE_RECOV:
seq_printf(s, "Recovery\n");
break;
case DWC3_LINK_STATE_HRESET:
seq_printf(s, "HRESET\n");
break;
case DWC3_LINK_STATE_CMPLY:
seq_printf(s, "Compliance\n");
break;
case DWC3_LINK_STATE_LPBK:
seq_printf(s, "Loopback\n");
break;
case DWC3_LINK_STATE_RESET:
seq_printf(s, "Reset\n");
break;
case DWC3_LINK_STATE_RESUME:
seq_printf(s, "Resume\n");
break;
default:
seq_printf(s, "UNKNOWN %d\n", state);
}
seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
return 0;
}
......@@ -689,30 +640,6 @@ static int dwc3_ep_transfer_type_show(struct seq_file *s, void *unused)
return 0;
}
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
{
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
case DWC3_TRBCTL_NORMAL:
return "normal";
case DWC3_TRBCTL_CONTROL_SETUP:
return "control-setup";
case DWC3_TRBCTL_CONTROL_STATUS2:
return "control-status2";
case DWC3_TRBCTL_CONTROL_STATUS3:
return "control-status3";
case DWC3_TRBCTL_CONTROL_DATA:
return "control-data";
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
return "isoc-first";
case DWC3_TRBCTL_ISOCHRONOUS:
return "isoc";
case DWC3_TRBCTL_LINK_TRB:
return "link";
default:
return "UNKNOWN";
}
}
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
{
struct dwc3_ep *dep = s->private;
......@@ -733,10 +660,11 @@ static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
for (i = 0; i < DWC3_TRB_NUM; i++) {
struct dwc3_trb *trb = &dep->trb_pool[i];
unsigned int type = DWC3_TRBCTL_TYPE(trb->ctrl);
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
trb->bph, trb->bpl, trb->size,
dwc3_trb_type_string(trb),
dwc3_trb_type_string(type),
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
......@@ -822,19 +750,8 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
{
int i;
for (i = 0; i < dwc->num_in_eps; i++) {
u8 epnum = (i << 1) | 1;
struct dwc3_ep *dep = dwc->eps[epnum];
if (!dep)
continue;
dwc3_debugfs_create_endpoint_dir(dep, parent);
}
for (i = 0; i < dwc->num_out_eps; i++) {
u8 epnum = (i << 1);
struct dwc3_ep *dep = dwc->eps[epnum];
for (i = 0; i < dwc->num_eps; i++) {
struct dwc3_ep *dep = dwc->eps[i];
if (!dep)
continue;
......
/**
* drd.c - DesignWare USB3 DRD Controller Dual-role support
*
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
*
* Authors: Roger Quadros <rogerq@ti.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 of
* the License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/extcon.h>
#include "debug.h"
#include "core.h"
#include "gadget.h"
static void dwc3_drd_update(struct dwc3 *dwc)
{
int id;
id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
if (id < 0)
id = 0;
dwc3_set_mode(dwc, id ?
DWC3_GCTL_PRTCAP_HOST :
DWC3_GCTL_PRTCAP_DEVICE);
}
static int dwc3_drd_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
dwc3_set_mode(dwc, event ?
DWC3_GCTL_PRTCAP_HOST :
DWC3_GCTL_PRTCAP_DEVICE);
return NOTIFY_DONE;
}
int dwc3_drd_init(struct dwc3 *dwc)
{
int ret;
if (dwc->dev->of_node) {
if (of_property_read_bool(dwc->dev->of_node, "extcon"))
dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
if (IS_ERR(dwc->edev))
return PTR_ERR(dwc->edev);
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb);
if (ret < 0) {
dev_err(dwc->dev, "couldn't register cable notifier\n");
return ret;
}
}
dwc3_drd_update(dwc);
return 0;
}
void dwc3_drd_exit(struct dwc3 *dwc)
{
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb);
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
flush_work(&dwc->drd_work);
dwc3_gadget_exit(dwc);
}
......@@ -147,53 +147,53 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
if (IS_ERR(exynos->vdd33)) {
ret = PTR_ERR(exynos->vdd33);
goto err2;
goto vdd33_err;
}
ret = regulator_enable(exynos->vdd33);
if (ret) {
dev_err(dev, "Failed to enable VDD33 supply\n");
goto err2;
goto vdd33_err;
}
exynos->vdd10 = devm_regulator_get(dev, "vdd10");
if (IS_ERR(exynos->vdd10)) {
ret = PTR_ERR(exynos->vdd10);
goto err3;
goto vdd10_err;
}
ret = regulator_enable(exynos->vdd10);
if (ret) {
dev_err(dev, "Failed to enable VDD10 supply\n");
goto err3;
goto vdd10_err;
}
ret = dwc3_exynos_register_phys(exynos);
if (ret) {
dev_err(dev, "couldn't register PHYs\n");
goto err4;
goto phys_err;
}
if (node) {
ret = of_platform_populate(node, NULL, NULL, dev);
if (ret) {
dev_err(dev, "failed to add dwc3 core\n");
goto err5;
goto populate_err;
}
} else {
dev_err(dev, "no device node, failed to add dwc3 core\n");
ret = -ENODEV;
goto err5;
goto populate_err;
}
return 0;
err5:
populate_err:
platform_device_unregister(exynos->usb2_phy);
platform_device_unregister(exynos->usb3_phy);
err4:
phys_err:
regulator_disable(exynos->vdd10);
err3:
vdd10_err:
regulator_disable(exynos->vdd33);
err2:
vdd33_err:
clk_disable_unprepare(exynos->axius_clk);
axius_clk_err:
clk_disable_unprepare(exynos->susp_clk);
......
......@@ -79,40 +79,40 @@
#define USBOTGSS_DEBUG_OFFSET 0x0600
/* SYSCONFIG REGISTER */
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
#define USBOTGSS_SYSCONFIG_DMADISABLE BIT(16)
/* IRQ_EOI REGISTER */
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
#define USBOTGSS_IRQ_EOI_LINE_NUMBER BIT(0)
/* IRQS0 BITS */
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
#define USBOTGSS_IRQO_COREIRQ_ST BIT(0)
/* IRQMISC BITS */
#define USBOTGSS_IRQMISC_DMADISABLECLR (1 << 17)
#define USBOTGSS_IRQMISC_OEVT (1 << 16)
#define USBOTGSS_IRQMISC_DRVVBUS_RISE (1 << 13)
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE (1 << 12)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE (1 << 11)
#define USBOTGSS_IRQMISC_IDPULLUP_RISE (1 << 8)
#define USBOTGSS_IRQMISC_DRVVBUS_FALL (1 << 5)
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL (1 << 4)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3)
#define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0)
#define USBOTGSS_IRQMISC_DMADISABLECLR BIT(17)
#define USBOTGSS_IRQMISC_OEVT BIT(16)
#define USBOTGSS_IRQMISC_DRVVBUS_RISE BIT(13)
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE BIT(12)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE BIT(11)
#define USBOTGSS_IRQMISC_IDPULLUP_RISE BIT(8)
#define USBOTGSS_IRQMISC_DRVVBUS_FALL BIT(5)
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL BIT(4)
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL BIT(3)
#define USBOTGSS_IRQMISC_IDPULLUP_FALL BIT(0)
/* UTMI_OTG_STATUS REGISTER */
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS (1 << 5)
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS (1 << 4)
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS (1 << 3)
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP (1 << 0)
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS BIT(5)
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS BIT(4)
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS BIT(3)
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP BIT(0)
/* UTMI_OTG_CTRL REGISTER */
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE (1 << 31)
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT (1 << 9)
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8)
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG (1 << 4)
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND (1 << 3)
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID (1 << 2)
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID (1 << 1)
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE BIT(31)
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT BIT(9)
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE BIT(8)
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG BIT(4)
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND BIT(3)
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID BIT(2)
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID BIT(1)
struct dwc3_omap {
struct device *dev;
......
......@@ -39,14 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
struct dwc3_ep *dep, struct dwc3_request *req);
static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
{
struct dwc3_trb *trb;
struct dwc3_ep *dep;
dep = dwc->eps[epnum];
struct dwc3 *dwc;
dwc = dep->dwc;
trb = &dwc->ep0_trb[dep->trb_enqueue];
if (chain)
......@@ -69,16 +68,17 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
trace_dwc3_prepare_trb(dep, trb);
}
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
static int dwc3_ep0_start_trans(struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_ep *dep;
struct dwc3 *dwc;
int ret;
dep = dwc->eps[epnum];
if (dep->flags & DWC3_EP_BUSY)
return 0;
dwc = dep->dwc;
memset(&params, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
......@@ -279,13 +279,15 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
void dwc3_ep0_out_start(struct dwc3 *dwc)
{
struct dwc3_ep *dep;
int ret;
complete(&dwc->ep0_in_setup);
dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
dep = dwc->eps[0];
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8,
DWC3_TRBCTL_CONTROL_SETUP, false);
ret = dwc3_ep0_start_trans(dwc, 0);
ret = dwc3_ep0_start_trans(dep);
WARN_ON(ret < 0);
}
......@@ -794,7 +796,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
const struct dwc3_event_depevt *event)
{
struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb;
int ret = -EINVAL;
u32 len;
......@@ -834,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct usb_request *ur;
struct dwc3_trb *trb;
struct dwc3_ep *ep0;
unsigned transfer_size = 0;
unsigned maxp;
unsigned remaining_ur_length;
void *buf;
......@@ -847,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
ep0 = dwc->eps[0];
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
trb = dwc->ep0_trb;
trace_dwc3_complete_trb(ep0, trb);
r = next_request(&ep0->pending_list);
......@@ -870,58 +869,23 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
remaining_ur_length = ur->length;
length = trb->size & DWC3_TRB_SIZE_MASK;
maxp = ep0->endpoint.maxpacket;
if (dwc->ep0_bounced) {
/*
* Handle the first TRB before handling the bounce buffer if
* the request length is greater than the bounce buffer size
*/
if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
transfer_size = ALIGN(ur->length - maxp, maxp);
transferred = transfer_size - length;
buf = (u8 *)buf + transferred;
transferred = ur->length - length;
ur->actual += transferred;
remaining_ur_length -= transferred;
if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
ur->length && ur->zero) || dwc->ep0_bounced) {
trb++;
length = trb->size & DWC3_TRB_SIZE_MASK;
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
trace_dwc3_complete_trb(ep0, trb);
ep0->trb_enqueue = 0;
dwc->ep0_bounced = false;
}
transfer_size = roundup((ur->length - transfer_size),
maxp);
transferred = min_t(u32, remaining_ur_length,
transfer_size - length);
memcpy(buf, dwc->ep0_bounce, transferred);
} else {
transferred = ur->length - length;
}
ur->actual += transferred;
if ((epnum & 1) && ur->actual < ur->length) {
/* for some reason we did not get everything out */
if ((epnum & 1) && ur->actual < ur->length)
dwc3_ep0_stall_and_restart(dwc);
} else {
else
dwc3_gadget_giveback(ep0, r, 0);
if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
ur->length && ur->zero) {
int ret;
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
0, DWC3_TRBCTL_CONTROL_DATA, false);
ret = dwc3_ep0_start_trans(dwc, epnum);
WARN_ON(ret < 0);
}
}
}
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
......@@ -997,14 +961,13 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
req->direction = !!dep->number;
if (req->request.length == 0) {
dwc3_ep0_prepare_one_trb(dwc, dep->number,
dwc->ctrl_req_addr, 0,
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0,
DWC3_TRBCTL_CONTROL_DATA, false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
ret = dwc3_ep0_start_trans(dep);
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
&& (dep->number == 0)) {
u32 transfer_size = 0;
u32 maxpacket;
u32 rem;
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number);
......@@ -1012,36 +975,55 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
return;
maxpacket = dep->endpoint.maxpacket;
rem = req->request.length % maxpacket;
dwc->ep0_bounced = true;
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
transfer_size = ALIGN(req->request.length - maxpacket,
maxpacket);
dwc3_ep0_prepare_one_trb(dwc, dep->number,
req->request.dma,
transfer_size,
/* prepare normal TRB */
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
req->request.length,
DWC3_TRBCTL_CONTROL_DATA,
true);
}
transfer_size = roundup((req->request.length - transfer_size),
maxpacket);
/* Now prepare one extra TRB to align transfer size */
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
maxpacket - rem,
DWC3_TRBCTL_CONTROL_DATA,
false);
ret = dwc3_ep0_start_trans(dep);
} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
req->request.length && req->request.zero) {
u32 maxpacket;
u32 rem;
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number);
if (ret)
return;
dwc->ep0_bounced = true;
maxpacket = dep->endpoint.maxpacket;
rem = req->request.length % maxpacket;
dwc3_ep0_prepare_one_trb(dwc, dep->number,
dwc->ep0_bounce_addr, transfer_size,
DWC3_TRBCTL_CONTROL_DATA, false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
/* prepare normal TRB */
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
req->request.length,
DWC3_TRBCTL_CONTROL_DATA,
true);
/* Now prepare one extra TRB to align transfer size */
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
0, DWC3_TRBCTL_CONTROL_DATA,
false);
ret = dwc3_ep0_start_trans(dep);
} else {
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
&req->request, dep->number);
if (ret)
return;
dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
false);
ret = dwc3_ep0_start_trans(dwc, dep->number);
ret = dwc3_ep0_start_trans(dep);
}
WARN_ON(ret < 0);
......@@ -1055,9 +1037,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
: DWC3_TRBCTL_CONTROL_STATUS2;
dwc3_ep0_prepare_one_trb(dwc, dep->number,
dwc->ctrl_req_addr, 0, type, false);
return dwc3_ep0_start_trans(dwc, dep->number);
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, type, false);
return dwc3_ep0_start_trans(dep);
}
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
......
This diff is collapsed.
......@@ -29,16 +29,16 @@ struct dwc3;
/* DEPCFG parameter 1 */
#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
#define DWC3_DEPCFG_XFER_COMPLETE_EN BIT(8)
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(12)
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 24)
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
#define DWC3_DEPCFG_BULK_BASED BIT(30)
#define DWC3_DEPCFG_FIFO_BASED BIT(31)
/* DEPCFG parameter 0 */
#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
......@@ -47,10 +47,10 @@ struct dwc3;
#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
/* This applies for core versions earlier than 1.94a */
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
#define DWC3_DEPCFG_IGN_SEQ_NUM BIT(31)
/* These apply for core versions 1.94a and later */
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30)
#define DWC3_DEPCFG_ACTION_RESTORE BIT(30)
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
/* DEPXFERCFG parameter 0 */
......
......@@ -27,31 +27,6 @@
#include "core.h"
#include "debug.h"
DECLARE_EVENT_CLASS(dwc3_log_msg,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf),
TP_STRUCT__entry(__dynamic_array(char, msg, DWC3_MSG_MAX)),
TP_fast_assign(
vsnprintf(__get_str(msg), DWC3_MSG_MAX, vaf->fmt, *vaf->va);
),
TP_printk("%s", __get_str(msg))
);
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)
);
DECLARE_EVENT_CLASS(dwc3_log_io,
TP_PROTO(void *base, u32 offset, u32 value),
TP_ARGS(base, offset, value),
......@@ -198,7 +173,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
__entry->param = param;
__entry->status = status;
),
TP_printk("cmd '%s' [%d] param %08x --> status: %s",
TP_printk("cmd '%s' [%x] param %08x --> status: %s",
dwc3_gadget_generic_cmd_string(__entry->cmd),
__entry->cmd, __entry->param,
dwc3_gadget_generic_cmd_status_string(__entry->status)
......@@ -298,36 +273,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
({char *s;
switch (__entry->ctrl & 0x3f0) {
case DWC3_TRBCTL_NORMAL:
s = "normal";
break;
case DWC3_TRBCTL_CONTROL_SETUP:
s = "setup";
break;
case DWC3_TRBCTL_CONTROL_STATUS2:
s = "status2";
break;
case DWC3_TRBCTL_CONTROL_STATUS3:
s = "status3";
break;
case DWC3_TRBCTL_CONTROL_DATA:
s = "data";
break;
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
s = "isoc-first";
break;
case DWC3_TRBCTL_ISOCHRONOUS:
s = "isoc";
break;
case DWC3_TRBCTL_LINK_TRB:
s = "link";
break;
default:
s = "UNKNOWN";
break;
} s; })
dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
)
);
......
......@@ -212,7 +212,7 @@ config USB_F_TCM
# this first set of drivers all depend on bulk-capable hardware.
config USB_CONFIGFS
tristate "USB functions configurable through configfs"
tristate "USB Gadget functions configurable through configfs"
select USB_LIBCOMPOSITE
help
A Linux USB "gadget" can be set up through configfs.
......@@ -458,8 +458,9 @@ config USB_CONFIGFS_F_TCM
UAS utilizes the USB 3.0 feature called streams support.
choice
tristate "USB Gadget Drivers"
tristate "USB Gadget precomposed configurations"
default USB_ETH
optional
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller
driver through the abstract "gadget" API. Some other operating
......@@ -476,6 +477,12 @@ choice
not be able work with that controller, or might need to implement
a less common variant of a device class protocol.
The available choices each represent a single precomposed USB
gadget configuration. In the device model, each option contains
both the device instantiation as a child for a USB gadget
controller, and the relevant drivers for each function declared
by the device.
source "drivers/usb/gadget/legacy/Kconfig"
endchoice
......
......@@ -246,7 +246,6 @@ EXPORT_SYMBOL_GPL(ffs_lock);
static struct ffs_dev *_ffs_find_dev(const char *name);
static struct ffs_dev *_ffs_alloc_dev(void);
static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
static void _ffs_free_dev(struct ffs_dev *dev);
static void *ffs_acquire_dev(const char *dev_name);
static void ffs_release_dev(struct ffs_data *ffs_data);
......@@ -3302,9 +3301,10 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name)
{
struct ffs_dev *dev;
if (!name)
return NULL;
list_for_each_entry(dev, &ffs_devices, entry) {
if (!dev->name || !name)
continue;
if (strcmp(dev->name, name) == 0)
return dev;
}
......@@ -3380,42 +3380,11 @@ static void ffs_free_inst(struct usb_function_instance *f)
kfree(opts);
}
#define MAX_INST_NAME_LEN 40
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
{
struct f_fs_opts *opts;
char *ptr;
const char *tmp;
int name_len, ret;
name_len = strlen(name) + 1;
if (name_len > MAX_INST_NAME_LEN)
if (strlen(name) >= FIELD_SIZEOF(struct ffs_dev, name))
return -ENAMETOOLONG;
ptr = kstrndup(name, name_len, GFP_KERNEL);
if (!ptr)
return -ENOMEM;
opts = to_f_fs_opts(fi);
tmp = NULL;
ffs_dev_lock();
tmp = opts->dev->name_allocated ? opts->dev->name : NULL;
ret = _ffs_name_dev(opts->dev, ptr);
if (ret) {
kfree(ptr);
ffs_dev_unlock();
return ret;
}
opts->dev->name_allocated = true;
ffs_dev_unlock();
kfree(tmp);
return 0;
return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
}
static struct usb_function_instance *ffs_alloc_inst(void)
......@@ -3545,32 +3514,19 @@ static struct ffs_dev *_ffs_alloc_dev(void)
return dev;
}
/*
* ffs_lock must be taken by the caller of this function
* The caller is responsible for "name" being available whenever f_fs needs it
*/
static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
int ffs_name_dev(struct ffs_dev *dev, const char *name)
{
struct ffs_dev *existing;
int ret = 0;
existing = _ffs_do_find_dev(name);
if (existing)
return -EBUSY;
dev->name = name;
return 0;
}
ffs_dev_lock();
/*
* The caller is responsible for "name" being available whenever f_fs needs it
*/
int ffs_name_dev(struct ffs_dev *dev, const char *name)
{
int ret;
existing = _ffs_do_find_dev(name);
if (!existing)
strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
else if (existing != dev)
ret = -EBUSY;
ffs_dev_lock();
ret = _ffs_name_dev(dev, name);
ffs_dev_unlock();
return ret;
......@@ -3600,8 +3556,6 @@ EXPORT_SYMBOL_GPL(ffs_single_dev);
static void _ffs_free_dev(struct ffs_dev *dev)
{
list_del(&dev->entry);
if (dev->name_allocated)
kfree(dev->name);
/* Clear the private_data pointer to stop incorrect dev access */
if (dev->ffs_data)
......
......@@ -178,6 +178,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req);
static int
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
{
struct usb_gadget *g = dev->gadget;
struct sk_buff *skb;
int retval = -ENOMEM;
size_t size = 0;
......@@ -209,8 +210,11 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
*/
size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
size += dev->port_usb->header_len;
if (g->quirk_ep_out_aligned_size) {
size += out->maxpacket - 1;
size -= size % out->maxpacket;
}
if (dev->port_usb->is_fixed)
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
......@@ -401,13 +405,12 @@ static int alloc_requests(struct eth_dev *dev, struct gether *link, unsigned n)
static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
{
struct usb_request *req;
struct usb_request *tmp;
unsigned long flags;
/* fill unused rxq slots with some skb */
spin_lock_irqsave(&dev->req_lock, flags);
while (!list_empty(&dev->rx_reqs)) {
req = container_of(dev->rx_reqs.next,
struct usb_request, list);
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
list_del_init(&req->list);
spin_unlock_irqrestore(&dev->req_lock, flags);
......@@ -527,7 +530,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
req = container_of(dev->tx_reqs.next, struct usb_request, list);
req = list_first_entry(&dev->tx_reqs, struct usb_request, list);
list_del(&req->list);
/* temporarily stop TX queue when the freelist empties */
......@@ -1122,6 +1125,7 @@ void gether_disconnect(struct gether *link)
{
struct eth_dev *dev = link->ioport;
struct usb_request *req;
struct usb_request *tmp;
WARN_ON(!dev);
if (!dev)
......@@ -1138,9 +1142,7 @@ void gether_disconnect(struct gether *link)
*/
usb_ep_disable(link->in_ep);
spin_lock(&dev->req_lock);
while (!list_empty(&dev->tx_reqs)) {
req = container_of(dev->tx_reqs.next,
struct usb_request, list);
list_for_each_entry_safe(req, tmp, &dev->tx_reqs, list) {
list_del(&req->list);
spin_unlock(&dev->req_lock);
......@@ -1152,9 +1154,7 @@ void gether_disconnect(struct gether *link)
usb_ep_disable(link->out_ep);
spin_lock(&dev->req_lock);
while (!list_empty(&dev->rx_reqs)) {
req = container_of(dev->rx_reqs.next,
struct usb_request, list);
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
list_del(&req->list);
spin_unlock(&dev->req_lock);
......
......@@ -40,15 +40,16 @@
struct f_fs_opts;
struct ffs_dev {
const char *name;
bool name_allocated;
bool mounted;
bool desc_ready;
bool single;
struct ffs_data *ffs_data;
struct f_fs_opts *opts;
struct list_head entry;
char name[41];
bool mounted;
bool desc_ready;
bool single;
int (*ffs_ready_callback)(struct ffs_data *ffs);
void (*ffs_closed_callback)(struct ffs_data *ffs);
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
......
......@@ -2125,7 +2125,7 @@ static struct configfs_item_operations uvc_item_ops = {
.release = uvc_attr_release,
};
#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
static ssize_t f_uvc_opts_##cname##_show( \
struct config_item *item, char *page) \
{ \
......@@ -2168,16 +2168,16 @@ end: \
return ret; \
} \
\
UVC_ATTR(f_uvc_opts_, cname, aname)
UVC_ATTR(f_uvc_opts_, cname, cname)
#define identity_conv(x) (x)
UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
16);
UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
3072);
UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
15);
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
kstrtou8, u8, identity_conv, 16);
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
kstrtou16, u16, le16_to_cpu, 3072);
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
kstrtou8, u8, identity_conv, 15);
#undef identity_conv
......
......@@ -62,8 +62,9 @@ config USB_ATMEL_USBA
The fifo_mode parameter is used to select endpoint allocation mode.
fifo_mode = 0 is used to let the driver autoconfigure the endpoints.
In this case 2 banks are allocated for isochronous endpoints and
only one bank is allocated for the rest of the endpoints.
In this case, for ep1 2 banks are allocated if it works in isochronous
mode and only 1 bank otherwise. For the rest of the endpoints
only 1 bank is allocated.
fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration
allowing the usage of ep1 - ep6
......@@ -191,6 +192,7 @@ config USB_RENESAS_USBHS_UDC
config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST
depends on EXTCON
help
Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers.
......@@ -253,6 +255,20 @@ config USB_MV_U3D
MARVELL PXA2128 Processor series include a super speed USB3.0 device
controller, which support super speed USB peripheral.
config USB_SNP_CORE
depends on USB_AMD5536UDC
tristate
help
This enables core driver support for Synopsys USB 2.0 Device
controller.
This will be enabled when PCI or Platform driver for this UDC is
selected. Currently, this will be enabled by USB_SNP_UDC_PLAT or
USB_AMD5536UDC options.
This IP is different to the High Speed OTG IP that can be enabled
by selecting USB_DWC2 or USB_DWC3 options.
#
# Controllers available in both integrated and discrete versions
#
......@@ -278,6 +294,7 @@ source "drivers/usb/gadget/udc/bdc/Kconfig"
config USB_AMD5536UDC
tristate "AMD5536 UDC"
depends on USB_PCI
select USB_SNP_CORE
help
The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
It is a USB Highspeed DMA capable USB device controller. Beside ep0
......@@ -285,6 +302,9 @@ config USB_AMD5536UDC
The UDC port supports OTG operation, and may be used as a host port
if it's not being used to implement peripheral or OTG roles.
This UDC is based on Synopsys USB device controller IP and selects
CONFIG_USB_SNP_CORE option to build the core driver.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "amd5536udc" and force all
gadget drivers to also be dynamically linked.
......
......@@ -10,7 +10,8 @@ obj-$(CONFIG_USB_GADGET) += udc-core.o
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
obj-$(CONFIG_USB_NET2272) += net2272.o
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_SNP_CORE) += amd5536udc.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc_pci.o
obj-$(CONFIG_USB_PXA25X) += pxa25x_udc.o
obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
......
This diff is collapsed.
......@@ -13,6 +13,12 @@
#ifndef AMD5536UDC_H
#define AMD5536UDC_H
/* debug control */
/* #define UDC_VERBOSE */
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
/* various constants */
#define UDC_RDE_TIMER_SECONDS 1
#define UDC_RDE_TIMER_DIV 10
......@@ -567,6 +573,36 @@ union udc_setup_data {
struct usb_ctrlrequest request;
};
/* Function declarations */
int udc_enable_dev_setup_interrupts(struct udc *dev);
int udc_mask_unused_interrupts(struct udc *dev);
irqreturn_t udc_irq(int irq, void *pdev);
void gadget_release(struct device *pdev);
void udc_basic_init(struct udc *dev);
void free_dma_pools(struct udc *dev);
int init_dma_pools(struct udc *dev);
void udc_remove(struct udc *dev);
int udc_probe(struct udc *dev);
/* DMA usage flag */
static bool use_dma = 1;
/* packet per buffer dma */
static bool use_dma_ppb = 1;
/* with per descr. update */
static bool use_dma_ppb_du;
/* full speed only mode */
static bool use_fullspeed;
/* module parameters */
module_param(use_dma, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma, "true for DMA");
module_param(use_dma_ppb, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
module_param(use_dma_ppb_du, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma_ppb_du,
"true for DMA in packet per buffer mode with descriptor update");
module_param(use_fullspeed, bool, S_IRUGO);
MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
/*
*---------------------------------------------------------------------------
* SET and GET bitfields in u32 values
......
/*
* amd5536udc_pci.c -- AMD 5536 UDC high/full speed USB device controller
*
* Copyright (C) 2005-2007 AMD (http://www.amd.com)
* Author: Thomas Dahlmann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
/*
* The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
* It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
* provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
*
* Make sure that UDC is assigned to port 4 by BIOS settings (port can also
* be used as host port) and UOC bits PAD_EN and APU are set (should be done
* by BIOS init).
*
* UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
* work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
* can be used with gadget ether.
*
* This file does pci device registration, and the core driver implementation
* is done in amd5536udc.c
*
* The driver is split so as to use the core UDC driver which is based on
* Synopsys device controller IP (different than HS OTG IP) in UDCs
* integrated to SoC platforms.
*
*/
/* Driver strings */
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
/* system */
#include <linux/device.h>
#include <linux/dmapool.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/prefetch.h>
#include <linux/pci.h>
/* udc specific */
#include "amd5536udc.h"
/* pointer to device object */
static struct udc *udc;
/* description */
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
static const char name[] = "amd5536udc-pci";
/* Reset all pci context */
static void udc_pci_remove(struct pci_dev *pdev)
{
struct udc *dev;
dev = pci_get_drvdata(pdev);
usb_del_gadget_udc(&udc->gadget);
/* gadget driver must not be registered */
if (WARN_ON(dev->driver))
return;
/* dma pool cleanup */
free_dma_pools(dev);
/* reset controller */
writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg);
free_irq(pdev->irq, dev);
iounmap(dev->virt_addr);
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
pci_disable_device(pdev);
udc_remove(dev);
}
/* Called by pci bus driver to init pci context */
static int udc_pci_probe(
struct pci_dev *pdev,
const struct pci_device_id *id
)
{
struct udc *dev;
unsigned long resource;
unsigned long len;
int retval = 0;
/* one udc only */
if (udc) {
dev_dbg(&pdev->dev, "already probed\n");
return -EBUSY;
}
/* init */
dev = kzalloc(sizeof(struct udc), GFP_KERNEL);
if (!dev)
return -ENOMEM;
/* pci setup */
if (pci_enable_device(pdev) < 0) {
retval = -ENODEV;
goto err_pcidev;
}
/* PCI resource allocation */
resource = pci_resource_start(pdev, 0);
len = pci_resource_len(pdev, 0);
if (!request_mem_region(resource, len, name)) {
dev_dbg(&pdev->dev, "pci device used already\n");
retval = -EBUSY;
goto err_memreg;
}
dev->virt_addr = ioremap_nocache(resource, len);
if (!dev->virt_addr) {
dev_dbg(&pdev->dev, "start address cannot be mapped\n");
retval = -EFAULT;
goto err_ioremap;
}
if (!pdev->irq) {
dev_err(&pdev->dev, "irq not set\n");
retval = -ENODEV;
goto err_irq;
}
spin_lock_init(&dev->lock);
/* udc csr registers base */
dev->csr = dev->virt_addr + UDC_CSR_ADDR;
/* dev registers base */
dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR;
/* ep registers base */
dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR;
/* fifo's base */
dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR);
dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR);
if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) {
dev_dbg(&pdev->dev, "request_irq(%d) fail\n", pdev->irq);
retval = -EBUSY;
goto err_irq;
}
pci_set_drvdata(pdev, dev);
/* chip revision for Hs AMD5536 */
dev->chiprev = pdev->revision;
pci_set_master(pdev);
pci_try_set_mwi(pdev);
/* init dma pools */
if (use_dma) {
retval = init_dma_pools(dev);
if (retval != 0)
goto err_dma;
}
dev->phys_addr = resource;
dev->irq = pdev->irq;
dev->pdev = pdev;
/* general probing */
if (udc_probe(dev)) {
retval = -ENODEV;
goto err_probe;
}
return 0;
err_probe:
if (use_dma)
free_dma_pools(dev);
err_dma:
free_irq(pdev->irq, dev);
err_irq:
iounmap(dev->virt_addr);
err_ioremap:
release_mem_region(resource, len);
err_memreg:
pci_disable_device(pdev);
err_pcidev:
kfree(dev);
return retval;
}
/* PCI device parameters */
static const struct pci_device_id pci_id[] = {
{
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
.class = PCI_CLASS_SERIAL_USB_DEVICE,
.class_mask = 0xffffffff,
},
{},
};
MODULE_DEVICE_TABLE(pci, pci_id);
/* PCI functions */
static struct pci_driver udc_pci_driver = {
.name = (char *) name,
.id_table = pci_id,
.probe = udc_pci_probe,
.remove = udc_pci_remove,
};
module_pci_driver(udc_pci_driver);
MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION);
MODULE_AUTHOR("Thomas Dahlmann");
MODULE_LICENSE("GPL");
......@@ -321,7 +321,6 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
static ushort fifo_mode;
/* "modprobe ... fifo_mode=1" etc */
module_param(fifo_mode, ushort, 0x0);
MODULE_PARM_DESC(fifo_mode, "Endpoint configuration mode");
......@@ -371,7 +370,7 @@ static struct usba_fifo_cfg mode_4_cfg[] = {
};
/* Add additional configurations here */
int usba_config_fifo_table(struct usba_udc *udc)
static int usba_config_fifo_table(struct usba_udc *udc)
{
int n;
......@@ -1076,11 +1075,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
static int atmel_usba_stop(struct usb_gadget *gadget);
static struct usb_ep *atmel_usba_match_ep(
struct usb_gadget *gadget,
static struct usb_ep *atmel_usba_match_ep(struct usb_gadget *gadget,
struct usb_endpoint_descriptor *desc,
struct usb_ss_ep_comp_descriptor *ep_comp
)
struct usb_ss_ep_comp_descriptor *ep_comp)
{
struct usb_ep *_ep;
struct usba_ep *ep;
......@@ -1100,7 +1097,6 @@ static struct usb_ep *atmel_usba_match_ep(
ep = to_usba_ep(_ep);
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
break;
......@@ -1141,7 +1137,7 @@ static struct usb_ep *atmel_usba_match_ep(
ep->udc->configured_ep++;
}
return _ep;
return _ep;
}
static const struct usb_gadget_ops usba_udc_ops = {
......@@ -1855,7 +1851,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
* but it's clearly harmless...
*/
if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
dev_dbg(&udc->pdev->dev,
dev_err(&udc->pdev->dev,
"ODD: EP0 configuration is invalid!\n");
/* Preallocate other endpoints */
......@@ -1864,7 +1860,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
ep = &udc->usba_ep[i];
usba_ep_writel(ep, CFG, ep->ept_cfg);
if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED))
dev_dbg(&udc->pdev->dev,
dev_err(&udc->pdev->dev,
"ODD: EP%d configuration is invalid!\n", i);
}
}
......@@ -2089,8 +2085,9 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
while ((pp = of_get_next_child(np, pp)))
udc->num_ep++;
udc->configured_ep = 1;
} else
} else {
udc->num_ep = usba_config_fifo_table(udc);
}
eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep,
GFP_KERNEL);
......@@ -2118,14 +2115,34 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret);
goto err;
}
ep->fifo_size = fifo_mode ? udc->fifo_cfg[i].fifo_size : val;
if (fifo_mode) {
if (val < udc->fifo_cfg[i].fifo_size) {
dev_warn(&pdev->dev,
"Using max fifo-size value from DT\n");
ep->fifo_size = val;
} else {
ep->fifo_size = udc->fifo_cfg[i].fifo_size;
}
} else {
ep->fifo_size = val;
}
ret = of_property_read_u32(pp, "atmel,nb-banks", &val);
if (ret) {
dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret);
goto err;
}
ep->nr_banks = fifo_mode ? udc->fifo_cfg[i].nr_banks : val;
if (fifo_mode) {
if (val < udc->fifo_cfg[i].nr_banks) {
dev_warn(&pdev->dev,
"Using max nb-banks value from DT\n");
ep->nr_banks = val;
} else {
ep->nr_banks = udc->fifo_cfg[i].nr_banks;
}
} else {
ep->nr_banks = val;
}
ep->can_dma = of_property_read_bool(pp, "atmel,can-dma");
ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc");
......
......@@ -1273,6 +1273,7 @@ void usb_del_gadget_udc(struct usb_gadget *gadget)
flush_work(&gadget->work);
device_unregister(&udc->dev);
device_unregister(&gadget->dev);
memset(&gadget->dev, 0x00, sizeof(gadget->dev));
}
EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
......
......@@ -2062,16 +2062,13 @@ static int dummy_hub_control(
}
break;
case USB_PORT_FEAT_POWER:
if (hcd->speed == HCD_USB3) {
if (dum_hcd->port_status & USB_PORT_STAT_POWER)
dev_dbg(dummy_dev(dum_hcd),
"power-off\n");
} else
if (dum_hcd->port_status &
USB_SS_PORT_STAT_POWER)
dev_dbg(dummy_dev(dum_hcd),
"power-off\n");
/* FALLS THROUGH */
dev_dbg(dummy_dev(dum_hcd), "power-off\n");
if (hcd->speed == HCD_USB3)
dum_hcd->port_status &= ~USB_SS_PORT_STAT_POWER;
else
dum_hcd->port_status &= ~USB_PORT_STAT_POWER;
set_link_state(dum_hcd);
break;
default:
dum_hcd->port_status &= ~(1 << wValue);
set_link_state(dum_hcd);
......@@ -2242,14 +2239,13 @@ static int dummy_hub_control(
if ((dum_hcd->port_status &
USB_SS_PORT_STAT_POWER) != 0) {
dum_hcd->port_status |= (1 << wValue);
set_link_state(dum_hcd);
}
} else
if ((dum_hcd->port_status &
USB_PORT_STAT_POWER) != 0) {
dum_hcd->port_status |= (1 << wValue);
set_link_state(dum_hcd);
}
set_link_state(dum_hcd);
}
break;
case GetPortErrorCount:
......
......@@ -2675,6 +2675,8 @@ static const struct platform_device_id fsl_udc_devtype[] = {
.name = "imx-udc-mx27",
}, {
.name = "imx-udc-mx51",
}, {
.name = "fsl-usb2-udc",
}, {
/* sentinel */
}
......
......@@ -1835,13 +1835,18 @@ static int mv_u3d_probe(struct platform_device *dev)
}
/* we will access controller register, so enable the u3d controller */
clk_enable(u3d->clk);
retval = clk_enable(u3d->clk);
if (retval) {
dev_err(&dev->dev, "clk_enable error %d\n", retval);
goto err_u3d_enable;
}
if (pdata->phy_init) {
retval = pdata->phy_init(u3d->phy_regs);
if (retval) {
dev_err(&dev->dev, "init phy error %d\n", retval);
goto err_u3d_enable;
clk_disable(u3d->clk);
goto err_phy_init;
}
}
......@@ -1974,15 +1979,13 @@ static int mv_u3d_probe(struct platform_device *dev)
dma_free_coherent(&dev->dev, u3d->ep_context_size,
u3d->ep_context, u3d->ep_context_dma);
err_alloc_ep_context:
if (pdata->phy_deinit)
pdata->phy_deinit(u3d->phy_regs);
clk_disable(u3d->clk);
err_phy_init:
err_u3d_enable:
iounmap(u3d->cap_regs);
err_map_cap_regs:
err_get_cap_regs:
err_get_clk:
clk_put(u3d->clk);
err_get_clk:
kfree(u3d);
err_alloc_private:
err_pdata:
......
......@@ -445,7 +445,8 @@ static int mv_ep_enable(struct usb_ep *_ep,
struct mv_dqh *dqh;
u16 max = 0;
u32 bit_pos, epctrlx, direction;
unsigned char zlt = 0, ios = 0, mult = 0;
const unsigned char zlt = 1;
unsigned char ios, mult;
unsigned long flags;
ep = container_of(_ep, struct mv_ep, ep);
......@@ -465,8 +466,6 @@ static int mv_ep_enable(struct usb_ep *_ep,
* disable HW zero length termination select
* driver handles zero length packet through req->req.zero
*/
zlt = 1;
bit_pos = 1 << ((direction == EP_DIR_OUT ? 0 : 16) + ep->ep_num);
/* Check if the Endpoint is Primed */
......@@ -481,16 +480,16 @@ static int mv_ep_enable(struct usb_ep *_ep,
(unsigned)bit_pos);
goto en_done;
}
/* Set the max packet length, interrupt on Setup and Mult fields */
ios = 0;
mult = 0;
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
case USB_ENDPOINT_XFER_BULK:
zlt = 1;
mult = 0;
case USB_ENDPOINT_XFER_INT:
break;
case USB_ENDPOINT_XFER_CONTROL:
ios = 1;
case USB_ENDPOINT_XFER_INT:
mult = 0;
break;
case USB_ENDPOINT_XFER_ISOC:
/* Calculate transactions needed for high bandwidth iso */
......
......@@ -1608,9 +1608,6 @@ static int pxa_udc_pullup(struct usb_gadget *_gadget, int is_active)
return 0;
}
static void udc_enable(struct pxa_udc *udc);
static void udc_disable(struct pxa_udc *udc);
/**
* pxa_udc_vbus_session - Called by external transceiver to enable/disable udc
* @_gadget: usb gadget
......
......@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/extcon.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
......@@ -37,6 +38,9 @@
#define USB3_USB_INT_ENA_2 0x22c
#define USB3_STUP_DAT_0 0x230
#define USB3_STUP_DAT_1 0x234
#define USB3_USB_OTG_STA 0x268
#define USB3_USB_OTG_INT_STA 0x26c
#define USB3_USB_OTG_INT_ENA 0x270
#define USB3_P0_MOD 0x280
#define USB3_P0_CON 0x288
#define USB3_P0_STA 0x28c
......@@ -124,6 +128,9 @@
/* USB_INT_ENA_2 and USB_INT_STA_2 */
#define USB_INT_2_PIPE(n) BIT(n)
/* USB_OTG_STA, USB_OTG_INT_STA and USB_OTG_INT_ENA */
#define USB_OTG_IDMON BIT(4)
/* P0_MOD */
#define P0_MOD_DIR BIT(6)
......@@ -257,6 +264,8 @@ struct renesas_usb3 {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct extcon_dev *extcon;
struct work_struct extcon_work;
struct renesas_usb3_ep *usb3_ep;
int num_usb3_eps;
......@@ -269,6 +278,8 @@ struct renesas_usb3 {
u8 ep0_buf[USB3_EP0_BUF_SIZE];
bool softconnect;
bool workaround_for_vbus;
bool extcon_host; /* check id and set EXTCON_USB_HOST */
bool extcon_usb; /* check vbus and set EXTCON_USB */
};
#define gadget_to_renesas_usb3(_gadget) \
......@@ -332,6 +343,15 @@ static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
return -EBUSY;
}
static void renesas_usb3_extcon_work(struct work_struct *work)
{
struct renesas_usb3 *usb3 = container_of(work, struct renesas_usb3,
extcon_work);
extcon_set_state_sync(usb3->extcon, EXTCON_USB_HOST, usb3->extcon_host);
extcon_set_state_sync(usb3->extcon, EXTCON_USB, usb3->extcon_usb);
}
static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits)
{
usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1);
......@@ -352,6 +372,11 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
usb3_clear_bit(usb3, USB_INT_2_PIPE(num), USB3_USB_INT_ENA_2);
}
static bool usb3_is_host(struct renesas_usb3 *usb3)
{
return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
}
static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
{
/* Set AXI_INT */
......@@ -362,10 +387,6 @@ static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
static void usb3_init_epc_registers(struct renesas_usb3 *usb3)
{
/* FIXME: How to change host / peripheral mode as well? */
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
usb3_write(usb3, ~0, USB3_USB_INT_STA_1);
usb3_enable_irq_1(usb3, USB_INT_1_VBUS_CNG);
}
......@@ -531,18 +552,70 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
if (usb3->workaround_for_vbus) {
usb3_connect(usb3);
} else {
if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA)
usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
USB_STA_VBUS_STA);
if (usb3->extcon_usb)
usb3_connect(usb3);
else
usb3_disconnect(usb3);
schedule_work(&usb3->extcon_work);
}
}
static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
{
if (host)
usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
else
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
}
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
{
if (enable)
usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
else
usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
}
static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
{
unsigned long flags;
spin_lock_irqsave(&usb3->lock, flags);
usb3_set_mode(usb3, host);
usb3_vbus_out(usb3, a_dev);
if (!host && a_dev) /* for A-Peripheral */
usb3_connect(usb3);
spin_unlock_irqrestore(&usb3->lock, flags);
}
static bool usb3_is_a_device(struct renesas_usb3 *usb3)
{
return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
}
static void usb3_check_id(struct renesas_usb3 *usb3)
{
usb3->extcon_host = usb3_is_a_device(usb3);
if (usb3->extcon_host)
usb3_mode_config(usb3, true, true);
else
usb3_mode_config(usb3, false, false);
schedule_work(&usb3->extcon_work);
}
static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
{
usb3_init_axi_bridge(usb3);
usb3_init_epc_registers(usb3);
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_STA);
usb3_write(usb3, USB_OTG_IDMON, USB3_USB_OTG_INT_ENA);
usb3_check_id(usb3);
usb3_check_vbus(usb3);
}
......@@ -551,6 +624,7 @@ static void renesas_usb3_stop_controller(struct renesas_usb3 *usb3)
usb3_disconnect(usb3);
usb3_write(usb3, 0, USB3_P0_INT_ENA);
usb3_write(usb3, 0, USB3_PN_INT_ENA);
usb3_write(usb3, 0, USB3_USB_OTG_INT_ENA);
usb3_write(usb3, 0, USB3_USB_INT_ENA_1);
usb3_write(usb3, 0, USB3_USB_INT_ENA_2);
usb3_write(usb3, 0, USB3_AXI_INT_ENA);
......@@ -1474,10 +1548,22 @@ static void usb3_irq_epc_int_2(struct renesas_usb3 *usb3, u32 int_sta_2)
}
}
static void usb3_irq_idmon_change(struct renesas_usb3 *usb3)
{
usb3_check_id(usb3);
}
static void usb3_irq_otg_int(struct renesas_usb3 *usb3, u32 otg_int_sta)
{
if (otg_int_sta & USB_OTG_IDMON)
usb3_irq_idmon_change(usb3);
}
static void usb3_irq_epc(struct renesas_usb3 *usb3)
{
u32 int_sta_1 = usb3_read(usb3, USB3_USB_INT_STA_1);
u32 int_sta_2 = usb3_read(usb3, USB3_USB_INT_STA_2);
u32 otg_int_sta = usb3_read(usb3, USB3_USB_OTG_INT_STA);
int_sta_1 &= usb3_read(usb3, USB3_USB_INT_ENA_1);
if (int_sta_1) {
......@@ -1488,6 +1574,12 @@ static void usb3_irq_epc(struct renesas_usb3 *usb3)
int_sta_2 &= usb3_read(usb3, USB3_USB_INT_ENA_2);
if (int_sta_2)
usb3_irq_epc_int_2(usb3, int_sta_2);
otg_int_sta &= usb3_read(usb3, USB3_USB_OTG_INT_ENA);
if (otg_int_sta) {
usb3_write(usb3, otg_int_sta, USB3_USB_OTG_INT_STA);
usb3_irq_otg_int(usb3, otg_int_sta);
}
}
static irqreturn_t renesas_usb3_irq(int irq, void *_usb3)
......@@ -1756,11 +1848,49 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
.set_selfpowered = renesas_usb3_set_selfpowered,
};
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
bool new_mode_is_host;
if (!usb3->driver)
return -ENODEV;
if (!strncmp(buf, "host", strlen("host")))
new_mode_is_host = true;
else if (!strncmp(buf, "peripheral", strlen("peripheral")))
new_mode_is_host = false;
else
return -EINVAL;
if (new_mode_is_host == usb3_is_host(usb3))
return -EINVAL;
usb3_mode_config(usb3, new_mode_is_host, usb3_is_a_device(usb3));
return count;
}
static ssize_t role_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
if (!usb3->driver)
return -ENODEV;
return sprintf(buf, "%s\n", usb3_is_host(usb3) ? "host" : "peripheral");
}
static DEVICE_ATTR_RW(role);
/*------- platform_driver ------------------------------------------------*/
static int renesas_usb3_remove(struct platform_device *pdev)
{
struct renesas_usb3 *usb3 = platform_get_drvdata(pdev);
device_remove_file(&pdev->dev, &dev_attr_role);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
......@@ -1894,6 +2024,12 @@ static const struct of_device_id usb3_of_match[] = {
};
MODULE_DEVICE_TABLE(of, usb3_of_match);
static const unsigned int renesas_usb3_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
static int renesas_usb3_probe(struct platform_device *pdev)
{
struct renesas_usb3 *usb3;
......@@ -1937,6 +2073,17 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0)
return ret;
INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
if (IS_ERR(usb3->extcon))
return PTR_ERR(usb3->extcon);
ret = devm_extcon_dev_register(&pdev->dev, usb3->extcon);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register extcon\n");
return ret;
}
/* for ep0 handling */
usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL);
if (!usb3->ep0_req)
......@@ -1946,6 +2093,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0)
goto err_add_udc;
ret = device_create_file(&pdev->dev, &dev_attr_role);
if (ret < 0)
goto err_dev_create;
usb3->workaround_for_vbus = priv->workaround_for_vbus;
pm_runtime_enable(&pdev->dev);
......@@ -1955,6 +2106,9 @@ static int renesas_usb3_probe(struct platform_device *pdev)
return 0;
err_dev_create:
usb_del_gadget_udc(&usb3->gadget);
err_add_udc:
__renesas_usb3_ep_free_request(usb3->ep0_req);
......
......@@ -223,25 +223,25 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)
return 0;
otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier;
ret = extcon_register_notifier(edev, EXTCON_USB,
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB,
&otg_sx->vbus_nb);
if (ret < 0)
dev_err(ssusb->dev, "failed to register notifier for USB\n");
otg_sx->id_nb.notifier_call = ssusb_id_notifier;
ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST,
&otg_sx->id_nb);
if (ret < 0)
dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n");
dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n",
extcon_get_cable_state_(edev, EXTCON_USB),
extcon_get_cable_state_(edev, EXTCON_USB_HOST));
extcon_get_state(edev, EXTCON_USB),
extcon_get_state(edev, EXTCON_USB_HOST));
/* default as host, switch to device mode if needed */
if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == false)
if (extcon_get_state(edev, EXTCON_USB_HOST) == false)
ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
if (extcon_get_state(edev, EXTCON_USB) == true)
ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
return 0;
......@@ -367,13 +367,6 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
if (otg_sx->edev) {
extcon_unregister_notifier(otg_sx->edev,
EXTCON_USB, &otg_sx->vbus_nb);
extcon_unregister_notifier(otg_sx->edev,
EXTCON_USB_HOST, &otg_sx->id_nb);
}
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
}
......@@ -44,6 +44,13 @@
#include "phy-fsl-usb.h"
#ifdef VERBOSE
#define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
__func__, ## args)
#else
#define VDBG(stuff...) do {} while (0)
#endif
#define DRIVER_VERSION "Rev. 1.55"
#define DRIVER_AUTHOR "Jerry Huang/Li Yang"
#define DRIVER_DESC "Freescale USB OTG Transceiver Driver"
......
......@@ -21,21 +21,6 @@
#include <linux/mutex.h>
#include <linux/errno.h>
#undef VERBOSE
#ifdef VERBOSE
#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \
__func__, ## args)
#else
#define VDBG(stuff...) do {} while (0)
#endif
#ifdef VERBOSE
#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__)
#else
#define MPC_LOC do {} while (0)
#endif
#define PROTO_UNDEF (0)
#define PROTO_HOST (1)
#define PROTO_GADGET (2)
......
......@@ -158,7 +158,7 @@ struct usb_ext_prop_desc {
* |-----+-----------------------+------+-------------------------------------|
* | 0 | bFirstInterfaceNumber | U8 | index of the interface or of the 1st|
* | | | | interface in an IAD group |
* | 1 | Reserved | U8 | 0 |
* | 1 | Reserved | U8 | 1 |
* | 2 | CompatibleID | U8[8]| compatible ID string |
* | 10 | SubCompatibleID | U8[8]| subcompatible ID string |
* | 18 | Reserved | U8[6]| 0 |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment