S5PV210 LINUX-3.15.4 USB HOST

arch\arm\plat-samsung\devs.c

 

/* 2015/11/17 fuchch */

/* USB HOST */

#ifdef CONFIG_USB_SUPPORT

#ifdef CONFIG_USB_EHCI_S5PV210

 /* USB Host Controlle EHCI registrations */

static struct resource s5p_usb_ehci_resource[] = {

[0] = {

.start = S5PV210_PA_USB_EHCI,

.end   = S5P_PA_USB_EHCI  + S5P_SZ_USB_EHCI - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_UHOST,

.end   = IRQ_UHOST,

.flags = IORESOURCE_IRQ,

}

};

 

static u64 s5p_device_usb_ehci_dmamask = 0xffffffffUL;

 

struct platform_device s5p_device_usb_ehci = {

.name = "s5p-ehci",

.id = -1,

.num_resources = ARRAY_SIZE(s5p_usb_ehci_resource),

.resource = s5p_usb_ehci_resource,

.dev = {

.dma_mask = &s5p_device_usb_ehci_dmamask,

.coherent_dma_mask = 0xffffffffUL

}

};

#endif /* CONFIG_USB_EHCI_S5PV210 */

 

#ifdef CONFIG_USB_OHCI_S5PV210

/* USB Host Controlle OHCI registrations */

static struct resource s5p_usb__ohci_resource[] = {

[0] = {

.start = S5P_PA_USB_OHCI,

.end   = S5P_PA_USB_OHCI  + S5P_SZ_USB_OHCI - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_UHOST,

.end   = IRQ_UHOST,

.flags = IORESOURCE_IRQ,

}

};

 

static u64 s5p_device_usb_ohci_dmamask = 0xffffffffUL;

 

struct platform_device s5p_device_usb_ohci = {

.name = "s5p-ohci",

.id = -1,

.num_resources = ARRAY_SIZE(s5p_usb__ohci_resource),

.resource = s5p_usb__ohci_resource,

.dev = {

.dma_mask = &s5p_device_usb_ohci_dmamask,

.coherent_dma_mask = 0xffffffffUL

}

};

#endif /* CONFIG_USB_OHCI_S5PV210 */

 

/* USB Device (Gadget)*/

static struct resource s5p_usbgadget_resource[] = {

[0] = {

.start = S5PV210_PA_OTG,

.end = S5PV210_PA_OTG + S5PV210_SZ_OTG - 1,

.flags = IORESOURCE_MEM,

},

[1] = {

.start = IRQ_OTG,

.end = IRQ_OTG,

.flags = IORESOURCE_IRQ,

}

};

 

struct platform_device s5p_device_usbgadget = {

.name = "s5p-usbgadget",

.id = -1,

.num_resources = ARRAY_SIZE(s5p_usbgadget_resource),

.resource = s5p_usbgadget_resource,

};

#endif /* CONFIG_USB_SUPPORT */

 

arch\arm\plat-samsung\include\plat\devs.h

/* 2015/11/7 fuchch */

extern struct platform_device s5p_device_usb_ehci;

extern struct platform_device s5p_device_usb_ohci;

 

arch\arm\mach-s5pv210\include\mach\map.h

/* 2015/11/7 fuchch */

/* usb */

#define S5PV210_PA_OTG          (0xEC000000)

#define S5PV210_SZ_OTG          SZ_1M

 

#define S5PV210_PA_OTGSFR       (0xEC100000)

#define S5PV210_SZ_OTGSFR       SZ_1M

 

#define S5PV210_PA_USB_EHCI (0xEC200000)

#define S5P_PA_USB_EHCI S5PV210_PA_USB_EHCI

#define S5P_SZ_USB_EHCI      SZ_1M

 

#define S5PV210_PA_USB_OHCI (0xEC300000)

#define S5P_PA_USB_OHCI S5PV210_PA_USB_OHCI

#define S5P_SZ_USB_OHCI      SZ_1M

/* end usb */

 

arch\arm\mach-s5pv210\mach-smdkv210.c

 

#include <plat/regs-usb-hsotg-phy.h>

 

static struct platform_device *smdkv210_devices[] __initdata = {

...

/* 2015/11/7 fuchch */

#ifdef CONFIG_USB_SUPPORT

#ifdef CONFIG_USB_EHCI_S5PV210

&s5p_device_usb_ehci,

#endif

#ifdef CONFIG_USB_OHCI_S5PV210

&s5p_device_usb_ohci,

#endif

#endif

}

 

#if CONFIG_USB_SUPPORT

extern struct clk *clk_get(struct device *dev, const char *id);

