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

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

Felipe writes:

USB: changes for v5.9 merge window

CDNS3 got several improvements, most of which are non-critical fixes.
DWC3 has a reset fix for the meson platform, while dwc2 has
improvements for role switch on STM32MP15 SoCs.

Apart from these, we have the usual set of non-critical fixes all over
the place and support for new Ingenic SoC to their PHY driver.

* tag 'usb-for-v5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb: (38 commits)
  usb: dwc3: gadget: when the started list is empty stop the active xfer
  usb: dwc3: gadget: make starting isoc transfers more robust
  usb: dwc3: gadget: add frame number mask
  usb: gadget: function: printer: Interface is disabled and returns error
  usb: gadget: f_uac2: fix AC Interface Header Descriptor wTotalLength
  dt-bindings: usb: ti,keystone-dwc3.yaml: Improve schema
  usb: bdc: Use devm_clk_get_optional()
  usb: bdc: Halt controller on suspend
  usb: bdc: driver runs out of buffer descriptors on large ADB transfers
  usb: bdc: Adb shows offline after resuming from S2
  bdc: Fix bug causing crash after multiple disconnects
  usb: bdc: Add compatible string for new style USB DT nodes
  dt-bindings: usb: bdc: Update compatible strings
  USB: PHY: JZ4770: Reformat the code to align it.
  USB: PHY: JZ4770: Add support for new Ingenic SoCs.
  USB: PHY: JZ4770: Unify code style and simplify code.
  dt-bindings: USB: Add bindings for new Ingenic SoCs.
  usb: gadget: net2280: fix memory leak on probe error handling paths
  usb: cdns3: drd: simplify *switch_gadet and *switch_host
  usb: cdns3: core: removed overwriting some error code
  ...
