163 lines
5.5 KiB
Diff
163 lines
5.5 KiB
Diff
From 132e23775779cc895c37f7883c33a60a1a8a7cdd Mon Sep 17 00:00:00 2001
|
|
From: Hans de Goede <hdegoede@redhat.com>
|
|
Date: Wed, 8 Jul 2015 16:41:39 +0200
|
|
Subject: [PATCH] usb: musb: sunxi: Add support for musb controller in A31 SoC
|
|
|
|
The A31 SoC uses the same musb controller as found in earlier SoCs, but it
|
|
is hooked up slightly different. Its SRAM is private and no longer controlled
|
|
through the SRAM controller, and its reset is controlled via a separate
|
|
reset controller. This commit adds support for this setup.
|
|
|
|
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
|
|
Signed-off-by: Felipe Balbi <balbi@ti.com>
|
|
---
|
|
.../bindings/usb/allwinner,sun4i-a10-musb.txt | 3 +-
|
|
drivers/usb/musb/sunxi.c | 50 +++++++++++++++++++---
|
|
2 files changed, 46 insertions(+), 7 deletions(-)
|
|
|
|
--- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
|
|
+++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt
|
|
@@ -2,9 +2,10 @@ Allwinner sun4i A10 musb DRC/OTG control
|
|
-------------------------------------------
|
|
|
|
Required properties:
|
|
- - compatible : "allwinner,sun4i-a10-musb"
|
|
+ - compatible : "allwinner,sun4i-a10-musb" or "allwinner,sun6i-a31-musb"
|
|
- reg : mmio address range of the musb controller
|
|
- clocks : clock specifier for the musb controller ahb gate clock
|
|
+ - reset : reset specifier for the ahb reset (A31 and newer only)
|
|
- interrupts : interrupt to which the musb controller is connected
|
|
- interrupt-names : must be "mc"
|
|
- phys : phy specifier for the otg phy
|
|
--- a/drivers/usb/musb/sunxi.c
|
|
+++ b/drivers/usb/musb/sunxi.c
|
|
@@ -26,6 +26,7 @@
|
|
#include <linux/of.h>
|
|
#include <linux/phy/phy-sun4i-usb.h>
|
|
#include <linux/platform_device.h>
|
|
+#include <linux/reset.h>
|
|
#include <linux/soc/sunxi/sunxi_sram.h>
|
|
#include <linux/usb/musb.h>
|
|
#include <linux/usb/of.h>
|
|
@@ -70,6 +71,8 @@
|
|
#define SUNXI_MUSB_FL_HOSTMODE_PEND 2
|
|
#define SUNXI_MUSB_FL_VBUS_ON 3
|
|
#define SUNXI_MUSB_FL_PHY_ON 4
|
|
+#define SUNXI_MUSB_FL_HAS_SRAM 5
|
|
+#define SUNXI_MUSB_FL_HAS_RESET 6
|
|
|
|
/* Our read/write methods need access and do not get passed in a musb ref :| */
|
|
static struct musb *sunxi_musb;
|
|
@@ -78,6 +81,7 @@ struct sunxi_glue {
|
|
struct device *dev;
|
|
struct platform_device *musb;
|
|
struct clk *clk;
|
|
+ struct reset_control *rst;
|
|
struct phy *phy;
|
|
struct platform_device *usb_phy;
|
|
struct usb_phy *xceiv;
|
|
@@ -229,14 +233,22 @@ static int sunxi_musb_init(struct musb *
|
|
musb->phy = glue->phy;
|
|
musb->xceiv = glue->xceiv;
|
|
|
|
- ret = sunxi_sram_claim(musb->controller->parent);
|
|
- if (ret)
|
|
- return ret;
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags)) {
|
|
+ ret = sunxi_sram_claim(musb->controller->parent);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ }
|
|
|
|
ret = clk_prepare_enable(glue->clk);
|
|
if (ret)
|
|
goto error_sram_release;
|
|
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
|
|
+ ret = reset_control_deassert(glue->rst);
|
|
+ if (ret)
|
|
+ goto error_clk_disable;
|
|
+ }
|
|
+
|
|
writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0);
|
|
|
|
/* Register notifier before calling phy_init() */
|
|
@@ -244,7 +256,7 @@ static int sunxi_musb_init(struct musb *
|
|
ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST,
|
|
&glue->host_nb);
|
|
if (ret)
|
|
- goto error_clk_disable;
|
|
+ goto error_reset_assert;
|
|
}
|
|
|
|
ret = phy_init(glue->phy);
|
|
@@ -273,10 +285,14 @@ error_unregister_notifier:
|
|
if (musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)
|
|
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
|
|
&glue->host_nb);
|
|
+error_reset_assert:
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
|
|
+ reset_control_assert(glue->rst);
|
|
error_clk_disable:
|
|
clk_disable_unprepare(glue->clk);
|
|
error_sram_release:
|
|
- sunxi_sram_release(musb->controller->parent);
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
|
|
+ sunxi_sram_release(musb->controller->parent);
|
|
return ret;
|
|
}
|
|
|
|
@@ -296,8 +312,12 @@ static int sunxi_musb_exit(struct musb *
|
|
extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST,
|
|
&glue->host_nb);
|
|
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags))
|
|
+ reset_control_assert(glue->rst);
|
|
+
|
|
clk_disable_unprepare(glue->clk);
|
|
- sunxi_sram_release(musb->controller->parent);
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags))
|
|
+ sunxi_sram_release(musb->controller->parent);
|
|
|
|
return 0;
|
|
}
|
|
@@ -617,6 +637,12 @@ static int sunxi_musb_probe(struct platf
|
|
INIT_WORK(&glue->work, sunxi_musb_work);
|
|
glue->host_nb.notifier_call = sunxi_musb_host_notifier;
|
|
|
|
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-musb"))
|
|
+ set_bit(SUNXI_MUSB_FL_HAS_SRAM, &glue->flags);
|
|
+
|
|
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb"))
|
|
+ set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags);
|
|
+
|
|
glue->clk = devm_clk_get(&pdev->dev, NULL);
|
|
if (IS_ERR(glue->clk)) {
|
|
dev_err(&pdev->dev, "Error getting clock: %ld\n",
|
|
@@ -624,6 +650,17 @@ static int sunxi_musb_probe(struct platf
|
|
return PTR_ERR(glue->clk);
|
|
}
|
|
|
|
+ if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) {
|
|
+ glue->rst = devm_reset_control_get(&pdev->dev, NULL);
|
|
+ if (IS_ERR(glue->rst)) {
|
|
+ if (PTR_ERR(glue->rst) == -EPROBE_DEFER)
|
|
+ return -EPROBE_DEFER;
|
|
+ dev_err(&pdev->dev, "Error getting reset %ld\n",
|
|
+ PTR_ERR(glue->rst));
|
|
+ return PTR_ERR(glue->rst);
|
|
+ }
|
|
+ }
|
|
+
|
|
glue->phy = devm_phy_get(&pdev->dev, "usb");
|
|
if (IS_ERR(glue->phy)) {
|
|
if (PTR_ERR(glue->phy) == -EPROBE_DEFER)
|
|
@@ -685,6 +722,7 @@ static int sunxi_musb_remove(struct plat
|
|
|
|
static const struct of_device_id sunxi_musb_match[] = {
|
|
{ .compatible = "allwinner,sun4i-a10-musb", },
|
|
+ { .compatible = "allwinner,sun6i-a31-musb", },
|
|
{}
|
|
};
|
|
|