extern int clk_enable(struct clk *clk);

 

void usb_host_phy_init(void)

{

struct clk *otg_clk;

 

otg_clk = clk_get(NULL, "otg");

clk_enable(otg_clk);

 

if (readl(S5P_USB_PHY_CONTROL) & (0x1<<1))

return;

 

__raw_writel(__raw_readl(S5P_USB_PHY_CONTROL) | (0x1<<1),

S5P_USB_PHY_CONTROL);

__raw_writel((__raw_readl(S3C_PHYPWR)

& ~(0x1<<7) & ~(0x1<<6)) | (0x1<<8) | (0x1<<5),

S3C_PHYPWR);

__raw_writel((__raw_readl(S3C_PHYCLK) & ~(0x1<<7)) | (0x3<<0),

S3C_PHYCLK);

__raw_writel((__raw_readl(S3C_RSTCON)) | (0x1<<4) | (0x1<<3),

S3C_RSTCON);

__raw_writel(__raw_readl(S3C_RSTCON) & ~(0x1<<4) & ~(0x1<<3),

S3C_RSTCON);

}

EXPORT_SYMBOL(usb_host_phy_init);

 

void usb_host_phy_off(void)

{

__raw_writel(__raw_readl(S3C_PHYPWR) | (0x1<<7)|(0x1<<6),

S3C_PHYPWR);

__raw_writel(__raw_readl(S5P_USB_PHY_CONTROL) & ~(1<<1),

S5P_USB_PHY_CONTROL);

}

EXPORT_SYMBOL(usb_host_phy_off);

#endif

 

drivers\usb\host\

 

/* ehci-s5pv210.c - Driver for USB HOST on Samsung S5PV210 processor

 *

 * Bus Glue for SAMSUNG S5PV210 USB HOST EHCI Controller

 *

 * Copyright (c) 2010 Samsung Electronics Co., Ltd.

 * Author: Jingoo Han <[email protected]>

 *

 * Based on "ehci-au1xxx.c" by by K.Boge <[email protected]>

 * Modified for SAMSUNG s5pv210 EHCI by Jingoo Han <[email protected]>

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation.

*/

 

#include <linux/clk.h>

#include <linux/platform_device.h>

#include <linux/usb/hcd.h>

 

static struct clk *usb_clk;

 

extern int usb_disabled(void);

 

extern void usb_host_phy_init(void);

extern void usb_host_phy_off(void);

 

static void s5pv210_start_ehc(void);

static void s5pv210_stop_ehc(void);

static int ehci_hcd_s5pv210_drv_probe(struct platform_device *pdev);

static int ehci_hcd_s5pv210_drv_remove(struct platform_device *pdev);

 

#ifdef CONFIG_PM

static int ehci_hcd_s5pv210_drv_suspend(

struct platform_device *pdev,

pm_message_t message)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

struct ehci_hcd *ehci = hcd_to_ehci(hcd);

unsigned long flags;

int rc = 0;

 

if (time_before(jiffies, ehci->next_statechange))

msleep(10);

 

/* Root hub was already suspended. Disable irq emission and

 * mark HW unaccessible, bail out if RH has been resumed. Use

 * the spinlock to properly synchronize with possible pending

 * RH suspend or resume activity.

 *

 * This is still racy as hcd->state is manipulated outside of

 * any locks =P But that will be a different fix.

 */

 

spin_lock_irqsave(&ehci->lock, flags);

if (hcd->state != HC_STATE_SUSPENDED) {

rc = -EINVAL;

goto bail;

}

ehci_writel(ehci, 0, &ehci->regs->intr_enable);

(void)ehci_readl(ehci, &ehci->regs->intr_enable);

 

/* make sure snapshot being resumed re-enumerates everything */

if (message.event == PM_EVENT_PRETHAW) {

ehci_halt(ehci);

ehci_reset(ehci);

}

 

clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

 

s5pv210_stop_ehc();

bail:

spin_unlock_irqrestore(&ehci->lock, flags);

 

return rc;

}

static int ehci_hcd_s5pv210_drv_resume(struct platform_device *pdev)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

struct ehci_hcd *ehci = hcd_to_ehci(hcd);

 

s5pv210_start_ehc();

 

if (time_before(jiffies, ehci->next_statechange))

msleep(10);

 

/* Mark hardware accessible again as we are out of D3 state by now */

set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

 

if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {

int mask = INTR_MASK;

 

if (!hcd->self.root_hub->do_remote_wakeup)

mask &= ~STS_PCD;

ehci_writel(ehci, mask, &ehci->regs->intr_enable);

ehci_readl(ehci, &ehci->regs->intr_enable);

return 0;

}

 