parents c9779308 f5e46aa4
...@@ -4,7 +4,7 @@ Broadcom USB Device Controller (BDC) ...@@ -4,7 +4,7 @@ Broadcom USB Device Controller (BDC)
Required properties: Required properties:
- compatible: must be one of: - compatible: must be one of:
"brcm,bdc-v0.16" "brcm,bdc-udc-v2"
"brcm,bdc" "brcm,bdc"
- reg: the base register address and length - reg: the base register address and length
- interrupts: the interrupt line for this controller - interrupts: the interrupt line for this controller
...@@ -21,7 +21,7 @@ On Broadcom STB platforms, these properties are required: ...@@ -21,7 +21,7 @@ On Broadcom STB platforms, these properties are required:
Example: Example:
bdc@f0b02000 { bdc@f0b02000 {
compatible = "brcm,bdc-v0.16"; compatible = "brcm,bdc-udc-v2";
reg = <0xf0b02000 0xfc4>; reg = <0xf0b02000 0xfc4>;
interrupts = <0x0 0x60 0x0>; interrupts = <0x0 0x60 0x0>;
phys = <&usbphy_0 0x0>; phys = <&usbphy_0 0x0>;
......
...@@ -4,10 +4,11 @@ ...@@ -4,10 +4,11 @@
$id: http://devicetree.org/schemas/usb/ingenic,jz4770-phy.yaml# $id: http://devicetree.org/schemas/usb/ingenic,jz4770-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Ingenic JZ4770 USB PHY devicetree bindings title: Ingenic SoCs USB PHY devicetree bindings
maintainers: maintainers:
- Paul Cercueil <paul@crapouillou.net> - Paul Cercueil <paul@crapouillou.net>
- 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
properties: properties:
$nodename: $nodename:
...@@ -16,6 +17,9 @@ properties: ...@@ -16,6 +17,9 @@ properties:
compatible: compatible:
enum: enum:
- ingenic,jz4770-phy - ingenic,jz4770-phy
- ingenic,jz4780-phy
- ingenic,x1000-phy
- ingenic,x1830-phy
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -11,22 +11,36 @@ maintainers: ...@@ -11,22 +11,36 @@ maintainers:
properties: properties:
compatible: compatible:
oneOf: items:
- const: "ti,keystone-dwc3" - enum:
- const: "ti,am654-dwc3" - ti,keystone-dwc3
- ti,am654-dwc3
reg: reg:
maxItems: 1 maxItems: 1
description: Address and length of the register set for the USB subsystem on
the SOC. '#address-cells':
const: 1
'#size-cells':
const: 1
ranges: true
interrupts: interrupts:
maxItems: 1 maxItems: 1
description: The irq number of this device that is used to interrupt the MPU.
clocks: clocks:
description: Clock ID for USB functional clock. minItems: 1
maxItems: 2
assigned-clocks:
minItems: 1
maxItems: 2
assigned-clock-parents:
minItems: 1
maxItems: 2
power-domains: power-domains:
description: Should contain a phandle to a PM domain provider node description: Should contain a phandle to a PM domain provider node
...@@ -42,33 +56,42 @@ properties: ...@@ -42,33 +56,42 @@ properties:
phy-names: phy-names:
items: items:
- const: "usb3-phy" - const: usb3-phy
dma-coherent: true
dwc3: dma-ranges: true
patternProperties:
"usb@[a-f0-9]+$":
type: object
description: This is the node representing the DWC3 controller instance description: This is the node representing the DWC3 controller instance
Documentation/devicetree/bindings/usb/dwc3.txt Documentation/devicetree/bindings/usb/dwc3.txt
required: required:
- compatible - compatible
- reg - reg
- "#address-cells"
- "#size-cells"
- ranges
- interrupts - interrupts
- clocks
additionalProperties: false
examples: examples:
- | - |
#include <dt-bindings/interrupt-controller/arm-gic.h> #include <dt-bindings/interrupt-controller/arm-gic.h>
usb: usb@2680000 { dwc3@2680000 {
compatible = "ti,keystone-dwc3"; compatible = "ti,keystone-dwc3";
#address-cells = <1>; #address-cells = <1>;
#size-cells = <1>; #size-cells = <1>;
reg = <0x2680000 0x10000>; reg = <0x2680000 0x10000>;
clocks = <&clkusb>; clocks = <&clkusb>;
clock-names = "usb";
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>; interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
ranges; ranges;
dwc3@2690000 { usb@2690000 {
compatible = "synopsys,dwc3"; compatible = "synopsys,dwc3";
reg = <0x2690000 0x70000>; reg = <0x2690000 0x70000>;
interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>; interrupts = <GIC_SPI 393 IRQ_TYPE_EDGE_RISING>;
......
...@@ -27,13 +27,6 @@ ...@@ -27,13 +27,6 @@
static int cdns3_idle_init(struct cdns3 *cdns); static int cdns3_idle_init(struct cdns3 *cdns);
static inline
struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns)
{
WARN_ON(!cdns->roles[cdns->role]);
return cdns->roles[cdns->role];
}
static int cdns3_role_start(struct cdns3 *cdns, enum usb_role role) static int cdns3_role_start(struct cdns3 *cdns, enum usb_role role)
{ {
int ret; int ret;
...@@ -93,7 +86,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -93,7 +86,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
struct device *dev = cdns->dev; struct device *dev = cdns->dev;
enum usb_dr_mode best_dr_mode; enum usb_dr_mode best_dr_mode;
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
int ret = 0; int ret;
dr_mode = usb_get_dr_mode(dev); dr_mode = usb_get_dr_mode(dev);
cdns->role = USB_ROLE_NONE; cdns->role = USB_ROLE_NONE;
...@@ -184,7 +177,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -184,7 +177,7 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
goto err; goto err;
} }
return ret; return 0;
err: err:
cdns3_exit_roles(cdns); cdns3_exit_roles(cdns);
return ret; return ret;
...@@ -198,11 +191,17 @@ static int cdns3_core_init_role(struct cdns3 *cdns) ...@@ -198,11 +191,17 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
*/ */
static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns) static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns)
{ {
enum usb_role role; enum usb_role role = USB_ROLE_NONE;
int id, vbus; int id, vbus;
if (cdns->dr_mode != USB_DR_MODE_OTG) if (cdns->dr_mode != USB_DR_MODE_OTG) {
goto not_otg; if (cdns3_is_host(cdns))
role = USB_ROLE_HOST;
if (cdns3_is_device(cdns))
role = USB_ROLE_DEVICE;
return role;
}
id = cdns3_get_id(cdns); id = cdns3_get_id(cdns);
vbus = cdns3_get_vbus(cdns); vbus = cdns3_get_vbus(cdns);
...@@ -239,14 +238,6 @@ static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns) ...@@ -239,14 +238,6 @@ static enum usb_role cdns3_hw_role_state_machine(struct cdns3 *cdns)
dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role); dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role);
return role; return role;
not_otg:
if (cdns3_is_host(cdns))
role = USB_ROLE_HOST;
if (cdns3_is_device(cdns))
role = USB_ROLE_DEVICE;
return role;
} }
static int cdns3_idle_role_start(struct cdns3 *cdns) static int cdns3_idle_role_start(struct cdns3 *cdns)
...@@ -356,7 +347,6 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role) ...@@ -356,7 +347,6 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role)
case USB_ROLE_HOST: case USB_ROLE_HOST:
break; break;
default: default:
ret = -EPERM;
goto pm_put; goto pm_put;
} }
} }
...@@ -367,17 +357,14 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role) ...@@ -367,17 +357,14 @@ static int cdns3_role_set(struct usb_role_switch *sw, enum usb_role role)
case USB_ROLE_DEVICE: case USB_ROLE_DEVICE:
break; break;
default: default:
ret = -EPERM;
goto pm_put; goto pm_put;
} }
} }
cdns3_role_stop(cdns); cdns3_role_stop(cdns);
ret = cdns3_role_start(cdns, role); ret = cdns3_role_start(cdns, role);
if (ret) { if (ret)
dev_err(cdns->dev, "set role %d has failed\n", role); dev_err(cdns->dev, "set role %d has failed\n", role);
ret = -EPERM;
}
pm_put: pm_put:
pm_runtime_put_sync(cdns->dev); pm_runtime_put_sync(cdns->dev);
...@@ -402,7 +389,7 @@ static int cdns3_probe(struct platform_device *pdev) ...@@ -402,7 +389,7 @@ static int cdns3_probe(struct platform_device *pdev)
ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
if (ret) { if (ret) {
dev_err(dev, "error setting dma mask: %d\n", ret); dev_err(dev, "error setting dma mask: %d\n", ret);
return -ENODEV; return ret;
} }
cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL); cdns = devm_kzalloc(dev, sizeof(*cdns), GFP_KERNEL);
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
*/ */
int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
{ {
int ret = 0;
u32 reg; u32 reg;
switch (mode) { switch (mode) {
...@@ -61,7 +60,7 @@ int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode) ...@@ -61,7 +60,7 @@ int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode)
return -EINVAL; return -EINVAL;
} }
return ret; return 0;
} }
int cdns3_get_id(struct cdns3 *cdns) int cdns3_get_id(struct cdns3 *cdns)
...@@ -84,25 +83,25 @@ int cdns3_get_vbus(struct cdns3 *cdns) ...@@ -84,25 +83,25 @@ int cdns3_get_vbus(struct cdns3 *cdns)
return vbus; return vbus;
} }
int cdns3_is_host(struct cdns3 *cdns) bool cdns3_is_host(struct cdns3 *cdns)
{ {
if (cdns->dr_mode == USB_DR_MODE_HOST) if (cdns->dr_mode == USB_DR_MODE_HOST)
return 1; return true;
else if (!cdns3_get_id(cdns)) else if (cdns3_get_id(cdns) == CDNS3_ID_HOST)
return 1; return true;
return 0; return false;
} }
int cdns3_is_device(struct cdns3 *cdns) bool cdns3_is_device(struct cdns3 *cdns)
{ {
if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL) if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL)
return 1; return true;
else if (cdns->dr_mode == USB_DR_MODE_OTG) else if (cdns->dr_mode == USB_DR_MODE_OTG)
if (cdns3_get_id(cdns)) if (cdns3_get_id(cdns) == CDNS3_ID_PERIPHERAL)
return 1; return true;
return 0; return false;
} }
/** /**
...@@ -125,85 +124,97 @@ static void cdns3_otg_enable_irq(struct cdns3 *cdns) ...@@ -125,85 +124,97 @@ static void cdns3_otg_enable_irq(struct cdns3 *cdns)
} }
/** /**
* cdns3_drd_switch_host - start/stop host * cdns3_drd_host_on - start host.
* @cdns: Pointer to controller context structure * @cdns: Pointer to controller context structure.
* @on: 1 for start, 0 for stop
* *
* Returns 0 on success otherwise negative errno * Returns 0 on success otherwise negative errno.
*/ */
int cdns3_drd_switch_host(struct cdns3 *cdns, int on) int cdns3_drd_host_on(struct cdns3 *cdns)
{ {
int ret, val; u32 val;
u32 reg = OTGCMD_OTG_DIS; int ret;
/* switch OTG core */ /* Enable host mode. */
if (on) { writel(OTGCMD_HOST_BUS_REQ | OTGCMD_OTG_DIS,
writel(OTGCMD_HOST_BUS_REQ | reg, &cdns->otg_regs->cmd); &cdns->otg_regs->cmd);
dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
val & OTGSTS_XHCI_READY,
1, 100000);
if (ret) {
dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
return ret;
}
} else {
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till H_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_HOST_STATE_MASK),
1, 2000000);
}
return 0; dev_dbg(cdns->dev, "Waiting till Host mode is turned on\n");
ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
val & OTGSTS_XHCI_READY, 1, 100000);
if (ret)
dev_err(cdns->dev, "timeout waiting for xhci_ready\n");
return ret;
} }
/** /**
* cdns3_drd_switch_gadget - start/stop gadget * cdns3_drd_host_off - stop host.
* @cdns: Pointer to controller context structure * @cdns: Pointer to controller context structure.
* @on: 1 for start, 0 for stop */
void cdns3_drd_host_off(struct cdns3 *cdns)
{
u32 val;
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till H_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_HOST_STATE_MASK),
1, 2000000);
}
/**
* cdns3_drd_gadget_on - start gadget.
* @cdns: Pointer to controller context structure.
* *
* Returns 0 on success otherwise negative errno * Returns 0 on success otherwise negative errno
*/ */
int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) int cdns3_drd_gadget_on(struct cdns3 *cdns)
{ {
int ret, val; int ret, val;
u32 reg = OTGCMD_OTG_DIS; u32 reg = OTGCMD_OTG_DIS;
/* switch OTG core */ /* switch OTG core */
if (on) { writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
writel(OTGCMD_DEV_BUS_REQ | reg, &cdns->otg_regs->cmd);
dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n"); dev_dbg(cdns->dev, "Waiting till Device mode is turned on\n");
ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val, ret = readl_poll_timeout_atomic(&cdns->otg_regs->sts, val,
val & OTGSTS_DEV_READY, val & OTGSTS_DEV_READY,
1, 100000); 1, 100000);
if (ret) { if (ret) {
dev_err(cdns->dev, "timeout waiting for dev_ready\n"); dev_err(cdns->dev, "timeout waiting for dev_ready\n");
return ret; return ret;
}
} else {
/*
* driver should wait at least 10us after disabling Device
* before turning-off Device (DEV_BUS_DROP)
*/
usleep_range(20, 30);
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till DEV_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_DEV_STATE_MASK),
1, 2000000);
} }
return 0; return 0;
} }
/**
* cdns3_drd_gadget_off - stop gadget.
* @cdns: Pointer to controller context structure.
*/
void cdns3_drd_gadget_off(struct cdns3 *cdns)
{
u32 val;
/*
* Driver should wait at least 10us after disabling Device
* before turning-off Device (DEV_BUS_DROP).
*/
usleep_range(20, 30);
writel(OTGCMD_HOST_BUS_DROP | OTGCMD_DEV_BUS_DROP |
OTGCMD_DEV_POWER_OFF | OTGCMD_HOST_POWER_OFF,
&cdns->otg_regs->cmd);
/* Waiting till DEV_IDLE state.*/
readl_poll_timeout_atomic(&cdns->otg_regs->state, val,
!(val & OTGSTATE_DEV_STATE_MASK),
1, 2000000);
}
/** /**
* cdns3_init_otg_mode - initialize drd controller * cdns3_init_otg_mode - initialize drd controller
* @cdns: Pointer to controller context structure * @cdns: Pointer to controller context structure
...@@ -212,7 +223,7 @@ int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on) ...@@ -212,7 +223,7 @@ int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on)
*/ */
static int cdns3_init_otg_mode(struct cdns3 *cdns) static int cdns3_init_otg_mode(struct cdns3 *cdns)
{ {
int ret = 0; int ret;
cdns3_otg_disable_irq(cdns); cdns3_otg_disable_irq(cdns);
/* clear all interrupts */ /* clear all interrupts */
...@@ -223,7 +234,8 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns) ...@@ -223,7 +234,8 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns)
return ret; return ret;
cdns3_otg_enable_irq(cdns); cdns3_otg_enable_irq(cdns);
return ret;
return 0;
} }
/** /**
...@@ -234,7 +246,7 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns) ...@@ -234,7 +246,7 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns)
*/ */
int cdns3_drd_update_mode(struct cdns3 *cdns) int cdns3_drd_update_mode(struct cdns3 *cdns)
{ {
int ret = 0; int ret;
switch (cdns->dr_mode) { switch (cdns->dr_mode) {
case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_PERIPHERAL:
...@@ -279,12 +291,12 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data) ...@@ -279,12 +291,12 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data)
u32 reg; u32 reg;
if (cdns->dr_mode != USB_DR_MODE_OTG) if (cdns->dr_mode != USB_DR_MODE_OTG)
return ret; return IRQ_NONE;
reg = readl(&cdns->otg_regs->ivect); reg = readl(&cdns->otg_regs->ivect);
if (!reg) if (!reg)
return ret; return IRQ_NONE;
if (reg & OTGIEN_ID_CHANGE_INT) { if (reg & OTGIEN_ID_CHANGE_INT) {
dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n", dev_dbg(cdns->dev, "OTG IRQ: new ID: %d\n",
...@@ -307,8 +319,8 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data) ...@@ -307,8 +319,8 @@ static irqreturn_t cdns3_drd_irq(int irq, void *data)
int cdns3_drd_init(struct cdns3 *cdns) int cdns3_drd_init(struct cdns3 *cdns)
{ {
void __iomem *regs; void __iomem *regs;
int ret = 0;
u32 state; u32 state;
int ret;
regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res); regs = devm_ioremap_resource(cdns->dev, &cdns->otg_res);
if (IS_ERR(regs)) if (IS_ERR(regs))
...@@ -359,19 +371,18 @@ int cdns3_drd_init(struct cdns3 *cdns) ...@@ -359,19 +371,18 @@ int cdns3_drd_init(struct cdns3 *cdns)
cdns3_drd_thread_irq, cdns3_drd_thread_irq,
IRQF_SHARED, IRQF_SHARED,
dev_name(cdns->dev), cdns); dev_name(cdns->dev), cdns);
if (ret) { if (ret) {
dev_err(cdns->dev, "couldn't get otg_irq\n"); dev_err(cdns->dev, "couldn't get otg_irq\n");
return ret; return ret;
} }
state = readl(&cdns->otg_regs->sts); state = readl(&cdns->otg_regs->sts);
if (OTGSTS_OTG_NRDY(state) != 0) { if (OTGSTS_OTG_NRDY(state)) {
dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n"); dev_err(cdns->dev, "Cadence USB3 OTG device not ready\n");
return -ENODEV; return -ENODEV;
} }
return ret; return 0;
} }
int cdns3_drd_exit(struct cdns3 *cdns) int cdns3_drd_exit(struct cdns3 *cdns)
......
...@@ -153,15 +153,20 @@ struct cdns3_otg_common_regs { ...@@ -153,15 +153,20 @@ struct cdns3_otg_common_regs {
/* Only for CDNS3_CONTROLLER_V0 version */ /* Only for CDNS3_CONTROLLER_V0 version */
#define OVERRIDE_IDPULLUP_V0 BIT(24) #define OVERRIDE_IDPULLUP_V0 BIT(24)
int cdns3_is_host(struct cdns3 *cdns); #define CDNS3_ID_PERIPHERAL 1
int cdns3_is_device(struct cdns3 *cdns); #define CDNS3_ID_HOST 0
bool cdns3_is_host(struct cdns3 *cdns);
bool cdns3_is_device(struct cdns3 *cdns);
int cdns3_get_id(struct cdns3 *cdns); int cdns3_get_id(struct cdns3 *cdns);
int cdns3_get_vbus(struct cdns3 *cdns); int cdns3_get_vbus(struct cdns3 *cdns);
int cdns3_drd_init(struct cdns3 *cdns); int cdns3_drd_init(struct cdns3 *cdns);
int cdns3_drd_exit(struct cdns3 *cdns); int cdns3_drd_exit(struct cdns3 *cdns);
int cdns3_drd_update_mode(struct cdns3 *cdns); int cdns3_drd_update_mode(struct cdns3 *cdns);
int cdns3_drd_switch_gadget(struct cdns3 *cdns, int on); int cdns3_drd_gadget_on(struct cdns3 *cdns);
int cdns3_drd_switch_host(struct cdns3 *cdns, int on); void cdns3_drd_gadget_off(struct cdns3 *cdns);
int cdns3_drd_host_on(struct cdns3 *cdns);
void cdns3_drd_host_off(struct cdns3 *cdns);
int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode); int cdns3_set_mode(struct cdns3 *cdns, enum usb_dr_mode mode);
#endif /* __LINUX_CDNS3_DRD */ #endif /* __LINUX_CDNS3_DRD */
...@@ -123,8 +123,6 @@ static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev, ...@@ -123,8 +123,6 @@ static void cdns3_ep0_complete_setup(struct cdns3_device *priv_dev,
priv_dev->ep0_stage = CDNS3_SETUP_STAGE; priv_dev->ep0_stage = CDNS3_SETUP_STAGE;
writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL, writel((send_erdy ? EP_CMD_ERDY : 0) | EP_CMD_REQ_CMPL,
&priv_dev->regs->ep_cmd); &priv_dev->regs->ep_cmd);
cdns3_allow_enable_l1(priv_dev, 1);
} }
/** /**
...@@ -161,13 +159,12 @@ static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev, ...@@ -161,13 +159,12 @@ static int cdns3_req_ep0_set_configuration(struct cdns3_device *priv_dev,
if (result) if (result)
return result; return result;
if (config) { if (!config) {
cdns3_set_hw_configuration(priv_dev);
} else {
cdns3_hw_reset_eps_config(priv_dev); cdns3_hw_reset_eps_config(priv_dev);
usb_gadget_set_state(&priv_dev->gadget, usb_gadget_set_state(&priv_dev->gadget,
USB_STATE_ADDRESS); USB_STATE_ADDRESS);
} }
break; break;
case USB_STATE_CONFIGURED: case USB_STATE_CONFIGURED:
result = cdns3_ep0_delegate_req(priv_dev, ctrl_req); result = cdns3_ep0_delegate_req(priv_dev, ctrl_req);
...@@ -640,7 +637,6 @@ void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir) ...@@ -640,7 +637,6 @@ void cdns3_check_ep0_interrupt_proceed(struct cdns3_device *priv_dev, int dir)
if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) { if (priv_dev->wait_for_setup && ep_sts_reg & EP_STS_IOC) {
priv_dev->wait_for_setup = 0; priv_dev->wait_for_setup = 0;
cdns3_allow_enable_l1(priv_dev, 0);
cdns3_ep0_setup_phase(priv_dev); cdns3_ep0_setup_phase(priv_dev);
} else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) { } else if ((ep_sts_reg & EP_STS_IOC) || (ep_sts_reg & EP_STS_ISP)) {
priv_dev->ep0_data_dir = dir; priv_dev->ep0_data_dir = dir;
...@@ -707,7 +703,6 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, ...@@ -707,7 +703,6 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep); struct cdns3_endpoint *priv_ep = ep_to_cdns3_ep(ep);
struct cdns3_device *priv_dev = priv_ep->cdns3_dev; struct cdns3_device *priv_dev = priv_ep->cdns3_dev;
unsigned long flags; unsigned long flags;
int erdy_sent = 0;
int ret = 0; int ret = 0;
u8 zlp = 0; u8 zlp = 0;
...@@ -723,15 +718,8 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep, ...@@ -723,15 +718,8 @@ static int cdns3_gadget_ep0_queue(struct usb_ep *ep,
/* send STATUS stage. Should be called only for SET_CONFIGURATION */ /* send STATUS stage. Should be called only for SET_CONFIGURATION */
if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) { if (priv_dev->ep0_stage == CDNS3_STATUS_STAGE) {
cdns3_select_ep(priv_dev, 0x00); cdns3_select_ep(priv_dev, 0x00);
erdy_sent = !priv_dev->hw_configured_flag;
cdns3_set_hw_configuration(priv_dev); cdns3_set_hw_configuration(priv_dev);
cdns3_ep0_complete_setup(priv_dev, 0, 1);
if (!erdy_sent)
cdns3_ep0_complete_setup(priv_dev, 0, 1);
cdns3_allow_enable_l1(priv_dev, 1);
request->actual = 0; request->actual = 0;
priv_dev->status_completion_no_call = true; priv_dev->status_completion_no_call = true;
priv_dev->pending_status_request = request; priv_dev->pending_status_request = request;
......
...@@ -242,9 +242,10 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep) ...@@ -242,9 +242,10 @@ int cdns3_allocate_trb_pool(struct cdns3_endpoint *priv_ep)
return -ENOMEM; return -ENOMEM;
priv_ep->alloc_ring_size = ring_size; priv_ep->alloc_ring_size = ring_size;
memset(priv_ep->trb_pool, 0, ring_size);
} }
memset(priv_ep->trb_pool, 0, ring_size);
priv_ep->num_trbs = num_trbs; priv_ep->num_trbs = num_trbs;
if (!priv_ep->num) if (!priv_ep->num)
...@@ -1315,7 +1316,6 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) ...@@ -1315,7 +1316,6 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
return; return;
writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf); writel(USB_CONF_CFGSET, &priv_dev->regs->usb_conf);
writel(EP_CMD_ERDY | EP_CMD_REQ_CMPL, &priv_dev->regs->ep_cmd);
cdns3_set_register_bit(&priv_dev->regs->usb_conf, cdns3_set_register_bit(&priv_dev->regs->usb_conf,
USB_CONF_U1EN | USB_CONF_U2EN); USB_CONF_U1EN | USB_CONF_U2EN);
...@@ -1332,6 +1332,8 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev) ...@@ -1332,6 +1332,8 @@ void cdns3_set_hw_configuration(struct cdns3_device *priv_dev)
cdns3_start_all_request(priv_dev, priv_ep); cdns3_start_all_request(priv_dev, priv_ep);
} }
} }
cdns3_allow_enable_l1(priv_dev, 1);
} }
/** /**
...@@ -3015,7 +3017,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns) ...@@ -3015,7 +3017,7 @@ void cdns3_gadget_exit(struct cdns3 *cdns)
kfree(priv_dev->zlp_buf); kfree(priv_dev->zlp_buf);
kfree(priv_dev); kfree(priv_dev);
cdns->gadget_dev = NULL; cdns->gadget_dev = NULL;
cdns3_drd_switch_gadget(cdns, 0); cdns3_drd_gadget_off(cdns);
} }
static int cdns3_gadget_start(struct cdns3 *cdns) static int cdns3_gadget_start(struct cdns3 *cdns)
...@@ -3146,7 +3148,7 @@ static int __cdns3_gadget_init(struct cdns3 *cdns) ...@@ -3146,7 +3148,7 @@ static int __cdns3_gadget_init(struct cdns3 *cdns)
return ret; return ret;
} }
cdns3_drd_switch_gadget(cdns, 1); cdns3_drd_gadget_on(cdns);
pm_runtime_get_sync(cdns->dev); pm_runtime_get_sync(cdns->dev);
ret = cdns3_gadget_start(cdns); ret = cdns3_gadget_start(cdns);
......
...@@ -19,7 +19,7 @@ static int __cdns3_host_init(struct cdns3 *cdns) ...@@ -19,7 +19,7 @@ static int __cdns3_host_init(struct cdns3 *cdns)
struct platform_device *xhci; struct platform_device *xhci;
int ret; int ret;
cdns3_drd_switch_host(cdns, 1); cdns3_drd_host_on(cdns);
xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO); xhci = platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
if (!xhci) { if (!xhci) {
...@@ -53,7 +53,7 @@ static void cdns3_host_exit(struct cdns3 *cdns) ...@@ -53,7 +53,7 @@ static void cdns3_host_exit(struct cdns3 *cdns)
{ {
platform_device_unregister(cdns->host_dev); platform_device_unregister(cdns->host_dev);
cdns->host_dev = NULL; cdns->host_dev = NULL;
cdns3_drd_switch_host(cdns, 0); cdns3_drd_host_off(cdns);
} }
int cdns3_host_init(struct cdns3 *cdns) int cdns3_host_init(struct cdns3 *cdns)
......
...@@ -47,6 +47,7 @@ config USB_DWC2_PERIPHERAL ...@@ -47,6 +47,7 @@ config USB_DWC2_PERIPHERAL
config USB_DWC2_DUAL_ROLE config USB_DWC2_DUAL_ROLE
bool "Dual Role mode" bool "Dual Role mode"
depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET) depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
select USB_ROLE_SWITCH
help help
Select this option if you want the driver to work in a dual-role Select this option if you want the driver to work in a dual-role
mode. In this mode both host and gadget features are enabled, and mode. In this mode both host and gadget features are enabled, and
......
...@@ -3,7 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG ...@@ -3,7 +3,7 @@ ccflags-$(CONFIG_USB_DWC2_DEBUG) += -DDEBUG
ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG ccflags-$(CONFIG_USB_DWC2_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC2) += dwc2.o obj-$(CONFIG_USB_DWC2) += dwc2.o
dwc2-y := core.o core_intr.o platform.o dwc2-y := core.o core_intr.o platform.o drd.o
dwc2-y += params.o dwc2-y += params.o
ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),) ifneq ($(filter y,$(CONFIG_USB_DWC2_HOST) $(CONFIG_USB_DWC2_DUAL_ROLE)),)
......
...@@ -860,6 +860,7 @@ struct dwc2_hregs_backup { ...@@ -860,6 +860,7 @@ struct dwc2_hregs_backup {
* - USB_DR_MODE_PERIPHERAL * - USB_DR_MODE_PERIPHERAL
* - USB_DR_MODE_HOST * - USB_DR_MODE_HOST
* - USB_DR_MODE_OTG * - USB_DR_MODE_OTG
* @role_sw: usb_role_switch handle
* @hcd_enabled: Host mode sub-driver initialization indicator. * @hcd_enabled: Host mode sub-driver initialization indicator.
* @gadget_enabled: Peripheral mode sub-driver initialization indicator. * @gadget_enabled: Peripheral mode sub-driver initialization indicator.
* @ll_hw_enabled: Status of low-level hardware resources. * @ll_hw_enabled: Status of low-level hardware resources.
...@@ -1054,6 +1055,7 @@ struct dwc2_hsotg { ...@@ -1054,6 +1055,7 @@ struct dwc2_hsotg {
struct dwc2_core_params params; struct dwc2_core_params params;
enum usb_otg_state op_state; enum usb_otg_state op_state;
enum usb_dr_mode dr_mode; enum usb_dr_mode dr_mode;
struct usb_role_switch *role_sw;
unsigned int hcd_enabled:1; unsigned int hcd_enabled:1;
unsigned int gadget_enabled:1; unsigned int gadget_enabled:1;
unsigned int ll_hw_enabled:1; unsigned int ll_hw_enabled:1;
...@@ -1376,6 +1378,11 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) ...@@ -1376,6 +1378,11 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0; return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
} }
int dwc2_drd_init(struct dwc2_hsotg *hsotg);
void dwc2_drd_suspend(struct dwc2_hsotg *hsotg);
void dwc2_drd_resume(struct dwc2_hsotg *hsotg);
void dwc2_drd_exit(struct dwc2_hsotg *hsotg);
/* /*
* Dump core registers and SPRAM * Dump core registers and SPRAM
*/ */
...@@ -1392,6 +1399,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); ...@@ -1392,6 +1399,7 @@ int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2);
int dwc2_gadget_init(struct dwc2_hsotg *hsotg); int dwc2_gadget_init(struct dwc2_hsotg *hsotg);
void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
bool reset); bool reset);
void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg);
void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg);
void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2);
int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode);
......
// SPDX-License-Identifier: GPL-2.0
/*
* drd.c - DesignWare USB2 DRD Controller Dual-role support
*
* Copyright (C) 2020 STMicroelectronics
*
* Author(s): Amelie Delaunay <amelie.delaunay@st.com>
*/
#include <linux/iopoll.h>
#include <linux/platform_device.h>
#include <linux/usb/role.h>
#include "core.h"
static void dwc2_ovr_init(struct dwc2_hsotg *hsotg)
{
unsigned long flags;
u32 gotgctl;
spin_lock_irqsave(&hsotg->lock, flags);
gotgctl = dwc2_readl(hsotg, GOTGCTL);
gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN;
gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS;
gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
dwc2_writel(hsotg, gotgctl, GOTGCTL);
dwc2_force_mode(hsotg, false);
spin_unlock_irqrestore(&hsotg->lock, flags);
}
static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid)
{
u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
/* Check if A-Session is already in the right state */
if ((valid && (gotgctl & GOTGCTL_ASESVLD)) ||
(!valid && !(gotgctl & GOTGCTL_ASESVLD)))
return -EALREADY;
if (valid)
gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL;
else
gotgctl &= ~(GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL);
dwc2_writel(hsotg, gotgctl, GOTGCTL);
return 0;
}
static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid)
{
u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
/* Check if B-Session is already in the right state */
if ((valid && (gotgctl & GOTGCTL_BSESVLD)) ||
(!valid && !(gotgctl & GOTGCTL_BSESVLD)))
return -EALREADY;
if (valid)
gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL;
else
gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL);
dwc2_writel(hsotg, gotgctl, GOTGCTL);
return 0;
}
static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role)
{
struct dwc2_hsotg *hsotg = usb_role_switch_get_drvdata(sw);
unsigned long flags;
/* Skip session not in line with dr_mode */
if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) ||
(role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL))
return -EINVAL;
/* Skip session if core is in test mode */
if (role == USB_ROLE_NONE && hsotg->test_mode) {
dev_dbg(hsotg->dev, "Core is in test mode\n");
return -EBUSY;
}
spin_lock_irqsave(&hsotg->lock, flags);
if (role == USB_ROLE_HOST) {
if (dwc2_ovr_avalid(hsotg, true))
goto unlock;
if (hsotg->dr_mode == USB_DR_MODE_OTG)
/*
* This will raise a Connector ID Status Change
* Interrupt - connID A
*/
dwc2_force_mode(hsotg, true);
} else if (role == USB_ROLE_DEVICE) {
if (dwc2_ovr_bvalid(hsotg, true))
goto unlock;
if (hsotg->dr_mode == USB_DR_MODE_OTG)
/*
* This will raise a Connector ID Status Change
* Interrupt - connID B
*/
dwc2_force_mode(hsotg, false);
/* This clear DCTL.SFTDISCON bit */
dwc2_hsotg_core_connect(hsotg);
} else {
if (dwc2_is_device_mode(hsotg)) {
if (!dwc2_ovr_bvalid(hsotg, false))
/* This set DCTL.SFTDISCON bit */
dwc2_hsotg_core_disconnect(hsotg);
} else {
dwc2_ovr_avalid(hsotg, false);
}
}
unlock:
spin_unlock_irqrestore(&hsotg->lock, flags);
dev_dbg(hsotg->dev, "%s-session valid\n",
role == USB_ROLE_NONE ? "No" :
role == USB_ROLE_HOST ? "A" : "B");
return 0;
}
int dwc2_drd_init(struct dwc2_hsotg *hsotg)
{
struct usb_role_switch_desc role_sw_desc = {0};
struct usb_role_switch *role_sw;
int ret;
if (!device_property_read_bool(hsotg->dev, "usb-role-switch"))
return 0;
role_sw_desc.driver_data = hsotg;
role_sw_desc.fwnode = dev_fwnode(hsotg->dev);
role_sw_desc.set = dwc2_drd_role_sw_set;
role_sw_desc.allow_userspace_control = true;
role_sw = usb_role_switch_register(hsotg->dev, &role_sw_desc);
if (IS_ERR(role_sw)) {
ret = PTR_ERR(role_sw);
dev_err(hsotg->dev,
"failed to register role switch: %d\n", ret);
return ret;
}
hsotg->role_sw = role_sw;
/* Enable override and initialize values */
dwc2_ovr_init(hsotg);
return 0;
}
void dwc2_drd_suspend(struct dwc2_hsotg *hsotg)
{
u32 gintsts, gintmsk;
if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) {
gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk &= ~GINTSTS_CONIDSTSCHNG;
dwc2_writel(hsotg, gintmsk, GINTMSK);
gintsts = dwc2_readl(hsotg, GINTSTS);
dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS);
}
}
void dwc2_drd_resume(struct dwc2_hsotg *hsotg)
{
u32 gintsts, gintmsk;
if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) {
gintsts = dwc2_readl(hsotg, GINTSTS);
dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS);
gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk |= GINTSTS_CONIDSTSCHNG;
dwc2_writel(hsotg, gintmsk, GINTMSK);
}
}
void dwc2_drd_exit(struct dwc2_hsotg *hsotg)
{
if (hsotg->role_sw)
usb_role_switch_unregister(hsotg->role_sw);
}
...@@ -3530,7 +3530,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, ...@@ -3530,7 +3530,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
dwc2_readl(hsotg, DOEPCTL0)); dwc2_readl(hsotg, DOEPCTL0));
} }
static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
{ {
/* set the soft-disconnect bit */ /* set the soft-disconnect bit */
dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON); dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
......
...@@ -183,9 +183,11 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) ...@@ -183,9 +183,11 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg)
static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg)
{ {
struct dwc2_core_params *p = &hsotg->params; struct dwc2_core_params *p = &hsotg->params;
struct device_node *np = hsotg->dev->of_node;
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
p->activate_stm_id_vb_detection = true; p->activate_stm_id_vb_detection =
!of_property_read_bool(np, "usb-role-switch");
p->host_rx_fifo_size = 440; p->host_rx_fifo_size = 440;
p->host_nperio_tx_fifo_size = 256; p->host_nperio_tx_fifo_size = 256;
p->host_perio_tx_fifo_size = 256; p->host_perio_tx_fifo_size = 256;
......
...@@ -317,6 +317,8 @@ static int dwc2_driver_remove(struct platform_device *dev) ...@@ -317,6 +317,8 @@ static int dwc2_driver_remove(struct platform_device *dev)
if (hsotg->params.activate_stm_id_vb_detection) if (hsotg->params.activate_stm_id_vb_detection)
regulator_disable(hsotg->usb33d); regulator_disable(hsotg->usb33d);
dwc2_drd_exit(hsotg);
if (hsotg->ll_hw_enabled) if (hsotg->ll_hw_enabled)
dwc2_lowlevel_hw_disable(hsotg); dwc2_lowlevel_hw_disable(hsotg);
...@@ -533,6 +535,13 @@ static int dwc2_driver_probe(struct platform_device *dev) ...@@ -533,6 +535,13 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_writel(hsotg, ggpio, GGPIO); dwc2_writel(hsotg, ggpio, GGPIO);
} }
retval = dwc2_drd_init(hsotg);
if (retval) {
if (retval != -EPROBE_DEFER)
dev_err(hsotg->dev, "failed to initialize dual-role\n");
goto error_init;
}
if (hsotg->dr_mode != USB_DR_MODE_HOST) { if (hsotg->dr_mode != USB_DR_MODE_HOST) {
retval = dwc2_gadget_init(hsotg); retval = dwc2_gadget_init(hsotg);
if (retval) if (retval)
...@@ -582,6 +591,7 @@ static int dwc2_driver_probe(struct platform_device *dev) ...@@ -582,6 +591,7 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (hsotg->gadget_enabled) { if (hsotg->gadget_enabled) {
retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget); retval = usb_add_gadget_udc(hsotg->dev, &hsotg->gadget);
if (retval) { if (retval) {
hsotg->gadget.udc = NULL;
dwc2_hsotg_remove(hsotg); dwc2_hsotg_remove(hsotg);
goto error_init; goto error_init;
} }
...@@ -593,7 +603,8 @@ static int dwc2_driver_probe(struct platform_device *dev) ...@@ -593,7 +603,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (hsotg->params.activate_stm_id_vb_detection) if (hsotg->params.activate_stm_id_vb_detection)
regulator_disable(hsotg->usb33d); regulator_disable(hsotg->usb33d);
error: error:
dwc2_lowlevel_hw_disable(hsotg); if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL)
dwc2_lowlevel_hw_disable(hsotg);
return retval; return retval;
} }
...@@ -606,6 +617,8 @@ static int __maybe_unused dwc2_suspend(struct device *dev) ...@@ -606,6 +617,8 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
if (is_device_mode) if (is_device_mode)
dwc2_hsotg_suspend(dwc2); dwc2_hsotg_suspend(dwc2);
dwc2_drd_suspend(dwc2);
if (dwc2->params.activate_stm_id_vb_detection) { if (dwc2->params.activate_stm_id_vb_detection) {
unsigned long flags; unsigned long flags;
u32 ggpio, gotgctl; u32 ggpio, gotgctl;
...@@ -686,6 +699,8 @@ static int __maybe_unused dwc2_resume(struct device *dev) ...@@ -686,6 +699,8 @@ static int __maybe_unused dwc2_resume(struct device *dev)
/* Need to restore FORCEDEVMODE/FORCEHOSTMODE */ /* Need to restore FORCEDEVMODE/FORCEHOSTMODE */
dwc2_force_dr_mode(dwc2); dwc2_force_dr_mode(dwc2);
dwc2_drd_resume(dwc2);
if (dwc2_is_device_mode(dwc2)) if (dwc2_is_device_mode(dwc2))
ret = dwc2_hsotg_resume(dwc2); ret = dwc2_hsotg_resume(dwc2);
......
...@@ -737,13 +737,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ...@@ -737,13 +737,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
goto err_disable_clks; goto err_disable_clks;
} }
ret = reset_control_reset(priv->reset); ret = reset_control_deassert(priv->reset);
if (ret) if (ret)
goto err_disable_clks; goto err_assert_reset;
ret = dwc3_meson_g12a_get_phys(priv); ret = dwc3_meson_g12a_get_phys(priv);
if (ret) if (ret)
goto err_disable_clks; goto err_assert_reset;
ret = priv->drvdata->setup_regmaps(priv, base); ret = priv->drvdata->setup_regmaps(priv, base);
if (ret) if (ret)
...@@ -752,7 +752,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ...@@ -752,7 +752,7 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
if (priv->vbus) { if (priv->vbus) {
ret = regulator_enable(priv->vbus); ret = regulator_enable(priv->vbus);
if (ret) if (ret)
goto err_disable_clks; goto err_assert_reset;
} }
/* Get dr_mode */ /* Get dr_mode */
...@@ -765,13 +765,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ...@@ -765,13 +765,13 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
ret = priv->drvdata->usb_init(priv); ret = priv->drvdata->usb_init(priv);
if (ret) if (ret)
goto err_disable_clks; goto err_assert_reset;
/* Init PHYs */ /* Init PHYs */
for (i = 0 ; i < PHY_COUNT ; ++i) { for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_init(priv->phys[i]); ret = phy_init(priv->phys[i]);
if (ret) if (ret)
goto err_disable_clks; goto err_assert_reset;
} }
/* Set PHY Power */ /* Set PHY Power */
...@@ -809,6 +809,9 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev) ...@@ -809,6 +809,9 @@ static int dwc3_meson_g12a_probe(struct platform_device *pdev)
for (i = 0 ; i < PHY_COUNT ; ++i) for (i = 0 ; i < PHY_COUNT ; ++i)
phy_exit(priv->phys[i]); phy_exit(priv->phys[i]);
err_assert_reset:
reset_control_assert(priv->reset);
err_disable_clks: err_disable_clks:
clk_bulk_disable_unprepare(priv->drvdata->num_clks, clk_bulk_disable_unprepare(priv->drvdata->num_clks,
priv->drvdata->clks); priv->drvdata->clks);
......
...@@ -1403,7 +1403,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) ...@@ -1403,7 +1403,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
* Check if we can start isoc transfer on the next interval or * Check if we can start isoc transfer on the next interval or
* 4 uframes in the future with BIT[15:14] as dep->combo_num * 4 uframes in the future with BIT[15:14] as dep->combo_num
*/ */
test_frame_number = dep->frame_number & 0x3fff; test_frame_number = dep->frame_number & DWC3_FRNUMBER_MASK;
test_frame_number |= dep->combo_num << 14; test_frame_number |= dep->combo_num << 14;
test_frame_number += max_t(u32, 4, dep->interval); test_frame_number += max_t(u32, 4, dep->interval);
...@@ -1450,7 +1450,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) ...@@ -1450,7 +1450,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
else if (test0 && test1) else if (test0 && test1)
dep->combo_num = 0; dep->combo_num = 0;
dep->frame_number &= 0x3fff; dep->frame_number &= DWC3_FRNUMBER_MASK;
dep->frame_number |= dep->combo_num << 14; dep->frame_number |= dep->combo_num << 14;
dep->frame_number += max_t(u32, 4, dep->interval); dep->frame_number += max_t(u32, 4, dep->interval);
...@@ -1463,6 +1463,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep) ...@@ -1463,6 +1463,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
{ {
const struct usb_endpoint_descriptor *desc = dep->endpoint.desc;
struct dwc3 *dwc = dep->dwc; struct dwc3 *dwc = dep->dwc;
int ret; int ret;
int i; int i;
...@@ -1480,6 +1481,27 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep) ...@@ -1480,6 +1481,27 @@ static int __dwc3_gadget_start_isoc(struct dwc3_ep *dep)
return dwc3_gadget_start_isoc_quirk(dep); return dwc3_gadget_start_isoc_quirk(dep);
} }
if (desc->bInterval <= 14 &&
dwc->gadget.speed >= USB_SPEED_HIGH) {
u32 frame = __dwc3_gadget_get_frame(dwc);
bool rollover = frame <
(dep->frame_number & DWC3_FRNUMBER_MASK);
/*
* frame_number is set from XferNotReady and may be already
* out of date. DSTS only provides the lower 14 bit of the
* current frame number. So add the upper two bits of
* frame_number and handle a possible rollover.
* This will provide the correct frame_number unless more than
* rollover has happened since XferNotReady.
*/
dep->frame_number = (dep->frame_number & ~DWC3_FRNUMBER_MASK) |
frame;
if (rollover)
dep->frame_number += BIT(14);
}
for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) { for (i = 0; i < DWC3_ISOC_MAX_RETRIES; i++) {
dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1); dep->frame_number = DWC3_ALIGN_FRAME(dep, i + 1);
...@@ -2716,7 +2738,9 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep, ...@@ -2716,7 +2738,9 @@ static bool dwc3_gadget_endpoint_trbs_complete(struct dwc3_ep *dep,
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) if (dep->flags & DWC3_EP_END_TRANSFER_PENDING)
goto out; goto out;
if (status == -EXDEV && list_empty(&dep->started_list)) if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
list_empty(&dep->started_list) &&
(list_empty(&dep->pending_list) || status == -EXDEV))
dwc3_stop_active_transfer(dep, true, true); dwc3_stop_active_transfer(dep, true, true);
else if (dwc3_gadget_ep_should_continue(dep)) else if (dwc3_gadget_ep_should_continue(dep))
if (__dwc3_gadget_kick_transfer(dep) == 0) if (__dwc3_gadget_kick_transfer(dep) == 0)
......
...@@ -54,6 +54,8 @@ struct dwc3; ...@@ -54,6 +54,8 @@ struct dwc3;
/* U2 Device exit Latency */ /* U2 Device exit Latency */
#define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */ #define DWC3_DEFAULT_U2_DEV_EXIT_LAT 0x1FF /* Less then 511 microsec */
/* Frame/Microframe Number Mask */
#define DWC3_FRNUMBER_MASK 0x3fff
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
#define to_dwc3_request(r) (container_of(r, struct dwc3_request, request)) #define to_dwc3_request(r) (container_of(r, struct dwc3_request, request))
......
...@@ -338,6 +338,11 @@ printer_open(struct inode *inode, struct file *fd) ...@@ -338,6 +338,11 @@ printer_open(struct inode *inode, struct file *fd)
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
return -ENODEV;
}
if (!dev->printer_cdev_open) { if (!dev->printer_cdev_open) {
dev->printer_cdev_open = 1; dev->printer_cdev_open = 1;
fd->private_data = dev; fd->private_data = dev;
...@@ -430,6 +435,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr) ...@@ -430,6 +435,12 @@ printer_read(struct file *fd, char __user *buf, size_t len, loff_t *ptr)
mutex_lock(&dev->lock_printer_io); mutex_lock(&dev->lock_printer_io);
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return -ENODEV;
}
/* We will use this flag later to check if a printer reset happened /* We will use this flag later to check if a printer reset happened
* after we turn interrupts back on. * after we turn interrupts back on.
*/ */
...@@ -561,6 +572,12 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr) ...@@ -561,6 +572,12 @@ printer_write(struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
mutex_lock(&dev->lock_printer_io); mutex_lock(&dev->lock_printer_io);
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return -ENODEV;
}
/* Check if a printer reset happens while we have interrupts on */ /* Check if a printer reset happens while we have interrupts on */
dev->reset_printer = 0; dev->reset_printer = 0;
...@@ -667,6 +684,13 @@ printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync) ...@@ -667,6 +684,13 @@ printer_fsync(struct file *fd, loff_t start, loff_t end, int datasync)
inode_lock(inode); inode_lock(inode);
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
inode_unlock(inode);
return -ENODEV;
}
tx_list_empty = (likely(list_empty(&dev->tx_reqs))); tx_list_empty = (likely(list_empty(&dev->tx_reqs)));
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
...@@ -689,6 +713,13 @@ printer_poll(struct file *fd, poll_table *wait) ...@@ -689,6 +713,13 @@ printer_poll(struct file *fd, poll_table *wait)
mutex_lock(&dev->lock_printer_io); mutex_lock(&dev->lock_printer_io);
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io);
return EPOLLERR | EPOLLHUP;
}
setup_rx_reqs(dev); setup_rx_reqs(dev);
spin_unlock_irqrestore(&dev->lock, flags); spin_unlock_irqrestore(&dev->lock, flags);
mutex_unlock(&dev->lock_printer_io); mutex_unlock(&dev->lock_printer_io);
...@@ -722,6 +753,11 @@ printer_ioctl(struct file *fd, unsigned int code, unsigned long arg) ...@@ -722,6 +753,11 @@ printer_ioctl(struct file *fd, unsigned int code, unsigned long arg)
spin_lock_irqsave(&dev->lock, flags); spin_lock_irqsave(&dev->lock, flags);
if (dev->interface < 0) {
spin_unlock_irqrestore(&dev->lock, flags);
return -ENODEV;
}
switch (code) { switch (code) {
case GADGET_GET_PRINTER_STATUS: case GADGET_GET_PRINTER_STATUS:
status = (int)dev->printer_status; status = (int)dev->printer_status;
......
...@@ -215,10 +215,7 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = { ...@@ -215,10 +215,7 @@ static struct uac2_ac_header_descriptor ac_hdr_desc = {
.bDescriptorSubtype = UAC_MS_HEADER, .bDescriptorSubtype = UAC_MS_HEADER,
.bcdADC = cpu_to_le16(0x200), .bcdADC = cpu_to_le16(0x200),
.bCategory = UAC2_FUNCTION_IO_BOX, .bCategory = UAC2_FUNCTION_IO_BOX,
.wTotalLength = cpu_to_le16(sizeof in_clk_src_desc /* .wTotalLength = DYNAMIC */
+ sizeof out_clk_src_desc + sizeof usb_out_it_desc
+ sizeof io_in_it_desc + sizeof usb_in_ot_desc
+ sizeof io_out_ot_desc),
.bmControls = 0, .bmControls = 0,
}; };
...@@ -501,7 +498,7 @@ static void setup_descriptor(struct f_uac2_opts *opts) ...@@ -501,7 +498,7 @@ static void setup_descriptor(struct f_uac2_opts *opts)
as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID; as_in_hdr_desc.bTerminalLink = usb_in_ot_desc.bTerminalID;
iad_desc.bInterfaceCount = 1; iad_desc.bInterfaceCount = 1;
ac_hdr_desc.wTotalLength = 0; ac_hdr_desc.wTotalLength = cpu_to_le16(sizeof(ac_hdr_desc));
if (EPIN_EN(opts)) { if (EPIN_EN(opts)) {
u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength); u16 len = le16_to_cpu(ac_hdr_desc.wTotalLength);
......
...@@ -1028,6 +1028,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) ...@@ -1028,6 +1028,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
return 0; return 0;
} }
static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on);
static int atmel_usba_start(struct usb_gadget *gadget, static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver); struct usb_gadget_driver *driver);
static int atmel_usba_stop(struct usb_gadget *gadget); static int atmel_usba_stop(struct usb_gadget *gadget);
...@@ -1101,6 +1102,7 @@ static const struct usb_gadget_ops usba_udc_ops = { ...@@ -1101,6 +1102,7 @@ static const struct usb_gadget_ops usba_udc_ops = {
.get_frame = usba_udc_get_frame, .get_frame = usba_udc_get_frame,
.wakeup = usba_udc_wakeup, .wakeup = usba_udc_wakeup,
.set_selfpowered = usba_udc_set_selfpowered, .set_selfpowered = usba_udc_set_selfpowered,
.pullup = atmel_usba_pullup,
.udc_start = atmel_usba_start, .udc_start = atmel_usba_start,
.udc_stop = atmel_usba_stop, .udc_stop = atmel_usba_stop,
.match_ep = atmel_usba_match_ep, .match_ep = atmel_usba_match_ep,
...@@ -1957,6 +1959,24 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid) ...@@ -1957,6 +1959,24 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int atmel_usba_pullup(struct usb_gadget *gadget, int is_on)
{
struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget);
unsigned long flags;
u32 ctrl;
spin_lock_irqsave(&udc->lock, flags);
ctrl = usba_readl(udc, CTRL);
if (is_on)
ctrl &= ~USBA_DETACH;
else
ctrl |= USBA_DETACH;
usba_writel(udc, CTRL, ctrl);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
static int atmel_usba_start(struct usb_gadget *gadget, static int atmel_usba_start(struct usb_gadget *gadget,
struct usb_gadget_driver *driver) struct usb_gadget_driver *driver)
{ {
......
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
#define NUM_SR_ENTRIES 64 #define NUM_SR_ENTRIES 64
/* Num of bds per table */ /* Num of bds per table */
#define NUM_BDS_PER_TABLE 32 #define NUM_BDS_PER_TABLE 64
/* Num of tables in bd list for control,bulk and Int ep */ /* Num of tables in bd list for control,bulk and Int ep */
#define NUM_TABLES 2 #define NUM_TABLES 2
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -29,24 +30,19 @@ ...@@ -29,24 +30,19 @@
#include "bdc_dbg.h" #include "bdc_dbg.h"
/* Poll till controller status is not OIP */ /* Poll till controller status is not OIP */
static int poll_oip(struct bdc *bdc, int usec) static int poll_oip(struct bdc *bdc, u32 usec)
{ {
u32 status; u32 status;
/* Poll till STS!= OIP */ int ret;
while (usec) {
status = bdc_readl(bdc->regs, BDC_BDCSC);
if (BDC_CSTS(status) != BDC_OIP) {
dev_dbg(bdc->dev,
"poll_oip complete status=%d",
BDC_CSTS(status));
return 0;
}
udelay(10);
usec -= 10;
}
dev_err(bdc->dev, "Err: operation timedout BDCSC: 0x%08x\n", status);
return -ETIMEDOUT; ret = readl_poll_timeout(bdc->regs + BDC_BDCSC, status,
(BDC_CSTS(status) != BDC_OIP), 10, usec);
if (ret)
dev_err(bdc->dev, "operation timedout BDCSC: 0x%08x\n", status);
else
dev_dbg(bdc->dev, "%s complete status=%d", __func__, BDC_CSTS(status));
return ret;
} }
/* Stop the BDC controller */ /* Stop the BDC controller */
...@@ -282,6 +278,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) ...@@ -282,6 +278,7 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
* in that case reinit is passed as 1 * in that case reinit is passed as 1
*/ */
if (reinit) { if (reinit) {
int i;
/* Enable interrupts */ /* Enable interrupts */
temp = bdc_readl(bdc->regs, BDC_BDCSC); temp = bdc_readl(bdc->regs, BDC_BDCSC);
temp |= BDC_GIE; temp |= BDC_GIE;
...@@ -291,6 +288,13 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit) ...@@ -291,6 +288,13 @@ static void bdc_mem_init(struct bdc *bdc, bool reinit)
/* Initialize SRR to 0 */ /* Initialize SRR to 0 */
memset(bdc->srr.sr_bds, 0, memset(bdc->srr.sr_bds, 0,
NUM_SR_ENTRIES * sizeof(struct bdc_bd)); NUM_SR_ENTRIES * sizeof(struct bdc_bd));
/*
* clear ep flags to avoid post disconnect stops/deconfigs but
* not during S2 exit
*/
if (!bdc->gadget.speed)
for (i = 1; i < bdc->num_eps; ++i)
bdc->bdc_ep_array[i]->flags = 0;
} else { } else {
/* One time initiaization only */ /* One time initiaization only */
/* Enable status report function pointers */ /* Enable status report function pointers */
...@@ -489,11 +493,9 @@ static int bdc_probe(struct platform_device *pdev) ...@@ -489,11 +493,9 @@ static int bdc_probe(struct platform_device *pdev)
dev_dbg(dev, "%s()\n", __func__); dev_dbg(dev, "%s()\n", __func__);
clk = devm_clk_get(dev, "sw_usbd"); clk = devm_clk_get_optional(dev, "sw_usbd");
if (IS_ERR(clk)) { if (IS_ERR(clk))
dev_info(dev, "Clock not found in Device Tree\n"); return PTR_ERR(clk);
clk = NULL;
}
ret = clk_prepare_enable(clk); ret = clk_prepare_enable(clk);
if (ret) { if (ret) {
...@@ -599,9 +601,14 @@ static int bdc_remove(struct platform_device *pdev) ...@@ -599,9 +601,14 @@ static int bdc_remove(struct platform_device *pdev)
static int bdc_suspend(struct device *dev) static int bdc_suspend(struct device *dev)
{ {
struct bdc *bdc = dev_get_drvdata(dev); struct bdc *bdc = dev_get_drvdata(dev);
int ret;
clk_disable_unprepare(bdc->clk); /* Halt the controller */
return 0; ret = bdc_stop(bdc);
if (!ret)
clk_disable_unprepare(bdc->clk);
return ret;
} }
static int bdc_resume(struct device *dev) static int bdc_resume(struct device *dev)
...@@ -629,7 +636,7 @@ static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend, ...@@ -629,7 +636,7 @@ static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend,
bdc_resume); bdc_resume);
static const struct of_device_id bdc_of_match[] = { static const struct of_device_id bdc_of_match[] = {
{ .compatible = "brcm,bdc-v0.16" }, { .compatible = "brcm,bdc-udc-v2" },
{ .compatible = "brcm,bdc" }, { .compatible = "brcm,bdc" },
{ /* sentinel */ } { /* sentinel */ }
}; };
......
...@@ -615,7 +615,6 @@ int bdc_ep_enable(struct bdc_ep *ep) ...@@ -615,7 +615,6 @@ int bdc_ep_enable(struct bdc_ep *ep)
} }
bdc_dbg_bd_list(bdc, ep); bdc_dbg_bd_list(bdc, ep);
/* only for ep0: config ep is called for ep0 from connect event */ /* only for ep0: config ep is called for ep0 from connect event */
ep->flags |= BDC_EP_ENABLED;
if (ep->ep_num == 1) if (ep->ep_num == 1)
return ret; return ret;
...@@ -759,10 +758,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req) ...@@ -759,10 +758,13 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)
__func__, ep->name, start_bdi, end_bdi); __func__, ep->name, start_bdi, end_bdi);
dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n", dev_dbg(bdc->dev, "ep_dequeue ep=%p ep->desc=%p\n",
ep, (void *)ep->usb_ep.desc); ep, (void *)ep->usb_ep.desc);
/* Stop the ep to see where the HW is ? */ /* if still connected, stop the ep to see where the HW is ? */
ret = bdc_stop_ep(bdc, ep->ep_num); if (!(bdc_readl(bdc->regs, BDC_USPC) & BDC_PST_MASK)) {
/* if there is an issue with stopping ep, then no need to go further */ ret = bdc_stop_ep(bdc, ep->ep_num);
if (ret) /* if there is an issue, then no need to go further */
if (ret)
return 0;
} else
return 0; return 0;
/* /*
...@@ -1911,7 +1913,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep) ...@@ -1911,7 +1913,9 @@ static int bdc_gadget_ep_disable(struct usb_ep *_ep)
__func__, ep->name, ep->flags); __func__, ep->name, ep->flags);
if (!(ep->flags & BDC_EP_ENABLED)) { if (!(ep->flags & BDC_EP_ENABLED)) {
dev_warn(bdc->dev, "%s is already disabled\n", ep->name); if (bdc->gadget.speed != USB_SPEED_UNKNOWN)
dev_warn(bdc->dev, "%s is already disabled\n",
ep->name);
return 0; return 0;
} }
spin_lock_irqsave(&bdc->lock, flags); spin_lock_irqsave(&bdc->lock, flags);
......
...@@ -1230,6 +1230,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, ...@@ -1230,6 +1230,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
return 0; return 0;
err_del_udc: err_del_udc:
flush_work(&gadget->work);
device_del(&udc->dev); device_del(&udc->dev);
err_unlist_udc: err_unlist_udc:
......
...@@ -2370,6 +2370,8 @@ net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev) ...@@ -2370,6 +2370,8 @@ net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev)
err: err:
while (--i >= 0) { while (--i >= 0) {
if (i == 1)
continue; /* BAR1 unused */
iounmap(mem_mapped_addr[i]); iounmap(mem_mapped_addr[i]);
release_mem_region(pci_resource_start(pdev, i), release_mem_region(pci_resource_start(pdev, i),
pci_resource_len(pdev, i)); pci_resource_len(pdev, i));
......
...@@ -3781,8 +3781,10 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -3781,8 +3781,10 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0; return 0;
done: done:
if (dev) if (dev) {
net2280_remove(pdev); net2280_remove(pdev);
kfree(dev);
}
return retval; return retval;
} }
......
...@@ -185,11 +185,11 @@ config USB_ULPI_VIEWPORT ...@@ -185,11 +185,11 @@ config USB_ULPI_VIEWPORT
controllers with a viewport register (e.g. Chipidea/ARC controllers). controllers with a viewport register (e.g. Chipidea/ARC controllers).
config JZ4770_PHY config JZ4770_PHY
tristate "Ingenic JZ4770 Transceiver Driver" tristate "Ingenic SoCs Transceiver Driver"
depends on MIPS || COMPILE_TEST depends on MIPS || COMPILE_TEST
select USB_PHY select USB_PHY
help help
This driver provides PHY support for the USB controller found This driver provides PHY support for the USB controller found
on the JZ4770 SoC from Ingenic. on the JZ-series and X-series SoCs from Ingenic.
endmenu endmenu
// SPDX-License-Identifier: GPL-2.0 // SPDX-License-Identifier: GPL-2.0
/* /*
* Ingenic JZ4770 USB PHY driver * Ingenic SoCs USB PHY driver
* Copyright (c) Paul Cercueil <paul@crapouillou.net> * Copyright (c) Paul Cercueil <paul@crapouillou.net>
* Copyright (c) 漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>
* Copyright (c) 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
*/ */
#include <linux/clk.h> #include <linux/clk.h>
...@@ -12,66 +14,95 @@ ...@@ -12,66 +14,95 @@
#include <linux/usb/otg.h> #include <linux/usb/otg.h>
#include <linux/usb/phy.h> #include <linux/usb/phy.h>
#define REG_USBPCR_OFFSET 0x00 /* OTGPHY register offsets */
#define REG_USBRDT_OFFSET 0x04 #define REG_USBPCR_OFFSET 0x00
#define REG_USBVBFIL_OFFSET 0x08 #define REG_USBRDT_OFFSET 0x04
#define REG_USBPCR1_OFFSET 0x0c #define REG_USBVBFIL_OFFSET 0x08
#define REG_USBPCR1_OFFSET 0x0c
/* USBPCR */
#define USBPCR_USB_MODE BIT(31) /* bits within the USBPCR register */
#define USBPCR_AVLD_REG BIT(30) #define USBPCR_USB_MODE BIT(31)
#define USBPCR_INCRM BIT(27) #define USBPCR_AVLD_REG BIT(30)
#define USBPCR_CLK12_EN BIT(26) #define USBPCR_COMMONONN BIT(25)
#define USBPCR_COMMONONN BIT(25) #define USBPCR_VBUSVLDEXT BIT(24)
#define USBPCR_VBUSVLDEXT BIT(24) #define USBPCR_VBUSVLDEXTSEL BIT(23)
#define USBPCR_VBUSVLDEXTSEL BIT(23) #define USBPCR_POR BIT(22)
#define USBPCR_POR BIT(22) #define USBPCR_SIDDQ BIT(21)
#define USBPCR_SIDDQ BIT(21) #define USBPCR_OTG_DISABLE BIT(20)
#define USBPCR_OTG_DISABLE BIT(20) #define USBPCR_TXPREEMPHTUNE BIT(6)
#define USBPCR_TXPREEMPHTUNE BIT(6)
#define USBPCR_IDPULLUP_LSB 28 #define USBPCR_IDPULLUP_LSB 28
#define USBPCR_IDPULLUP_MASK GENMASK(29, USBPCR_IDPULLUP_LSB) #define USBPCR_IDPULLUP_MASK GENMASK(29, USBPCR_IDPULLUP_LSB)
#define USBPCR_IDPULLUP_ALWAYS (3 << USBPCR_IDPULLUP_LSB) #define USBPCR_IDPULLUP_ALWAYS (0x2 << USBPCR_IDPULLUP_LSB)
#define USBPCR_IDPULLUP_SUSPEND (1 << USBPCR_IDPULLUP_LSB) #define USBPCR_IDPULLUP_SUSPEND (0x1 << USBPCR_IDPULLUP_LSB)
#define USBPCR_IDPULLUP_OTG (0 << USBPCR_IDPULLUP_LSB) #define USBPCR_IDPULLUP_OTG (0x0 << USBPCR_IDPULLUP_LSB)
#define USBPCR_COMPDISTUNE_LSB 17 #define USBPCR_COMPDISTUNE_LSB 17
#define USBPCR_COMPDISTUNE_MASK GENMASK(19, USBPCR_COMPDISTUNE_LSB) #define USBPCR_COMPDISTUNE_MASK GENMASK(19, USBPCR_COMPDISTUNE_LSB)
#define USBPCR_COMPDISTUNE_DFT 4 #define USBPCR_COMPDISTUNE_DFT (0x4 << USBPCR_COMPDISTUNE_LSB)
#define USBPCR_OTGTUNE_LSB 14 #define USBPCR_OTGTUNE_LSB 14
#define USBPCR_OTGTUNE_MASK GENMASK(16, USBPCR_OTGTUNE_LSB) #define USBPCR_OTGTUNE_MASK GENMASK(16, USBPCR_OTGTUNE_LSB)
#define USBPCR_OTGTUNE_DFT 4 #define USBPCR_OTGTUNE_DFT (0x4 << USBPCR_OTGTUNE_LSB)
#define USBPCR_SQRXTUNE_LSB 11 #define USBPCR_SQRXTUNE_LSB 11
#define USBPCR_SQRXTUNE_MASK GENMASK(13, USBPCR_SQRXTUNE_LSB) #define USBPCR_SQRXTUNE_MASK GENMASK(13, USBPCR_SQRXTUNE_LSB)
#define USBPCR_SQRXTUNE_DFT 3 #define USBPCR_SQRXTUNE_DCR_20PCT (0x7 << USBPCR_SQRXTUNE_LSB)
#define USBPCR_SQRXTUNE_DFT (0x3 << USBPCR_SQRXTUNE_LSB)
#define USBPCR_TXFSLSTUNE_LSB 7
#define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB) #define USBPCR_TXFSLSTUNE_LSB 7
#define USBPCR_TXFSLSTUNE_DFT 3 #define USBPCR_TXFSLSTUNE_MASK GENMASK(10, USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXFSLSTUNE_DCR_50PPT (0xf << USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXRISETUNE_LSB 4 #define USBPCR_TXFSLSTUNE_DCR_25PPT (0x7 << USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB) #define USBPCR_TXFSLSTUNE_DFT (0x3 << USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXRISETUNE_DFT 3 #define USBPCR_TXFSLSTUNE_INC_25PPT (0x1 << USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXFSLSTUNE_INC_50PPT (0x0 << USBPCR_TXFSLSTUNE_LSB)
#define USBPCR_TXVREFTUNE_LSB 0
#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB) #define USBPCR_TXHSXVTUNE_LSB 4
#define USBPCR_TXVREFTUNE_DFT 5 #define USBPCR_TXHSXVTUNE_MASK GENMASK(5, USBPCR_TXHSXVTUNE_LSB)
#define USBPCR_TXHSXVTUNE_DFT (0x3 << USBPCR_TXHSXVTUNE_LSB)
/* USBRDT */ #define USBPCR_TXHSXVTUNE_DCR_15MV (0x1 << USBPCR_TXHSXVTUNE_LSB)
#define USBRDT_VBFIL_LD_EN BIT(25)
#define USBRDT_IDDIG_EN BIT(24) #define USBPCR_TXRISETUNE_LSB 4
#define USBRDT_IDDIG_REG BIT(23) #define USBPCR_TXRISETUNE_MASK GENMASK(5, USBPCR_TXRISETUNE_LSB)
#define USBPCR_TXRISETUNE_DFT (0x3 << USBPCR_TXRISETUNE_LSB)
#define USBPCR_TXVREFTUNE_LSB 0
#define USBPCR_TXVREFTUNE_MASK GENMASK(3, USBPCR_TXVREFTUNE_LSB)
#define USBPCR_TXVREFTUNE_INC_25PPT (0x7 << USBPCR_TXVREFTUNE_LSB)
#define USBPCR_TXVREFTUNE_DFT (0x5 << USBPCR_TXVREFTUNE_LSB)
/* bits within the USBRDTR register */
#define USBRDT_UTMI_RST BIT(27)
#define USBRDT_HB_MASK BIT(26)
#define USBRDT_VBFIL_LD_EN BIT(25)
#define USBRDT_IDDIG_EN BIT(24)
#define USBRDT_IDDIG_REG BIT(23)
#define USBRDT_VBFIL_EN BIT(2)
/* bits within the USBPCR1 register */
#define USBPCR1_BVLD_REG BIT(31)
#define USBPCR1_DPPD BIT(29)
#define USBPCR1_DMPD BIT(28)
#define USBPCR1_USB_SEL BIT(28)
#define USBPCR1_WORD_IF_16BIT BIT(19)
enum ingenic_usb_phy_version {
ID_JZ4770,
ID_JZ4780,
ID_X1000,
ID_X1830,
};
#define USBRDT_USBRDT_LSB 0 struct ingenic_soc_info {
#define USBRDT_USBRDT_MASK GENMASK(22, USBRDT_USBRDT_LSB) enum ingenic_usb_phy_version version;
/* USBPCR1 */ void (*usb_phy_init)(struct usb_phy *phy);
#define USBPCR1_UHC_POWON BIT(5) };
struct jz4770_phy { struct jz4770_phy {
const struct ingenic_soc_info *soc_info;
struct usb_phy phy; struct usb_phy phy;
struct usb_otg otg; struct usb_otg otg;
struct device *dev; struct device *dev;
...@@ -90,12 +121,18 @@ static inline struct jz4770_phy *phy_to_jz4770_phy(struct usb_phy *phy) ...@@ -90,12 +121,18 @@ static inline struct jz4770_phy *phy_to_jz4770_phy(struct usb_phy *phy)
return container_of(phy, struct jz4770_phy, phy); return container_of(phy, struct jz4770_phy, phy);
} }
static int jz4770_phy_set_peripheral(struct usb_otg *otg, static int ingenic_usb_phy_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget) struct usb_gadget *gadget)
{ {
struct jz4770_phy *priv = otg_to_jz4770_phy(otg); struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
u32 reg; u32 reg;
if (priv->soc_info->version >= ID_X1000) {
reg = readl(priv->base + REG_USBPCR1_OFFSET);
reg |= USBPCR1_BVLD_REG;
writel(reg, priv->base + REG_USBPCR1_OFFSET);
}
reg = readl(priv->base + REG_USBPCR_OFFSET); reg = readl(priv->base + REG_USBPCR_OFFSET);
reg &= ~USBPCR_USB_MODE; reg &= ~USBPCR_USB_MODE;
reg |= USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE; reg |= USBPCR_VBUSVLDEXT | USBPCR_VBUSVLDEXTSEL | USBPCR_OTG_DISABLE;
...@@ -104,7 +141,7 @@ static int jz4770_phy_set_peripheral(struct usb_otg *otg, ...@@ -104,7 +141,7 @@ static int jz4770_phy_set_peripheral(struct usb_otg *otg,
return 0; return 0;
} }
static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host) static int ingenic_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
{ {
struct jz4770_phy *priv = otg_to_jz4770_phy(otg); struct jz4770_phy *priv = otg_to_jz4770_phy(otg);
u32 reg; u32 reg;
...@@ -117,7 +154,7 @@ static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host) ...@@ -117,7 +154,7 @@ static int jz4770_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
return 0; return 0;
} }
static int jz4770_phy_init(struct usb_phy *phy) static int ingenic_usb_phy_init(struct usb_phy *phy)
{ {
struct jz4770_phy *priv = phy_to_jz4770_phy(phy); struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
int err; int err;
...@@ -135,15 +172,7 @@ static int jz4770_phy_init(struct usb_phy *phy) ...@@ -135,15 +172,7 @@ static int jz4770_phy_init(struct usb_phy *phy)
return err; return err;
} }
reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS | priv->soc_info->usb_phy_init(phy);
(USBPCR_COMPDISTUNE_DFT << USBPCR_COMPDISTUNE_LSB) |
(USBPCR_OTGTUNE_DFT << USBPCR_OTGTUNE_LSB) |
(USBPCR_SQRXTUNE_DFT << USBPCR_SQRXTUNE_LSB) |
(USBPCR_TXFSLSTUNE_DFT << USBPCR_TXFSLSTUNE_LSB) |
(USBPCR_TXRISETUNE_DFT << USBPCR_TXRISETUNE_LSB) |
(USBPCR_TXVREFTUNE_DFT << USBPCR_TXVREFTUNE_LSB) |
USBPCR_POR;
writel(reg, priv->base + REG_USBPCR_OFFSET);
/* Wait for PHY to reset */ /* Wait for PHY to reset */
usleep_range(30, 300); usleep_range(30, 300);
...@@ -153,7 +182,7 @@ static int jz4770_phy_init(struct usb_phy *phy) ...@@ -153,7 +182,7 @@ static int jz4770_phy_init(struct usb_phy *phy)
return 0; return 0;
} }
static void jz4770_phy_shutdown(struct usb_phy *phy) static void ingenic_usb_phy_shutdown(struct usb_phy *phy)
{ {
struct jz4770_phy *priv = phy_to_jz4770_phy(phy); struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
...@@ -161,11 +190,100 @@ static void jz4770_phy_shutdown(struct usb_phy *phy) ...@@ -161,11 +190,100 @@ static void jz4770_phy_shutdown(struct usb_phy *phy)
regulator_disable(priv->vcc_supply); regulator_disable(priv->vcc_supply);
} }
static void jz4770_phy_remove(void *phy) static void ingenic_usb_phy_remove(void *phy)
{ {
usb_remove_phy(phy); usb_remove_phy(phy);
} }
static void jz4770_usb_phy_init(struct usb_phy *phy)
{
struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
u32 reg;
reg = USBPCR_AVLD_REG | USBPCR_COMMONONN | USBPCR_IDPULLUP_ALWAYS |
USBPCR_COMPDISTUNE_DFT | USBPCR_OTGTUNE_DFT | USBPCR_SQRXTUNE_DFT |
USBPCR_TXFSLSTUNE_DFT | USBPCR_TXRISETUNE_DFT | USBPCR_TXVREFTUNE_DFT |
USBPCR_POR;
writel(reg, priv->base + REG_USBPCR_OFFSET);
}
static void jz4780_usb_phy_init(struct usb_phy *phy)
{
struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
u32 reg;
reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_USB_SEL |
USBPCR1_WORD_IF_16BIT;
writel(reg, priv->base + REG_USBPCR1_OFFSET);
reg = USBPCR_TXPREEMPHTUNE | USBPCR_COMMONONN | USBPCR_POR;
writel(reg, priv->base + REG_USBPCR_OFFSET);
}
static void x1000_usb_phy_init(struct usb_phy *phy)
{
struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
u32 reg;
reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT;
writel(reg, priv->base + REG_USBPCR1_OFFSET);
reg = USBPCR_SQRXTUNE_DCR_20PCT | USBPCR_TXPREEMPHTUNE |
USBPCR_TXHSXVTUNE_DCR_15MV | USBPCR_TXVREFTUNE_INC_25PPT |
USBPCR_COMMONONN | USBPCR_POR;
writel(reg, priv->base + REG_USBPCR_OFFSET);
}
static void x1830_usb_phy_init(struct usb_phy *phy)
{
struct jz4770_phy *priv = phy_to_jz4770_phy(phy);
u32 reg;
/* rdt */
writel(USBRDT_VBFIL_EN | USBRDT_UTMI_RST, priv->base + REG_USBRDT_OFFSET);
reg = readl(priv->base + REG_USBPCR1_OFFSET) | USBPCR1_WORD_IF_16BIT |
USBPCR1_DMPD | USBPCR1_DPPD;
writel(reg, priv->base + REG_USBPCR1_OFFSET);
reg = USBPCR_IDPULLUP_OTG | USBPCR_VBUSVLDEXT | USBPCR_TXPREEMPHTUNE |
USBPCR_COMMONONN | USBPCR_POR;
writel(reg, priv->base + REG_USBPCR_OFFSET);
}
static const struct ingenic_soc_info jz4770_soc_info = {
.version = ID_JZ4770,
.usb_phy_init = jz4770_usb_phy_init,
};
static const struct ingenic_soc_info jz4780_soc_info = {
.version = ID_JZ4780,
.usb_phy_init = jz4780_usb_phy_init,
};
static const struct ingenic_soc_info x1000_soc_info = {
.version = ID_X1000,
.usb_phy_init = x1000_usb_phy_init,
};
static const struct ingenic_soc_info x1830_soc_info = {
.version = ID_X1830,
.usb_phy_init = x1830_usb_phy_init,
};
static const struct of_device_id ingenic_usb_phy_of_matches[] = {
{ .compatible = "ingenic,jz4770-phy", .data = &jz4770_soc_info },
{ .compatible = "ingenic,jz4780-phy", .data = &jz4780_soc_info },
{ .compatible = "ingenic,x1000-phy", .data = &x1000_soc_info },
{ .compatible = "ingenic,x1830-phy", .data = &x1830_soc_info },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ingenic_usb_phy_of_matches);
static int jz4770_phy_probe(struct platform_device *pdev) static int jz4770_phy_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -176,18 +294,24 @@ static int jz4770_phy_probe(struct platform_device *pdev) ...@@ -176,18 +294,24 @@ static int jz4770_phy_probe(struct platform_device *pdev)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
priv->soc_info = device_get_match_data(&pdev->dev);
if (!priv->soc_info) {
dev_err(&pdev->dev, "Error: No device match found\n");
return -ENODEV;
}
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
priv->dev = dev; priv->dev = dev;
priv->phy.dev = dev; priv->phy.dev = dev;
priv->phy.otg = &priv->otg; priv->phy.otg = &priv->otg;
priv->phy.label = "jz4770-phy"; priv->phy.label = "ingenic-usb-phy";
priv->phy.init = jz4770_phy_init; priv->phy.init = ingenic_usb_phy_init;
priv->phy.shutdown = jz4770_phy_shutdown; priv->phy.shutdown = ingenic_usb_phy_shutdown;
priv->otg.state = OTG_STATE_UNDEFINED; priv->otg.state = OTG_STATE_UNDEFINED;
priv->otg.usb_phy = &priv->phy; priv->otg.usb_phy = &priv->phy;
priv->otg.set_host = jz4770_phy_set_host; priv->otg.set_host = ingenic_usb_phy_set_host;
priv->otg.set_peripheral = jz4770_phy_set_peripheral; priv->otg.set_peripheral = ingenic_usb_phy_set_peripheral;
priv->base = devm_platform_ioremap_resource(pdev, 0); priv->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv->base)) { if (IS_ERR(priv->base)) {
...@@ -218,26 +342,20 @@ static int jz4770_phy_probe(struct platform_device *pdev) ...@@ -218,26 +342,20 @@ static int jz4770_phy_probe(struct platform_device *pdev)
return err; return err;
} }
return devm_add_action_or_reset(dev, jz4770_phy_remove, &priv->phy); return devm_add_action_or_reset(dev, ingenic_usb_phy_remove, &priv->phy);
} }
#ifdef CONFIG_OF static struct platform_driver ingenic_phy_driver = {
static const struct of_device_id jz4770_phy_of_matches[] = {
{ .compatible = "ingenic,jz4770-phy" },
{ }
};
MODULE_DEVICE_TABLE(of, jz4770_phy_of_matches);
#endif
static struct platform_driver jz4770_phy_driver = {
.probe = jz4770_phy_probe, .probe = jz4770_phy_probe,
.driver = { .driver = {
.name = "jz4770-phy", .name = "jz4770-phy",
.of_match_table = of_match_ptr(jz4770_phy_of_matches), .of_match_table = of_match_ptr(ingenic_usb_phy_of_matches),
}, },
}; };
module_platform_driver(jz4770_phy_driver); module_platform_driver(ingenic_phy_driver);
MODULE_AUTHOR("周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>");
MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
MODULE_DESCRIPTION("Ingenic JZ4770 USB PHY driver"); MODULE_DESCRIPTION("Ingenic SoCs USB PHY driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
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