1
0
Files
kernel-49/arch/mips/rt2880/dev-ehci_ohci.c
Andrey Zolotarev 92b41e38d1 arch: mips: add support SoC mt7621 & mt7628, case 13803
Based on Ralink/MTK SDK.
2019-02-08 17:26:04 +03:00

213 lines
5.8 KiB
C

/**************************************************************************
*
* BRIEF MODULE DESCRIPTION
* EHCI/OHCI init for Ralink RT3xxx
*
* Copyright 2009 Ralink Inc. (yyhuang@ralinktech.com.tw)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
**************************************************************************
* March 2009 YYHuang Initial Release
**************************************************************************
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
#if IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM)
#include <linux/usb/ehci_pdriver.h>
#endif
#if IS_ENABLED(CONFIG_USB_OHCI_HCD_PLATFORM)
#include <linux/usb/ohci_pdriver.h>
#endif
#include <asm/irq.h>
#include <asm/rt2880/rt_mmap.h>
#define RT3XXX_EHCI_MEM_START (RALINK_USB_HOST_BASE)
#define RT3XXX_OHCI_MEM_START (RALINK_USB_HOST_BASE + 0x1000)
static struct resource rt3xxx_ehci_resources[] = {
[0] = {
.start = RT3XXX_EHCI_MEM_START,
.end = RT3XXX_EHCI_MEM_START + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SURFBOARDINT_UHST,
.flags = IORESOURCE_IRQ,
},
};
static struct resource rt3xxx_ohci_resources[] = {
[0] = {
.start = RT3XXX_OHCI_MEM_START,
.end = RT3XXX_OHCI_MEM_START + 0xfff,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SURFBOARDINT_UHST,
.flags = IORESOURCE_IRQ,
},
};
static u64 rt3xxx_ehci_dmamask = DMA_BIT_MASK(32);
static u64 rt3xxx_ohci_dmamask = DMA_BIT_MASK(32);
#if IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM) || IS_ENABLED(CONFIG_USB_OHCI_HCD_PLATFORM)
static atomic_t rt3xxx_power_instance = ATOMIC_INIT(0);
extern void uphy_init(void);
#define SYSCFG1_REG (RALINK_SYSCTL_BASE + 0x14)
#define RALINK_UHST_MODE (1UL<<10)
#define CLKCFG1_REG (RALINK_SYSCTL_BASE + 0x30)
#define RSTCTRL_REG (RALINK_SYSCTL_BASE + 0x34)
static void rt_usb_wake_up(void)
{
u32 val;
/* enable PHY0/1 clock */
val = le32_to_cpu(*(volatile u32 *)(CLKCFG1_REG));
val |= (RALINK_UPHY0_CLK_EN | RALINK_UPHY1_CLK_EN);
*(volatile u32 *)(CLKCFG1_REG) = cpu_to_le32(val);
mdelay(10);
/* set HOST mode */
val = le32_to_cpu(*(volatile u32 *)(SYSCFG1_REG));
val |= (RALINK_UHST_MODE);
*(volatile u32 *)(SYSCFG1_REG) = cpu_to_le32(val);
mdelay(1);
/* release reset */
val = le32_to_cpu(*(volatile u32 *)(RSTCTRL_REG));
val &= ~(RALINK_UHST_RST | RALINK_UDEV_RST);
*(volatile u32 *)(RSTCTRL_REG) = cpu_to_le32(val);
mdelay(100);
uphy_init();
}
static void rt_usb_sleep(void)
{
u32 val;
/* raise reset */
val = le32_to_cpu(*(volatile u32 *)(RSTCTRL_REG));
val |= (RALINK_UHST_RST | RALINK_UDEV_RST);
*(volatile u32 *)(RSTCTRL_REG) = cpu_to_le32(val);
mdelay(10);
/* disable PHY0/1 clock */
val = le32_to_cpu(*(volatile u32 *)(CLKCFG1_REG));
val &= ~(RALINK_UPHY0_CLK_EN | RALINK_UPHY1_CLK_EN);
*(volatile u32 *)(CLKCFG1_REG) = cpu_to_le32(val);
udelay(10);
}
static int rt3xxx_power_on(struct platform_device *pdev)
{
if (atomic_inc_return(&rt3xxx_power_instance) == 1)
rt_usb_wake_up();
return 0;
}
static void rt3xxx_power_off(struct platform_device *pdev)
{
if (atomic_dec_return(&rt3xxx_power_instance) == 0)
rt_usb_sleep();
}
static struct usb_ehci_pdata rt3xxx_ehci_pdata = {
.caps_offset = 0,
.has_synopsys_hc_bug = 1,
.power_on = rt3xxx_power_on,
.power_off = rt3xxx_power_off,
};
static struct usb_ohci_pdata rt3xxx_ohci_pdata = {
.power_on = rt3xxx_power_on,
.power_off = rt3xxx_power_off,
};
#endif
static struct platform_device rt3xxx_ehci_device = {
.name = "ehci-platform",
.id = -1,
.dev = {
#if IS_ENABLED(CONFIG_USB_EHCI_HCD_PLATFORM)
.platform_data = &rt3xxx_ehci_pdata,
#endif
.dma_mask = &rt3xxx_ehci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(rt3xxx_ehci_resources),
.resource = rt3xxx_ehci_resources,
};
static struct platform_device rt3xxx_ohci_device = {
.name = "ohci-platform",
.id = -1,
.dev = {
#if IS_ENABLED(CONFIG_USB_OHCI_HCD_PLATFORM)
.platform_data = &rt3xxx_ohci_pdata,
#endif
.dma_mask = &rt3xxx_ohci_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
.num_resources = ARRAY_SIZE(rt3xxx_ohci_resources),
.resource = rt3xxx_ohci_resources,
};
static struct platform_device *rt3xxx_devices[] __initdata = {
&rt3xxx_ehci_device,
&rt3xxx_ohci_device,
};
int __init init_rt3xxx_ehci_ohci(void)
{
int retval = 0;
retval = platform_add_devices(rt3xxx_devices, ARRAY_SIZE(rt3xxx_devices));
if (retval != 0) {
printk(KERN_ERR "register %s device fail!\n", "EHCI/OHCI");
return retval;
}
return retval;
}
device_initcall(init_rt3xxx_ehci_ohci);