ehci_dbg(ehci, "lost power, restarting\n");

usb_root_hub_lost_power(hcd->self.root_hub);

 

(void) ehci_halt(ehci);

(void) ehci_reset(ehci);

 

/* emptying the schedule aborts any urbs */

spin_lock_irq(&ehci->lock);

if (ehci->reclaim)

end_unlink_async(ehci);

ehci_work(ehci);

spin_unlock_irq(&ehci->lock);

 

ehci_writel(ehci, ehci->command, &ehci->regs->command);

ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);

ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */

 

/* here we "know" root ports should always stay powered */

ehci_port_power(ehci, 1);

 

hcd->state = HC_STATE_SUSPENDED;

 

return 0;

}

 

#else

#define ehci_hcd_s5pv210_drv_suspend NULL

#define ehci_hcd_s5pv210_drv_resume NULL

#endif

 

static void s5pv210_start_ehc(void)

{

clk_enable(usb_clk);

usb_host_phy_init();

}

 

static void s5pv210_stop_ehc(void)

{

usb_host_phy_off();

clk_disable(usb_clk);

}

 

static const struct hc_driver ehci_s5pv210_hc_driver = {

.description = hcd_name,

.product_desc = "s5pv210 EHCI",

.hcd_priv_size = sizeof(struct ehci_hcd),

 

.irq = ehci_irq,

.flags = HCD_MEMORY|HCD_USB2,

 

.reset = ehci_init,

.start = ehci_run,

.stop = ehci_stop,

.shutdown = ehci_shutdown,

 

.get_frame_number = ehci_get_frame,

 

.urb_enqueue = ehci_urb_enqueue,

.urb_dequeue = ehci_urb_dequeue,

.endpoint_disable = ehci_endpoint_disable,

.endpoint_reset = ehci_endpoint_reset,

 

.hub_status_data = ehci_hub_status_data,

.hub_control = ehci_hub_control,

.bus_suspend = ehci_bus_suspend,

.bus_resume = ehci_bus_resume,

.relinquish_port = ehci_relinquish_port,

.port_handed_over = ehci_port_handed_over,

 

.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,

};

 

static int ehci_hcd_s5pv210_drv_probe(struct platform_device *pdev)

{

struct usb_hcd  *hcd = NULL;

struct ehci_hcd *ehci = NULL;

int retval = 0;

 

if (usb_disabled())

return -ENODEV;

 

usb_host_phy_off();

 

if (pdev->resource[1].flags != IORESOURCE_IRQ) {

dev_err(&pdev->dev, "resource[1] is not IORESOURCE_IRQ.\n");

return -ENODEV;

}

 

hcd = usb_create_hcd(&ehci_s5pv210_hc_driver, &pdev->dev, "s5pv210");

if (!hcd) {

dev_err(&pdev->dev, "usb_create_hcd failed!\n");

return -ENODEV;

}

hcd->rsrc_start = pdev->resource[0].start;

hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;

 

if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {

dev_err(&pdev->dev, "request_mem_region failed!\n");

retval = -EBUSY;

goto err1;

}

 

usb_clk = clk_get(&pdev->dev, "usb-host");

if (IS_ERR(usb_clk)) {

dev_err(&pdev->dev, "cannot get usb-host clock\n");

retval = -ENODEV;

goto err2;

}

 

s5pv210_start_ehc();

 

hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);

if (!hcd->regs) {

dev_err(&pdev->dev, "ioremap failed!\n");

retval = -ENOMEM;

goto err2;

}

 

ehci = hcd_to_ehci(hcd);

ehci->caps = hcd->regs;

ehci->regs = hcd->regs + ((readl(&ehci->caps->hc_capbase)>>00)&0x00ff);

/* cache this readonly data; minimize chip reads */

ehci->hcs_params = readl(&ehci->caps->hcs_params);

 

#if defined(CONFIG_ARCH_S5PV210)

writel(0x000F0000, hcd->regs + 0x90);

#endif

 

retval = usb_add_hcd(hcd, pdev->resource[1].start,

IRQF_DISABLED | IRQF_SHARED);

 

if (retval == 0) {

platform_set_drvdata(pdev, hcd);

return retval;

}

 

s5pv210_stop_ehc();

iounmap(hcd->regs);

err2:

release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

err1:

clk_put(usb_clk);

usb_put_hcd(hcd);

return retval;

}

 

static int ehci_hcd_s5pv210_drv_remove(struct platform_device *pdev)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

 

usb_remove_hcd(hcd);

iounmap(hcd->regs);

release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

