Commit 2d5afd51 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

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

Felipe writes:

usb: changes for v4.15 merge window

Not much going on this time around. With only 51 non-merge commits,
this was one of the smallest pull requests from the Gadget tree.

Most of the changes are in the mtu3 driver which added support for
36-bit DMA, support for USB 3.1 and support for dual-role (along with
some non-critical fixes).

The dwc2 driver got a few improvements to how we handle gadget state
tracking and also added support for STM32F7xx devices.

Other than that, we just some minor non-critical fixes and
improvements all over the place.
parents 0520d37b ce2b21a4
......@@ -19,6 +19,8 @@ Required properties:
configured in FS mode;
- "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in STM32F4x9 SoCs
configured in HS mode;
- "st,stm32f7xx-hsotg": The DWC2 USB HS controller instance in STM32F7xx SoCs
configured in HS mode;
- reg : Should contain 1 register range (address and length)
- interrupts : Should contain 1 interrupt
- clocks: clock provider specifier
......
......@@ -14,9 +14,9 @@ Required properties:
- vusb33-supply : regulator of USB avdd3.3v
- clocks : a list of phandle + clock-specifier pairs, one for each
entry in clock-names
- clock-names : must contain "sys_ck" and "ref_ck" for clock of controller;
"wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are
depends on "mediatek,enable-wakeup"
- clock-names : must contain "sys_ck" for clock of controller,
the following clocks are optional:
"ref_ck", "mcu_ck" and "dam_ck";
- phys : a list of phandle + phy specifier pairs
- dr_mode : should be one of "host", "peripheral" or "otg",
refer to usb/generic.txt
......@@ -30,9 +30,10 @@ Optional properties:
when supports dual-role mode.
- vbus-supply : reference to the VBUS regulator, needed when supports
dual-role mode.
- pinctl-names : a pinctrl state named "default" must be defined,
"id_float" and "id_ground" are optinal which depends on
"mediatek,enable-manual-drd"
- pinctrl-names : a pinctrl state named "default" is optional, and need be
defined if auto drd switch is enabled, that means the property dr_mode
is set as "otg", and meanwhile the property "mediatek,enable-manual-drd"
is not set.
- pinctrl-0 : pin control group
See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
......@@ -44,6 +45,8 @@ Optional properties:
- mediatek,enable-wakeup : supports ip sleep wakeup used by host mode
- mediatek,syscon-wakeup : phandle to syscon used to access USB wakeup
control register, it depends on "mediatek,enable-wakeup".
- mediatek,u3p-dis-msk : mask to disable u3ports, bit0 for u3port0,
bit1 for u3port1, ... etc;
Sub-nodes:
The xhci should be added as subnode to mtu3 as shown in the following example
......@@ -63,9 +66,7 @@ ssusb: usb@11271000 {
clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>,
<&pericfg CLK_PERI_USB0>,
<&pericfg CLK_PERI_USB1>;
clock-names = "sys_ck", "ref_ck",
"wakeup_deb_p0",
"wakeup_deb_p1";
clock-names = "sys_ck", "ref_ck";
vusb33-supply = <&mt6397_vusb_reg>;
vbus-supply = <&usb_p0_vbus>;
extcon = <&extcon_usb>;
......
......@@ -15,6 +15,10 @@ Required properties:
- interrupts: Interrupt specifier for the USB3.0 Peripheral
- clocks: clock phandle and specifier pair
Optional properties:
- phys: phandle + phy specifier pair
- phy-names: must be "usb"
Example of R-Car H3 ES1.x:
usb3_peri0: usb@ee020000 {
compatible = "renesas,r8a7795-usb3-peri",
......
......@@ -3,6 +3,8 @@ Renesas Electronics USBHS driver
Required properties:
- compatible: Must contain one or more of the following:
- "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
......@@ -10,7 +12,8 @@ Required properties:
- "renesas,usbhs-r8a7794" for r8a7794 (R-Car E2) compatible device
- "renesas,usbhs-r8a7795" for r8a7795 (R-Car H3) compatible device
- "renesas,usbhs-r8a7796" for r8a7796 (R-Car M3-W) compatible device
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 compatible device
- "renesas,usbhs-r8a77995" for r8a77995 (R-Car D3) compatible device
- "renesas,rcar-gen2-usbhs" for R-Car Gen2 or RZ/G1 compatible devices
- "renesas,rcar-gen3-usbhs" for R-Car Gen3 compatible device
When compatible with the generic version, nodes must list the
......
......@@ -395,6 +395,9 @@ enum dwc2_ep0_state {
* (default when phy_type is UTMI+ or ULPI)
* 1 - 6 MHz
* (default when phy_type is Full Speed)
* @oc_disable: Flag to disable overcurrent condition.
* 0 - Allow overcurrent condition to get detected
* 1 - Disable overcurrent condtion to get detected
* @ts_dline: Enable Term Select Dline pulsing
* 0 - No (default)
* 1 - Yes
......@@ -492,6 +495,7 @@ struct dwc2_core_params {
bool dma_desc_fs_enable;
bool host_support_fs_ls_low_power;
bool host_ls_low_power_phy_clk;
bool oc_disable;
u8 host_channels;
u16 host_rx_fifo_size;
......
......@@ -3202,6 +3202,8 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg)
call_gadget(hsotg, disconnect);
hsotg->lx_state = DWC2_L3;
usb_gadget_set_state(&hsotg->gadget, USB_STATE_NOTATTACHED);
}
/**
......@@ -4004,6 +4006,11 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
return -EINVAL;
}
if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) {
dev_err(hsotg->dev, "%s: called in host mode?\n", __func__);
return -EINVAL;
}
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
spin_lock_irqsave(&hsotg->lock, flags);
......
......@@ -213,6 +213,11 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL);
if (hsotg->params.phy_ulpi_ddr)
usbcfg |= GUSBCFG_DDRSEL;
/* Set external VBUS indicator as needed. */
if (hsotg->params.oc_disable)
usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND |
GUSBCFG_INDICATORPASSTHROUGH);
break;
case DWC2_PHY_TYPE_PARAM_UTMI:
/* UTMI+ interface */
......@@ -3277,7 +3282,6 @@ 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);
......@@ -3296,8 +3300,12 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
if (count > 250)
dev_err(hsotg->dev,
"Connection id status change timed out\n");
hsotg->op_state = OTG_STATE_A_HOST;
spin_lock_irqsave(&hsotg->lock, flags);
dwc2_hsotg_disconnect(hsotg);
spin_unlock_irqrestore(&hsotg->lock, flags);
hsotg->op_state = OTG_STATE_A_HOST;
/* Initialize the Core for Host mode */
dwc2_core_init(hsotg, false);
dwc2_enable_global_interrupts(hsotg);
......
......@@ -136,6 +136,15 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
p->activate_stm_fs_transceiver = true;
}
static void dwc2_set_stm32f7xx_hsotg_params(struct dwc2_hsotg *hsotg)
{
struct dwc2_core_params *p = &hsotg->params;
p->host_rx_fifo_size = 622;
p->host_nperio_tx_fifo_size = 128;
p->host_perio_tx_fifo_size = 256;
}
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 },
......@@ -154,6 +163,8 @@ const struct of_device_id dwc2_of_match_table[] = {
{ .compatible = "st,stm32f4x9-fsotg",
.data = dwc2_set_stm32f4x9_fsotg_params },
{ .compatible = "st,stm32f4x9-hsotg" },
{ .compatible = "st,stm32f7xx-hsotg",
.data = dwc2_set_stm32f7xx_hsotg_params },
{},
};
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
......@@ -335,6 +346,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg)
num);
}
}
if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL))
p->oc_disable = true;
}
static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg)
......
......@@ -156,9 +156,8 @@ static void __dwc3_set_mode(struct work_struct *work)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
......@@ -166,8 +165,8 @@ static void __dwc3_set_mode(struct work_struct *work)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
......@@ -927,12 +926,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_DEVICE;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
......@@ -942,12 +942,13 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
}
break;
case USB_DR_MODE_HOST:
dwc->current_dr_role = DWC3_GCTL_PRTCAP_HOST;
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
if (dwc->usb2_generic_phy)
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb2_generic_phy, PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy, PHY_MODE_USB_HOST);
ret = dwc3_host_init(dwc);
if (ret) {
......@@ -1293,21 +1294,19 @@ static int dwc3_suspend_common(struct dwc3 *dwc)
{
unsigned long flags;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_suspend(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
dwc3_core_exit(dwc);
break;
case USB_DR_MODE_HOST:
case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
}
dwc3_core_exit(dwc);
return 0;
}
......@@ -1316,18 +1315,17 @@ static int dwc3_resume_common(struct dwc3 *dwc)
unsigned long flags;
int ret;
ret = dwc3_core_init(dwc);
if (ret)
return ret;
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
ret = dwc3_core_init(dwc);
if (ret)
return ret;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
spin_lock_irqsave(&dwc->lock, flags);
dwc3_gadget_resume(dwc);
spin_unlock_irqrestore(&dwc->lock, flags);
/* FALLTHROUGH */
case USB_DR_MODE_HOST:
break;
case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
......@@ -1338,7 +1336,7 @@ static int dwc3_resume_common(struct dwc3 *dwc)
static int dwc3_runtime_checks(struct dwc3 *dwc)
{
switch (dwc->dr_mode) {
switch (dwc->current_dr_role) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
if (dwc->connected)
......@@ -1381,19 +1379,17 @@ static int dwc3_runtime_resume(struct device *dev)
if (ret)
return ret;
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
dwc3_gadget_process_pending_events(dwc);
break;
case USB_DR_MODE_HOST:
case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put(dev);
return 0;
}
......@@ -1402,13 +1398,12 @@ static int dwc3_runtime_idle(struct device *dev)
{
struct dwc3 *dwc = dev_get_drvdata(dev);
switch (dwc->dr_mode) {
case USB_DR_MODE_PERIPHERAL:
case USB_DR_MODE_OTG:
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc3_runtime_checks(dwc))
return -EBUSY;
break;
case USB_DR_MODE_HOST:
case DWC3_GCTL_PRTCAP_HOST:
default:
/* do nothing */
break;
......
......@@ -529,6 +529,7 @@ struct dwc3_event_buffer {
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
* @frame_number: set to the frame number we want this transfer to start (ISOC)
* @interval: the interval on which the ISOC transfer is started
* @allocated_requests: number of requests allocated
* @queued_requests: number of requests queued for transfer
......@@ -581,6 +582,7 @@ struct dwc3_ep {
u8 resource_index;
u32 allocated_requests;
u32 queued_requests;
u32 frame_number;
u32 interval;
char name[20];
......
......@@ -28,11 +28,13 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
struct dwc3_of_simple {
struct device *dev;
struct clk **clks;
int num_clocks;
struct reset_control *resets;
};
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
......@@ -95,10 +97,21 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, simple);
simple->dev = dev;
simple->resets = of_reset_control_array_get_optional_exclusive(np);
if (IS_ERR(simple->resets)) {
ret = PTR_ERR(simple->resets);
dev_err(dev, "failed to get device resets, err=%d\n", ret);
return ret;
}
ret = reset_control_deassert(simple->resets);
if (ret)
goto err_resetc_put;
ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np,
"clocks", "#clock-cells"));
if (ret)
return ret;
goto err_resetc_assert;
ret = of_platform_populate(np, NULL, NULL, dev);
if (ret) {
......@@ -107,7 +120,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
clk_put(simple->clks[i]);
}
return ret;
goto err_resetc_assert;
}
pm_runtime_set_active(dev);
......@@ -115,6 +128,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
pm_runtime_get_sync(dev);
return 0;
err_resetc_assert:
reset_control_assert(simple->resets);
err_resetc_put:
reset_control_put(simple->resets);
return ret;
}
static int dwc3_of_simple_remove(struct platform_device *pdev)
......@@ -123,12 +143,15 @@ static int dwc3_of_simple_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int i;
of_platform_depopulate(dev);
for (i = 0; i < simple->num_clocks; i++) {
clk_disable_unprepare(simple->clks[i]);
clk_put(simple->clks[i]);
}
of_platform_depopulate(dev);
reset_control_assert(simple->resets);
reset_control_put(simple->resets);
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
......
......@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/gpio/consumer.h>
......@@ -61,6 +62,7 @@ struct dwc3_pci {
guid_t guid;
unsigned int has_dsm_for_pm:1;
struct work_struct wakeup_work;
};
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
......@@ -174,6 +176,22 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
return 0;
}
#ifdef CONFIG_PM
static void dwc3_pci_resume_work(struct work_struct *work)
{
struct dwc3_pci *dwc = container_of(work, struct dwc3_pci, wakeup_work);
struct platform_device *dwc3 = dwc->dwc3;
int ret;
ret = pm_runtime_get_sync(&dwc3->dev);
if (ret)
return;
pm_runtime_mark_last_busy(&dwc3->dev);
pm_runtime_put_sync_autosuspend(&dwc3->dev);
}
#endif
static int dwc3_pci_probe(struct pci_dev *pci,
const struct pci_device_id *id)
{
......@@ -232,6 +250,9 @@ static int dwc3_pci_probe(struct pci_dev *pci,
device_init_wakeup(dev, true);
pci_set_drvdata(pci, dwc);
pm_runtime_put(dev);
#ifdef CONFIG_PM
INIT_WORK(&dwc->wakeup_work, dwc3_pci_resume_work);
#endif
return 0;
err:
......@@ -243,6 +264,9 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{
struct dwc3_pci *dwc = pci_get_drvdata(pci);
#ifdef CONFIG_PM
cancel_work_sync(&dwc->wakeup_work);
#endif
device_init_wakeup(&pci->dev, false);
pm_runtime_get(&pci->dev);
platform_device_unregister(dwc->dwc3);
......@@ -318,14 +342,15 @@ static int dwc3_pci_runtime_suspend(struct device *dev)
static int dwc3_pci_runtime_resume(struct device *dev)
{
struct dwc3_pci *dwc = dev_get_drvdata(dev);
struct platform_device *dwc3 = dwc->dwc3;
int ret;
ret = dwc3_pci_dsm(dwc, PCI_INTEL_BXT_STATE_D0);
if (ret)
return ret;
return pm_runtime_get(&dwc3->dev);
queue_work(pm_wq, &dwc->wakeup_work);
return 0;
}
#endif /* CONFIG_PM */
......
......@@ -487,14 +487,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc,
static int dwc3_ep0_handle_intf(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl, int set)
{
enum usb_device_state state;
u32 wValue;
u32 wIndex;
int ret = 0;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
state = dwc->gadget.state;
switch (wValue) {
case USB_INTRF_FUNC_SUSPEND:
......@@ -517,14 +513,10 @@ static int dwc3_ep0_handle_endpoint(struct dwc3 *dwc,
struct usb_ctrlrequest *ctrl, int set)
{
struct dwc3_ep *dep;
enum usb_device_state state;
u32 wValue;
u32 wIndex;
int ret;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
state = dwc->gadget.state;
switch (wValue) {
case USB_ENDPOINT_HALT:
......@@ -551,10 +543,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
{
u32 recip;
int ret;
enum usb_device_state state;
recip = ctrl->bRequestType & USB_RECIP_MASK;
state = dwc->gadget.state;
switch (recip) {
case USB_RECIP_DEVICE:
......@@ -712,12 +702,10 @@ static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
struct dwc3_ep *dep;
enum usb_device_state state = dwc->gadget.state;
u16 wLength;
u16 wValue;
if (state == USB_STATE_DEFAULT)
return -EINVAL;
wValue = le16_to_cpu(ctrl->wValue);
wLength = le16_to_cpu(ctrl->wLength);
if (wLength != 6) {
......@@ -842,9 +830,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
struct usb_request *ur;
struct dwc3_trb *trb;
struct dwc3_ep *ep0;
unsigned maxp;
unsigned remaining_ur_length;
void *buf;
u32 transferred = 0;
u32 status;
u32 length;
......@@ -871,11 +856,8 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
}
ur = &r->request;
buf = ur->buf;
remaining_ur_length = ur->length;
length = trb->size & DWC3_TRB_SIZE_MASK;
maxp = ep0->endpoint.maxpacket;
transferred = ur->length - length;
ur->actual += transferred;
......@@ -1001,7 +983,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
} 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);
......@@ -1009,7 +990,6 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
return;
maxpacket = dep->endpoint.maxpacket;
rem = req->request.length % maxpacket;
/* prepare normal TRB */
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
......
......@@ -1151,9 +1151,6 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
if (!dwc3_calc_trbs_left(dep))
return;
/*
* We can get in a situation where there's a request in the started list
* but there weren't enough TRBs to fully kick it in the first time
......@@ -1194,7 +1191,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep)
}
}
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep)
{
struct dwc3_gadget_ep_cmd_params params;
struct dwc3_request *req;
......@@ -1202,6 +1199,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
int ret;
u32 cmd;
if (!dwc3_calc_trbs_left(dep))
return 0;
starting = !(dep->flags & DWC3_EP_BUSY);
dwc3_prepare_trbs(dep);
......@@ -1216,8 +1216,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
if (starting) {
params.param0 = upper_32_bits(req->trb_dma);
params.param1 = lower_32_bits(req->trb_dma);
cmd = DWC3_DEPCMD_STARTTRANSFER |
DWC3_DEPCMD_PARAM(cmd_param);
cmd = DWC3_DEPCMD_STARTTRANSFER;
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
cmd |= DWC3_DEPCMD_PARAM(dep->frame_number);
} else {
cmd = DWC3_DEPCMD_UPDATETRANSFER |
DWC3_DEPCMD_PARAM(dep->resource_index);
......@@ -1258,8 +1260,6 @@ static int __dwc3_gadget_get_frame(struct dwc3 *dwc)
static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, u32 cur_uf)
{
u32 uf;
if (list_empty(&dep->pending_list)) {
dev_info(dwc->dev, "%s: ran out of requests\n",
dep->name);
......@@ -1271,9 +1271,8 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
* Schedule the first trb for one interval in the future or at
* least 4 microframes.
*/
uf = cur_uf + max_t(u32, 4, dep->interval);
__dwc3_gadget_kick_transfer(dep, uf);
dep->frame_number = cur_uf + max_t(u32, 4, dep->interval);
__dwc3_gadget_kick_transfer(dep);
}
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
......@@ -1290,7 +1289,6 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
struct dwc3 *dwc = dep->dwc;
int ret = 0;
if (!dep->endpoint.desc) {
dev_err(dwc->dev, "%s: can't queue to disabled endpoint\n",
......@@ -1337,24 +1335,14 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
}
if ((dep->flags & DWC3_EP_BUSY) &&
!(dep->flags & DWC3_EP_MISSED_ISOC)) {
WARN_ON_ONCE(!dep->resource_index);
ret = __dwc3_gadget_kick_transfer(dep,
dep->resource_index);
}
goto out;
}
!(dep->flags & DWC3_EP_MISSED_ISOC))
goto out;
if (!dwc3_calc_trbs_left(dep))
return 0;
}
ret = __dwc3_gadget_kick_transfer(dep, 0);
out:
if (ret == -EBUSY)
ret = 0;
return ret;
return __dwc3_gadget_kick_transfer(dep);
}
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
......@@ -2347,7 +2335,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
req->request.actual = length - req->remaining;
if ((req->request.actual < length) && req->num_pending_sgs)
return __dwc3_gadget_kick_transfer(dep, 0);
return __dwc3_gadget_kick_transfer(dep);
dwc3_gadget_giveback(dep, req, status);
......@@ -2440,13 +2428,8 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
if (!dep->endpoint.desc)
return;
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
int ret;
ret = __dwc3_gadget_kick_transfer(dep, 0);
if (!ret || ret == -EBUSY)
return;
}
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc))
__dwc3_gadget_kick_transfer(dep);
}
static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
......@@ -2487,15 +2470,10 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dwc3_endpoint_transfer_complete(dwc, dep, event);
break;
case DWC3_DEPEVT_XFERNOTREADY:
if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) {
if (usb_endpoint_xfer_isoc(dep->endpoint.desc))
dwc3_gadget_start_isoc(dwc, dep, event);
} else {
int ret;
ret = __dwc3_gadget_kick_transfer(dep, 0);
if (!ret || ret == -EBUSY)
return;
}
else
__dwc3_gadget_kick_transfer(dep);
break;
case DWC3_DEPEVT_STREAMEVT:
......
......@@ -1145,6 +1145,7 @@ static int usbg_submit_command(struct f_uas *fu,
default:
pr_debug_once("Unsupported prio_attr: %02x.\n",
cmd_iu->prio_attr);
/* fall through */
case UAS_SIMPLE_TAG:
cmd->prio_attr = TCM_SIMPLE_TAG;
break;
......
......@@ -1078,6 +1078,7 @@ static void gs_complete_out(struct usb_ep *ep, struct usb_request *req)
default:
pr_warn("%s: unexpected %s status %d\n",
__func__, ep->name, req->status);
/* fall through */
case 0:
/* normal completion */
spin_lock(&info->con_lock);
......
......@@ -354,7 +354,7 @@ static unsigned long uvcg_v4l2_get_unmapped_area(struct file *file,
}
#endif
struct v4l2_file_operations uvc_v4l2_fops = {
const struct v4l2_file_operations uvc_v4l2_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
......
......@@ -17,6 +17,6 @@
#define __UVC_V4L2_H__
extern const struct v4l2_ioctl_ops uvc_v4l2_ioctl_ops;
extern struct v4l2_file_operations uvc_v4l2_fops;
extern const struct v4l2_file_operations uvc_v4l2_fops;
#endif /* __UVC_V4L2_H__ */
......@@ -912,7 +912,7 @@ int usb_gadget_ep_match_desc(struct usb_gadget *gadget,
return 0;
type = usb_endpoint_type(desc);
max = 0x7ff & usb_endpoint_maxp(desc);
max = usb_endpoint_maxp(desc);
if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in)
return 0;
......
......@@ -23,6 +23,8 @@
*
* Having this all in one kernel can help some stages of development,
* bypassing some hardware (and driver) issues. UML could help too.
*
* Note: The emulation does not include isochronous transfers!
*/
#include <linux/module.h>
......@@ -137,6 +139,9 @@ static const struct {
.caps = _caps, \
}
/* we don't provide isochronous endpoints since we don't support them */
#define TYPE_BULK_OR_INT (USB_EP_CAPS_TYPE_BULK | USB_EP_CAPS_TYPE_INT)
/* everyone has ep0 */
EP_INFO(ep0name,
USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
......@@ -145,64 +150,72 @@ static const struct {
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep2out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep3in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep4out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep5in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep6in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep7out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep8in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep9out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep10in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep11in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep12out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
/*
EP_INFO("ep13in-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep14out-iso",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_OUT)),
*/
EP_INFO("ep15in-int",
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
/* or like sa1100: two fixed function endpoints */
EP_INFO("ep1out-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep2in-bulk",
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_IN)),
/* and now some generic EPs so we have enough in multi config */
EP_INFO("ep3out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep4in",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep5out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep6out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep7in",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep8out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep9in",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep10out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep11out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep12in",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep13out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
EP_INFO("ep14in",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_IN)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_IN)),
EP_INFO("ep15out",
USB_EP_CAPS(USB_EP_CAPS_TYPE_ALL, USB_EP_CAPS_DIR_OUT)),
USB_EP_CAPS(TYPE_BULK_OR_INT, USB_EP_CAPS_DIR_OUT)),
#undef EP_INFO
};
......@@ -1769,6 +1782,7 @@ static void dummy_timer(unsigned long _dum_hcd)
int i;
/* simplistic model for one frame's bandwidth */
/* FIXME: account for transaction and packet overhead */
switch (dum->gadget.speed) {
case USB_SPEED_LOW:
total = 8/*bytes*/ * 12/*packets*/;
......@@ -1813,7 +1827,6 @@ static void dummy_timer(unsigned long _dum_hcd)
struct dummy_request *req;
u8 address;
struct dummy_ep *ep = NULL;
int type;
int status = -EINPROGRESS;
/* stop when we reach URBs queued after the timer interrupt */
......@@ -1825,14 +1838,10 @@ static void dummy_timer(unsigned long _dum_hcd)
goto return_urb;
else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
continue;
type = usb_pipetype(urb->pipe);
/* used up this frame's non-periodic bandwidth?
* FIXME there's infinite bandwidth for control and
* periodic transfers ... unrealistic.
*/
if (total <= 0 && type == PIPE_BULK)
continue;
/* Used up this frame's bandwidth? */
if (total <= 0)
break;
/* find the gadget's ep for this request (if configured) */
address = usb_pipeendpoint (urb->pipe);
......@@ -1930,13 +1939,17 @@ static void dummy_timer(unsigned long _dum_hcd)
limit = total;
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
/* FIXME is it urb->interval since the last xfer?
* use urb->iso_frame_desc[i].
* complete whether or not ep has requests queued.
* report random errors, to debug drivers.
/*
* We don't support isochronous. But if we did,
* here are some of the issues we'd have to face:
*
* Is it urb->interval since the last xfer?
* Use urb->iso_frame_desc[i].
* Complete whether or not ep has requests queued.
* Report random errors, to debug drivers.
*/
limit = max(limit, periodic_bytes(dum, ep));
status = -ENOSYS;
status = -EINVAL; /* fail all xfers */
break;
case PIPE_INTERRUPT:
......
......@@ -127,11 +127,15 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
mode = 0;
max = get_unaligned_le16(&desc->wMaxPacketSize);
switch (max) {
case 64: mode++;
case 32: mode++;
case 16: mode++;
case 8: mode <<= 3;
break;
case 64:
mode++; /* fall through */
case 32:
mode++; /* fall through */
case 16:
mode++; /* fall through */
case 8:
mode <<= 3;
break;
default:
return -EINVAL;
}
......
......@@ -1538,7 +1538,7 @@ static int gr_ep_enable(struct usb_ep *_ep,
* Bits 10-0 set the max payload. 12-11 set the number of
* additional transactions.
*/
max = 0x7ff & usb_endpoint_maxp(desc);
max = usb_endpoint_maxp(desc);
nt = usb_endpoint_maxp_mult(desc) - 1;
buffer_size = GR_BUFFER_SIZE(epctrl);
if (nt && (mode == 0 || mode == 2)) {
......
/*
* Renesas USB3.0 Peripheral driver (USB gadget)
*
* Copyright (C) 2015 Renesas Electronics Corporation
* Copyright (C) 2015-2017 Renesas Electronics Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
......@@ -334,6 +335,7 @@ struct renesas_usb3 {
struct usb_gadget_driver *driver;
struct extcon_dev *extcon;
struct work_struct extcon_work;
struct phy *phy;
struct renesas_usb3_ep *usb3_ep;
int num_usb3_eps;
......@@ -2239,7 +2241,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
/* hook up the driver */
usb3->driver = driver;
pm_runtime_enable(usb3_to_dev(usb3));
if (usb3->phy)
phy_init(usb3->phy);
pm_runtime_get_sync(usb3_to_dev(usb3));
renesas_usb3_init_controller(usb3);
......@@ -2256,8 +2260,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
usb3->driver = NULL;
renesas_usb3_stop_controller(usb3);
if (usb3->phy)
phy_exit(usb3->phy);
pm_runtime_put(usb3_to_dev(usb3));
pm_runtime_disable(usb3_to_dev(usb3));
return 0;
}
......@@ -2405,6 +2411,9 @@ static int renesas_usb3_remove(struct platform_device *pdev)
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
__renesas_usb3_ep_free_request(usb3->ep0_req);
if (usb3->phy)
phy_put(usb3->phy);
pm_runtime_disable(usb3_to_dev(usb3));
return 0;
}
......@@ -2560,20 +2569,15 @@ static int renesas_usb3_probe(struct platform_device *pdev)
{
struct renesas_usb3 *usb3;
struct resource *res;
const struct of_device_id *match;
int irq, ret;
const struct renesas_usb3_priv *priv;
const struct soc_device_attribute *attr;
match = of_match_node(usb3_of_match, pdev->dev.of_node);
if (!match)
return -ENODEV;
attr = soc_device_match(renesas_usb3_quirks_match);
if (attr)
priv = attr->data;
else
priv = match->data;
priv = of_device_get_match_data(&pdev->dev);
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
......@@ -2635,11 +2639,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0)
goto err_dev_create;
/*
* This is an optional. So, if this driver cannot get a phy,
* this driver will not handle a phy anymore.
*/
usb3->phy = devm_phy_get(&pdev->dev, "usb");
if (IS_ERR(usb3->phy))
usb3->phy = NULL;
usb3->workaround_for_vbus = priv->workaround_for_vbus;
renesas_usb3_debugfs_init(usb3, &pdev->dev);
dev_info(&pdev->dev, "probed\n");
dev_info(&pdev->dev, "probed%s\n", usb3->phy ? " with phy" : "");
pm_runtime_enable(usb3_to_dev(usb3));
return 0;
......@@ -2655,11 +2668,49 @@ static int renesas_usb3_probe(struct platform_device *pdev)
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int renesas_usb3_suspend(struct device *dev)
{
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
/* Not started */
if (!usb3->driver)
return 0;
renesas_usb3_stop_controller(usb3);
if (usb3->phy)
phy_exit(usb3->phy);
pm_runtime_put(dev);
return 0;
}
static int renesas_usb3_resume(struct device *dev)
{
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
/* Not started */
if (!usb3->driver)
return 0;
if (usb3->phy)
phy_init(usb3->phy);
pm_runtime_get_sync(dev);
renesas_usb3_init_controller(usb3);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(renesas_usb3_pm_ops, renesas_usb3_suspend,
renesas_usb3_resume);
static struct platform_driver renesas_usb3_driver = {
.probe = renesas_usb3_probe,
.remove = renesas_usb3_remove,
.driver = {
.name = (char *)udc_name,
.pm = &renesas_usb3_pm_ops,
.of_match_table = of_match_ptr(usb3_of_match),
},
};
......
......@@ -46,6 +46,9 @@ struct mtu3_request;
#define MU3D_EP_RXCR1(epnum) (U3D_RX1CSR1 + (((epnum) - 1) * 0x10))
#define MU3D_EP_RXCR2(epnum) (U3D_RX1CSR2 + (((epnum) - 1) * 0x10))
#define USB_QMU_TQHIAR(epnum) (U3D_TXQHIAR1 + (((epnum) - 1) * 0x4))
#define USB_QMU_RQHIAR(epnum) (U3D_RXQHIAR1 + (((epnum) - 1) * 0x4))
#define USB_QMU_RQCSR(epnum) (U3D_RXQCSR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQSAR(epnum) (U3D_RXQSAR1 + (((epnum) - 1) * 0x10))
#define USB_QMU_RQCPR(epnum) (U3D_RXQCPR1 + (((epnum) - 1) * 0x10))
......@@ -91,6 +94,7 @@ enum mtu3_speed {
MTU3_SPEED_FULL = 1,
MTU3_SPEED_HIGH = 3,
MTU3_SPEED_SUPER = 4,
MTU3_SPEED_SUPER_PLUS = 5,
};
/**
......@@ -111,6 +115,19 @@ enum mtu3_g_ep0_state {
MU3D_EP0_STATE_STALL,
};
/**
* MTU3_DR_FORCE_NONE: automatically switch host and periperal mode
* by IDPIN signal.
* MTU3_DR_FORCE_HOST: force to enter host mode and override OTG
* IDPIN signal.
* MTU3_DR_FORCE_DEVICE: force to enter peripheral mode.
*/
enum mtu3_dr_force_mode {
MTU3_DR_FORCE_NONE = 0,
MTU3_DR_FORCE_HOST,
MTU3_DR_FORCE_DEVICE,
};
/**
* @base: the base address of fifo
* @limit: the bitmap size in bits
......@@ -138,23 +155,33 @@ struct mtu3_fifo_info {
* Checksum value is calculated over the 16 bytes of the GPD by default;
* @data_buf_len (RX ONLY): This value indicates the length of
* the assigned data buffer
* @tx_ext_addr (TX ONLY): [3:0] are 4 extension bits of @buffer,
* [7:4] are 4 extension bits of @next_gpd
* @next_gpd: Physical address of the next GPD
* @buffer: Physical address of the data buffer
* @buf_len:
* (TX): This value indicates the length of the assigned data buffer
* (RX): The total length of data received
* @ext_len: reserved
* @rx_ext_addr(RX ONLY): [3:0] are 4 extension bits of @buffer,
* [7:4] are 4 extension bits of @next_gpd
* @ext_flag:
* bit5 (TX ONLY): Zero Length Packet (ZLP),
*/
struct qmu_gpd {
__u8 flag;
__u8 chksum;
__le16 data_buf_len;
union {
__le16 data_buf_len;
__le16 tx_ext_addr;
};
__le32 next_gpd;
__le32 buffer;
__le16 buf_len;
__u8 ext_len;
union {
__u8 ext_len;
__u8 rx_ext_addr;
};
__u8 ext_flag;
} __packed;
......@@ -183,7 +210,6 @@ struct mtu3_gpd_ring {
* xHCI driver initialization, it's necessary for system bootup
* as device.
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
* @id_*: used to maually switch between host and device modes by idpin
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input.
*/
......@@ -194,10 +220,6 @@ struct otg_switch_mtk {
struct notifier_block id_nb;
struct delayed_work extcon_reg_dwork;
bool is_u3_drd;
/* dual-role switch by debugfs */
struct pinctrl *id_pinctrl;
struct pinctrl_state *id_float;
struct pinctrl_state *id_ground;
bool manual_drd_enabled;
};
......@@ -206,14 +228,17 @@ struct otg_switch_mtk {
* @ippc_base: register base address of IP Power and Clock interface (IPPC)
* @vusb33: usb3.3V shared by device/host IP
* @sys_clk: system clock of mtu3, shared by device/host IP
* @ref_clk: reference clock
* @mcu_clk: mcu_bus_ck clock for AHB bus etc
* @dma_clk: dma_bus_ck clock for AXI bus etc
* @dr_mode: works in which mode:
* host only, device only or dual-role mode
* @u2_ports: number of usb2.0 host ports
* @u3_ports: number of usb3.0 host ports
* @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to
* disable u3port0, bit1==1 to disable u3port1,... etc
* @dbgfs_root: only used when supports manual dual-role switch via debugfs
* @wakeup_en: it's true when supports remote wakeup in host mode
* @wk_deb_p0: port0's wakeup debounce clock
* @wk_deb_p1: it's optional, and depends on port1 is supported or not
*/
struct ssusb_mtk {
struct device *dev;
......@@ -226,17 +251,18 @@ struct ssusb_mtk {
struct regulator *vusb33;
struct clk *sys_clk;
struct clk *ref_clk;
struct clk *mcu_clk;
struct clk *dma_clk;
/* otg */
struct otg_switch_mtk otg_switch;
enum usb_dr_mode dr_mode;
bool is_host;
int u2_ports;
int u3_ports;
int u3p_dis_msk;
struct dentry *dbgfs_root;
/* usb wakeup for host mode */
bool wakeup_en;
struct clk *wk_deb_p0;
struct clk *wk_deb_p1;
struct regmap *pericfg;
};
......
......@@ -17,6 +17,7 @@
*
*/
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_address.h>
......@@ -114,7 +115,9 @@ static int mtu3_device_enable(struct mtu3 *mtu)
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0),
(SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN |
SSUSB_U2_PORT_HOST_SEL));
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
mtu3_setbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
return ssusb_check_clocks(mtu->ssusb, check_clk);
}
......@@ -129,7 +132,10 @@ static void mtu3_device_disable(struct mtu3 *mtu)
mtu3_setbits(ibase, SSUSB_U2_CTRL(0),
SSUSB_U2_PORT_DIS | SSUSB_U2_PORT_PDN);
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG)
mtu3_clrbits(ibase, SSUSB_U2_CTRL(0), SSUSB_U2_PORT_OTG_SEL);
mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN);
}
......@@ -236,7 +242,7 @@ void mtu3_ep_stall_set(struct mtu3_ep *mep, bool set)
void mtu3_dev_on_off(struct mtu3 *mtu, int is_on)
{
if (mtu->is_u3_ip && (mtu->max_speed == USB_SPEED_SUPER))
if (mtu->is_u3_ip && mtu->max_speed >= USB_SPEED_SUPER)
mtu3_ss_func_set(mtu, is_on);
else
mtu3_hs_softconn_set(mtu, is_on);
......@@ -546,6 +552,9 @@ static void mtu3_set_speed(struct mtu3 *mtu)
mtu3_clrbits(mbase, U3D_USB3_CONFIG, USB3_EN);
/* HS/FS detected by HW */
mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, HS_ENABLE);
} else if (mtu->max_speed == USB_SPEED_SUPER) {
mtu3_clrbits(mtu->ippc_base, SSUSB_U3_CTRL(0),
SSUSB_U3_PORT_SSP_SPEED);
}
dev_info(mtu->dev, "max_speed: %s\n",
......@@ -623,6 +632,10 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu)
udev_speed = USB_SPEED_SUPER;
maxpkt = 512;
break;
case MTU3_SPEED_SUPER_PLUS:
udev_speed = USB_SPEED_SUPER_PLUS;
maxpkt = 512;
break;
default:
udev_speed = USB_SPEED_UNKNOWN;
break;
......@@ -759,7 +772,31 @@ static void mtu3_hw_exit(struct mtu3 *mtu)
mtu3_mem_free(mtu);
}
/*-------------------------------------------------------------------------*/
/**
* we set 32-bit DMA mask by default, here check whether the controller
* supports 36-bit DMA or not, if it does, set 36-bit DMA mask.
*/
static int mtu3_set_dma_mask(struct mtu3 *mtu)
{
struct device *dev = mtu->dev;
bool is_36bit = false;
int ret = 0;
u32 value;
value = mtu3_readl(mtu->mac_base, U3D_MISC_CTRL);
if (value & DMA_ADDR_36BIT) {
is_36bit = true;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(36));
/* If set 36-bit DMA mask fails, fall back to 32-bit DMA mask */
if (ret) {
is_36bit = false;
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
}
}
dev_info(dev, "dma mask: %s bits\n", is_36bit ? "36" : "32");
return ret;
}
int ssusb_gadget_init(struct ssusb_mtk *ssusb)
{
......@@ -774,9 +811,9 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return -ENOMEM;
mtu->irq = platform_get_irq(pdev, 0);
if (mtu->irq <= 0) {
if (mtu->irq < 0) {
dev_err(dev, "fail to get irq number\n");
return -ENODEV;
return mtu->irq;
}
dev_info(dev, "irq %d\n", mtu->irq);
......@@ -800,14 +837,15 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
case USB_SPEED_FULL:
case USB_SPEED_HIGH:
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
break;
default:
dev_err(dev, "invalid max_speed: %s\n",
usb_speed_string(mtu->max_speed));
/* fall through */
case USB_SPEED_UNKNOWN:
/* default as SS */
mtu->max_speed = USB_SPEED_SUPER;
/* default as SSP */
mtu->max_speed = USB_SPEED_SUPER_PLUS;
break;
}
......@@ -820,6 +858,12 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
return ret;
}
ret = mtu3_set_dma_mask(mtu);
if (ret) {
dev_err(dev, "mtu3 set dma_mask failed:%d\n", ret);
goto dma_mask_err;
}
ret = devm_request_irq(dev, mtu->irq, mtu3_irq, 0, dev_name(dev), mtu);
if (ret) {
dev_err(dev, "request irq %d failed!\n", mtu->irq);
......@@ -845,6 +889,7 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb)
gadget_err:
device_init_wakeup(dev, false);
dma_mask_err:
irq_err:
mtu3_hw_exit(mtu);
ssusb->u3d = NULL;
......
......@@ -261,21 +261,22 @@ static void extcon_register_dwork(struct work_struct *work)
* depending on user input.
* This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode.
* It generates cable state changes by pulling up/down IDPIN and
* notifies driver to switch mode by "extcon-usb-gpio".
* NOTE: when use MICRO receptacle, should not enable this interface.
*/
static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
if (to_host)
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_ground);
else
pinctrl_select_state(otg_sx->id_pinctrl, otg_sx->id_float);
if (to_host) {
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
ssusb_set_mailbox(otg_sx, MTU3_VBUS_OFF);
ssusb_set_mailbox(otg_sx, MTU3_ID_GROUND);
} else {
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE);
ssusb_set_mailbox(otg_sx, MTU3_ID_FLOAT);
ssusb_set_mailbox(otg_sx, MTU3_VBUS_VALID);
}
}
static int ssusb_mode_show(struct seq_file *sf, void *unused)
{
struct ssusb_mtk *ssusb = sf->private;
......@@ -388,17 +389,45 @@ static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb)
debugfs_remove_recursive(ssusb->dbgfs_root);
}
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
enum mtu3_dr_force_mode mode)
{
u32 value;
value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0));
switch (mode) {
case MTU3_DR_FORCE_DEVICE:
value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG;
break;
case MTU3_DR_FORCE_HOST:
value |= SSUSB_U2_PORT_FORCE_IDDIG;
value &= ~SSUSB_U2_PORT_RG_IDDIG;
break;
case MTU3_DR_FORCE_NONE:
value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG);
break;
default:
return;
}
mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);
}
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork, extcon_register_dwork);
if (otg_sx->manual_drd_enabled)
if (otg_sx->manual_drd_enabled) {
ssusb_debugfs_init(ssusb);
/* It is enough to delay 1s for waiting for host initialization */
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
} else {
INIT_DELAYED_WORK(&otg_sx->extcon_reg_dwork,
extcon_register_dwork);
/*
* It is enough to delay 1s for waiting for
* host initialization
*/
schedule_delayed_work(&otg_sx->extcon_reg_dwork, HZ);
}
return 0;
}
......@@ -407,8 +436,8 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
if (otg_sx->manual_drd_enabled)
ssusb_debugfs_exit(ssusb);
else
cancel_delayed_work(&otg_sx->extcon_reg_dwork);
}
......@@ -87,6 +87,8 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
enum mtu3_dr_force_mode mode);
#else
......@@ -103,6 +105,10 @@ static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
return 0;
}
static inline void
ssusb_set_force_mode(struct ssusb_mtk *ssusb, enum mtu3_dr_force_mode mode)
{}
#endif
#endif /* _MTU3_DR_H_ */
......@@ -89,6 +89,7 @@ static int mtu3_ep_enable(struct mtu3_ep *mep)
switch (mtu->g.speed) {
case USB_SPEED_SUPER:
case USB_SPEED_SUPER_PLUS:
if (usb_endpoint_xfer_int(desc) ||
usb_endpoint_xfer_isoc(desc)) {
interval = desc->bInterval;
......@@ -456,7 +457,7 @@ static int mtu3_gadget_wakeup(struct usb_gadget *gadget)
return -EOPNOTSUPP;
spin_lock_irqsave(&mtu->lock, flags);
if (mtu->g.speed == USB_SPEED_SUPER) {
if (mtu->g.speed >= USB_SPEED_SUPER) {
mtu3_setbits(mtu->mac_base, U3D_LINK_POWER_CONTROL, UX_EXIT);
} else {
mtu3_setbits(mtu->mac_base, U3D_POWER_MANAGEMENT, RESUME);
......
......@@ -212,8 +212,8 @@ ep0_get_status(struct mtu3 *mtu, const struct usb_ctrlrequest *setup)
case USB_RECIP_DEVICE:
result[0] = mtu->is_self_powered << USB_DEVICE_SELF_POWERED;
result[0] |= mtu->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
/* superspeed only */
if (mtu->g.speed == USB_SPEED_SUPER) {
if (mtu->g.speed >= USB_SPEED_SUPER) {
result[0] |= mtu->u1_enable << USB_DEV_STAT_U1_ENABLED;
result[0] |= mtu->u2_enable << USB_DEV_STAT_U2_ENABLED;
}
......@@ -329,8 +329,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = handle_test_mode(mtu, setup);
break;
case USB_DEVICE_U1_ENABLE:
if (mtu->g.speed != USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED)
if (mtu->g.speed < USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED)
break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
......@@ -344,8 +344,8 @@ static int ep0_handle_feature_dev(struct mtu3 *mtu,
handled = 1;
break;
case USB_DEVICE_U2_ENABLE:
if (mtu->g.speed != USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED)
if (mtu->g.speed < USB_SPEED_SUPER ||
mtu->g.state != USB_STATE_CONFIGURED)
break;
lpc = mtu3_readl(mbase, U3D_LINK_POWER_CONTROL);
......@@ -384,8 +384,8 @@ static int ep0_handle_feature(struct mtu3 *mtu,
break;
case USB_RECIP_INTERFACE:
/* superspeed only */
if ((value == USB_INTRF_FUNC_SUSPEND)
&& (mtu->g.speed == USB_SPEED_SUPER)) {
if (value == USB_INTRF_FUNC_SUSPEND &&
mtu->g.speed >= USB_SPEED_SUPER) {
/*
* forward the request because function drivers
* should handle it
......
......@@ -79,20 +79,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
if (!ssusb->wakeup_en)
return 0;
ssusb->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0");
if (IS_ERR(ssusb->wk_deb_p0)) {
dev_err(dev, "fail to get wakeup_deb_p0\n");
return PTR_ERR(ssusb->wk_deb_p0);
}
if (of_property_read_bool(dn, "wakeup_deb_p1")) {
ssusb->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1");
if (IS_ERR(ssusb->wk_deb_p1)) {
dev_err(dev, "fail to get wakeup_deb_p1\n");
return PTR_ERR(ssusb->wk_deb_p1);
}
}
ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
"mediatek,syscon-wakeup");
if (IS_ERR(ssusb->pericfg)) {
......@@ -103,36 +89,6 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
return 0;
}
static int ssusb_wakeup_clks_enable(struct ssusb_mtk *ssusb)
{
int ret;
ret = clk_prepare_enable(ssusb->wk_deb_p0);
if (ret) {
dev_err(ssusb->dev, "failed to enable wk_deb_p0\n");
goto usb_p0_err;
}
ret = clk_prepare_enable(ssusb->wk_deb_p1);
if (ret) {
dev_err(ssusb->dev, "failed to enable wk_deb_p1\n");
goto usb_p1_err;
}
return 0;
usb_p1_err:
clk_disable_unprepare(ssusb->wk_deb_p0);
usb_p0_err:
return -EINVAL;
}
static void ssusb_wakeup_clks_disable(struct ssusb_mtk *ssusb)
{
clk_disable_unprepare(ssusb->wk_deb_p1);
clk_disable_unprepare(ssusb->wk_deb_p0);
}
static void host_ports_num_get(struct ssusb_mtk *ssusb)
{
u32 xhci_cap;
......@@ -151,6 +107,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
void __iomem *ibase = ssusb->ippc_base;
int num_u3p = ssusb->u3_ports;
int num_u2p = ssusb->u2_ports;
int u3_ports_disabed;
u32 check_clk;
u32 value;
int i;
......@@ -158,8 +115,14 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
/* power on host ip */
mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN);
/* power on and enable all u3 ports */
/* power on and enable u3 ports except skipped ones */
u3_ports_disabed = 0;
for (i = 0; i < num_u3p; i++) {
if ((0x1 << i) & ssusb->u3p_dis_msk) {
u3_ports_disabed++;
continue;
}
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS);
value |= SSUSB_U3_PORT_HOST_SEL;
......@@ -175,7 +138,7 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb)
}
check_clk = SSUSB_XHCI_RST_B_STS;
if (num_u3p)
if (num_u3p > u3_ports_disabed)
check_clk = SSUSB_U3_MAC_RST_B_STS;
return ssusb_check_clocks(ssusb, check_clk);
......@@ -190,8 +153,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
int ret;
int i;
/* power down and disable all u3 ports */
/* power down and disable u3 ports except skipped ones */
for (i = 0; i < num_u3p; i++) {
if ((0x1 << i) & ssusb->u3p_dis_msk)
continue;
value = mtu3_readl(ibase, SSUSB_U3_CTRL(i));
value |= SSUSB_U3_PORT_PDN;
value |= suspend ? 0 : SSUSB_U3_PORT_DIS;
......@@ -223,6 +189,8 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend)
static void ssusb_host_setup(struct ssusb_mtk *ssusb)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
host_ports_num_get(ssusb);
/*
......@@ -231,6 +199,9 @@ static void ssusb_host_setup(struct ssusb_mtk *ssusb)
*/
ssusb_host_enable(ssusb);
if (otg_sx->manual_drd_enabled)
ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST);
/* if port0 supports dual-role, works as host mode by default */
ssusb_set_vbus(&ssusb->otg_switch, 1);
}
......@@ -276,19 +247,14 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
{
int ret = 0;
if (ssusb->wakeup_en) {
ret = ssusb_wakeup_clks_enable(ssusb);
if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_en(ssusb);
}
return ret;
return 0;
}
void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
{
if (ssusb->wakeup_en) {
if (ssusb->wakeup_en)
ssusb_wakeup_ip_sleep_dis(ssusb);
ssusb_wakeup_clks_disable(ssusb);
}
}
......@@ -58,6 +58,8 @@
#define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404)
#define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408)
#define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C)
#define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484)
#define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4)
#define U3D_TXQCSR1 (SSUSB_DEV_BASE + 0x0510)
#define U3D_TXQSAR1 (SSUSB_DEV_BASE + 0x0514)
......@@ -189,6 +191,13 @@
#define QMU_RX_COZ(x) (BIT(16) << (x))
#define QMU_RX_ZLP(x) (BIT(0) << (x))
/* U3D_TXQHIAR1 */
/* U3D_RXQHIAR1 */
#define QMU_LAST_DONE_PTR_HI(x) (((x) >> 16) & 0xf)
#define QMU_CUR_GPD_ADDR_HI(x) (((x) >> 8) & 0xf)
#define QMU_START_ADDR_HI_MSK GENMASK(3, 0)
#define QMU_START_ADDR_HI(x) (((x) & 0xf) << 0)
/* U3D_TXQCSR1 */
/* U3D_RXQCSR1 */
#define QMU_Q_ACTIVE BIT(15)
......@@ -225,6 +234,7 @@
#define CAP_TX_EP_NUM(x) ((x) & 0x1f)
/* U3D_MISC_CTRL */
#define DMA_ADDR_36BIT BIT(31)
#define VBUS_ON BIT(1)
#define VBUS_FRC_EN BIT(0)
......@@ -457,11 +467,14 @@
#define SSUSB_VBUS_CHG_INT_B_EN BIT(6)
/* U3D_SSUSB_U3_CTRL_0P */
#define SSUSB_U3_PORT_SSP_SPEED BIT(9)
#define SSUSB_U3_PORT_HOST_SEL BIT(2)
#define SSUSB_U3_PORT_PDN BIT(1)
#define SSUSB_U3_PORT_DIS BIT(0)
/* U3D_SSUSB_U2_CTRL_0P */
#define SSUSB_U2_PORT_RG_IDDIG BIT(12)
#define SSUSB_U2_PORT_FORCE_IDDIG BIT(11)
#define SSUSB_U2_PORT_VBUSVALID BIT(9)
#define SSUSB_U2_PORT_OTG_SEL BIT(7)
#define SSUSB_U2_PORT_HOST BIT(2)
......
......@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include "mtu3.h"
......@@ -110,15 +109,9 @@ static void ssusb_phy_power_off(struct ssusb_mtk *ssusb)
phy_power_off(ssusb->phys[i]);
}
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
static int ssusb_clks_enable(struct ssusb_mtk *ssusb)
{
int ret = 0;
ret = regulator_enable(ssusb->vusb33);
if (ret) {
dev_err(ssusb->dev, "failed to enable vusb33\n");
goto vusb33_err;
}
int ret;
ret = clk_prepare_enable(ssusb->sys_clk);
if (ret) {
......@@ -132,6 +125,52 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
goto ref_clk_err;
}
ret = clk_prepare_enable(ssusb->mcu_clk);
if (ret) {
dev_err(ssusb->dev, "failed to enable mcu_clk\n");
goto mcu_clk_err;
}
ret = clk_prepare_enable(ssusb->dma_clk);
if (ret) {
dev_err(ssusb->dev, "failed to enable dma_clk\n");
goto dma_clk_err;
}
return 0;
dma_clk_err:
clk_disable_unprepare(ssusb->mcu_clk);
mcu_clk_err:
clk_disable_unprepare(ssusb->ref_clk);
ref_clk_err:
clk_disable_unprepare(ssusb->sys_clk);
sys_clk_err:
return ret;
}
static void ssusb_clks_disable(struct ssusb_mtk *ssusb)
{
clk_disable_unprepare(ssusb->dma_clk);
clk_disable_unprepare(ssusb->mcu_clk);
clk_disable_unprepare(ssusb->ref_clk);
clk_disable_unprepare(ssusb->sys_clk);
}
static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
{
int ret = 0;
ret = regulator_enable(ssusb->vusb33);
if (ret) {
dev_err(ssusb->dev, "failed to enable vusb33\n");
goto vusb33_err;
}
ret = ssusb_clks_enable(ssusb);
if (ret)
goto clks_err;
ret = ssusb_phy_init(ssusb);
if (ret) {
dev_err(ssusb->dev, "failed to init phy\n");
......@@ -149,20 +188,16 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb)
phy_err:
ssusb_phy_exit(ssusb);
phy_init_err:
clk_disable_unprepare(ssusb->ref_clk);
ref_clk_err:
clk_disable_unprepare(ssusb->sys_clk);
sys_clk_err:
ssusb_clks_disable(ssusb);
clks_err:
regulator_disable(ssusb->vusb33);
vusb33_err:
return ret;
}
static void ssusb_rscs_exit(struct ssusb_mtk *ssusb)
{
clk_disable_unprepare(ssusb->sys_clk);
clk_disable_unprepare(ssusb->ref_clk);
ssusb_clks_disable(ssusb);
regulator_disable(ssusb->vusb33);
ssusb_phy_power_off(ssusb);
ssusb_phy_exit(ssusb);
......@@ -176,31 +211,17 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb)
mtu3_clrbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL0, SSUSB_IP_SW_RST);
}
static int get_iddig_pinctrl(struct ssusb_mtk *ssusb)
/* ignore the error if the clock does not exist */
static struct clk *get_optional_clk(struct device *dev, const char *id)
{
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch;
struct clk *opt_clk;
otg_sx->id_pinctrl = devm_pinctrl_get(ssusb->dev);
if (IS_ERR(otg_sx->id_pinctrl)) {
dev_err(ssusb->dev, "Cannot find id pinctrl!\n");
return PTR_ERR(otg_sx->id_pinctrl);
}
opt_clk = devm_clk_get(dev, id);
/* ignore error number except EPROBE_DEFER */
if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER))
opt_clk = NULL;
otg_sx->id_float =
pinctrl_lookup_state(otg_sx->id_pinctrl, "id_float");
if (IS_ERR(otg_sx->id_float)) {
dev_err(ssusb->dev, "Cannot find pinctrl id_float!\n");
return PTR_ERR(otg_sx->id_float);
}
otg_sx->id_ground =
pinctrl_lookup_state(otg_sx->id_pinctrl, "id_ground");
if (IS_ERR(otg_sx->id_ground)) {
dev_err(ssusb->dev, "Cannot find pinctrl id_ground!\n");
return PTR_ERR(otg_sx->id_ground);
}
return 0;
return opt_clk;
}
static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
......@@ -225,18 +246,17 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->sys_clk);
}
/*
* reference clock is usually a "fixed-clock", make it optional
* for backward compatibility and ignore the error if it does
* not exist.
*/
ssusb->ref_clk = devm_clk_get(dev, "ref_ck");
if (IS_ERR(ssusb->ref_clk)) {
if (PTR_ERR(ssusb->ref_clk) == -EPROBE_DEFER)
return -EPROBE_DEFER;
ssusb->ref_clk = get_optional_clk(dev, "ref_ck");
if (IS_ERR(ssusb->ref_clk))
return PTR_ERR(ssusb->ref_clk);
ssusb->ref_clk = NULL;
}
ssusb->mcu_clk = get_optional_clk(dev, "mcu_ck");
if (IS_ERR(ssusb->mcu_clk))
return PTR_ERR(ssusb->mcu_clk);
ssusb->dma_clk = get_optional_clk(dev, "dma_ck");
if (IS_ERR(ssusb->dma_clk))
return PTR_ERR(ssusb->dma_clk);
ssusb->num_phys = of_count_phandle_with_args(node,
"phys", "#phy-cells");
......@@ -263,10 +283,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
return PTR_ERR(ssusb->ippc_base);
ssusb->dr_mode = usb_get_dr_mode(dev);
if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) {
dev_err(dev, "dr_mode is error\n");
return -EINVAL;
}
if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN)
ssusb->dr_mode = USB_DR_MODE_OTG;
if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL)
return 0;
......@@ -276,10 +294,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
if (ret)
return ret;
if (ssusb->dr_mode != USB_DR_MODE_OTG)
return 0;
/* optional property, ignore the error if it does not exist */
of_property_read_u32(node, "mediatek,u3p-dis-msk",
&ssusb->u3p_dis_msk);
/* if dual-role mode is supported */
vbus = devm_regulator_get(&pdev->dev, "vbus");
if (IS_ERR(vbus)) {
dev_err(dev, "failed to get vbus\n");
......@@ -287,6 +305,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
}
otg_sx->vbus = vbus;
if (ssusb->dr_mode == USB_DR_MODE_HOST)
return 0;
/* if dual-role mode is supported */
otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
otg_sx->manual_drd_enabled =
of_property_read_bool(node, "enable-manual-drd");
......@@ -297,15 +319,11 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
dev_err(ssusb->dev, "couldn't get extcon device\n");
return -EPROBE_DEFER;
}
if (otg_sx->manual_drd_enabled) {
ret = get_iddig_pinctrl(ssusb);
if (ret)
return ret;
}
}
dev_info(dev, "dr_mode: %d, is_u3_dr: %d\n",
ssusb->dr_mode, otg_sx->is_u3_drd);
dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n",
ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk,
otg_sx->manual_drd_enabled ? "manual" : "auto");
return 0;
}
......@@ -447,8 +465,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
ssusb_host_disable(ssusb, true);
ssusb_phy_power_off(ssusb);
clk_disable_unprepare(ssusb->sys_clk);
clk_disable_unprepare(ssusb->ref_clk);
ssusb_clks_disable(ssusb);
ssusb_wakeup_enable(ssusb);
return 0;
......@@ -466,27 +483,21 @@ static int __maybe_unused mtu3_resume(struct device *dev)
return 0;
ssusb_wakeup_disable(ssusb);
ret = clk_prepare_enable(ssusb->sys_clk);
if (ret)
goto err_sys_clk;
ret = clk_prepare_enable(ssusb->ref_clk);
ret = ssusb_clks_enable(ssusb);
if (ret)
goto err_ref_clk;
goto clks_err;
ret = ssusb_phy_power_on(ssusb);
if (ret)
goto err_power_on;
goto phy_err;
ssusb_host_enable(ssusb);
return 0;
err_power_on:
clk_disable_unprepare(ssusb->ref_clk);
err_ref_clk:
clk_disable_unprepare(ssusb->sys_clk);
err_sys_clk:
phy_err:
ssusb_clks_disable(ssusb);
clks_err:
return ret;
}
......
......@@ -40,7 +40,58 @@
#define GPD_FLAGS_IOC BIT(7)
#define GPD_EXT_FLAG_ZLP BIT(5)
#define GPD_EXT_NGP(x) (((x) & 0xf) << 4)
#define GPD_EXT_BUF(x) (((x) & 0xf) << 0)
#define HILO_GEN64(hi, lo) (((u64)(hi) << 32) + (lo))
#define HILO_DMA(hi, lo) \
((dma_addr_t)HILO_GEN64((le32_to_cpu(hi)), (le32_to_cpu(lo))))
static dma_addr_t read_txq_cur_addr(void __iomem *mbase, u8 epnum)
{
u32 txcpr;
u32 txhiar;
txcpr = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
txhiar = mtu3_readl(mbase, USB_QMU_TQHIAR(epnum));
return HILO_DMA(QMU_CUR_GPD_ADDR_HI(txhiar), txcpr);
}
static dma_addr_t read_rxq_cur_addr(void __iomem *mbase, u8 epnum)
{
u32 rxcpr;
u32 rxhiar;
rxcpr = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
rxhiar = mtu3_readl(mbase, USB_QMU_RQHIAR(epnum));
return HILO_DMA(QMU_CUR_GPD_ADDR_HI(rxhiar), rxcpr);
}
static void write_txq_start_addr(void __iomem *mbase, u8 epnum, dma_addr_t dma)
{
u32 tqhiar;
mtu3_writel(mbase, USB_QMU_TQSAR(epnum),
cpu_to_le32(lower_32_bits(dma)));
tqhiar = mtu3_readl(mbase, USB_QMU_TQHIAR(epnum));
tqhiar &= ~QMU_START_ADDR_HI_MSK;
tqhiar |= QMU_START_ADDR_HI(upper_32_bits(dma));
mtu3_writel(mbase, USB_QMU_TQHIAR(epnum), tqhiar);
}
static void write_rxq_start_addr(void __iomem *mbase, u8 epnum, dma_addr_t dma)
{
u32 rqhiar;
mtu3_writel(mbase, USB_QMU_RQSAR(epnum),
cpu_to_le32(lower_32_bits(dma)));
rqhiar = mtu3_readl(mbase, USB_QMU_RQHIAR(epnum));
rqhiar &= ~QMU_START_ADDR_HI_MSK;
rqhiar |= QMU_START_ADDR_HI(upper_32_bits(dma));
mtu3_writel(mbase, USB_QMU_RQHIAR(epnum), rqhiar);
}
static struct qmu_gpd *gpd_dma_to_virt(struct mtu3_gpd_ring *ring,
dma_addr_t dma_addr)
......@@ -193,21 +244,27 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request;
dma_addr_t enq_dma;
u16 ext_addr;
/* set all fields to zero as default value */
memset(gpd, 0, sizeof(*gpd));
gpd->buffer = cpu_to_le32((u32)req->dma);
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
gpd->buf_len = cpu_to_le16(req->length);
gpd->flag |= GPD_FLAGS_IOC;
/* get the next GPD */
enq = advance_enq_gpd(ring);
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p\n",
mep->epnum, gpd, enq);
enq_dma = gpd_virt_to_dma(ring, enq);
dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
mep->epnum, gpd, enq, enq_dma);
enq->flag &= ~GPD_FLAGS_HWO;
gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
gpd->tx_ext_addr = cpu_to_le16(ext_addr);
if (req->zero)
gpd->ext_flag |= GPD_EXT_FLAG_ZLP;
......@@ -226,21 +283,27 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
struct qmu_gpd *gpd = ring->enqueue;
struct usb_request *req = &mreq->request;
dma_addr_t enq_dma;
u16 ext_addr;
/* set all fields to zero as default value */
memset(gpd, 0, sizeof(*gpd));
gpd->buffer = cpu_to_le32((u32)req->dma);
gpd->buffer = cpu_to_le32(lower_32_bits(req->dma));
ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma));
gpd->data_buf_len = cpu_to_le16(req->length);
gpd->flag |= GPD_FLAGS_IOC;
/* get the next GPD */
enq = advance_enq_gpd(ring);
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p\n",
mep->epnum, gpd, enq);
enq_dma = gpd_virt_to_dma(ring, enq);
dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n",
mep->epnum, gpd, enq, enq_dma);
enq->flag &= ~GPD_FLAGS_HWO;
gpd->next_gpd = cpu_to_le32((u32)gpd_virt_to_dma(ring, enq));
gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma));
ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma));
gpd->rx_ext_addr = cpu_to_le16(ext_addr);
gpd->chksum = qmu_calc_checksum((u8 *)gpd);
gpd->flag |= GPD_FLAGS_HWO;
......@@ -267,8 +330,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
if (mep->is_in) {
/* set QMU start address */
mtu3_writel(mbase, USB_QMU_TQSAR(mep->epnum), ring->dma);
mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN);
write_txq_start_addr(mbase, epnum, ring->dma);
mtu3_setbits(mbase, MU3D_EP_TXCR0(epnum), TX_DMAREQEN);
mtu3_setbits(mbase, U3D_QCR0, QMU_TX_CS_EN(epnum));
/* send zero length packet according to ZLP flag in GPD */
mtu3_setbits(mbase, U3D_QCR1, QMU_TX_ZLP(epnum));
......@@ -282,8 +345,8 @@ int mtu3_qmu_start(struct mtu3_ep *mep)
mtu3_writel(mbase, USB_QMU_TQCSR(epnum), QMU_Q_START);
} else {
mtu3_writel(mbase, USB_QMU_RQSAR(mep->epnum), ring->dma);
mtu3_setbits(mbase, MU3D_EP_RXCR0(mep->epnum), RX_DMAREQEN);
write_rxq_start_addr(mbase, epnum, ring->dma);
mtu3_setbits(mbase, MU3D_EP_RXCR0(epnum), RX_DMAREQEN);
mtu3_setbits(mbase, U3D_QCR0, QMU_RX_CS_EN(epnum));
/* don't expect ZLP */
mtu3_clrbits(mbase, U3D_QCR3, QMU_RX_ZLP(epnum));
......@@ -353,9 +416,9 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
struct mtu3_gpd_ring *ring = &mep->gpd_ring;
void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
struct usb_request *req = NULL;
struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
u32 txcsr = 0;
int ret;
......@@ -365,7 +428,8 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum)
else
return;
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
if (le16_to_cpu(gpd_current->buf_len) != 0) {
dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum);
......@@ -408,12 +472,13 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum)
void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd = ring->dequeue;
struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_TQCPR(epnum));
struct usb_request *request = NULL;
struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
/*transfer phy address got from QMU register to virtual address */
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
cur_gpd_dma = read_txq_cur_addr(mbase, epnum);
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
......@@ -446,11 +511,12 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum)
void __iomem *mbase = mtu->mac_base;
struct qmu_gpd *gpd = ring->dequeue;
struct qmu_gpd *gpd_current = NULL;
dma_addr_t gpd_dma = mtu3_readl(mbase, USB_QMU_RQCPR(epnum));
struct usb_request *req = NULL;
struct mtu3_request *mreq;
dma_addr_t cur_gpd_dma;
gpd_current = gpd_dma_to_virt(ring, gpd_dma);
cur_gpd_dma = read_rxq_cur_addr(mbase, epnum);
gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma);
dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n",
__func__, epnum, gpd, gpd_current, ring->enqueue);
......
......@@ -224,7 +224,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
int err = 0;
u32 clk_rate = 0;
bool needs_vcc = false;
bool needs_vcc = false, needs_clk = false;
if (dev->of_node) {
struct device_node *node = dev->of_node;
......@@ -233,6 +233,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
needs_clk = of_property_read_bool(node, "clocks");
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_ASIS);
err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
......@@ -275,6 +276,8 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
if (IS_ERR(nop->clk)) {
dev_dbg(dev, "Can't get phy clock: %ld\n",
PTR_ERR(nop->clk));
if (needs_clk)
return PTR_ERR(nop->clk);
}
if (!IS_ERR(nop->clk) && clk_rate) {
......
......@@ -1261,6 +1261,7 @@ static void msm_chg_detect_work(struct work_struct *w)
/* fall through */
case USB_CHG_STATE_SECONDARY_DONE:
motg->chg_state = USB_CHG_STATE_DETECTED;
/* fall through */
case USB_CHG_STATE_DETECTED:
msm_chg_block_off(motg);
dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
......
......@@ -67,11 +67,26 @@
#define ANADIG_ANA_MISC0_SET 0x154
#define ANADIG_ANA_MISC0_CLR 0x158
#define ANADIG_USB1_CHRG_DETECT_SET 0x1b4
#define ANADIG_USB1_CHRG_DETECT_CLR 0x1b8
#define ANADIG_USB1_CHRG_DETECT_EN_B BIT(20)
#define ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B BIT(19)
#define ANADIG_USB1_CHRG_DETECT_CHK_CONTACT BIT(18)
#define ANADIG_USB1_VBUS_DET_STAT 0x1c0
#define ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID BIT(3)
#define ANADIG_USB1_CHRG_DET_STAT 0x1d0
#define ANADIG_USB1_CHRG_DET_STAT_DM_STATE BIT(2)
#define ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED BIT(1)
#define ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT BIT(0)
#define ANADIG_USB2_VBUS_DET_STAT 0x220
#define ANADIG_USB1_LOOPBACK_SET 0x1e4
#define ANADIG_USB1_LOOPBACK_CLR 0x1e8
#define ANADIG_USB1_LOOPBACK_UTMI_TESTSTART BIT(0)
#define ANADIG_USB2_LOOPBACK_SET 0x244
#define ANADIG_USB2_LOOPBACK_CLR 0x248
......@@ -479,6 +494,144 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
return 0;
}
#define MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT 100
static int mxs_charger_data_contact_detect(struct mxs_phy *x)
{
struct regmap *regmap = x->regmap_anatop;
int i, stable_contact_count = 0;
u32 val;
/* Check if vbus is valid */
regmap_read(regmap, ANADIG_USB1_VBUS_DET_STAT, &val);
if (!(val & ANADIG_USB1_VBUS_DET_STAT_VBUS_VALID)) {
dev_err(x->phy.dev, "vbus is not valid\n");
return -EINVAL;
}
/* Enable charger detector */
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
ANADIG_USB1_CHRG_DETECT_EN_B);
/*
* - Do not check whether a charger is connected to the USB port
* - Check whether the USB plug has been in contact with each other
*/
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
/* Check if plug is connected */
for (i = 0; i < MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT; i++) {
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
if (val & ANADIG_USB1_CHRG_DET_STAT_PLUG_CONTACT) {
stable_contact_count++;
if (stable_contact_count > 5)
/* Data pin makes contact */
break;
else
usleep_range(5000, 10000);
} else {
stable_contact_count = 0;
usleep_range(5000, 6000);
}
}
if (i == MXS_USB_CHARGER_DATA_CONTACT_TIMEOUT) {
dev_err(x->phy.dev,
"Data pin can't make good contact.\n");
/* Disable charger detector */
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
ANADIG_USB1_CHRG_DETECT_EN_B |
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
return -ENXIO;
}
return 0;
}
static enum usb_charger_type mxs_charger_primary_detection(struct mxs_phy *x)
{
struct regmap *regmap = x->regmap_anatop;
enum usb_charger_type chgr_type = UNKNOWN_TYPE;
u32 val;
/*
* - Do check whether a charger is connected to the USB port
* - Do not Check whether the USB plug has been in contact with
* each other
*/
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_CLR,
ANADIG_USB1_CHRG_DETECT_CHK_CONTACT |
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
msleep(100);
/* Check if it is a charger */
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
if (!(val & ANADIG_USB1_CHRG_DET_STAT_CHRG_DETECTED)) {
chgr_type = SDP_TYPE;
dev_dbg(x->phy.dev, "It is a stardard downstream port\n");
}
/* Disable charger detector */
regmap_write(regmap, ANADIG_USB1_CHRG_DETECT_SET,
ANADIG_USB1_CHRG_DETECT_EN_B |
ANADIG_USB1_CHRG_DETECT_CHK_CHRG_B);
return chgr_type;
}
/*
* It must be called after DP is pulled up, which is used to
* differentiate DCP and CDP.
*/
enum usb_charger_type mxs_charger_secondary_detection(struct mxs_phy *x)
{
struct regmap *regmap = x->regmap_anatop;
int val;
msleep(80);
regmap_read(regmap, ANADIG_USB1_CHRG_DET_STAT, &val);
if (val & ANADIG_USB1_CHRG_DET_STAT_DM_STATE) {
dev_dbg(x->phy.dev, "It is a dedicate charging port\n");
return DCP_TYPE;
} else {
dev_dbg(x->phy.dev, "It is a charging downstream port\n");
return CDP_TYPE;
}
}
static enum usb_charger_type mxs_phy_charger_detect(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
struct regmap *regmap = mxs_phy->regmap_anatop;
void __iomem *base = phy->io_priv;
enum usb_charger_type chgr_type = UNKNOWN_TYPE;
if (mxs_charger_data_contact_detect(mxs_phy))
return chgr_type;
chgr_type = mxs_charger_primary_detection(mxs_phy);
if (chgr_type != SDP_TYPE) {
/* Pull up DP via test */
writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
base + HW_USBPHY_DEBUG_CLR);
regmap_write(regmap, ANADIG_USB1_LOOPBACK_SET,
ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
chgr_type = mxs_charger_secondary_detection(mxs_phy);
/* Stop the test */
regmap_write(regmap, ANADIG_USB1_LOOPBACK_CLR,
ANADIG_USB1_LOOPBACK_UTMI_TESTSTART);
writel_relaxed(BM_USBPHY_DEBUG_CLKGATE,
base + HW_USBPHY_DEBUG_SET);
}
return chgr_type;
}
static int mxs_phy_probe(struct platform_device *pdev)
{
struct resource *res;
......@@ -567,6 +720,7 @@ static int mxs_phy_probe(struct platform_device *pdev)
mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect;
mxs_phy->phy.type = USB_PHY_TYPE_USB2;
mxs_phy->phy.set_wakeup = mxs_phy_set_wakeup;
mxs_phy->phy.charger_detect = mxs_phy_charger_detect;
mxs_phy->clk = clk;
mxs_phy->data = of_id->data;
......
......@@ -368,7 +368,8 @@ static int tahvo_usb_probe(struct platform_device *pdev)
tu->extcon = devm_extcon_dev_allocate(&pdev->dev, tahvo_cable);
if (IS_ERR(tu->extcon)) {
dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
return -ENOMEM;
ret = PTR_ERR(tu->extcon);
goto err_disable_clk;
}
ret = devm_extcon_dev_register(&pdev->dev, tu->extcon);
......
......@@ -485,6 +485,10 @@ static const struct of_device_id usbhs_of_match[] = {
.compatible = "renesas,usbhs-r8a7796",
.data = (void *)USBHS_TYPE_RCAR_GEN3,
},
{
.compatible = "renesas,usbhs-r8a77995",
.data = (void *)USBHS_TYPE_RCAR_GEN3_WITH_PLL,
},
{
.compatible = "renesas,rcar-gen2-usbhs",
.data = (void *)USBHS_TYPE_RCAR_GEN2,
......@@ -501,7 +505,6 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
{
struct renesas_usbhs_platform_info *info;
struct renesas_usbhs_driver_param *dparam;
const struct of_device_id *of_id = of_match_device(usbhs_of_match, dev);
u32 tmp;
int gpio;
......@@ -510,7 +513,7 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
return NULL;
dparam = &info->driver_param;
dparam->type = of_id ? (uintptr_t)of_id->data : 0;
dparam->type = (uintptr_t)of_device_get_match_data(dev);
if (!of_property_read_u32(dev->of_node, "renesas,buswait", &tmp))
dparam->buswait_bwait = tmp;
gpio = of_get_named_gpio_flags(dev->of_node, "renesas,enable-gpio", 0,
......@@ -519,8 +522,12 @@ static struct renesas_usbhs_platform_info *usbhs_parse_dt(struct device *dev)
dparam->enable_gpio = gpio;
if (dparam->type == USBHS_TYPE_RCAR_GEN2 ||
dparam->type == USBHS_TYPE_RCAR_GEN3)
dparam->type == USBHS_TYPE_RCAR_GEN3 ||
dparam->type == USBHS_TYPE_RCAR_GEN3_WITH_PLL) {
dparam->has_usb_dmac = 1;
dparam->pipe_configs = usbhsc_new_pipe;
dparam->pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
return info;
}
......@@ -577,17 +584,12 @@ static int usbhs_probe(struct platform_device *pdev)
switch (priv->dparam.type) {
case USBHS_TYPE_RCAR_GEN2:
priv->pfunc = usbhs_rcar2_ops;
if (!priv->dparam.pipe_configs) {
priv->dparam.pipe_configs = usbhsc_new_pipe;
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
break;
case USBHS_TYPE_RCAR_GEN3:
priv->pfunc = usbhs_rcar3_ops;
if (!priv->dparam.pipe_configs) {
priv->dparam.pipe_configs = usbhsc_new_pipe;
priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_new_pipe);
}
break;
case USBHS_TYPE_RCAR_GEN3_WITH_PLL:
priv->pfunc = usbhs_rcar3_with_pll_ops;
break;
default:
if (!info->platform_callback.get_id) {
......
......@@ -15,24 +15,39 @@
#include "rcar3.h"
#define LPSTS 0x102
#define UGCTRL 0x180 /* 32-bit register */
#define UGCTRL2 0x184 /* 32-bit register */
#define UGSTS 0x188 /* 32-bit register */
/* Low Power Status register (LPSTS) */
#define LPSTS_SUSPM 0x4000
/* R-Car D3 only: USB General control register (UGCTRL) */
#define UGCTRL_PLLRESET 0x00000001
#define UGCTRL_CONNECT 0x00000004
/*
* USB General control register 2 (UGCTRL2)
* Remarks: bit[31:11] and bit[9:6] should be 0
*/
#define UGCTRL2_RESERVED_3 0x00000001 /* bit[3:0] should be B'0001 */
#define UGCTRL2_USB0SEL_HSUSB 0x00000020
#define UGCTRL2_USB0SEL_OTG 0x00000030
#define UGCTRL2_VBUSSEL 0x00000400
/* R-Car D3 only: USB General status register (UGSTS) */
#define UGSTS_LOCK 0x00000100
static void usbhs_write32(struct usbhs_priv *priv, u32 reg, u32 data)
{
iowrite32(data, priv->base + reg);
}
static u32 usbhs_read32(struct usbhs_priv *priv, u32 reg)
{
return ioread32(priv->base + reg);
}
static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
......@@ -52,6 +67,34 @@ static int usbhs_rcar3_power_ctrl(struct platform_device *pdev,
return 0;
}
/* R-Car D3 needs to release UGCTRL.PLLRESET */
static int usbhs_rcar3_power_and_pll_ctrl(struct platform_device *pdev,
void __iomem *base, int enable)
{
struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
u32 val;
int timeout = 1000;
if (enable) {
usbhs_write32(priv, UGCTRL, 0); /* release PLLRESET */
usbhs_write32(priv, UGCTRL2, UGCTRL2_RESERVED_3 |
UGCTRL2_USB0SEL_HSUSB);
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, LPSTS_SUSPM);
do {
val = usbhs_read32(priv, UGSTS);
udelay(1);
} while (!(val & UGSTS_LOCK) && timeout--);
usbhs_write32(priv, UGCTRL, UGCTRL_CONNECT);
} else {
usbhs_write32(priv, UGCTRL, 0);
usbhs_bset(priv, LPSTS, LPSTS_SUSPM, 0);
usbhs_write32(priv, UGCTRL, UGCTRL_PLLRESET);
}
return 0;
}
static int usbhs_rcar3_get_id(struct platform_device *pdev)
{
return USBHS_GADGET;
......@@ -61,3 +104,8 @@ const struct renesas_usbhs_platform_callback usbhs_rcar3_ops = {
.power_ctrl = usbhs_rcar3_power_ctrl,
.get_id = usbhs_rcar3_get_id,
};
const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops = {
.power_ctrl = usbhs_rcar3_power_and_pll_ctrl,
.get_id = usbhs_rcar3_get_id,
};
#include "common.h"
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_ops;
extern const struct renesas_usbhs_platform_callback usbhs_rcar3_with_pll_ops;
......@@ -188,6 +188,8 @@ struct usb_ep_caps {
* @ops: Function pointers used to access hardware-specific operations.
* @ep_list:the gadget's ep_list holds all of its endpoints
* @caps:The structure describing types and directions supported by endoint.
* @enabled: The current endpoint enabled/disabled state.
* @claimed: True if this endpoint is claimed by a function.
* @maxpacket:The maximum packet size used on this endpoint. The initial
* value can sometimes be reduced (hardware allowing), according to
* the endpoint descriptor used to configure the endpoint.
......@@ -349,6 +351,9 @@ struct usb_gadget_ops {
* or B-Peripheral wants to take host role.
* @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to
* MaxPacketSize.
* @quirk_altset_not_supp: UDC controller doesn't support alt settings.
* @quirk_stall_not_supp: UDC controller doesn't support stalling.
* @quirk_zlp_not_supp: UDC controller doesn't support ZLP.
* @quirk_avoids_skb_reserve: udc/platform wants to avoid skb_reserve() in
* u_ether.c to improve performance.
* @is_selfpowered: if the gadget is self-powered.
......
......@@ -183,8 +183,9 @@ struct renesas_usbhs_driver_param {
#define USBHS_USB_DMAC_XFER_SIZE 32 /* hardcode the xfer size */
};
#define USBHS_TYPE_RCAR_GEN2 1
#define USBHS_TYPE_RCAR_GEN3 2
#define USBHS_TYPE_RCAR_GEN2 1
#define USBHS_TYPE_RCAR_GEN3 2
#define USBHS_TYPE_RCAR_GEN3_WITH_PLL 3
/*
* option:
......
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