|
@@ -20,14 +20,17 @@
|
|
|
*/
|
|
|
|
|
|
#include <linux/clk.h>
|
|
|
+#include <linux/delay.h>
|
|
|
#include <linux/err.h>
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/input.h>
|
|
|
+#include <linux/irq.h>
|
|
|
#include <linux/platform_device.h>
|
|
|
#include <linux/gpio.h>
|
|
|
#include <linux/gpio_keys.h>
|
|
|
#include <linux/sh_eth.h>
|
|
|
#include <linux/videodev2.h>
|
|
|
+#include <linux/usb/renesas_usbhs.h>
|
|
|
#include <mach/common.h>
|
|
|
#include <mach/irqs.h>
|
|
|
#include <asm/page.h>
|
|
@@ -90,6 +93,9 @@
|
|
|
* 0 | SDHI1 | COM8 enable, COM14 disable
|
|
|
* 1 | SDHI1 | COM8 enable, COM14 disable
|
|
|
* -12345678-+---------------+----------------------------
|
|
|
+ * 0 | USB0 | COM20 enable, COM24 disable
|
|
|
+ * 1 | USB0 | COM20 disable, COM24 enable
|
|
|
+ * -12345678-+---------------+----------------------------
|
|
|
* 00 | JTAG | SH-X2
|
|
|
* 10 | JTAG | ARM
|
|
|
* 01 | JTAG | -
|
|
@@ -97,6 +103,195 @@
|
|
|
*-----------+---------------+----------------------------
|
|
|
*/
|
|
|
|
|
|
+/*
|
|
|
+ * USB function
|
|
|
+ *
|
|
|
+ * When you use USB Function,
|
|
|
+ * set SW1.6 ON, and connect cable to CN24.
|
|
|
+ *
|
|
|
+ * USBF needs workaround on R8A7740 chip.
|
|
|
+ * These are a little bit complex.
|
|
|
+ * see
|
|
|
+ * usbhsf_power_ctrl()
|
|
|
+ *
|
|
|
+ * CAUTION
|
|
|
+ *
|
|
|
+ * It uses autonomy mode for USB hotplug at this point
|
|
|
+ * (= usbhs_private.platform_callback.get_vbus is NULL),
|
|
|
+ * since we don't know what's happen on PM control
|
|
|
+ * on this workaround.
|
|
|
+ */
|
|
|
+#define USBCR1 0xe605810a
|
|
|
+#define USBH 0xC6700000
|
|
|
+#define USBH_USBCTR 0x10834
|
|
|
+
|
|
|
+struct usbhsf_private {
|
|
|
+ struct clk *phy;
|
|
|
+ struct clk *usb24;
|
|
|
+ struct clk *pci;
|
|
|
+ struct clk *func;
|
|
|
+ struct clk *host;
|
|
|
+ void __iomem *usbh_base;
|
|
|
+ struct renesas_usbhs_platform_info info;
|
|
|
+};
|
|
|
+
|
|
|
+#define usbhsf_get_priv(pdev) \
|
|
|
+ container_of(renesas_usbhs_get_info(pdev), \
|
|
|
+ struct usbhsf_private, info)
|
|
|
+
|
|
|
+static int usbhsf_get_id(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ return USBHS_GADGET;
|
|
|
+}
|
|
|
+
|
|
|
+static void usbhsf_power_ctrl(struct platform_device *pdev,
|
|
|
+ void __iomem *base, int enable)
|
|
|
+{
|
|
|
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Work around for USB Function.
|
|
|
+ * It needs USB host clock, and settings
|
|
|
+ */
|
|
|
+ if (enable) {
|
|
|
+ /*
|
|
|
+ * enable all the related usb clocks
|
|
|
+ * for usb workaround
|
|
|
+ */
|
|
|
+ clk_enable(priv->usb24);
|
|
|
+ clk_enable(priv->pci);
|
|
|
+ clk_enable(priv->host);
|
|
|
+ clk_enable(priv->func);
|
|
|
+ clk_enable(priv->phy);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * set USBCR1
|
|
|
+ *
|
|
|
+ * Port1 is driven by USB function,
|
|
|
+ * Port2 is driven by USB HOST
|
|
|
+ * One HOST (Port1 or Port2 is HOST)
|
|
|
+ * USB PLL input clock = 24MHz
|
|
|
+ */
|
|
|
+ __raw_writew(0xd750, USBCR1);
|
|
|
+ mdelay(1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * start USB Host
|
|
|
+ */
|
|
|
+ __raw_writel(0x0000000c, priv->usbh_base + USBH_USBCTR);
|
|
|
+ __raw_writel(0x00000008, priv->usbh_base + USBH_USBCTR);
|
|
|
+ mdelay(10);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * USB PHY Power ON
|
|
|
+ */
|
|
|
+ __raw_writew(0xd770, USBCR1);
|
|
|
+ __raw_writew(0x4000, base + 0x102); /* USBF :: SUSPMODE */
|
|
|
+
|
|
|
+ } else {
|
|
|
+ __raw_writel(0x0000010f, priv->usbh_base + USBH_USBCTR);
|
|
|
+ __raw_writew(0xd7c0, USBCR1); /* GPIO */
|
|
|
+
|
|
|
+ clk_disable(priv->phy);
|
|
|
+ clk_disable(priv->func); /* usb work around */
|
|
|
+ clk_disable(priv->host); /* usb work around */
|
|
|
+ clk_disable(priv->pci); /* usb work around */
|
|
|
+ clk_disable(priv->usb24); /* usb work around */
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void usbhsf_hardware_exit(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
|
|
|
+
|
|
|
+ if (!IS_ERR(priv->phy))
|
|
|
+ clk_put(priv->phy);
|
|
|
+ if (!IS_ERR(priv->usb24))
|
|
|
+ clk_put(priv->usb24);
|
|
|
+ if (!IS_ERR(priv->pci))
|
|
|
+ clk_put(priv->pci);
|
|
|
+ if (!IS_ERR(priv->host))
|
|
|
+ clk_put(priv->host);
|
|
|
+ if (!IS_ERR(priv->func))
|
|
|
+ clk_put(priv->func);
|
|
|
+ if (priv->usbh_base)
|
|
|
+ iounmap(priv->usbh_base);
|
|
|
+
|
|
|
+ priv->phy = NULL;
|
|
|
+ priv->usb24 = NULL;
|
|
|
+ priv->pci = NULL;
|
|
|
+ priv->host = NULL;
|
|
|
+ priv->func = NULL;
|
|
|
+ priv->usbh_base = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static int usbhsf_hardware_init(struct platform_device *pdev)
|
|
|
+{
|
|
|
+ struct usbhsf_private *priv = usbhsf_get_priv(pdev);
|
|
|
+
|
|
|
+ priv->phy = clk_get(&pdev->dev, "phy");
|
|
|
+ priv->usb24 = clk_get(&pdev->dev, "usb24");
|
|
|
+ priv->pci = clk_get(&pdev->dev, "pci");
|
|
|
+ priv->func = clk_get(&pdev->dev, "func");
|
|
|
+ priv->host = clk_get(&pdev->dev, "host");
|
|
|
+ priv->usbh_base = ioremap_nocache(USBH, 0x20000);
|
|
|
+
|
|
|
+ if (IS_ERR(priv->phy) ||
|
|
|
+ IS_ERR(priv->usb24) ||
|
|
|
+ IS_ERR(priv->pci) ||
|
|
|
+ IS_ERR(priv->host) ||
|
|
|
+ IS_ERR(priv->func) ||
|
|
|
+ !priv->usbh_base) {
|
|
|
+ dev_err(&pdev->dev, "USB clock setting failed\n");
|
|
|
+ usbhsf_hardware_exit(pdev);
|
|
|
+ return -EIO;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* usb24 use 1/1 of parent clock (= usb24s = 24MHz) */
|
|
|
+ clk_set_rate(priv->usb24,
|
|
|
+ clk_get_rate(clk_get_parent(priv->usb24)));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct usbhsf_private usbhsf_private = {
|
|
|
+ .info = {
|
|
|
+ .platform_callback = {
|
|
|
+ .get_id = usbhsf_get_id,
|
|
|
+ .hardware_init = usbhsf_hardware_init,
|
|
|
+ .hardware_exit = usbhsf_hardware_exit,
|
|
|
+ .power_ctrl = usbhsf_power_ctrl,
|
|
|
+ },
|
|
|
+ .driver_param = {
|
|
|
+ .buswait_bwait = 5,
|
|
|
+ .detection_delay = 5,
|
|
|
+ },
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+static struct resource usbhsf_resources[] = {
|
|
|
+ {
|
|
|
+ .name = "USBHS",
|
|
|
+ .start = 0xe6890000,
|
|
|
+ .end = 0xe6890104 - 1,
|
|
|
+ .flags = IORESOURCE_MEM,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .start = evt2irq(0x0A20),
|
|
|
+ .flags = IORESOURCE_IRQ,
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+static struct platform_device usbhsf_device = {
|
|
|
+ .name = "renesas_usbhs",
|
|
|
+ .dev = {
|
|
|
+ .platform_data = &usbhsf_private.info,
|
|
|
+ },
|
|
|
+ .id = -1,
|
|
|
+ .num_resources = ARRAY_SIZE(usbhsf_resources),
|
|
|
+ .resource = usbhsf_resources,
|
|
|
+};
|
|
|
+
|
|
|
/* Ether */
|
|
|
static struct sh_eth_plat_data sh_eth_platdata = {
|
|
|
.phy = 0x00, /* LAN8710A */
|
|
@@ -224,11 +419,41 @@ static struct platform_device *eva_devices[] __initdata = {
|
|
|
&sh_eth_device,
|
|
|
};
|
|
|
|
|
|
+static void __init eva_clock_init(void)
|
|
|
+{
|
|
|
+ struct clk *system = clk_get(NULL, "system_clk");
|
|
|
+ struct clk *xtal1 = clk_get(NULL, "extal1");
|
|
|
+ struct clk *usb24s = clk_get(NULL, "usb24s");
|
|
|
+
|
|
|
+ if (IS_ERR(system) ||
|
|
|
+ IS_ERR(xtal1) ||
|
|
|
+ IS_ERR(usb24s)) {
|
|
|
+ pr_err("armadillo800eva board clock init failed\n");
|
|
|
+ goto clock_error;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* armadillo 800 eva extal1 is 24MHz */
|
|
|
+ clk_set_rate(xtal1, 24000000);
|
|
|
+
|
|
|
+ /* usb24s use extal1 (= system) clock (= 24MHz) */
|
|
|
+ clk_set_parent(usb24s, system);
|
|
|
+
|
|
|
+clock_error:
|
|
|
+ if (!IS_ERR(system))
|
|
|
+ clk_put(system);
|
|
|
+ if (!IS_ERR(xtal1))
|
|
|
+ clk_put(xtal1);
|
|
|
+ if (!IS_ERR(usb24s))
|
|
|
+ clk_put(usb24s);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* board init
|
|
|
*/
|
|
|
static void __init eva_init(void)
|
|
|
{
|
|
|
+ eva_clock_init();
|
|
|
+
|
|
|
r8a7740_pinmux_init();
|
|
|
|
|
|
/* SCIFA1 */
|
|
@@ -302,6 +527,18 @@ static void __init eva_init(void)
|
|
|
gpio_request(GPIO_PORT18, NULL); /* PHY_RST */
|
|
|
gpio_direction_output(GPIO_PORT18, 1);
|
|
|
|
|
|
+ /* USB */
|
|
|
+ gpio_request(GPIO_PORT159, NULL); /* USB_DEVICE_MODE */
|
|
|
+ gpio_direction_input(GPIO_PORT159);
|
|
|
+
|
|
|
+ if (gpio_get_value(GPIO_PORT159)) {
|
|
|
+ /* USB Host */
|
|
|
+ } else {
|
|
|
+ /* USB Func */
|
|
|
+ gpio_request(GPIO_FN_VBUS, NULL);
|
|
|
+ platform_device_register(&usbhsf_device);
|
|
|
+ }
|
|
|
+
|
|
|
/*
|
|
|
* CAUTION
|
|
|
*
|
|
@@ -326,17 +563,7 @@ static void __init eva_init(void)
|
|
|
|
|
|
static void __init eva_earlytimer_init(void)
|
|
|
{
|
|
|
- struct clk *xtal1;
|
|
|
-
|
|
|
r8a7740_clock_init(MD_CK0 | MD_CK2);
|
|
|
-
|
|
|
- xtal1 = clk_get(NULL, "extal1");
|
|
|
- if (!IS_ERR(xtal1)) {
|
|
|
- /* armadillo 800 eva extal1 is 24MHz */
|
|
|
- clk_set_rate(xtal1, 24000000);
|
|
|
- clk_put(xtal1);
|
|
|
- }
|
|
|
-
|
|
|
shmobile_earlytimer_init();
|
|
|
}
|
|
|
|