usb_put_hcd(hcd);

s5pv210_stop_ehc();

clk_put(usb_clk);

platform_set_drvdata(pdev, NULL);

 

return 0;

}

 

static struct platform_driver  ehci_hcd_s5pv210_driver = {

.probe = ehci_hcd_s5pv210_drv_probe,

.remove = ehci_hcd_s5pv210_drv_remove,

.shutdown = usb_hcd_platform_shutdown,

.suspend = ehci_hcd_s5pv210_drv_suspend,

.resume = ehci_hcd_s5pv210_drv_resume,

.driver = {

.name = "s5p-ehci",

.owner = THIS_MODULE,

}

};

 

MODULE_ALIAS("platform:s5p-ehci");

 

/* ohci-s5pv210.c - Driver for USB HOST on Samsung S5PV210 processor

 *

 * Bus Glue for SAMSUNG S5PV210 USB HOST OHCI Controller

 *

 * (C) Copyright 1999 Roman Weissgaerber <[email protected]>

 * (C) Copyright 2000-2002 David Brownell <[email protected]>

 * (C) Copyright 2002 Hewlett-Packard Company

 * Copyright (c) 2010 Samsung Electronics Co., Ltd.

 * Author: Jingoo Han <[email protected]>

 *

 * Based on "ohci-au1xxx.c" by Matt Porter <[email protected]>

 * Modified for SAMSUNG s5pv210 OHCI by Jingoo Han <[email protected]>

 *

 * This program is free software; you can redistribute it and/or modify

 * it under the terms of the GNU General Public License version 2 as

 * published by the Free Software Foundation.

*/

 

#include <linux/clk.h>

#include <linux/platform_device.h>

 

static struct clk *usb_clk;

 

extern int usb_disabled(void);

 

extern void usb_host_phy_init(void);

extern void usb_host_phy_off(void);

 

static void s5pv210_start_ohc(void);

static void s5pv210_stop_ohc(void);

static int ohci_hcd_s5pv210_drv_probe(struct platform_device *pdev);

static int ohci_hcd_s5pv210_drv_remove(struct platform_device *pdev);

 

#ifdef CONFIG_PM

static int ohci_hcd_s5pv210_drv_suspend(

struct platform_device *pdev,

pm_message_t message

)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

struct ohci_hcd *ohci = hcd_to_ohci(hcd);

unsigned long flags;

int rc = 0;

 

/* Root hub was already suspended. Disable irq emission and

 * mark HW unaccessible, bail out if RH has been resumed. Use

 * the spinlock to properly synchronize with possible pending

 * RH suspend or resume activity.

 *

 * This is still racy as hcd->state is manipulated outside of

 * any locks =P But that will be a different fix.

 */

spin_lock_irqsave(&ohci->lock, flags);

if (hcd->state != HC_STATE_SUSPENDED) {

rc = -EINVAL;

goto bail;

}

 

/* make sure snapshot being resumed re-enumerates everything */

if (message.event == PM_EVENT_PRETHAW)

ohci_usb_reset(ohci);

 

clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

 

s5pv210_stop_ohc();

bail:

spin_unlock_irqrestore(&ohci->lock, flags);

 

return rc;

}

static int ohci_hcd_s5pv210_drv_resume(struct platform_device *pdev)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

int rc = 0;

 

s5pv210_start_ohc();

 

/* Mark hardware accessible again as we are out of D3 state by now */

set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);

 

ohci_finish_controller_resume(hcd);

 

return rc;

}

#else

#define ohci_hcd_s5pv210_drv_suspend NULL

#define ohci_hcd_s5pv210_drv_resume NULL

#endif

 

static void s5pv210_start_ohc(void)

{

clk_enable(usb_clk);

usb_host_phy_init();

}

 

static void s5pv210_stop_ohc(void)

{

usb_host_phy_off();

clk_disable(usb_clk);

}

 

static int ohci_s5pv210_start(struct usb_hcd *hcd)

{

struct ohci_hcd *ohci = hcd_to_ohci(hcd);

int ret;

 

ohci_dbg(ohci, "ohci_s5pv210_start, ohci:%p", ohci);

 

ret = ohci_init(ohci);

if (ret < 0)

return ret;

 

ret = ohci_run(ohci);

if (ret < 0) {

printk("can't start %s", hcd->self.bus_name);

ohci_stop(hcd);

return ret;

}

 

return 0;

}

 

