diff options
author | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
---|---|---|
committer | codeworkx <daniel.hillenbrand@codeworkx.de> | 2012-06-02 13:09:29 +0200 |
commit | c6da2cfeb05178a11c6d062a06f8078150ee492f (patch) | |
tree | f3b4021d252c52d6463a9b3c1bb7245e399b009c /arch/arm/mach-exynos/u1-otg.c | |
parent | c6d7c4dbff353eac7919342ae6b3299a378160a6 (diff) | |
download | kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.zip kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.gz kernel_samsung_smdk4412-c6da2cfeb05178a11c6d062a06f8078150ee492f.tar.bz2 |
samsung update 1
Diffstat (limited to 'arch/arm/mach-exynos/u1-otg.c')
-rw-r--r-- | arch/arm/mach-exynos/u1-otg.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/arch/arm/mach-exynos/u1-otg.c b/arch/arm/mach-exynos/u1-otg.c new file mode 100644 index 0000000..a70c69d --- /dev/null +++ b/arch/arm/mach-exynos/u1-otg.c @@ -0,0 +1,218 @@ + +#include <mach/regs-usb-phy.h> +#include "../../../drivers/usb/gadget/s3c_udc.h" +#include <plat/s5p-otghost.h> +#include <plat/usb-phy.h> + +#define PHY_ENABLE (1 << 0) +#define PHY_DISABLE (0) + +static int usb_status; +static u64 s3c_device_usb_otghcd_dmamask = 0xffffffffUL; + +#ifdef USE_S3C_OTG_PHY +static int c210_otg_host_phy_init(int mode) +{ + struct clk *otg_clk; + u32 value; + int err; + + otg_clk = clk_get(NULL, "usbotg"); + if (IS_ERR(otg_clk)) { + pr_err("otg: Failed to get otg clock\n"); + return PTR_ERR(otg_clk); + } + + err = clk_enable(otg_clk); + if (err) { + pr_err("otg: Failed to enable otg clock\n"); + clk_put(otg_clk); + return err; + } + + writel(PHY_ENABLE, S5P_USBOTG_PHY_CONTROL); + + value = readl(EXYNOS4_PHYCLK) & (~(1<<4) | (7<<0)); + pr_info("otg : phy clk 0x%x\n", value); + writel(value, EXYNOS4_PHYCLK); + + value = readl(EXYNOS4_PHYPWR) & (~(7<<3) & ~(1<<0)); + pr_info("otg : phy pwr 0x%x\n", value); + writel(value, EXYNOS4_PHYPWR); + + value = readl(EXYNOS4_RSTCON) & (~(3<<1) | (1<<0)); + writel(value, EXYNOS4_RSTCON); + udelay(10); + value &= ~(7<<0); + writel(value, EXYNOS4_RSTCON); + + clk_put(otg_clk); + + return 0; +} + +static int c210_otg_host_phy_exit(int mode) +{ + struct clk *otg_clk; + + otg_clk = clk_get(NULL, "usbotg"); + if (IS_ERR(otg_clk)) { + pr_err("otg: Failed to get otg clock\n"); + return PTR_ERR(otg_clk); + } + + writel((readl(EXYNOS4_PHYPWR) | PHY0_NORMAL_MASK), + EXYNOS4_PHYPWR); + + writel(PHY_DISABLE, S5P_USBOTG_PHY_CONTROL); + + clk_disable(otg_clk); + clk_put(otg_clk); + + return 0; +} +#else +static int c210_otg_host_phy_init(int mode) +{ + s5p_usb_phy_init(&s3c_device_usbgadget, S5P_USB_PHY_OTGHOST); + return 0; +} +static int c210_otg_host_phy_exit(int mode) +{ + s5p_usb_phy_exit(&s3c_device_usbgadget, S5P_USB_PHY_OTGHOST); + return 0; +} +#endif + +static void c210_host_notify_cb(int mode) +{ + pr_info("otg host_notify : %d\n", mode); + host_state_notify(&host_notifier_pdata.ndev, mode); +} + +static struct sec_otghost_data otghost_data = { + .clk_usage = 0, + .set_pwr_cb = usb_otg_accessory_power, + .sec_whlist_table_num = 1, + .start = 0, + .stop = 0, + + .phy_init = c210_otg_host_phy_init, + .phy_exit = c210_otg_host_phy_exit, + .host_notify_cb = c210_host_notify_cb, +}; + +static struct resource s3c_usb_otghcd_resource[] = { + [0] = { + .start = S5P_PA_HSOTG, + .end = S5P_PA_HSOTG + SZ_4K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_USB_HSOTG, + .end = IRQ_USB_HSOTG, + .flags = IORESOURCE_IRQ, + } +}; + +static struct platform_device s3c_device_usb_otghcd = { + .name = "s3c_otghcd", + .id = -1, + .num_resources = ARRAY_SIZE(s3c_usb_otghcd_resource), + .resource = s3c_usb_otghcd_resource, + .dev = { + .platform_data = &otghost_data, + .dma_mask = &s3c_device_usb_otghcd_dmamask, + .coherent_dma_mask = 0xffffffffUL, + } +}; + +static char *get_usb_cable_string(int mode) +{ + switch (mode) { + case USB_CABLE_DETACHED: return "USB Cable Detached"; + case USB_CABLE_ATTACHED: return "USB Cable Attached"; + case USB_OTGHOST_ATTACHED: return "Host Attached"; + case USB_OTGHOST_DETACHED: return "Host Detached"; + case USB_CABLE_DETACHED_WITHOUT_NOTI: + return "USB Cable Detached without noti"; + default: return "Unknown cable state"; + } +} + + +static void c210_otghost_start(struct s3c_udc *dev) +{ + host_notifier_pdata.ndev.mode = NOTIFY_HOST_MODE; + host_state_notify(&host_notifier_pdata.ndev, NOTIFY_HOST_ADD); + + pr_info("otg start: udc %p, regs %p\n", dev, dev->regs); + free_irq(IRQ_USB_HSOTG, dev); + + if (otghost_data.start) + otghost_data.start((u32)dev->regs); +} + +static int c210_otghost_stop(struct s3c_udc *dev) +{ + struct s5p_usbgadget_platdata *pdata; + int ret = 0; + + host_notifier_pdata.ndev.mode = NOTIFY_NONE_MODE; + host_state_notify(&host_notifier_pdata.ndev, NOTIFY_HOST_REMOVE); + + if (otghost_data.stop) + otghost_data.stop(); + + pdata = (struct s5p_usbgadget_platdata *) + s3c_device_usbgadget.dev.platform_data; + + pr_info("otg pdata %p, irq_cb %p, irq %p\n", + pdata, &pdata->udc_irq, pdata->udc_irq); + + if (pdata && pdata->udc_irq) { + pr_info("otg request_irq irq %p, dev %p\n", + pdata->udc_irq, dev); + + ret = request_irq(IRQ_USB_HSOTG, + pdata->udc_irq, 0, "s3c-udc", dev); + if (ret != 0) { + pr_info("otg host - can't get irq %i, err %d\n", + IRQ_USB_HSOTG, ret); + return -1; + } + } + + return ret; +} + +static int c210_change_usb_mode(struct s3c_udc *dev, int mode) +{ + pr_info("otg change mode : %s --> %s (%d --> %d) %s\n", + get_usb_cable_string(usb_status), + get_usb_cable_string(mode), + usb_status, mode, + dev->udc_enabled ? "enabled" : "disabled" + ); + + switch (mode) { + case USB_CABLE_DETACHED: + if (dev->udc_enabled) + usb_gadget_vbus_disconnect(&dev->gadget); + break; + case USB_CABLE_ATTACHED: + if (!dev->udc_enabled) + usb_gadget_vbus_connect(&dev->gadget); + break; + case USB_OTGHOST_ATTACHED: + c210_otghost_start(dev); + break; + + case USB_OTGHOST_DETACHED: + c210_otghost_stop(dev); + break; + } + usb_status = mode; + return 0; +} + |