static const struct hc_driver ohci_s5pv210_hc_driver = {

.description = hcd_name,

.product_desc = "s5pv210 OHCI",

.hcd_priv_size = sizeof(struct ohci_hcd),

 

.irq = ohci_irq,

.flags = HCD_MEMORY|HCD_USB11,

 

.start = ohci_s5pv210_start,

.stop = ohci_stop,

.shutdown = ohci_shutdown,

 

.get_frame_number = ohci_get_frame,

 

.urb_enqueue = ohci_urb_enqueue,

.urb_dequeue = ohci_urb_dequeue,

.endpoint_disable = ohci_endpoint_disable,

 

.hub_status_data = ohci_hub_status_data,

.hub_control = ohci_hub_control,

#ifdef CONFIG_PM

.bus_suspend = ohci_bus_suspend,

.bus_resume = ohci_bus_resume,

#endif

.start_port_reset = ohci_start_port_reset,

};

 

static int ohci_hcd_s5pv210_drv_probe(struct platform_device *pdev)

{

struct usb_hcd  *hcd = NULL;

int retval = 0;

 

if (usb_disabled())

return -ENODEV;

 

if (pdev->resource[1].flags != IORESOURCE_IRQ) {

dev_err(&pdev->dev, "resource[1] is not IORESOURCE_IRQ.\n");

return -ENODEV;

}

 

hcd = usb_create_hcd(&ohci_s5pv210_hc_driver, &pdev->dev, "s5pv210");

if (!hcd) {

dev_err(&pdev->dev, "usb_create_hcd failed!\n");

return -ENODEV;

}

 

hcd->rsrc_start = pdev->resource[0].start;

hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;

 

if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {

dev_err(&pdev->dev, "request_mem_region failed!\n");

retval = -EBUSY;

goto err1;

}

 

usb_clk = clk_get(&pdev->dev, "usb-host");

if (IS_ERR(usb_clk)) {

dev_err(&pdev->dev, "cannot get usb-host clock\n");

retval = -ENODEV;

goto err2;

}

 

s5pv210_start_ohc();

 

hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);

if (!hcd->regs) {

dev_err(&pdev->dev, "ioremap failed!\n");

retval = -ENOMEM;

goto err2;

}

 

ohci_hcd_init(hcd_to_ohci(hcd));

 

retval = usb_add_hcd(hcd, pdev->resource[1].start,

IRQF_DISABLED | IRQF_SHARED);

 

if (retval == 0) {

platform_set_drvdata(pdev, hcd);

return retval;

}

 

s5pv210_stop_ohc();

iounmap(hcd->regs);

err2:

release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

err1:

clk_put(usb_clk);

usb_put_hcd(hcd);

return retval;

}

 

static int ohci_hcd_s5pv210_drv_remove(struct platform_device *pdev)

{

struct usb_hcd *hcd = platform_get_drvdata(pdev);

 

usb_remove_hcd(hcd);

iounmap(hcd->regs);

release_mem_region(hcd->rsrc_start, hcd->rsrc_len);

usb_put_hcd(hcd);

s5pv210_stop_ohc();

clk_put(usb_clk);

platform_set_drvdata(pdev, NULL);

 

return 0;

}

 

static struct platform_driver  ohci_hcd_s5pv210_driver = {

.probe = ohci_hcd_s5pv210_drv_probe,

.remove = ohci_hcd_s5pv210_drv_remove,

.shutdown = usb_hcd_platform_shutdown,

.suspend = ohci_hcd_s5pv210_drv_suspend,

.resume = ohci_hcd_s5pv210_drv_resume,

.driver = {

.name = "s5p-ohci",

.owner = THIS_MODULE,

}

};

 

MODULE_ALIAS("platform:s5p-ohci");

 

 

drivers\usb\host\ehci-hcd.c

 

#ifdef CONFIG_USB_EHCI_S5PV210

#include "ehci-s5pv210.c"

#define PLATFORM_DRIVER ehci_hcd_s5pv210_driver

#endif

 

 

drivers\usb\host\ohci-hcd.c

 

#ifdef CONFIG_USB_OHCI_S5PV210

#include "ohci-s5pv210.c"

#define PLATFORM_DRIVER ohci_hcd_s5pv210_driver

#endif

 

drivers\usb\host\Kconfig

 

config USB_EHCI_S5PV210

       tristate "S5PV210 support for Samsung S5P SoC Series"

       depends on PLAT_S5P

       help

Enable support for the Samsung S5PV210 SOC's on-chip EHCI controller.

 

config USB_OHCI_S5PV210

tristate "OHCI support for Samsung S5PV210 SoC Series"

depends on PLAT_S5P

help

 Enable support for the Samsung S5PV210 SOC's on-chip OHCI controller.

你可能感兴趣的:(S5PV210 LINUX-3.15.4 USB HOST)