mirror of https://gitee.com/openkylin/linux.git
Merge branch 'musb-hw' of git://gitorious.org/usb/usb into musb
* 'musb-hw' of git://gitorious.org/usb/usb: (43 commits) usb: musb: core: kill unneeded #include's DA8xx: assign name to MUSB IRQ resource arm: OMAP4430: musb: Configure musb to OTG mode usb: musb: Adding musb support for OMAP4430 usb: otg: TWL6030: Add twl6030_usb file for compilation mfd: TWL6030: OMAP4: Registering the TWL6030-usb device usb: musb: TWL6030: Selecting TWL6030_USB transceiver usb: otg: Kconfig: Add Kconfig option for TWL6030 transceiver. usb: otg: Adding twl6030-usb transceiver driver for OMAP4430 mfd: TWL6030: USBOTG VBUS event generation on usb: musb: add support for ux500 platform musb: am35x: fix compile error due to control apis arm: omap4: enable usb on 4430sdp usb: musb: drop board_set_vbus usb: musb: drop musb_platform_suspend/resume usb: musb: blackfin: usb dev_pm_ops structure usb: musb: am35x: usb dev_pm_ops structure usb: musb: omap2430: use dev_pm_ops structure usb: musb: omap2430: drop the nops usb: musb: mark musb_save/restore_context static ...
This commit is contained in:
commit
5cdc5bd8b2
|
@ -76,7 +76,7 @@ static struct resource usb_resources[] = {
|
|||
static u64 usb_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device usb_dev = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-davinci",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.platform_data = &usb_data,
|
||||
|
@ -112,6 +112,7 @@ static struct resource da8xx_usb20_resources[] = {
|
|||
{
|
||||
.start = IRQ_DA8XX_USB_INT,
|
||||
.flags = IORESOURCE_IRQ,
|
||||
.name = "mc",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -123,6 +124,7 @@ int __init da8xx_register_usb20(unsigned mA, unsigned potpgt)
|
|||
|
||||
usb_dev.resource = da8xx_usb20_resources;
|
||||
usb_dev.num_resources = ARRAY_SIZE(da8xx_usb20_resources);
|
||||
usb_dev.name = "musb-da8xx";
|
||||
|
||||
return platform_device_register(&usb_dev);
|
||||
}
|
||||
|
|
|
@ -168,9 +168,11 @@ obj-$(CONFIG_MACH_IGEP0030) += board-igep0030.o \
|
|||
obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK) += board-omap3touchbook.o \
|
||||
hsmmc.o
|
||||
obj-$(CONFIG_MACH_OMAP_4430SDP) += board-4430sdp.o \
|
||||
hsmmc.o
|
||||
hsmmc.o \
|
||||
omap_phy_internal.o
|
||||
obj-$(CONFIG_MACH_OMAP4_PANDA) += board-omap4panda.o \
|
||||
hsmmc.o
|
||||
hsmmc.o \
|
||||
omap_phy_internal.o
|
||||
|
||||
obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
|
||||
|
||||
|
|
|
@ -238,10 +238,17 @@ static const struct ehci_hcd_omap_platform_data ehci_pdata __initconst = {
|
|||
|
||||
static struct omap_musb_board_data musb_board_data = {
|
||||
.interface_type = MUSB_INTERFACE_UTMI,
|
||||
.mode = MUSB_PERIPHERAL,
|
||||
.mode = MUSB_OTG,
|
||||
.power = 100,
|
||||
};
|
||||
|
||||
static struct twl4030_usb_data omap4_usbphy_data = {
|
||||
.phy_init = omap4430_phy_init,
|
||||
.phy_exit = omap4430_phy_exit,
|
||||
.phy_power = omap4430_phy_power,
|
||||
.phy_set_clock = omap4430_phy_set_clk,
|
||||
};
|
||||
|
||||
static struct omap2_hsmmc_info mmc[] = {
|
||||
{
|
||||
.mmc = 1,
|
||||
|
@ -461,6 +468,7 @@ static struct twl4030_platform_data sdp4430_twldata = {
|
|||
.vaux1 = &sdp4430_vaux1,
|
||||
.vaux2 = &sdp4430_vaux2,
|
||||
.vaux3 = &sdp4430_vaux3,
|
||||
.usb = &omap4_usbphy_data
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata sdp4430_i2c_boardinfo[] = {
|
||||
|
@ -533,12 +541,7 @@ static void __init omap_4430sdp_init(void)
|
|||
gpio_direction_output(OMAP4SDP_MDM_PWR_EN_GPIO, 1);
|
||||
}
|
||||
usb_ehci_init(&ehci_pdata);
|
||||
|
||||
/* OMAP4 SDP uses internal transceiver so register nop transceiver */
|
||||
usb_nop_xceiv_register();
|
||||
/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
|
||||
if (!cpu_is_omap44xx())
|
||||
usb_musb_init(&musb_board_data);
|
||||
usb_musb_init(&musb_board_data);
|
||||
|
||||
status = omap_ethernet_init();
|
||||
if (status) {
|
||||
|
|
|
@ -46,8 +46,7 @@ static struct device *mmc_device;
|
|||
#define TUSB6010_GPIO_ENABLE 0
|
||||
#define TUSB6010_DMACHAN 0x3f
|
||||
|
||||
#if defined(CONFIG_USB_TUSB6010) || \
|
||||
defined(CONFIG_USB_TUSB6010_MODULE)
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
/*
|
||||
* Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
|
||||
* 1.5 V voltage regulators of PM companion chip. Companion chip will then
|
||||
|
@ -134,7 +133,7 @@ static void __init n8x0_usb_init(void)
|
|||
|
||||
static void __init n8x0_usb_init(void) {}
|
||||
|
||||
#endif /*CONFIG_USB_TUSB6010 */
|
||||
#endif /*CONFIG_USB_MUSB_TUSB6010 */
|
||||
|
||||
|
||||
static struct omap2_mcspi_device_config p54spi_mcspi_config = {
|
||||
|
|
|
@ -133,10 +133,17 @@ static void __init omap4_ehci_init(void)
|
|||
|
||||
static struct omap_musb_board_data musb_board_data = {
|
||||
.interface_type = MUSB_INTERFACE_UTMI,
|
||||
.mode = MUSB_PERIPHERAL,
|
||||
.mode = MUSB_OTG,
|
||||
.power = 100,
|
||||
};
|
||||
|
||||
static struct twl4030_usb_data omap4_usbphy_data = {
|
||||
.phy_init = omap4430_phy_init,
|
||||
.phy_exit = omap4430_phy_exit,
|
||||
.phy_power = omap4430_phy_power,
|
||||
.phy_set_clock = omap4430_phy_set_clk,
|
||||
};
|
||||
|
||||
static struct omap2_hsmmc_info mmc[] = {
|
||||
{
|
||||
.mmc = 1,
|
||||
|
@ -345,6 +352,7 @@ static struct twl4030_platform_data omap4_panda_twldata = {
|
|||
.vaux1 = &omap4_panda_vaux1,
|
||||
.vaux2 = &omap4_panda_vaux2,
|
||||
.vaux3 = &omap4_panda_vaux3,
|
||||
.usb = &omap4_usbphy_data,
|
||||
};
|
||||
|
||||
static struct i2c_board_info __initdata omap4_panda_i2c_boardinfo[] = {
|
||||
|
@ -377,9 +385,7 @@ static void __init omap4_panda_init(void)
|
|||
/* OMAP4 Panda uses internal transceiver so register nop transceiver */
|
||||
usb_nop_xceiv_register();
|
||||
omap4_ehci_init();
|
||||
/* FIXME: allow multi-omap to boot until musb is updated for omap4 */
|
||||
if (!cpu_is_omap44xx())
|
||||
usb_musb_init(&musb_board_data);
|
||||
usb_musb_init(&musb_board_data);
|
||||
}
|
||||
|
||||
static void __init omap4_panda_map_io(void)
|
||||
|
|
|
@ -1877,7 +1877,7 @@ static struct omap_clk omap2420_clks[] = {
|
|||
CLK("omap-aes", "ick", &aes_ick, CK_242X),
|
||||
CLK(NULL, "pka_ick", &pka_ick, CK_242X),
|
||||
CLK(NULL, "usb_fck", &usb_fck, CK_242X),
|
||||
CLK("musb_hdrc", "fck", &osc_ck, CK_242X),
|
||||
CLK("musb-hdrc", "fck", &osc_ck, CK_242X),
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -1983,7 +1983,7 @@ static struct omap_clk omap2430_clks[] = {
|
|||
CLK("omap-aes", "ick", &aes_ick, CK_243X),
|
||||
CLK(NULL, "pka_ick", &pka_ick, CK_243X),
|
||||
CLK(NULL, "usb_fck", &usb_fck, CK_243X),
|
||||
CLK("musb_hdrc", "ick", &usbhs_ick, CK_243X),
|
||||
CLK("musb-omap2430", "ick", &usbhs_ick, CK_243X),
|
||||
CLK("mmci-omap-hs.0", "ick", &mmchs1_ick, CK_243X),
|
||||
CLK("mmci-omap-hs.0", "fck", &mmchs1_fck, CK_243X),
|
||||
CLK("mmci-omap-hs.1", "ick", &mmchs2_ick, CK_243X),
|
||||
|
|
|
@ -3306,8 +3306,8 @@ static struct omap_clk omap3xxx_clks[] = {
|
|||
CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1, CK_3430ES1),
|
||||
CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2, CK_3430ES2),
|
||||
CLK(NULL, "core_l3_ick", &core_l3_ick, CK_3XXX),
|
||||
CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es1, CK_3430ES1),
|
||||
CLK("musb_hdrc", "ick", &hsotgusb_ick_3430es2, CK_3430ES2),
|
||||
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1, CK_3430ES1),
|
||||
CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2, CK_3430ES2),
|
||||
CLK(NULL, "sdrc_ick", &sdrc_ick, CK_3XXX),
|
||||
CLK(NULL, "gpmc_fck", &gpmc_fck, CK_3XXX),
|
||||
CLK(NULL, "security_l3_ick", &security_l3_ick, CK_343X),
|
||||
|
@ -3442,8 +3442,8 @@ static struct omap_clk omap3xxx_clks[] = {
|
|||
CLK("davinci_emac", "phy_clk", &emac_fck, CK_AM35XX),
|
||||
CLK("vpfe-capture", "master", &vpfe_ick, CK_AM35XX),
|
||||
CLK("vpfe-capture", "slave", &vpfe_fck, CK_AM35XX),
|
||||
CLK("musb_hdrc", "ick", &hsotgusb_ick_am35xx, CK_AM35XX),
|
||||
CLK("musb_hdrc", "fck", &hsotgusb_fck_am35xx, CK_AM35XX),
|
||||
CLK("musb-am35x", "ick", &hsotgusb_ick_am35xx, CK_AM35XX),
|
||||
CLK("musb-am35x", "fck", &hsotgusb_fck_am35xx, CK_AM35XX),
|
||||
CLK(NULL, "hecc_ck", &hecc_ck, CK_AM35XX),
|
||||
CLK(NULL, "uart4_ick", &uart4_ick_am35xx, CK_AM35XX),
|
||||
};
|
||||
|
|
|
@ -2953,7 +2953,7 @@ static struct omap_clk omap44xx_clks[] = {
|
|||
CLK("ehci-omap.0", "usbhost_ick", &dummy_ck, CK_443X),
|
||||
CLK(NULL, "otg_60m_gfclk", &otg_60m_gfclk, CK_443X),
|
||||
CLK(NULL, "usb_otg_hs_xclk", &usb_otg_hs_xclk, CK_443X),
|
||||
CLK("musb_hdrc", "ick", &usb_otg_hs_ick, CK_443X),
|
||||
CLK("musb-omap2430", "ick", &usb_otg_hs_ick, CK_443X),
|
||||
CLK(NULL, "usb_phy_cm_clk32k", &usb_phy_cm_clk32k, CK_443X),
|
||||
CLK(NULL, "usb_tll_hs_usb_ch2_clk", &usb_tll_hs_usb_ch2_clk, CK_443X),
|
||||
CLK(NULL, "usb_tll_hs_usb_ch0_clk", &usb_tll_hs_usb_ch0_clk, CK_443X),
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* This file configures the internal USB PHY in OMAP4430. Used
|
||||
* with TWL6030 transceiver and MUSB on OMAP4430.
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
|
||||
* 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.
|
||||
*
|
||||
* Author: Hema HK <hemahk@ti.com>
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <plat/usb.h>
|
||||
|
||||
/* OMAP control module register for UTMI PHY */
|
||||
#define CONTROL_DEV_CONF 0x300
|
||||
#define PHY_PD 0x1
|
||||
|
||||
#define USBOTGHS_CONTROL 0x33c
|
||||
#define AVALID BIT(0)
|
||||
#define BVALID BIT(1)
|
||||
#define VBUSVALID BIT(2)
|
||||
#define SESSEND BIT(3)
|
||||
#define IDDIG BIT(4)
|
||||
|
||||
static struct clk *phyclk, *clk48m, *clk32k;
|
||||
static void __iomem *ctrl_base;
|
||||
|
||||
int omap4430_phy_init(struct device *dev)
|
||||
{
|
||||
ctrl_base = ioremap(OMAP443X_SCM_BASE, SZ_1K);
|
||||
if (!ctrl_base) {
|
||||
dev_err(dev, "control module ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
/* Power down the phy */
|
||||
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
|
||||
phyclk = clk_get(dev, "ocp2scp_usb_phy_ick");
|
||||
|
||||
if (IS_ERR(phyclk)) {
|
||||
dev_err(dev, "cannot clk_get ocp2scp_usb_phy_ick\n");
|
||||
iounmap(ctrl_base);
|
||||
return PTR_ERR(phyclk);
|
||||
}
|
||||
|
||||
clk48m = clk_get(dev, "ocp2scp_usb_phy_phy_48m");
|
||||
if (IS_ERR(clk48m)) {
|
||||
dev_err(dev, "cannot clk_get ocp2scp_usb_phy_phy_48m\n");
|
||||
clk_put(phyclk);
|
||||
iounmap(ctrl_base);
|
||||
return PTR_ERR(clk48m);
|
||||
}
|
||||
|
||||
clk32k = clk_get(dev, "usb_phy_cm_clk32k");
|
||||
if (IS_ERR(clk32k)) {
|
||||
dev_err(dev, "cannot clk_get usb_phy_cm_clk32k\n");
|
||||
clk_put(phyclk);
|
||||
clk_put(clk48m);
|
||||
iounmap(ctrl_base);
|
||||
return PTR_ERR(clk32k);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap4430_phy_set_clk(struct device *dev, int on)
|
||||
{
|
||||
static int state;
|
||||
|
||||
if (on && !state) {
|
||||
/* Enable the phy clocks */
|
||||
clk_enable(phyclk);
|
||||
clk_enable(clk48m);
|
||||
clk_enable(clk32k);
|
||||
state = 1;
|
||||
} else if (state) {
|
||||
/* Disable the phy clocks */
|
||||
clk_disable(phyclk);
|
||||
clk_disable(clk48m);
|
||||
clk_disable(clk32k);
|
||||
state = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap4430_phy_power(struct device *dev, int ID, int on)
|
||||
{
|
||||
if (on) {
|
||||
/* enabled the clocks */
|
||||
omap4430_phy_set_clk(dev, 1);
|
||||
/* power on the phy */
|
||||
if (__raw_readl(ctrl_base + CONTROL_DEV_CONF) & PHY_PD) {
|
||||
__raw_writel(~PHY_PD, ctrl_base + CONTROL_DEV_CONF);
|
||||
mdelay(200);
|
||||
}
|
||||
if (ID)
|
||||
/* enable VBUS valid, IDDIG groung */
|
||||
__raw_writel(AVALID | VBUSVALID, ctrl_base +
|
||||
USBOTGHS_CONTROL);
|
||||
else
|
||||
/*
|
||||
* Enable VBUS Valid, AValid and IDDIG
|
||||
* high impedence
|
||||
*/
|
||||
__raw_writel(IDDIG | AVALID | VBUSVALID,
|
||||
ctrl_base + USBOTGHS_CONTROL);
|
||||
} else {
|
||||
/* Enable session END and IDIG to high impedence. */
|
||||
__raw_writel(SESSEND | IDDIG, ctrl_base +
|
||||
USBOTGHS_CONTROL);
|
||||
/* Disable the clocks */
|
||||
omap4430_phy_set_clk(dev, 0);
|
||||
/* Power down the phy */
|
||||
__raw_writel(PHY_PD, ctrl_base + CONTROL_DEV_CONF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int omap4430_phy_exit(struct device *dev)
|
||||
{
|
||||
if (ctrl_base)
|
||||
iounmap(ctrl_base);
|
||||
if (phyclk)
|
||||
clk_put(phyclk);
|
||||
if (clk48m)
|
||||
clk_put(clk48m);
|
||||
if (clk32k)
|
||||
clk_put(clk32k);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -30,8 +30,101 @@
|
|||
#include <mach/irqs.h>
|
||||
#include <mach/am35xx.h>
|
||||
#include <plat/usb.h>
|
||||
#include "control.h"
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_SOC
|
||||
#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
|
||||
|
||||
static void am35x_musb_reset(void)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
/* Reset the musb interface */
|
||||
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
regval |= AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
regval &= ~AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(regval, AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
regval = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
|
||||
}
|
||||
|
||||
static void am35x_musb_phy_power(u8 on)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(100);
|
||||
u32 devconf2;
|
||||
|
||||
if (on) {
|
||||
/*
|
||||
* Start the on-chip PHY and its PLL.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
|
||||
devconf2 |= CONF2_PHY_PLLON;
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
pr_info(KERN_INFO "Waiting for PHY clock good...\n");
|
||||
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
|
||||
& CONF2_PHYCLKGD)) {
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
pr_err(KERN_ERR "musb PHY clock good timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Power down the on-chip PHY.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~CONF2_PHY_PLLON;
|
||||
devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
}
|
||||
}
|
||||
|
||||
static void am35x_musb_clear_irq(void)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
regval |= AM35XX_USBOTGSS_INT_CLR;
|
||||
omap_ctrl_writel(regval, AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
regval = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
}
|
||||
|
||||
static void am35x_musb_set_mode(u8 musb_mode)
|
||||
{
|
||||
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~CONF2_OTGMODE;
|
||||
switch (musb_mode) {
|
||||
#ifdef CONFIG_USB_MUSB_HDRC_HCD
|
||||
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
|
||||
devconf2 |= CONF2_FORCE_HOST;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
|
||||
devconf2 |= CONF2_FORCE_DEVICE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_MUSB_OTG
|
||||
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
|
||||
devconf2 |= CONF2_NO_OVERRIDE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
|
||||
}
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
}
|
||||
|
||||
static struct resource musb_resources[] = {
|
||||
[0] = { /* start and end set dynamically */
|
||||
|
@ -77,7 +170,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-omap2430",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
@ -93,8 +186,13 @@ void __init usb_musb_init(struct omap_musb_board_data *board_data)
|
|||
if (cpu_is_omap243x()) {
|
||||
musb_resources[0].start = OMAP243X_HS_BASE;
|
||||
} else if (cpu_is_omap3517() || cpu_is_omap3505()) {
|
||||
musb_device.name = "musb-am35x";
|
||||
musb_resources[0].start = AM35XX_IPSS_USBOTGSS_BASE;
|
||||
musb_resources[1].start = INT_35XX_USBOTG_IRQ;
|
||||
board_data->set_phy_power = am35x_musb_phy_power;
|
||||
board_data->clear_irq = am35x_musb_clear_irq;
|
||||
board_data->set_mode = am35x_musb_set_mode;
|
||||
board_data->reset = am35x_musb_reset;
|
||||
} else if (cpu_is_omap34xx()) {
|
||||
musb_resources[0].start = OMAP34XX_HSUSB_OTG_BASE;
|
||||
} else if (cpu_is_omap44xx()) {
|
||||
|
|
|
@ -223,7 +223,7 @@ static struct resource tusb_resources[] = {
|
|||
static u64 tusb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device tusb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-tusb",
|
||||
.id = -1,
|
||||
.dev = {
|
||||
.dma_mask = &tusb_dmamask,
|
||||
|
|
|
@ -70,6 +70,10 @@ struct omap_musb_board_data {
|
|||
u8 mode;
|
||||
u16 power;
|
||||
unsigned extvbus:1;
|
||||
void (*set_phy_power)(u8 on);
|
||||
void (*clear_irq)(void);
|
||||
void (*set_mode)(u8 mode);
|
||||
void (*reset)(void);
|
||||
};
|
||||
|
||||
enum musb_interface {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
|
||||
|
@ -80,6 +84,11 @@ extern void usb_ehci_init(const struct ehci_hcd_omap_platform_data *pdata);
|
|||
|
||||
extern void usb_ohci_init(const struct ohci_hcd_omap_platform_data *pdata);
|
||||
|
||||
extern int omap4430_phy_power(struct device *dev, int ID, int on);
|
||||
extern int omap4430_phy_set_clk(struct device *dev, int on);
|
||||
extern int omap4430_phy_init(struct device *dev);
|
||||
extern int omap4430_phy_exit(struct device *dev);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -120,7 +120,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -84,7 +84,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -124,7 +124,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -91,7 +91,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -520,7 +520,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -625,7 +625,7 @@ static struct musb_hdrc_platform_data musb_plat = {
|
|||
static u64 musb_dmamask = ~(u32)0;
|
||||
|
||||
static struct platform_device musb_device = {
|
||||
.name = "musb_hdrc",
|
||||
.name = "musb-blackfin",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.dma_mask = &musb_dmamask,
|
||||
|
|
|
@ -95,7 +95,8 @@
|
|||
#define twl_has_rtc() false
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
|
||||
#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
|
||||
defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
|
||||
#define twl_has_usb() true
|
||||
#else
|
||||
#define twl_has_usb() false
|
||||
|
@ -682,6 +683,43 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
|||
usb3v1.dev = child;
|
||||
}
|
||||
}
|
||||
if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
|
||||
|
||||
static struct regulator_consumer_supply usb3v3 = {
|
||||
.supply = "vusb",
|
||||
};
|
||||
|
||||
if (twl_has_regulator()) {
|
||||
/* this is a template that gets copied */
|
||||
struct regulator_init_data usb_fixed = {
|
||||
.constraints.valid_modes_mask =
|
||||
REGULATOR_MODE_NORMAL
|
||||
| REGULATOR_MODE_STANDBY,
|
||||
.constraints.valid_ops_mask =
|
||||
REGULATOR_CHANGE_MODE
|
||||
| REGULATOR_CHANGE_STATUS,
|
||||
};
|
||||
|
||||
child = add_regulator_linked(TWL6030_REG_VUSB,
|
||||
&usb_fixed, &usb3v3, 1);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
}
|
||||
|
||||
child = add_child(0, "twl6030_usb",
|
||||
pdata->usb, sizeof(*pdata->usb),
|
||||
true,
|
||||
/* irq1 = VBUS_PRES, irq0 = USB ID */
|
||||
pdata->irq_base + USBOTG_INTR_OFFSET,
|
||||
pdata->irq_base + USB_PRES_INTR_OFFSET);
|
||||
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
/* we need to connect regulators to this transceiver */
|
||||
if (twl_has_regulator() && child)
|
||||
usb3v3.dev = child;
|
||||
|
||||
}
|
||||
|
||||
if (twl_has_watchdog()) {
|
||||
child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
|
||||
|
@ -815,10 +853,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
|
|||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VUSB, pdata->vusb);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
||||
child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1);
|
||||
if (IS_ERR(child))
|
||||
return PTR_ERR(child);
|
||||
|
|
|
@ -74,7 +74,7 @@ static int twl6030_interrupt_mapping[24] = {
|
|||
USBOTG_INTR_OFFSET, /* Bit 16 ID_WKUP */
|
||||
USBOTG_INTR_OFFSET, /* Bit 17 VBUS_WKUP */
|
||||
USBOTG_INTR_OFFSET, /* Bit 18 ID */
|
||||
USBOTG_INTR_OFFSET, /* Bit 19 VBUS */
|
||||
USB_PRES_INTR_OFFSET, /* Bit 19 VBUS */
|
||||
CHARGER_INTR_OFFSET, /* Bit 20 CHRG_CTRL */
|
||||
CHARGER_INTR_OFFSET, /* Bit 21 EXT_CHRG */
|
||||
CHARGER_INTR_OFFSET, /* Bit 22 INT_CHRG */
|
||||
|
@ -128,6 +128,13 @@ static int twl6030_irq_thread(void *data)
|
|||
|
||||
sts.bytes[3] = 0; /* Only 24 bits are valid*/
|
||||
|
||||
/*
|
||||
* Since VBUS status bit is not reliable for VBUS disconnect
|
||||
* use CHARGER VBUS detection status bit instead.
|
||||
*/
|
||||
if (sts.bytes[2] & 0x10)
|
||||
sts.bytes[2] |= 0x08;
|
||||
|
||||
for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
|
||||
local_irq_disable();
|
||||
if (sts.int_sts & 0x1) {
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
|
||||
/* Mentor high speed "dual role" controller, in peripheral role */
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musb_hdrc", (g)->name)
|
||||
#define gadget_is_musbhdrc(g) !strcmp("musb-hdrc", (g)->name)
|
||||
#else
|
||||
#define gadget_is_musbhdrc(g) 0
|
||||
#endif
|
||||
|
|
|
@ -12,6 +12,7 @@ config USB_MUSB_HDRC
|
|||
depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
|
||||
select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
|
||||
select TWL4030_USB if MACH_OMAP_3430SDP
|
||||
select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
|
||||
select USB_OTG_UTILS
|
||||
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
|
||||
help
|
||||
|
@ -30,57 +31,41 @@ config USB_MUSB_HDRC
|
|||
If you do not know what this is, please say N.
|
||||
|
||||
To compile this driver as a module, choose M here; the
|
||||
module will be called "musb_hdrc".
|
||||
module will be called "musb-hdrc".
|
||||
|
||||
config USB_MUSB_SOC
|
||||
boolean
|
||||
choice
|
||||
prompt "Platform Glue Layer"
|
||||
depends on USB_MUSB_HDRC
|
||||
default y if ARCH_DAVINCI
|
||||
default y if ARCH_OMAP2430
|
||||
default y if ARCH_OMAP3
|
||||
default y if ARCH_OMAP4
|
||||
default y if (BF54x && !BF544)
|
||||
default y if (BF52x && !BF522 && !BF523)
|
||||
|
||||
comment "DaVinci 35x and 644x USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx
|
||||
config USB_MUSB_DAVINCI
|
||||
bool "DaVinci"
|
||||
depends on ARCH_DAVINCI_DMx
|
||||
|
||||
comment "DA8xx/OMAP-L1x USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DA8XX
|
||||
config USB_MUSB_DA8XX
|
||||
bool "DA8xx/OMAP-L1x"
|
||||
depends on ARCH_DAVINCI_DA8XX
|
||||
|
||||
comment "OMAP 243x high speed USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_OMAP2430
|
||||
config USB_MUSB_TUSB6010
|
||||
bool "TUSB6010"
|
||||
depends on ARCH_OMAP
|
||||
|
||||
comment "OMAP 343x high speed USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_OMAP3
|
||||
|
||||
comment "OMAP 44xx high speed USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_OMAP4
|
||||
|
||||
comment "Blackfin high speed USB Support"
|
||||
depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
|
||||
config USB_MUSB_OMAP2PLUS
|
||||
bool "OMAP2430 and onwards"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
|
||||
config USB_MUSB_AM35X
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4
|
||||
select NOP_USB_XCEIV
|
||||
default MACH_OMAP3517EVM
|
||||
help
|
||||
Select this option if your platform is based on AM35x. As
|
||||
AM35x has an updated MUSB with CPPI4.1 DMA so this config
|
||||
is introduced to differentiate musb ip between OMAP3x and
|
||||
AM35x platforms.
|
||||
bool "AM35x"
|
||||
depends on ARCH_OMAP
|
||||
|
||||
config USB_TUSB6010
|
||||
boolean "TUSB 6010 support"
|
||||
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
|
||||
select NOP_USB_XCEIV
|
||||
default y
|
||||
help
|
||||
The TUSB 6010 chip, from Texas Instruments, connects a discrete
|
||||
HDRC core using a 16-bit parallel bus (NOR flash style) or VLYNQ
|
||||
(a high speed serial link). It can use system-specific external
|
||||
DMA controllers.
|
||||
config USB_MUSB_BLACKFIN
|
||||
bool "Blackfin"
|
||||
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
|
||||
|
||||
config USB_MUSB_UX500
|
||||
bool "U8500 and U5500"
|
||||
depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500)
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Driver Mode"
|
||||
|
@ -158,7 +143,7 @@ config USB_MUSB_HDRC_HCD
|
|||
config MUSB_PIO_ONLY
|
||||
bool 'Disable DMA (always use PIO)'
|
||||
depends on USB_MUSB_HDRC
|
||||
default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X
|
||||
default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
|
||||
help
|
||||
All data is copied between memory and FIFO by the CPU.
|
||||
DMA controllers are ignored.
|
||||
|
@ -171,21 +156,21 @@ config MUSB_PIO_ONLY
|
|||
config USB_INVENTRA_DMA
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
|
||||
default ARCH_OMAP2430 || ARCH_OMAP3 || BLACKFIN || ARCH_OMAP4
|
||||
default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
|
||||
help
|
||||
Enable DMA transfers using Mentor's engine.
|
||||
|
||||
config USB_TI_CPPI_DMA
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
|
||||
default ARCH_DAVINCI
|
||||
default USB_MUSB_DAVINCI
|
||||
help
|
||||
Enable DMA transfers when TI CPPI DMA is available.
|
||||
|
||||
config USB_TUSB_OMAP_DMA
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
|
||||
depends on USB_TUSB6010
|
||||
depends on USB_MUSB_TUSB6010
|
||||
depends on ARCH_OMAP
|
||||
default y
|
||||
help
|
||||
|
|
|
@ -8,22 +8,19 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
|
|||
|
||||
musb_hdrc-y := musb_core.o
|
||||
|
||||
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx) += davinci.o
|
||||
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o
|
||||
musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o
|
||||
ifeq ($(CONFIG_USB_MUSB_AM35X),y)
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += am35x.o
|
||||
else
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o
|
||||
endif
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o
|
||||
musb_hdrc-$(CONFIG_BF54x) += blackfin.o
|
||||
musb_hdrc-$(CONFIG_BF52x) += blackfin.o
|
||||
musb_hdrc-$(CONFIG_USB_GADGET_MUSB_HDRC) += musb_gadget_ep0.o musb_gadget.o
|
||||
musb_hdrc-$(CONFIG_USB_MUSB_HDRC_HCD) += musb_virthub.o musb_host.o
|
||||
musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
|
||||
|
||||
# Hardware Glue Layer
|
||||
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
|
||||
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
|
||||
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
|
||||
obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o
|
||||
obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o
|
||||
obj-$(CONFIG_USB_MUSB_BLACKFIN) += blackfin.o
|
||||
obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
|
||||
|
||||
# the kconfig must guarantee that only one of the
|
||||
# possible I/O schemes will be enabled at a time ...
|
||||
# PIO only, or DMA (several potential schemes).
|
||||
|
|
|
@ -29,8 +29,9 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <plat/control.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
@ -80,51 +81,18 @@
|
|||
|
||||
#define USB_MENTOR_CORE_OFFSET 0x400
|
||||
|
||||
static inline void phy_on(void)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(100);
|
||||
u32 devconf2;
|
||||
|
||||
/*
|
||||
* Start the on-chip PHY and its PLL.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
|
||||
devconf2 |= CONF2_PHY_PLLON;
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
DBG(1, "Waiting for PHY clock good...\n");
|
||||
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
|
||||
& CONF2_PHYCLKGD)) {
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
DBG(1, "musb PHY clock good timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void phy_off(void)
|
||||
{
|
||||
u32 devconf2;
|
||||
|
||||
/*
|
||||
* Power down the on-chip PHY.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~CONF2_PHY_PLLON;
|
||||
devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
}
|
||||
struct am35x_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *phy_clk;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
/*
|
||||
* musb_platform_enable - enable interrupts
|
||||
* am35x_musb_enable - enable interrupts
|
||||
*/
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
static void am35x_musb_enable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 epmask;
|
||||
|
@ -143,9 +111,9 @@ void musb_platform_enable(struct musb *musb)
|
|||
}
|
||||
|
||||
/*
|
||||
* musb_platform_disable - disable HDRC and flush interrupts
|
||||
* am35x_musb_disable - disable HDRC and flush interrupts
|
||||
*/
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
static void am35x_musb_disable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
||||
|
@ -162,7 +130,7 @@ void musb_platform_disable(struct musb *musb)
|
|||
#define portstate(stmt)
|
||||
#endif
|
||||
|
||||
static void am35x_set_vbus(struct musb *musb, int is_on)
|
||||
static void am35x_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
WARN_ON(is_on && is_peripheral_active(musb));
|
||||
}
|
||||
|
@ -221,7 +189,7 @@ static void otg_timer(unsigned long _musb)
|
|||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
static unsigned long last_timer;
|
||||
|
||||
|
@ -251,13 +219,16 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
|||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
|
||||
static irqreturn_t am35x_interrupt(int irq, void *hci)
|
||||
static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 epintr, usbintr, lvl_intr;
|
||||
u32 epintr, usbintr;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
|
@ -346,9 +317,8 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)
|
|||
/* EOI needs to be written for the IRQ to be re-asserted. */
|
||||
if (ret == IRQ_HANDLED || epintr || usbintr) {
|
||||
/* clear level interrupt */
|
||||
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
|
||||
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
if (data->clear_irq)
|
||||
data->clear_irq();
|
||||
/* write EOI */
|
||||
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
|
||||
}
|
||||
|
@ -362,137 +332,85 @@ static irqreturn_t am35x_interrupt(int irq, void *hci)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
int retval = 0;
|
||||
|
||||
devconf2 &= ~CONF2_OTGMODE;
|
||||
switch (musb_mode) {
|
||||
#ifdef CONFIG_USB_MUSB_HDRC_HCD
|
||||
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
|
||||
devconf2 |= CONF2_FORCE_HOST;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
|
||||
devconf2 |= CONF2_FORCE_DEVICE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_MUSB_OTG
|
||||
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
|
||||
devconf2 |= CONF2_NO_OVERRIDE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
|
||||
}
|
||||
if (data->set_mode)
|
||||
data->set_mode(musb_mode);
|
||||
else
|
||||
retval = -EIO;
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
return 0;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb, void *board_data)
|
||||
static int am35x_musb_init(struct musb *musb)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 rev, lvl_intr, sw_reset;
|
||||
int status;
|
||||
u32 rev;
|
||||
|
||||
musb->mregs += USB_MENTOR_CORE_OFFSET;
|
||||
|
||||
clk_enable(musb->clock);
|
||||
DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock));
|
||||
|
||||
musb->phy_clock = clk_get(musb->controller, "fck");
|
||||
if (IS_ERR(musb->phy_clock)) {
|
||||
status = PTR_ERR(musb->phy_clock);
|
||||
goto exit0;
|
||||
}
|
||||
clk_enable(musb->phy_clock);
|
||||
DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock));
|
||||
|
||||
/* Returns zero if e.g. not clocked */
|
||||
rev = musb_readl(reg_base, USB_REVISION_REG);
|
||||
if (!rev) {
|
||||
status = -ENODEV;
|
||||
goto exit1;
|
||||
}
|
||||
if (!rev)
|
||||
return -ENODEV;
|
||||
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = otg_get_transceiver();
|
||||
if (!musb->xceiv) {
|
||||
status = -ENODEV;
|
||||
goto exit1;
|
||||
}
|
||||
if (!musb->xceiv)
|
||||
return -ENODEV;
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
|
||||
|
||||
musb->board_set_vbus = am35x_set_vbus;
|
||||
|
||||
/* Global reset */
|
||||
sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
sw_reset |= AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
|
||||
/* Reset the musb */
|
||||
if (data->reset)
|
||||
data->reset();
|
||||
|
||||
/* Reset the controller */
|
||||
musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
phy_on();
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
msleep(5);
|
||||
|
||||
musb->isr = am35x_interrupt;
|
||||
musb->isr = am35x_musb_interrupt;
|
||||
|
||||
/* clear level interrupt */
|
||||
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
|
||||
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
if (data->clear_irq)
|
||||
data->clear_irq();
|
||||
|
||||
return 0;
|
||||
exit1:
|
||||
clk_disable(musb->phy_clock);
|
||||
clk_put(musb->phy_clock);
|
||||
exit0:
|
||||
clk_disable(musb->clock);
|
||||
return status;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
static int am35x_musb_exit(struct musb *musb)
|
||||
{
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&otg_workaround);
|
||||
|
||||
phy_off();
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
|
||||
clk_disable(musb->clock);
|
||||
|
||||
clk_disable(musb->phy_clock);
|
||||
clk_put(musb->phy_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void musb_platform_save_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
{
|
||||
phy_off();
|
||||
}
|
||||
|
||||
void musb_platform_restore_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
{
|
||||
phy_on();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* AM35x supports only 32bit read operation */
|
||||
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
|
||||
{
|
||||
|
@ -522,3 +440,215 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
|
|||
memcpy(dst, &val, len);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops am35x_ops = {
|
||||
.init = am35x_musb_init,
|
||||
.exit = am35x_musb_exit,
|
||||
|
||||
.enable = am35x_musb_enable,
|
||||
.disable = am35x_musb_disable,
|
||||
|
||||
.set_mode = am35x_musb_set_mode,
|
||||
.try_idle = am35x_musb_try_idle,
|
||||
|
||||
.set_vbus = am35x_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 am35x_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init am35x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct am35x_glue *glue;
|
||||
|
||||
struct clk *phy_clk;
|
||||
struct clk *clk;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
phy_clk = clk_get(&pdev->dev, "fck");
|
||||
if (IS_ERR(phy_clk)) {
|
||||
dev_err(&pdev->dev, "failed to get PHY clock\n");
|
||||
ret = PTR_ERR(phy_clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err3;
|
||||
}
|
||||
|
||||
ret = clk_enable(phy_clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable PHY clock\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err5;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &am35x_dmamask;
|
||||
musb->dev.coherent_dma_mask = am35x_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->phy_clk = phy_clk;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &am35x_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err6:
|
||||
clk_disable(clk);
|
||||
|
||||
err5:
|
||||
clk_disable(phy_clk);
|
||||
|
||||
err4:
|
||||
clk_put(clk);
|
||||
|
||||
err3:
|
||||
clk_put(phy_clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit am35x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct am35x_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_disable(glue->phy_clk);
|
||||
clk_put(glue->clk);
|
||||
clk_put(glue->phy_clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int am35x_suspend(struct device *dev)
|
||||
{
|
||||
struct am35x_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
||||
/* Shutdown the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(0);
|
||||
|
||||
clk_disable(glue->phy_clk);
|
||||
clk_disable(glue->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int am35x_resume(struct device *dev)
|
||||
{
|
||||
struct am35x_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
int ret;
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
if (data->set_phy_power)
|
||||
data->set_phy_power(1);
|
||||
|
||||
ret = clk_enable(glue->phy_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable PHY clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_enable(glue->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops am35x_pm_ops = {
|
||||
.suspend = am35x_suspend,
|
||||
.resume = am35x_resume,
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS &am35x_pm_ops
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver am35x_driver = {
|
||||
.remove = __exit_p(am35x_remove),
|
||||
.driver = {
|
||||
.name = "musb-am35x",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init am35x_init(void)
|
||||
{
|
||||
return platform_driver_probe(&am35x_driver, am35x_probe);
|
||||
}
|
||||
subsys_initcall(am35x_init);
|
||||
|
||||
static void __exit am35x_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&am35x_driver);
|
||||
}
|
||||
module_exit(am35x_exit);
|
||||
|
|
|
@ -15,12 +15,20 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
#include "blackfin.h"
|
||||
|
||||
struct bfin_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
/*
|
||||
* Load an endpoint's FIFO
|
||||
*/
|
||||
|
@ -277,7 +285,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||
DBG(4, "state is %s\n", otg_state_string(musb));
|
||||
}
|
||||
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
static void bfin_musb_enable(struct musb *musb)
|
||||
{
|
||||
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
|
||||
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||
|
@ -285,11 +293,11 @@ void musb_platform_enable(struct musb *musb)
|
|||
}
|
||||
}
|
||||
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
static void bfin_musb_disable(struct musb *musb)
|
||||
{
|
||||
}
|
||||
|
||||
static void bfin_set_vbus(struct musb *musb, int is_on)
|
||||
static void bfin_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
int value = musb->config->gpio_vrsel_active;
|
||||
if (!is_on)
|
||||
|
@ -302,51 +310,29 @@ static void bfin_set_vbus(struct musb *musb, int is_on)
|
|||
musb_readb(musb->mregs, MUSB_DEVCTL));
|
||||
}
|
||||
|
||||
static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
|
||||
static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
if (!is_otg_enabled(musb) && is_host_enabled(musb))
|
||||
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||
}
|
||||
|
||||
int musb_platform_get_vbus_status(struct musb *musb)
|
||||
static int bfin_musb_get_vbus_status(struct musb *musb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
static int bfin_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb)
|
||||
static void bfin_musb_reg_init(struct musb *musb)
|
||||
{
|
||||
|
||||
/*
|
||||
* Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
|
||||
* and OTG HOST modes, while rev 1.1 and greater require PE7 to
|
||||
* be low for DEVICE mode and high for HOST mode. We set it high
|
||||
* here because we are in host mode
|
||||
*/
|
||||
|
||||
if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
|
||||
printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d \n",
|
||||
musb->config->gpio_vrsel);
|
||||
return -ENODEV;
|
||||
}
|
||||
gpio_direction_output(musb->config->gpio_vrsel, 0);
|
||||
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = otg_get_transceiver();
|
||||
if (!musb->xceiv) {
|
||||
gpio_free(musb->config->gpio_vrsel);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (ANOMALY_05000346) {
|
||||
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
|
||||
SSYNC();
|
||||
|
@ -380,21 +366,47 @@ int __init musb_platform_init(struct musb *musb)
|
|||
EP2_RX_ENA | EP3_RX_ENA | EP4_RX_ENA |
|
||||
EP5_RX_ENA | EP6_RX_ENA | EP7_RX_ENA);
|
||||
SSYNC();
|
||||
}
|
||||
|
||||
static int bfin_musb_init(struct musb *musb)
|
||||
{
|
||||
|
||||
/*
|
||||
* Rev 1.0 BF549 EZ-KITs require PE7 to be high for both DEVICE
|
||||
* and OTG HOST modes, while rev 1.1 and greater require PE7 to
|
||||
* be low for DEVICE mode and high for HOST mode. We set it high
|
||||
* here because we are in host mode
|
||||
*/
|
||||
|
||||
if (gpio_request(musb->config->gpio_vrsel, "USB_VRSEL")) {
|
||||
printk(KERN_ERR "Failed ro request USB_VRSEL GPIO_%d\n",
|
||||
musb->config->gpio_vrsel);
|
||||
return -ENODEV;
|
||||
}
|
||||
gpio_direction_output(musb->config->gpio_vrsel, 0);
|
||||
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = otg_get_transceiver();
|
||||
if (!musb->xceiv) {
|
||||
gpio_free(musb->config->gpio_vrsel);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bfin_musb_reg_init(musb);
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
musb->board_set_vbus = bfin_set_vbus;
|
||||
setup_timer(&musb_conn_timer,
|
||||
musb_conn_timer_handler, (unsigned long) musb);
|
||||
}
|
||||
if (is_peripheral_enabled(musb))
|
||||
musb->xceiv->set_power = bfin_set_power;
|
||||
musb->xceiv->set_power = bfin_musb_set_power;
|
||||
|
||||
musb->isr = blackfin_interrupt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
static int bfin_musb_exit(struct musb *musb)
|
||||
{
|
||||
gpio_free(musb->config->gpio_vrsel);
|
||||
|
||||
|
@ -402,3 +414,154 @@ int musb_platform_exit(struct musb *musb)
|
|||
usb_nop_xceiv_unregister();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops bfin_ops = {
|
||||
.init = bfin_musb_init,
|
||||
.exit = bfin_musb_exit,
|
||||
|
||||
.enable = bfin_musb_enable,
|
||||
.disable = bfin_musb_disable,
|
||||
|
||||
.set_mode = bfin_musb_set_mode,
|
||||
.try_idle = bfin_musb_try_idle,
|
||||
|
||||
.vbus_status = bfin_musb_vbus_status,
|
||||
.set_vbus = bfin_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 bfin_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init bfin_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct bfin_glue *glue;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &bfin_dmamask;
|
||||
musb->dev.coherent_dma_mask = bfin_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
|
||||
pdata->platform_ops = &bfin_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit bfin_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bfin_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int bfin_suspend(struct device *dev)
|
||||
{
|
||||
struct bfin_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
if (is_host_active(musb))
|
||||
/*
|
||||
* During hibernate gpio_vrsel will change from high to low
|
||||
* low which will generate wakeup event resume the system
|
||||
* immediately. Set it to 0 before hibernate to avoid this
|
||||
* wakeup event.
|
||||
*/
|
||||
gpio_set_value(musb->config->gpio_vrsel, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bfin_resume(struct device *dev)
|
||||
{
|
||||
struct bfin_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
bfin_musb_reg_init(musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops bfin_pm_ops = {
|
||||
.suspend = bfin_suspend,
|
||||
.resume = bfin_resume,
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS &bfin_pm_op,
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver bfin_driver = {
|
||||
.remove = __exit_p(bfin_remove),
|
||||
.driver = {
|
||||
.name = "musb-bfin",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init bfin_init(void)
|
||||
{
|
||||
return platform_driver_probe(&bfin_driver, bfin_probe);
|
||||
}
|
||||
subsys_initcall(bfin_init);
|
||||
|
||||
static void __exit bfin_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_driver);
|
||||
}
|
||||
module_exit(bfin_exit);
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <mach/da8xx.h>
|
||||
#include <mach/usb.h>
|
||||
|
@ -78,6 +80,12 @@
|
|||
|
||||
#define CFGCHIP2 IO_ADDRESS(DA8XX_SYSCFG0_BASE + DA8XX_CFGCHIP2_REG)
|
||||
|
||||
struct da8xx_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/*
|
||||
* REVISIT (PM): we should be able to keep the PHY in low power mode most
|
||||
* of the time (24 MHz oscillator and PLL off, etc.) by setting POWER.D0
|
||||
|
@ -131,9 +139,9 @@ static inline void phy_off(void)
|
|||
*/
|
||||
|
||||
/**
|
||||
* musb_platform_enable - enable interrupts
|
||||
* da8xx_musb_enable - enable interrupts
|
||||
*/
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
static void da8xx_musb_enable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 mask;
|
||||
|
@ -151,9 +159,9 @@ void musb_platform_enable(struct musb *musb)
|
|||
}
|
||||
|
||||
/**
|
||||
* musb_platform_disable - disable HDRC and flush interrupts
|
||||
* da8xx_musb_disable - disable HDRC and flush interrupts
|
||||
*/
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
static void da8xx_musb_disable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
||||
|
@ -170,7 +178,7 @@ void musb_platform_disable(struct musb *musb)
|
|||
#define portstate(stmt)
|
||||
#endif
|
||||
|
||||
static void da8xx_set_vbus(struct musb *musb, int is_on)
|
||||
static void da8xx_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
WARN_ON(is_on && is_peripheral_active(musb));
|
||||
}
|
||||
|
@ -252,7 +260,7 @@ static void otg_timer(unsigned long _musb)
|
|||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
static unsigned long last_timer;
|
||||
|
||||
|
@ -282,7 +290,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
|||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
|
||||
static irqreturn_t da8xx_interrupt(int irq, void *hci)
|
||||
static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
@ -380,7 +388,7 @@ static irqreturn_t da8xx_interrupt(int irq, void *hci)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
static int da8xx_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u32 cfgchip2 = __raw_readl(CFGCHIP2);
|
||||
|
||||
|
@ -409,15 +417,13 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb, void *board_data)
|
||||
static int da8xx_musb_init(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 rev;
|
||||
|
||||
musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
|
||||
|
||||
clk_enable(musb->clock);
|
||||
|
||||
/* Returns zero if e.g. not clocked */
|
||||
rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG);
|
||||
if (!rev)
|
||||
|
@ -431,8 +437,6 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
|
|||
if (is_host_enabled(musb))
|
||||
setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
|
||||
|
||||
musb->board_set_vbus = da8xx_set_vbus;
|
||||
|
||||
/* Reset the controller */
|
||||
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
|
||||
|
||||
|
@ -446,14 +450,13 @@ int __init musb_platform_init(struct musb *musb, void *board_data)
|
|||
rev, __raw_readl(CFGCHIP2),
|
||||
musb_readb(reg_base, DA8XX_USB_CTRL_REG));
|
||||
|
||||
musb->isr = da8xx_interrupt;
|
||||
musb->isr = da8xx_musb_interrupt;
|
||||
return 0;
|
||||
fail:
|
||||
clk_disable(musb->clock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
static int da8xx_musb_exit(struct musb *musb)
|
||||
{
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&otg_workaround);
|
||||
|
@ -463,7 +466,140 @@ int musb_platform_exit(struct musb *musb)
|
|||
otg_put_transceiver(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
|
||||
clk_disable(musb->clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops da8xx_ops = {
|
||||
.init = da8xx_musb_init,
|
||||
.exit = da8xx_musb_exit,
|
||||
|
||||
.enable = da8xx_musb_enable,
|
||||
.disable = da8xx_musb_disable,
|
||||
|
||||
.set_mode = da8xx_musb_set_mode,
|
||||
.try_idle = da8xx_musb_try_idle,
|
||||
|
||||
.set_vbus = da8xx_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 da8xx_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init da8xx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct da8xx_glue *glue;
|
||||
|
||||
struct clk *clk;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "usb20");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &da8xx_dmamask;
|
||||
musb->dev.coherent_dma_mask = da8xx_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &da8xx_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
clk_disable(clk);
|
||||
|
||||
err3:
|
||||
clk_put(clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit da8xx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da8xx_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_put(glue->clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da8xx_driver = {
|
||||
.remove = __exit_p(da8xx_remove),
|
||||
.driver = {
|
||||
.name = "musb-da8xx",
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init da8xx_init(void)
|
||||
{
|
||||
return platform_driver_probe(&da8xx_driver, da8xx_probe);
|
||||
}
|
||||
subsys_initcall(da8xx_init);
|
||||
|
||||
static void __exit da8xx_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&da8xx_driver);
|
||||
}
|
||||
module_exit(da8xx_exit);
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/memory.h>
|
||||
|
@ -51,6 +53,12 @@
|
|||
#define USB_PHY_CTRL IO_ADDRESS(USBPHY_CTL_PADDR)
|
||||
#define DM355_DEEPSLEEP IO_ADDRESS(DM355_DEEPSLEEP_PADDR)
|
||||
|
||||
struct davinci_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
/* REVISIT (PM) we should be able to keep the PHY in low power mode most
|
||||
* of the time (24 MHZ oscillator and PLL off, etc) by setting POWER.D0
|
||||
* and, when in host mode, autosuspending idle root ports... PHYPLLON
|
||||
|
@ -83,7 +91,7 @@ static inline void phy_off(void)
|
|||
|
||||
static int dma_off = 1;
|
||||
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
static void davinci_musb_enable(struct musb *musb)
|
||||
{
|
||||
u32 tmp, old, val;
|
||||
|
||||
|
@ -116,7 +124,7 @@ void musb_platform_enable(struct musb *musb)
|
|||
/*
|
||||
* Disable the HDRC and flush interrupts
|
||||
*/
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
static void davinci_musb_disable(struct musb *musb)
|
||||
{
|
||||
/* because we don't set CTRLR.UINT, "important" to:
|
||||
* - not read/write INTRUSB/INTRUSBE
|
||||
|
@ -167,7 +175,7 @@ static void evm_deferred_drvvbus(struct work_struct *ignored)
|
|||
|
||||
#endif /* EVM */
|
||||
|
||||
static void davinci_source_power(struct musb *musb, int is_on, int immediate)
|
||||
static void davinci_musb_source_power(struct musb *musb, int is_on, int immediate)
|
||||
{
|
||||
#ifdef CONFIG_MACH_DAVINCI_EVM
|
||||
if (is_on)
|
||||
|
@ -190,10 +198,10 @@ static void davinci_source_power(struct musb *musb, int is_on, int immediate)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void davinci_set_vbus(struct musb *musb, int is_on)
|
||||
static void davinci_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
WARN_ON(is_on && is_peripheral_active(musb));
|
||||
davinci_source_power(musb, is_on, 0);
|
||||
davinci_musb_source_power(musb, is_on, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -259,7 +267,7 @@ static void otg_timer(unsigned long _musb)
|
|||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t davinci_interrupt(int irq, void *__hci)
|
||||
static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
|
||||
{
|
||||
unsigned long flags;
|
||||
irqreturn_t retval = IRQ_NONE;
|
||||
|
@ -345,7 +353,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
|
|||
/* NOTE: this must complete poweron within 100 msec
|
||||
* (OTG_TIME_A_WAIT_VRISE) but we don't check for that.
|
||||
*/
|
||||
davinci_source_power(musb, drvvbus, 0);
|
||||
davinci_musb_source_power(musb, drvvbus, 0);
|
||||
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb),
|
||||
|
@ -370,13 +378,13 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
|
|||
return retval;
|
||||
}
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 mode)
|
||||
static int davinci_musb_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
/* EVM can't do this (right?) */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb)
|
||||
static int davinci_musb_init(struct musb *musb)
|
||||
{
|
||||
void __iomem *tibase = musb->ctrl_base;
|
||||
u32 revision;
|
||||
|
@ -388,8 +396,6 @@ int __init musb_platform_init(struct musb *musb)
|
|||
|
||||
musb->mregs += DAVINCI_BASE_OFFSET;
|
||||
|
||||
clk_enable(musb->clock);
|
||||
|
||||
/* returns zero if e.g. not clocked */
|
||||
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
|
||||
if (revision == 0)
|
||||
|
@ -398,8 +404,7 @@ int __init musb_platform_init(struct musb *musb)
|
|||
if (is_host_enabled(musb))
|
||||
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
|
||||
|
||||
musb->board_set_vbus = davinci_set_vbus;
|
||||
davinci_source_power(musb, 0, 1);
|
||||
davinci_musb_source_power(musb, 0, 1);
|
||||
|
||||
/* dm355 EVM swaps D+/D- for signal integrity, and
|
||||
* is clocked from the main 24 MHz crystal.
|
||||
|
@ -440,18 +445,16 @@ int __init musb_platform_init(struct musb *musb)
|
|||
revision, __raw_readl(USB_PHY_CTRL),
|
||||
musb_readb(tibase, DAVINCI_USB_CTRL_REG));
|
||||
|
||||
musb->isr = davinci_interrupt;
|
||||
musb->isr = davinci_musb_interrupt;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
clk_disable(musb->clock);
|
||||
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
static int davinci_musb_exit(struct musb *musb)
|
||||
{
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&otg_workaround);
|
||||
|
@ -465,7 +468,7 @@ int musb_platform_exit(struct musb *musb)
|
|||
__raw_writel(deepsleep, DM355_DEEPSLEEP);
|
||||
}
|
||||
|
||||
davinci_source_power(musb, 0 /*off*/, 1);
|
||||
davinci_musb_source_power(musb, 0 /*off*/, 1);
|
||||
|
||||
/* delay, to avoid problems with module reload */
|
||||
if (is_host_enabled(musb) && musb->xceiv->default_a) {
|
||||
|
@ -495,10 +498,141 @@ int musb_platform_exit(struct musb *musb)
|
|||
|
||||
phy_off();
|
||||
|
||||
clk_disable(musb->clock);
|
||||
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops davinci_ops = {
|
||||
.init = davinci_musb_init,
|
||||
.exit = davinci_musb_exit,
|
||||
|
||||
.enable = davinci_musb_enable,
|
||||
.disable = davinci_musb_disable,
|
||||
|
||||
.set_mode = davinci_musb_set_mode,
|
||||
|
||||
.set_vbus = davinci_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 davinci_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init davinci_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct davinci_glue *glue;
|
||||
struct clk *clk;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &davinci_dmamask;
|
||||
musb->dev.coherent_dma_mask = davinci_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &davinci_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
clk_disable(clk);
|
||||
|
||||
err3:
|
||||
clk_put(clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit davinci_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct davinci_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_put(glue->clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver davinci_driver = {
|
||||
.remove = __exit_p(davinci_remove),
|
||||
.driver = {
|
||||
.name = "musb-davinci",
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("DaVinci MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init davinci_init(void)
|
||||
{
|
||||
return platform_driver_probe(&davinci_driver, davinci_probe);
|
||||
}
|
||||
subsys_initcall(davinci_init);
|
||||
|
||||
static void __exit davinci_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&davinci_driver);
|
||||
}
|
||||
module_exit(davinci_exit);
|
||||
|
|
|
@ -99,19 +99,8 @@
|
|||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
#include <mach/hardware.h>
|
||||
#include <mach/memory.h>
|
||||
#include <asm/mach-types.h>
|
||||
#endif
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
|
||||
#ifdef CONFIG_ARCH_DAVINCI
|
||||
#include "davinci.h"
|
||||
#endif
|
||||
|
||||
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
|
||||
|
||||
|
||||
|
@ -126,7 +115,7 @@ MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
|
|||
|
||||
#define DRIVER_INFO DRIVER_DESC ", v" MUSB_VERSION
|
||||
|
||||
#define MUSB_DRIVER_NAME "musb_hdrc"
|
||||
#define MUSB_DRIVER_NAME "musb-hdrc"
|
||||
const char musb_driver_name[] = MUSB_DRIVER_NAME;
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_INFO);
|
||||
|
@ -230,7 +219,7 @@ static struct otg_io_access_ops musb_ulpi_access = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if !defined(CONFIG_USB_TUSB6010) && !defined(CONFIG_BLACKFIN)
|
||||
#if !defined(CONFIG_USB_MUSB_TUSB6010) && !defined(CONFIG_USB_MUSB_BLACKFIN)
|
||||
|
||||
/*
|
||||
* Load an endpoint's FIFO
|
||||
|
@ -390,7 +379,7 @@ void musb_otg_timer_func(unsigned long data)
|
|||
case OTG_STATE_A_SUSPEND:
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
|
||||
musb_set_vbus(musb, 0);
|
||||
musb_platform_set_vbus(musb, 0);
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
|
||||
break;
|
||||
default:
|
||||
|
@ -570,7 +559,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
|
|||
musb->ep0_stage = MUSB_EP0_START;
|
||||
musb->xceiv->state = OTG_STATE_A_IDLE;
|
||||
MUSB_HST_MODE(musb);
|
||||
musb_set_vbus(musb, 1);
|
||||
musb_platform_set_vbus(musb, 1);
|
||||
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
@ -641,7 +630,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
|
|||
|
||||
/* go through A_WAIT_VFALL then start a new session */
|
||||
if (!ignore)
|
||||
musb_set_vbus(musb, 0);
|
||||
musb_platform_set_vbus(musb, 0);
|
||||
handled = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -1048,8 +1037,6 @@ static void musb_shutdown(struct platform_device *pdev)
|
|||
spin_lock_irqsave(&musb->lock, flags);
|
||||
musb_platform_disable(musb);
|
||||
musb_generic_disable(musb);
|
||||
if (musb->clock)
|
||||
clk_put(musb->clock);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
/* FIXME power down */
|
||||
|
@ -1068,10 +1055,11 @@ static void musb_shutdown(struct platform_device *pdev)
|
|||
* We don't currently use dynamic fifo setup capability to do anything
|
||||
* more than selecting one of a bunch of predefined configurations.
|
||||
*/
|
||||
#if defined(CONFIG_USB_TUSB6010) || \
|
||||
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) \
|
||||
|| defined(CONFIG_ARCH_OMAP4)
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \
|
||||
|| defined(CONFIG_USB_MUSB_AM35X)
|
||||
static ushort __initdata fifo_mode = 4;
|
||||
#elif defined(CONFIG_USB_MUSB_UX500)
|
||||
static ushort __initdata fifo_mode = 5;
|
||||
#else
|
||||
static ushort __initdata fifo_mode = 2;
|
||||
#endif
|
||||
|
@ -1495,7 +1483,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
|
|||
struct musb_hw_ep *hw_ep = musb->endpoints + i;
|
||||
|
||||
hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
|
||||
hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
|
||||
hw_ep->fifo_sync_va =
|
||||
|
@ -1542,7 +1530,8 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
|
|||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) || \
|
||||
defined(CONFIG_ARCH_OMAP4)
|
||||
defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \
|
||||
defined(CONFIG_ARCH_U5500)
|
||||
|
||||
static irqreturn_t generic_interrupt(int irq, void *__hci)
|
||||
{
|
||||
|
@ -1898,6 +1887,7 @@ allocate_instance(struct device *dev,
|
|||
}
|
||||
|
||||
musb->controller = dev;
|
||||
|
||||
return musb;
|
||||
}
|
||||
|
||||
|
@ -1994,30 +1984,14 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
spin_lock_init(&musb->lock);
|
||||
musb->board_mode = plat->mode;
|
||||
musb->board_set_power = plat->set_power;
|
||||
musb->set_clock = plat->set_clock;
|
||||
musb->min_power = plat->min_power;
|
||||
|
||||
/* Clock usage is chip-specific ... functional clock (DaVinci,
|
||||
* OMAP2430), or PHY ref (some TUSB6010 boards). All this core
|
||||
* code does is make sure a clock handle is available; platform
|
||||
* code manages it during start/stop and suspend/resume.
|
||||
*/
|
||||
if (plat->clock) {
|
||||
musb->clock = clk_get(dev, plat->clock);
|
||||
if (IS_ERR(musb->clock)) {
|
||||
status = PTR_ERR(musb->clock);
|
||||
musb->clock = NULL;
|
||||
goto fail1;
|
||||
}
|
||||
}
|
||||
musb->ops = plat->platform_ops;
|
||||
|
||||
/* The musb_platform_init() call:
|
||||
* - adjusts musb->mregs and musb->isr if needed,
|
||||
* - may initialize an integrated tranceiver
|
||||
* - initializes musb->xceiv, usually by otg_get_transceiver()
|
||||
* - activates clocks.
|
||||
* - stops powering VBUS
|
||||
* - assigns musb->board_set_vbus if host mode is enabled
|
||||
*
|
||||
* There are various transciever configurations. Blackfin,
|
||||
* DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
|
||||
|
@ -2027,7 +2001,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
musb->isr = generic_interrupt;
|
||||
status = musb_platform_init(musb);
|
||||
if (status < 0)
|
||||
goto fail2;
|
||||
goto fail1;
|
||||
|
||||
if (!musb->isr) {
|
||||
status = -ENODEV;
|
||||
|
@ -2177,10 +2151,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
|
|||
device_init_wakeup(dev, 0);
|
||||
musb_platform_exit(musb);
|
||||
|
||||
fail2:
|
||||
if (musb->clock)
|
||||
clk_put(musb->clock);
|
||||
|
||||
fail1:
|
||||
dev_err(musb->controller,
|
||||
"musb_init_controller failed with status %d\n", status);
|
||||
|
@ -2263,144 +2233,138 @@ static int __exit musb_remove(struct platform_device *pdev)
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static struct musb_context_registers musb_context;
|
||||
|
||||
void musb_save_context(struct musb *musb)
|
||||
static void musb_save_context(struct musb *musb)
|
||||
{
|
||||
int i;
|
||||
void __iomem *musb_base = musb->mregs;
|
||||
void __iomem *epio;
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
|
||||
musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
|
||||
musb_context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
|
||||
musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
|
||||
musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
|
||||
musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
|
||||
}
|
||||
musb_context.power = musb_readb(musb_base, MUSB_POWER);
|
||||
musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
|
||||
musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
|
||||
musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
|
||||
musb_context.index = musb_readb(musb_base, MUSB_INDEX);
|
||||
musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
|
||||
musb->context.power = musb_readb(musb_base, MUSB_POWER);
|
||||
musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
|
||||
musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
|
||||
musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
|
||||
musb->context.index = musb_readb(musb_base, MUSB_INDEX);
|
||||
musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
|
||||
|
||||
for (i = 0; i < musb->config->num_eps; ++i) {
|
||||
epio = musb->endpoints[i].regs;
|
||||
musb_context.index_regs[i].txmaxp =
|
||||
musb->context.index_regs[i].txmaxp =
|
||||
musb_readw(epio, MUSB_TXMAXP);
|
||||
musb_context.index_regs[i].txcsr =
|
||||
musb->context.index_regs[i].txcsr =
|
||||
musb_readw(epio, MUSB_TXCSR);
|
||||
musb_context.index_regs[i].rxmaxp =
|
||||
musb->context.index_regs[i].rxmaxp =
|
||||
musb_readw(epio, MUSB_RXMAXP);
|
||||
musb_context.index_regs[i].rxcsr =
|
||||
musb->context.index_regs[i].rxcsr =
|
||||
musb_readw(epio, MUSB_RXCSR);
|
||||
|
||||
if (musb->dyn_fifo) {
|
||||
musb_context.index_regs[i].txfifoadd =
|
||||
musb->context.index_regs[i].txfifoadd =
|
||||
musb_read_txfifoadd(musb_base);
|
||||
musb_context.index_regs[i].rxfifoadd =
|
||||
musb->context.index_regs[i].rxfifoadd =
|
||||
musb_read_rxfifoadd(musb_base);
|
||||
musb_context.index_regs[i].txfifosz =
|
||||
musb->context.index_regs[i].txfifosz =
|
||||
musb_read_txfifosz(musb_base);
|
||||
musb_context.index_regs[i].rxfifosz =
|
||||
musb->context.index_regs[i].rxfifosz =
|
||||
musb_read_rxfifosz(musb_base);
|
||||
}
|
||||
if (is_host_enabled(musb)) {
|
||||
musb_context.index_regs[i].txtype =
|
||||
musb->context.index_regs[i].txtype =
|
||||
musb_readb(epio, MUSB_TXTYPE);
|
||||
musb_context.index_regs[i].txinterval =
|
||||
musb->context.index_regs[i].txinterval =
|
||||
musb_readb(epio, MUSB_TXINTERVAL);
|
||||
musb_context.index_regs[i].rxtype =
|
||||
musb->context.index_regs[i].rxtype =
|
||||
musb_readb(epio, MUSB_RXTYPE);
|
||||
musb_context.index_regs[i].rxinterval =
|
||||
musb->context.index_regs[i].rxinterval =
|
||||
musb_readb(epio, MUSB_RXINTERVAL);
|
||||
|
||||
musb_context.index_regs[i].txfunaddr =
|
||||
musb->context.index_regs[i].txfunaddr =
|
||||
musb_read_txfunaddr(musb_base, i);
|
||||
musb_context.index_regs[i].txhubaddr =
|
||||
musb->context.index_regs[i].txhubaddr =
|
||||
musb_read_txhubaddr(musb_base, i);
|
||||
musb_context.index_regs[i].txhubport =
|
||||
musb->context.index_regs[i].txhubport =
|
||||
musb_read_txhubport(musb_base, i);
|
||||
|
||||
musb_context.index_regs[i].rxfunaddr =
|
||||
musb->context.index_regs[i].rxfunaddr =
|
||||
musb_read_rxfunaddr(musb_base, i);
|
||||
musb_context.index_regs[i].rxhubaddr =
|
||||
musb->context.index_regs[i].rxhubaddr =
|
||||
musb_read_rxhubaddr(musb_base, i);
|
||||
musb_context.index_regs[i].rxhubport =
|
||||
musb->context.index_regs[i].rxhubport =
|
||||
musb_read_rxhubport(musb_base, i);
|
||||
}
|
||||
}
|
||||
|
||||
musb_platform_save_context(musb, &musb_context);
|
||||
}
|
||||
|
||||
void musb_restore_context(struct musb *musb)
|
||||
static void musb_restore_context(struct musb *musb)
|
||||
{
|
||||
int i;
|
||||
void __iomem *musb_base = musb->mregs;
|
||||
void __iomem *ep_target_regs;
|
||||
void __iomem *epio;
|
||||
|
||||
musb_platform_restore_context(musb, &musb_context);
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
|
||||
musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
|
||||
musb_write_ulpi_buscontrol(musb->mregs, musb_context.busctl);
|
||||
musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
|
||||
musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
|
||||
musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
|
||||
}
|
||||
musb_writeb(musb_base, MUSB_POWER, musb_context.power);
|
||||
musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
|
||||
musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
|
||||
musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
|
||||
musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
|
||||
musb_writeb(musb_base, MUSB_POWER, musb->context.power);
|
||||
musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
|
||||
musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
|
||||
musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe);
|
||||
musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
|
||||
|
||||
for (i = 0; i < musb->config->num_eps; ++i) {
|
||||
epio = musb->endpoints[i].regs;
|
||||
musb_writew(epio, MUSB_TXMAXP,
|
||||
musb_context.index_regs[i].txmaxp);
|
||||
musb->context.index_regs[i].txmaxp);
|
||||
musb_writew(epio, MUSB_TXCSR,
|
||||
musb_context.index_regs[i].txcsr);
|
||||
musb->context.index_regs[i].txcsr);
|
||||
musb_writew(epio, MUSB_RXMAXP,
|
||||
musb_context.index_regs[i].rxmaxp);
|
||||
musb->context.index_regs[i].rxmaxp);
|
||||
musb_writew(epio, MUSB_RXCSR,
|
||||
musb_context.index_regs[i].rxcsr);
|
||||
musb->context.index_regs[i].rxcsr);
|
||||
|
||||
if (musb->dyn_fifo) {
|
||||
musb_write_txfifosz(musb_base,
|
||||
musb_context.index_regs[i].txfifosz);
|
||||
musb->context.index_regs[i].txfifosz);
|
||||
musb_write_rxfifosz(musb_base,
|
||||
musb_context.index_regs[i].rxfifosz);
|
||||
musb->context.index_regs[i].rxfifosz);
|
||||
musb_write_txfifoadd(musb_base,
|
||||
musb_context.index_regs[i].txfifoadd);
|
||||
musb->context.index_regs[i].txfifoadd);
|
||||
musb_write_rxfifoadd(musb_base,
|
||||
musb_context.index_regs[i].rxfifoadd);
|
||||
musb->context.index_regs[i].rxfifoadd);
|
||||
}
|
||||
|
||||
if (is_host_enabled(musb)) {
|
||||
musb_writeb(epio, MUSB_TXTYPE,
|
||||
musb_context.index_regs[i].txtype);
|
||||
musb->context.index_regs[i].txtype);
|
||||
musb_writeb(epio, MUSB_TXINTERVAL,
|
||||
musb_context.index_regs[i].txinterval);
|
||||
musb->context.index_regs[i].txinterval);
|
||||
musb_writeb(epio, MUSB_RXTYPE,
|
||||
musb_context.index_regs[i].rxtype);
|
||||
musb->context.index_regs[i].rxtype);
|
||||
musb_writeb(epio, MUSB_RXINTERVAL,
|
||||
|
||||
musb_context.index_regs[i].rxinterval);
|
||||
musb->context.index_regs[i].rxinterval);
|
||||
musb_write_txfunaddr(musb_base, i,
|
||||
musb_context.index_regs[i].txfunaddr);
|
||||
musb->context.index_regs[i].txfunaddr);
|
||||
musb_write_txhubaddr(musb_base, i,
|
||||
musb_context.index_regs[i].txhubaddr);
|
||||
musb->context.index_regs[i].txhubaddr);
|
||||
musb_write_txhubport(musb_base, i,
|
||||
musb_context.index_regs[i].txhubport);
|
||||
musb->context.index_regs[i].txhubport);
|
||||
|
||||
ep_target_regs =
|
||||
musb_read_target_reg_base(i, musb_base);
|
||||
|
||||
musb_write_rxfunaddr(ep_target_regs,
|
||||
musb_context.index_regs[i].rxfunaddr);
|
||||
musb->context.index_regs[i].rxfunaddr);
|
||||
musb_write_rxhubaddr(ep_target_regs,
|
||||
musb_context.index_regs[i].rxhubaddr);
|
||||
musb->context.index_regs[i].rxhubaddr);
|
||||
musb_write_rxhubport(ep_target_regs,
|
||||
musb_context.index_regs[i].rxhubport);
|
||||
musb->context.index_regs[i].rxhubport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2411,9 +2375,6 @@ static int musb_suspend(struct device *dev)
|
|||
unsigned long flags;
|
||||
struct musb *musb = dev_to_musb(&pdev->dev);
|
||||
|
||||
if (!musb->clock)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
if (is_peripheral_active(musb)) {
|
||||
|
@ -2428,10 +2389,6 @@ static int musb_suspend(struct device *dev)
|
|||
|
||||
musb_save_context(musb);
|
||||
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 0);
|
||||
else
|
||||
clk_disable(musb->clock);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2441,14 +2398,6 @@ static int musb_resume_noirq(struct device *dev)
|
|||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct musb *musb = dev_to_musb(&pdev->dev);
|
||||
|
||||
if (!musb->clock)
|
||||
return 0;
|
||||
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 1);
|
||||
else
|
||||
clk_enable(musb->clock);
|
||||
|
||||
musb_restore_context(musb);
|
||||
|
||||
/* for static cmos like DaVinci, register values were preserved
|
||||
|
|
|
@ -222,7 +222,7 @@ enum musb_g_ep0_state {
|
|||
#endif
|
||||
|
||||
/* TUSB mapping: "flat" plus ep0 special cases */
|
||||
#if defined(CONFIG_USB_TUSB6010)
|
||||
#if defined(CONFIG_USB_MUSB_TUSB6010)
|
||||
#define musb_ep_select(_mbase, _epnum) \
|
||||
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
|
||||
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
|
||||
|
@ -253,6 +253,29 @@ enum musb_g_ep0_state {
|
|||
|
||||
/******************************** TYPES *************************************/
|
||||
|
||||
/**
|
||||
* struct musb_platform_ops - Operations passed to musb_core by HW glue layer
|
||||
* @init: turns on clocks, sets up platform-specific registers, etc
|
||||
* @exit: undoes @init
|
||||
* @set_mode: forcefully changes operating mode
|
||||
* @try_ilde: tries to idle the IP
|
||||
* @vbus_status: returns vbus status if possible
|
||||
* @set_vbus: forces vbus status
|
||||
*/
|
||||
struct musb_platform_ops {
|
||||
int (*init)(struct musb *musb);
|
||||
int (*exit)(struct musb *musb);
|
||||
|
||||
void (*enable)(struct musb *musb);
|
||||
void (*disable)(struct musb *musb);
|
||||
|
||||
int (*set_mode)(struct musb *musb, u8 mode);
|
||||
void (*try_idle)(struct musb *musb, unsigned long timeout);
|
||||
|
||||
int (*vbus_status)(struct musb *musb);
|
||||
void (*set_vbus)(struct musb *musb, int on);
|
||||
};
|
||||
|
||||
/*
|
||||
* struct musb_hw_ep - endpoint hardware (bidirectional)
|
||||
*
|
||||
|
@ -263,7 +286,7 @@ struct musb_hw_ep {
|
|||
void __iomem *fifo;
|
||||
void __iomem *regs;
|
||||
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
void __iomem *conf;
|
||||
#endif
|
||||
|
||||
|
@ -280,7 +303,7 @@ struct musb_hw_ep {
|
|||
struct dma_channel *tx_channel;
|
||||
struct dma_channel *rx_channel;
|
||||
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
/* TUSB has "asynchronous" and "synchronous" dma modes */
|
||||
dma_addr_t fifo_async;
|
||||
dma_addr_t fifo_sync;
|
||||
|
@ -323,14 +346,43 @@ static inline struct usb_request *next_out_request(struct musb_hw_ep *hw_ep)
|
|||
#endif
|
||||
}
|
||||
|
||||
struct musb_csr_regs {
|
||||
/* FIFO registers */
|
||||
u16 txmaxp, txcsr, rxmaxp, rxcsr;
|
||||
u16 rxfifoadd, txfifoadd;
|
||||
u8 txtype, txinterval, rxtype, rxinterval;
|
||||
u8 rxfifosz, txfifosz;
|
||||
u8 txfunaddr, txhubaddr, txhubport;
|
||||
u8 rxfunaddr, rxhubaddr, rxhubport;
|
||||
};
|
||||
|
||||
struct musb_context_registers {
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
|
||||
defined(CONFIG_ARCH_OMAP4)
|
||||
u32 otg_sysconfig, otg_forcestandby;
|
||||
#endif
|
||||
u8 power;
|
||||
u16 intrtxe, intrrxe;
|
||||
u8 intrusbe;
|
||||
u16 frame;
|
||||
u8 index, testmode;
|
||||
|
||||
u8 devctl, busctl, misc;
|
||||
|
||||
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
|
||||
};
|
||||
|
||||
/*
|
||||
* struct musb - Driver instance data.
|
||||
*/
|
||||
struct musb {
|
||||
/* device lock */
|
||||
spinlock_t lock;
|
||||
struct clk *clock;
|
||||
struct clk *phy_clock;
|
||||
|
||||
const struct musb_platform_ops *ops;
|
||||
struct musb_context_registers context;
|
||||
|
||||
irqreturn_t (*isr)(int, void *);
|
||||
struct work_struct irq_work;
|
||||
u16 hwvers;
|
||||
|
@ -359,11 +411,7 @@ struct musb {
|
|||
|
||||
struct timer_list otg_timer;
|
||||
#endif
|
||||
|
||||
/* called with IRQs blocked; ON/nonzero implies starting a session,
|
||||
* and waiting at least a_wait_vrise_tmout.
|
||||
*/
|
||||
void (*board_set_vbus)(struct musb *, int is_on);
|
||||
struct notifier_block nb;
|
||||
|
||||
struct dma_controller *dma_controller;
|
||||
|
||||
|
@ -371,7 +419,7 @@ struct musb {
|
|||
void __iomem *ctrl_base;
|
||||
void __iomem *mregs;
|
||||
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
dma_addr_t async;
|
||||
dma_addr_t sync;
|
||||
void __iomem *sync_va;
|
||||
|
@ -398,8 +446,6 @@ struct musb {
|
|||
u8 board_mode; /* enum musb_mode */
|
||||
int (*board_set_power)(int state);
|
||||
|
||||
int (*set_clock)(struct clk *clk, int is_active);
|
||||
|
||||
u8 min_power; /* vbus for periph, in mA/2 */
|
||||
|
||||
bool is_host;
|
||||
|
@ -458,52 +504,6 @@ struct musb {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
struct musb_csr_regs {
|
||||
/* FIFO registers */
|
||||
u16 txmaxp, txcsr, rxmaxp, rxcsr;
|
||||
u16 rxfifoadd, txfifoadd;
|
||||
u8 txtype, txinterval, rxtype, rxinterval;
|
||||
u8 rxfifosz, txfifosz;
|
||||
u8 txfunaddr, txhubaddr, txhubport;
|
||||
u8 rxfunaddr, rxhubaddr, rxhubport;
|
||||
};
|
||||
|
||||
struct musb_context_registers {
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
|
||||
defined(CONFIG_ARCH_OMAP4)
|
||||
u32 otg_sysconfig, otg_forcestandby;
|
||||
#endif
|
||||
u8 power;
|
||||
u16 intrtxe, intrrxe;
|
||||
u8 intrusbe;
|
||||
u16 frame;
|
||||
u8 index, testmode;
|
||||
|
||||
u8 devctl, busctl, misc;
|
||||
|
||||
struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
|
||||
defined(CONFIG_ARCH_OMAP4)
|
||||
extern void musb_platform_save_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context);
|
||||
extern void musb_platform_restore_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context);
|
||||
#else
|
||||
#define musb_platform_save_context(m, x) do {} while (0)
|
||||
#define musb_platform_restore_context(m, x) do {} while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static inline void musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
musb->board_set_vbus(musb, is_on);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
static inline struct musb *gadget_to_musb(struct usb_gadget *g)
|
||||
{
|
||||
|
@ -592,29 +592,63 @@ extern void musb_load_testpacket(struct musb *);
|
|||
|
||||
extern irqreturn_t musb_interrupt(struct musb *);
|
||||
|
||||
extern void musb_platform_enable(struct musb *musb);
|
||||
extern void musb_platform_disable(struct musb *musb);
|
||||
|
||||
extern void musb_hnp_stop(struct musb *musb);
|
||||
|
||||
extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
|
||||
static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
if (musb->ops->set_vbus)
|
||||
musb->ops->set_vbus(musb, is_on);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
|
||||
defined(CONFIG_ARCH_DAVINCI_DA8XX) || \
|
||||
defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) || \
|
||||
defined(CONFIG_ARCH_OMAP4)
|
||||
extern void musb_platform_try_idle(struct musb *musb, unsigned long timeout);
|
||||
#else
|
||||
#define musb_platform_try_idle(x, y) do {} while (0)
|
||||
#endif
|
||||
static inline void musb_platform_enable(struct musb *musb)
|
||||
{
|
||||
if (musb->ops->enable)
|
||||
musb->ops->enable(musb);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN)
|
||||
extern int musb_platform_get_vbus_status(struct musb *musb);
|
||||
#else
|
||||
#define musb_platform_get_vbus_status(x) 0
|
||||
#endif
|
||||
static inline void musb_platform_disable(struct musb *musb)
|
||||
{
|
||||
if (musb->ops->disable)
|
||||
musb->ops->disable(musb);
|
||||
}
|
||||
|
||||
extern int __init musb_platform_init(struct musb *musb);
|
||||
extern int musb_platform_exit(struct musb *musb);
|
||||
static inline int musb_platform_set_mode(struct musb *musb, u8 mode)
|
||||
{
|
||||
if (!musb->ops->set_mode)
|
||||
return 0;
|
||||
|
||||
return musb->ops->set_mode(musb, mode);
|
||||
}
|
||||
|
||||
static inline void musb_platform_try_idle(struct musb *musb,
|
||||
unsigned long timeout)
|
||||
{
|
||||
if (musb->ops->try_idle)
|
||||
musb->ops->try_idle(musb, timeout);
|
||||
}
|
||||
|
||||
static inline int musb_platform_get_vbus_status(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->vbus_status)
|
||||
return 0;
|
||||
|
||||
return musb->ops->vbus_status(musb);
|
||||
}
|
||||
|
||||
static inline int musb_platform_init(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->init)
|
||||
return -EINVAL;
|
||||
|
||||
return musb->ops->init(musb);
|
||||
}
|
||||
|
||||
static inline int musb_platform_exit(struct musb *musb)
|
||||
{
|
||||
if (!musb->ops->exit)
|
||||
return -EINVAL;
|
||||
|
||||
return musb->ops->exit(musb);
|
||||
}
|
||||
|
||||
#endif /* __MUSB_CORE_H__ */
|
||||
|
|
|
@ -74,7 +74,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
|
|||
{ __raw_writel(data, addr + offset); }
|
||||
|
||||
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
|
||||
/*
|
||||
* TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
|
||||
|
@ -114,7 +114,7 @@ static inline u8 musb_readb(const void __iomem *addr, unsigned offset)
|
|||
static inline void musb_writeb(void __iomem *addr, unsigned offset, u8 data)
|
||||
{ __raw_writeb(data, addr + offset); }
|
||||
|
||||
#endif /* CONFIG_USB_TUSB6010 */
|
||||
#endif /* CONFIG_USB_MUSB_TUSB6010 */
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@
|
|||
#define MUSB_TESTMODE 0x0F /* 8 bit */
|
||||
|
||||
/* Get offset for a given FIFO from musb->mregs */
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
|
||||
#else
|
||||
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
|
||||
|
@ -295,7 +295,7 @@
|
|||
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
|
||||
(0x100 + (0x10*(_epnum)) + (_offset))
|
||||
|
||||
#ifdef CONFIG_USB_TUSB6010
|
||||
#ifdef CONFIG_USB_MUSB_TUSB6010
|
||||
/* TUSB6010 EP0 configuration register is special */
|
||||
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
|
||||
(0x10 + _offset)
|
||||
|
|
|
@ -276,7 +276,7 @@ int musb_hub_control(
|
|||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
|
||||
musb_set_vbus(musb, 0);
|
||||
musb_platform_set_vbus(musb, 0);
|
||||
break;
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
case USB_PORT_FEAT_C_ENABLE:
|
||||
|
|
|
@ -31,10 +31,18 @@
|
|||
#include <linux/list.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
#include "omap2430.h"
|
||||
|
||||
struct omap2430_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
static struct timer_list musb_idle_timer;
|
||||
|
||||
|
@ -49,12 +57,8 @@ static void musb_do_idle(unsigned long _musb)
|
|||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
switch (musb->xceiv->state) {
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
devctl &= ~MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE) {
|
||||
|
@ -98,7 +102,7 @@ static void musb_do_idle(unsigned long _musb)
|
|||
}
|
||||
|
||||
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
|
||||
static unsigned long last_timer;
|
||||
|
@ -131,15 +135,11 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
|||
mod_timer(&musb_idle_timer, timeout);
|
||||
}
|
||||
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
{
|
||||
}
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
{
|
||||
}
|
||||
static void omap_set_vbus(struct musb *musb, int is_on)
|
||||
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
u8 devctl;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
|
||||
int ret = 1;
|
||||
/* HDRC controls CPEN, but beware current surges during device
|
||||
* connect. They can trigger transient overcurrent conditions
|
||||
* that must be ignored.
|
||||
|
@ -148,12 +148,35 @@ static void omap_set_vbus(struct musb *musb, int is_on)
|
|||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
if (is_on) {
|
||||
musb->is_active = 1;
|
||||
musb->xceiv->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
if (musb->xceiv->state == OTG_STATE_A_IDLE) {
|
||||
/* start the session */
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
/*
|
||||
* Wait for the musb to set as A device to enable the
|
||||
* VBUS
|
||||
*/
|
||||
while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
|
||||
|
||||
MUSB_HST_MODE(musb);
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
dev_err(musb->controller,
|
||||
"configured as A device timeout");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && musb->xceiv->set_vbus)
|
||||
otg_set_vbus(musb->xceiv, 1);
|
||||
} else {
|
||||
musb->is_active = 1;
|
||||
musb->xceiv->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
devctl |= MUSB_DEVCTL_SESSION;
|
||||
MUSB_HST_MODE(musb);
|
||||
}
|
||||
} else {
|
||||
musb->is_active = 0;
|
||||
|
||||
|
@ -175,9 +198,7 @@ static void omap_set_vbus(struct musb *musb, int is_on)
|
|||
musb_readb(musb->mregs, MUSB_DEVCTL));
|
||||
}
|
||||
|
||||
static int musb_platform_resume(struct musb *musb);
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
static int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
|
@ -187,9 +208,91 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb)
|
||||
static inline void omap2430_low_level_exit(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
/* in any role */
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l |= ENABLEFORCE; /* enable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
l |= ENABLEWAKEUP; /* enable wakeup */
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, l);
|
||||
}
|
||||
|
||||
static inline void omap2430_low_level_init(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
l &= ~ENABLEWAKEUP; /* disable wakeup */
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, l);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l &= ~ENABLEFORCE; /* disable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
}
|
||||
|
||||
/* blocking notifier support */
|
||||
static int musb_otg_notifications(struct notifier_block *nb,
|
||||
unsigned long event, void *unused)
|
||||
{
|
||||
struct musb *musb = container_of(nb, struct musb, nb);
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *pdata = dev->platform_data;
|
||||
struct omap_musb_board_data *data = pdata->board_data;
|
||||
|
||||
switch (event) {
|
||||
case USB_EVENT_ID:
|
||||
DBG(4, "ID GND\n");
|
||||
|
||||
if (is_otg_enabled(musb)) {
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
if (musb->gadget_driver) {
|
||||
otg_init(musb->xceiv);
|
||||
|
||||
if (data->interface_type ==
|
||||
MUSB_INTERFACE_UTMI)
|
||||
omap2430_musb_set_vbus(musb, 1);
|
||||
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
otg_init(musb->xceiv);
|
||||
if (data->interface_type ==
|
||||
MUSB_INTERFACE_UTMI)
|
||||
omap2430_musb_set_vbus(musb, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_EVENT_VBUS:
|
||||
DBG(4, "VBUS Connect\n");
|
||||
|
||||
otg_init(musb->xceiv);
|
||||
break;
|
||||
|
||||
case USB_EVENT_NONE:
|
||||
DBG(4, "VBUS Disconnect\n");
|
||||
|
||||
if (data->interface_type == MUSB_INTERFACE_UTMI) {
|
||||
if (musb->xceiv->set_vbus)
|
||||
otg_set_vbus(musb->xceiv, 0);
|
||||
}
|
||||
otg_shutdown(musb->xceiv);
|
||||
break;
|
||||
default:
|
||||
DBG(4, "ID float\n");
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int omap2430_musb_init(struct musb *musb)
|
||||
{
|
||||
u32 l, status = 0;
|
||||
struct device *dev = musb->controller;
|
||||
struct musb_hdrc_platform_data *plat = dev->platform_data;
|
||||
struct omap_musb_board_data *data = plat->board_data;
|
||||
|
@ -204,7 +307,7 @@ int __init musb_platform_init(struct musb *musb)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
musb_platform_resume(musb);
|
||||
omap2430_low_level_init(musb);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
l &= ~ENABLEWAKEUP; /* disable wakeup */
|
||||
|
@ -241,87 +344,214 @@ int __init musb_platform_init(struct musb *musb)
|
|||
musb_readl(musb->mregs, OTG_INTERFSEL),
|
||||
musb_readl(musb->mregs, OTG_SIMENABLE));
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
musb->board_set_vbus = omap_set_vbus;
|
||||
musb->nb.notifier_call = musb_otg_notifications;
|
||||
status = otg_register_notifier(musb->xceiv, &musb->nb);
|
||||
|
||||
if (status)
|
||||
DBG(1, "notification register failed\n");
|
||||
|
||||
/* check whether cable is already connected */
|
||||
if (musb->xceiv->state ==OTG_STATE_B_IDLE)
|
||||
musb_otg_notifications(&musb->nb, 1,
|
||||
musb->xceiv->gadget);
|
||||
|
||||
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void musb_platform_save_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
static int omap2430_musb_exit(struct musb *musb)
|
||||
{
|
||||
musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
}
|
||||
|
||||
void musb_platform_restore_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
{
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int musb_platform_suspend(struct musb *musb)
|
||||
{
|
||||
u32 l;
|
||||
|
||||
if (!musb->clock)
|
||||
return 0;
|
||||
|
||||
/* in any role */
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l |= ENABLEFORCE; /* enable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
l |= ENABLEWAKEUP; /* enable wakeup */
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, l);
|
||||
|
||||
otg_set_suspend(musb->xceiv, 1);
|
||||
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 0);
|
||||
else
|
||||
clk_disable(musb->clock);
|
||||
omap2430_low_level_exit(musb);
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int musb_platform_resume(struct musb *musb)
|
||||
static const struct musb_platform_ops omap2430_ops = {
|
||||
.init = omap2430_musb_init,
|
||||
.exit = omap2430_musb_exit,
|
||||
|
||||
.set_mode = omap2430_musb_set_mode,
|
||||
.try_idle = omap2430_musb_try_idle,
|
||||
|
||||
.set_vbus = omap2430_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init omap2430_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 l;
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct omap2430_glue *glue;
|
||||
struct clk *clk;
|
||||
|
||||
if (!musb->clock)
|
||||
return 0;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "ick");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &omap2430_dmamask;
|
||||
musb->dev.coherent_dma_mask = omap2430_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &omap2430_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
clk_disable(clk);
|
||||
|
||||
err3:
|
||||
clk_put(clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit omap2430_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap2430_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_put(glue->clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void omap2430_save_context(struct musb *musb)
|
||||
{
|
||||
musb->context.otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
musb->context.otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
}
|
||||
|
||||
static void omap2430_restore_context(struct musb *musb)
|
||||
{
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, musb->context.otg_sysconfig);
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, musb->context.otg_forcestandby);
|
||||
}
|
||||
|
||||
static int omap2430_suspend(struct device *dev)
|
||||
{
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
omap2430_low_level_exit(musb);
|
||||
otg_set_suspend(musb->xceiv, 1);
|
||||
omap2430_save_context(musb);
|
||||
clk_disable(glue->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap2430_resume(struct device *dev)
|
||||
{
|
||||
struct omap2430_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(glue->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "faled to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
omap2430_low_level_init(musb);
|
||||
omap2430_restore_context(musb);
|
||||
otg_set_suspend(musb->xceiv, 0);
|
||||
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 1);
|
||||
else
|
||||
clk_enable(musb->clock);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_SYSCONFIG);
|
||||
l &= ~ENABLEWAKEUP; /* disable wakeup */
|
||||
musb_writel(musb->mregs, OTG_SYSCONFIG, l);
|
||||
|
||||
l = musb_readl(musb->mregs, OTG_FORCESTDBY);
|
||||
l &= ~ENABLEFORCE; /* disable MSTANDBY */
|
||||
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dev_pm_ops omap2430_pm_ops = {
|
||||
.suspend = omap2430_suspend,
|
||||
.resume = omap2430_resume,
|
||||
};
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
#define DEV_PM_OPS (&omap2430_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver omap2430_driver = {
|
||||
.remove = __exit_p(omap2430_remove),
|
||||
.driver = {
|
||||
.name = "musb-omap2430",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init omap2430_init(void)
|
||||
{
|
||||
|
||||
musb_platform_suspend(musb);
|
||||
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
return 0;
|
||||
return platform_driver_probe(&omap2430_driver, omap2430_probe);
|
||||
}
|
||||
subsys_initcall(omap2430_init);
|
||||
|
||||
static void __exit omap2430_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&omap2430_driver);
|
||||
}
|
||||
module_exit(omap2430_exit);
|
||||
|
|
|
@ -21,10 +21,16 @@
|
|||
#include <linux/usb.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
static void tusb_source_power(struct musb *musb, int is_on);
|
||||
struct tusb6010_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
};
|
||||
|
||||
static void tusb_musb_set_vbus(struct musb *musb, int is_on);
|
||||
|
||||
#define TUSB_REV_MAJOR(reg_val) ((reg_val >> 4) & 0xf)
|
||||
#define TUSB_REV_MINOR(reg_val) (reg_val & 0xf)
|
||||
|
@ -50,7 +56,7 @@ u8 tusb_get_revision(struct musb *musb)
|
|||
return rev;
|
||||
}
|
||||
|
||||
static int __init tusb_print_revision(struct musb *musb)
|
||||
static int tusb_print_revision(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
u8 rev;
|
||||
|
@ -275,17 +281,6 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
|
|||
void __iomem *tbase = musb->ctrl_base;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Keep clock active when enabled. Note that this is not tied to
|
||||
* drawing VBUS, as with OTG mA can be less than musb->min_power.
|
||||
*/
|
||||
if (musb->set_clock) {
|
||||
if (mA)
|
||||
musb->set_clock(musb->clock, 1);
|
||||
else
|
||||
musb->set_clock(musb->clock, 0);
|
||||
}
|
||||
|
||||
/* tps65030 seems to consume max 100mA, with maybe 60mA available
|
||||
* (measured on one board) for things other than tps and tusb.
|
||||
*
|
||||
|
@ -348,7 +343,7 @@ static void tusb_set_clock_source(struct musb *musb, unsigned mode)
|
|||
* USB link is not suspended ... and tells us the relevant wakeup
|
||||
* events. SW_EN for voltage is handled separately.
|
||||
*/
|
||||
void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
|
||||
static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
u32 reg;
|
||||
|
@ -385,7 +380,7 @@ void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)
|
|||
/*
|
||||
* Updates cable VBUS status. Caller must take care of locking.
|
||||
*/
|
||||
int musb_platform_get_vbus_status(struct musb *musb)
|
||||
static int tusb_musb_vbus_status(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
u32 otg_stat, prcm_mngmt;
|
||||
|
@ -431,7 +426,7 @@ static void musb_do_idle(unsigned long _musb)
|
|||
}
|
||||
/* FALLTHROUGH */
|
||||
case OTG_STATE_A_IDLE:
|
||||
tusb_source_power(musb, 0);
|
||||
tusb_musb_set_vbus(musb, 0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -475,7 +470,7 @@ static void musb_do_idle(unsigned long _musb)
|
|||
* we don't want to treat that full speed J as a wakeup event.
|
||||
* ... peripherals must draw only suspend current after 10 msec.
|
||||
*/
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
unsigned long default_timeout = jiffies + msecs_to_jiffies(3);
|
||||
static unsigned long last_timer;
|
||||
|
@ -515,7 +510,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
|||
| TUSB_DEV_OTG_TIMER_ENABLE) \
|
||||
: 0)
|
||||
|
||||
static void tusb_source_power(struct musb *musb, int is_on)
|
||||
static void tusb_musb_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
u32 conf, prcm, timer;
|
||||
|
@ -531,8 +526,6 @@ static void tusb_source_power(struct musb *musb, int is_on)
|
|||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
|
||||
if (is_on) {
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 1);
|
||||
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
|
||||
musb->xceiv->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
|
@ -571,8 +564,6 @@ static void tusb_source_power(struct musb *musb, int is_on)
|
|||
|
||||
devctl &= ~MUSB_DEVCTL_SESSION;
|
||||
conf &= ~TUSB_DEV_CONF_USB_HOST_MODE;
|
||||
if (musb->set_clock)
|
||||
musb->set_clock(musb->clock, 0);
|
||||
}
|
||||
prcm &= ~(TUSB_PRCM_MNGMT_15_SW_EN | TUSB_PRCM_MNGMT_33_SW_EN);
|
||||
|
||||
|
@ -599,7 +590,7 @@ static void tusb_source_power(struct musb *musb, int is_on)
|
|||
* and peripheral modes in non-OTG configurations by reconfiguring hardware
|
||||
* and then setting musb->board_mode. For now, only support OTG mode.
|
||||
*/
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
|
||||
|
@ -677,7 +668,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
|
|||
default_a = is_host_enabled(musb);
|
||||
DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
|
||||
musb->xceiv->default_a = default_a;
|
||||
tusb_source_power(musb, default_a);
|
||||
tusb_musb_set_vbus(musb, default_a);
|
||||
|
||||
/* Don't allow idling immediately */
|
||||
if (default_a)
|
||||
|
@ -722,7 +713,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
|
|||
switch (musb->xceiv->state) {
|
||||
case OTG_STATE_A_IDLE:
|
||||
DBG(2, "Got SRP, turning on VBUS\n");
|
||||
musb_set_vbus(musb, 1);
|
||||
musb_platform_set_vbus(musb, 1);
|
||||
|
||||
/* CONNECT can wake if a_wait_bcon is set */
|
||||
if (musb->a_wait_bcon != 0)
|
||||
|
@ -748,11 +739,11 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
|
|||
*/
|
||||
if (musb->vbuserr_retry) {
|
||||
musb->vbuserr_retry--;
|
||||
tusb_source_power(musb, 1);
|
||||
tusb_musb_set_vbus(musb, 1);
|
||||
} else {
|
||||
musb->vbuserr_retry
|
||||
= VBUSERR_RETRY_COUNT;
|
||||
tusb_source_power(musb, 0);
|
||||
tusb_musb_set_vbus(musb, 0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -786,7 +777,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
|
|||
} else {
|
||||
/* REVISIT report overcurrent to hub? */
|
||||
ERR("vbus too slow, devctl %02x\n", devctl);
|
||||
tusb_source_power(musb, 0);
|
||||
tusb_musb_set_vbus(musb, 0);
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
|
@ -807,7 +798,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
|
|||
return idle_timeout;
|
||||
}
|
||||
|
||||
static irqreturn_t tusb_interrupt(int irq, void *__hci)
|
||||
static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
|
||||
{
|
||||
struct musb *musb = __hci;
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
|
@ -911,7 +902,7 @@ static irqreturn_t tusb_interrupt(int irq, void *__hci)
|
|||
musb_writel(tbase, TUSB_INT_SRC_CLEAR,
|
||||
int_src & ~TUSB_INT_MASK_RESERVED_BITS);
|
||||
|
||||
musb_platform_try_idle(musb, idle_timeout);
|
||||
tusb_musb_try_idle(musb, idle_timeout);
|
||||
|
||||
musb_writel(tbase, TUSB_INT_MASK, int_mask);
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
@ -926,7 +917,7 @@ static int dma_off;
|
|||
* REVISIT:
|
||||
* - Check what is unnecessary in MGC_HdrcStart()
|
||||
*/
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
static void tusb_musb_enable(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
|
||||
|
@ -970,7 +961,7 @@ void musb_platform_enable(struct musb *musb)
|
|||
/*
|
||||
* Disables TUSB6010. Caller must take care of locking.
|
||||
*/
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
static void tusb_musb_disable(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
|
||||
|
@ -995,7 +986,7 @@ void musb_platform_disable(struct musb *musb)
|
|||
* Sets up TUSB6010 CPU interface specific signals and registers
|
||||
* Note: Settings optimized for OMAP24xx
|
||||
*/
|
||||
static void __init tusb_setup_cpu_interface(struct musb *musb)
|
||||
static void tusb_setup_cpu_interface(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
|
||||
|
@ -1022,7 +1013,7 @@ static void __init tusb_setup_cpu_interface(struct musb *musb)
|
|||
musb_writel(tbase, TUSB_WAIT_COUNT, 1);
|
||||
}
|
||||
|
||||
static int __init tusb_start(struct musb *musb)
|
||||
static int tusb_musb_start(struct musb *musb)
|
||||
{
|
||||
void __iomem *tbase = musb->ctrl_base;
|
||||
int ret = 0;
|
||||
|
@ -1091,7 +1082,7 @@ static int __init tusb_start(struct musb *musb)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb)
|
||||
static int tusb_musb_init(struct musb *musb)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
struct resource *mem;
|
||||
|
@ -1131,16 +1122,14 @@ int __init musb_platform_init(struct musb *musb)
|
|||
*/
|
||||
musb->mregs += TUSB_BASE_OFFSET;
|
||||
|
||||
ret = tusb_start(musb);
|
||||
ret = tusb_musb_start(musb);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Could not start tusb6010 (%d)\n",
|
||||
ret);
|
||||
goto done;
|
||||
}
|
||||
musb->isr = tusb_interrupt;
|
||||
musb->isr = tusb_musb_interrupt;
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
musb->board_set_vbus = tusb_source_power;
|
||||
if (is_peripheral_enabled(musb)) {
|
||||
musb->xceiv->set_power = tusb_draw_power;
|
||||
the_musb = musb;
|
||||
|
@ -1159,7 +1148,7 @@ int __init musb_platform_init(struct musb *musb)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
static int tusb_musb_exit(struct musb *musb)
|
||||
{
|
||||
del_timer_sync(&musb_idle_timer);
|
||||
the_musb = NULL;
|
||||
|
@ -1173,3 +1162,115 @@ int musb_platform_exit(struct musb *musb)
|
|||
usb_nop_xceiv_unregister();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops tusb_ops = {
|
||||
.init = tusb_musb_init,
|
||||
.exit = tusb_musb_exit,
|
||||
|
||||
.enable = tusb_musb_enable,
|
||||
.disable = tusb_musb_disable,
|
||||
|
||||
.set_mode = tusb_musb_set_mode,
|
||||
.try_idle = tusb_musb_try_idle,
|
||||
|
||||
.vbus_status = tusb_musb_vbus_status,
|
||||
.set_vbus = tusb_musb_set_vbus,
|
||||
};
|
||||
|
||||
static u64 tusb_dmamask = DMA_BIT_MASK(32);
|
||||
|
||||
static int __init tusb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct tusb6010_glue *glue;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
musb->dev.dma_mask = &tusb_dmamask;
|
||||
musb->dev.coherent_dma_mask = tusb_dmamask;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
|
||||
pdata->platform_ops = &tusb_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit tusb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tusb6010_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tusb_driver = {
|
||||
.remove = __exit_p(tusb_remove),
|
||||
.driver = {
|
||||
.name = "musb-tusb",
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init tusb_init(void)
|
||||
{
|
||||
return platform_driver_probe(&tusb_driver, tusb_probe);
|
||||
}
|
||||
subsys_initcall(tusb_init);
|
||||
|
||||
static void __exit tusb_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&tusb_driver);
|
||||
}
|
||||
module_exit(tusb_exit);
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* Copyright (C) 2010 ST-Ericsson AB
|
||||
* Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
|
||||
*
|
||||
* Based on omap2430.c
|
||||
*
|
||||
* 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 program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
struct ux500_glue {
|
||||
struct device *dev;
|
||||
struct platform_device *musb;
|
||||
struct clk *clk;
|
||||
};
|
||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
||||
|
||||
static int ux500_musb_init(struct musb *musb)
|
||||
{
|
||||
musb->xceiv = otg_get_transceiver();
|
||||
if (!musb->xceiv) {
|
||||
pr_err("HS USB OTG: no transceiver configured\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ux500_musb_exit(struct musb *musb)
|
||||
{
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct musb_platform_ops ux500_ops = {
|
||||
.init = ux500_musb_init,
|
||||
.exit = ux500_musb_exit,
|
||||
};
|
||||
|
||||
static int __init ux500_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct platform_device *musb;
|
||||
struct ux500_glue *glue;
|
||||
struct clk *clk;
|
||||
|
||||
int ret = -ENOMEM;
|
||||
|
||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||
if (!glue) {
|
||||
dev_err(&pdev->dev, "failed to allocate glue context\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
musb = platform_device_alloc("musb-hdrc", -1);
|
||||
if (!musb) {
|
||||
dev_err(&pdev->dev, "failed to allocate musb device\n");
|
||||
goto err1;
|
||||
}
|
||||
|
||||
clk = clk_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
ret = PTR_ERR(clk);
|
||||
goto err2;
|
||||
}
|
||||
|
||||
ret = clk_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable clock\n");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
musb->dev.parent = &pdev->dev;
|
||||
|
||||
glue->dev = &pdev->dev;
|
||||
glue->musb = musb;
|
||||
glue->clk = clk;
|
||||
|
||||
pdata->platform_ops = &ux500_ops;
|
||||
|
||||
platform_set_drvdata(pdev, glue);
|
||||
|
||||
ret = platform_device_add_resources(musb, pdev->resource,
|
||||
pdev->num_resources);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add resources\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add platform_data\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
ret = platform_device_add(musb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register musb device\n");
|
||||
goto err4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
clk_disable(clk);
|
||||
|
||||
err3:
|
||||
clk_put(clk);
|
||||
|
||||
err2:
|
||||
platform_device_put(musb);
|
||||
|
||||
err1:
|
||||
kfree(glue);
|
||||
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __exit ux500_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ux500_glue *glue = platform_get_drvdata(pdev);
|
||||
|
||||
platform_device_del(glue->musb);
|
||||
platform_device_put(glue->musb);
|
||||
clk_disable(glue->clk);
|
||||
clk_put(glue->clk);
|
||||
kfree(glue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int ux500_suspend(struct device *dev)
|
||||
{
|
||||
struct ux500_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
|
||||
otg_set_suspend(musb->xceiv, 1);
|
||||
clk_disable(glue->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ux500_resume(struct device *dev)
|
||||
{
|
||||
struct ux500_glue *glue = dev_get_drvdata(dev);
|
||||
struct musb *musb = glue_to_musb(glue);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(glue->clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
otg_set_suspend(musb->xceiv, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops ux500_pm_ops = {
|
||||
.suspend = ux500_suspend,
|
||||
.resume = ux500_resume,
|
||||
};
|
||||
|
||||
#define DEV_PM_OPS (&ux500_pm_ops)
|
||||
#else
|
||||
#define DEV_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver ux500_driver = {
|
||||
.remove = __exit_p(ux500_remove),
|
||||
.driver = {
|
||||
.name = "musb-ux500",
|
||||
.pm = DEV_PM_OPS,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
|
||||
MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static int __init ux500_init(void)
|
||||
{
|
||||
return platform_driver_probe(&ux500_driver, ux500_probe);
|
||||
}
|
||||
subsys_initcall(ux500_init);
|
||||
|
||||
static void __exit ux500_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ux500_driver);
|
||||
}
|
||||
module_exit(ux500_exit);
|
|
@ -59,6 +59,18 @@ config TWL4030_USB
|
|||
This transceiver supports high and full speed devices plus,
|
||||
in host mode, low speed.
|
||||
|
||||
config TWL6030_USB
|
||||
tristate "TWL6030 USB Transceiver Driver"
|
||||
depends on TWL4030_CORE
|
||||
select USB_OTG_UTILS
|
||||
help
|
||||
Enable this to support the USB OTG transceiver on TWL6030
|
||||
family chips. This TWL6030 transceiver has the VBUS and ID GND
|
||||
and OTG SRP events capabilities. For all other transceiver functionality
|
||||
UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs
|
||||
are hooked to this driver through platform_data structure.
|
||||
The definition of internal PHY APIs are in the mach-omap2 layer.
|
||||
|
||||
config NOP_USB_XCEIV
|
||||
tristate "NOP USB Transceiver Driver"
|
||||
select USB_OTG_UTILS
|
||||
|
|
|
@ -12,6 +12,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
|
|||
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
|
||||
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
|
||||
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
|
||||
obj-$(CONFIG_TWL6030_USB) += twl6030-usb.o
|
||||
obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
|
||||
obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
|
||||
obj-$(CONFIG_USB_ULPI) += ulpi.o
|
||||
|
|
|
@ -0,0 +1,493 @@
|
|||
/*
|
||||
* twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
|
||||
*
|
||||
* Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
|
||||
* 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.
|
||||
*
|
||||
* Author: Hema HK <hemahk@ti.com>
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/i2c/twl.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
/* usb register definitions */
|
||||
#define USB_VENDOR_ID_LSB 0x00
|
||||
#define USB_VENDOR_ID_MSB 0x01
|
||||
#define USB_PRODUCT_ID_LSB 0x02
|
||||
#define USB_PRODUCT_ID_MSB 0x03
|
||||
#define USB_VBUS_CTRL_SET 0x04
|
||||
#define USB_VBUS_CTRL_CLR 0x05
|
||||
#define USB_ID_CTRL_SET 0x06
|
||||
#define USB_ID_CTRL_CLR 0x07
|
||||
#define USB_VBUS_INT_SRC 0x08
|
||||
#define USB_VBUS_INT_LATCH_SET 0x09
|
||||
#define USB_VBUS_INT_LATCH_CLR 0x0A
|
||||
#define USB_VBUS_INT_EN_LO_SET 0x0B
|
||||
#define USB_VBUS_INT_EN_LO_CLR 0x0C
|
||||
#define USB_VBUS_INT_EN_HI_SET 0x0D
|
||||
#define USB_VBUS_INT_EN_HI_CLR 0x0E
|
||||
#define USB_ID_INT_SRC 0x0F
|
||||
#define USB_ID_INT_LATCH_SET 0x10
|
||||
#define USB_ID_INT_LATCH_CLR 0x11
|
||||
|
||||
#define USB_ID_INT_EN_LO_SET 0x12
|
||||
#define USB_ID_INT_EN_LO_CLR 0x13
|
||||
#define USB_ID_INT_EN_HI_SET 0x14
|
||||
#define USB_ID_INT_EN_HI_CLR 0x15
|
||||
#define USB_OTG_ADP_CTRL 0x16
|
||||
#define USB_OTG_ADP_HIGH 0x17
|
||||
#define USB_OTG_ADP_LOW 0x18
|
||||
#define USB_OTG_ADP_RISE 0x19
|
||||
#define USB_OTG_REVISION 0x1A
|
||||
|
||||
/* to be moved to LDO */
|
||||
#define TWL6030_MISC2 0xE5
|
||||
#define TWL6030_CFG_LDO_PD2 0xF5
|
||||
#define TWL6030_BACKUP_REG 0xFA
|
||||
|
||||
#define STS_HW_CONDITIONS 0x21
|
||||
|
||||
/* In module TWL6030_MODULE_PM_MASTER */
|
||||
#define STS_HW_CONDITIONS 0x21
|
||||
#define STS_USB_ID BIT(2)
|
||||
|
||||
/* In module TWL6030_MODULE_PM_RECEIVER */
|
||||
#define VUSB_CFG_TRANS 0x71
|
||||
#define VUSB_CFG_STATE 0x72
|
||||
#define VUSB_CFG_VOLTAGE 0x73
|
||||
|
||||
/* in module TWL6030_MODULE_MAIN_CHARGE */
|
||||
|
||||
#define CHARGERUSB_CTRL1 0x8
|
||||
|
||||
#define CONTROLLER_STAT1 0x03
|
||||
#define VBUS_DET BIT(2)
|
||||
|
||||
struct twl6030_usb {
|
||||
struct otg_transceiver otg;
|
||||
struct device *dev;
|
||||
|
||||
/* for vbus reporting with irqs disabled */
|
||||
spinlock_t lock;
|
||||
|
||||
struct regulator *usb3v3;
|
||||
|
||||
int irq1;
|
||||
int irq2;
|
||||
u8 linkstat;
|
||||
u8 asleep;
|
||||
bool irq_enabled;
|
||||
};
|
||||
|
||||
#define xceiv_to_twl(x) container_of((x), struct twl6030_usb, otg);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
|
||||
u8 data, u8 address)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = twl_i2c_write_u8(module, data, address);
|
||||
if (ret < 0)
|
||||
dev_err(twl->dev,
|
||||
"Write[0x%x] Error %d\n", address, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
|
||||
{
|
||||
u8 data, ret = 0;
|
||||
|
||||
ret = twl_i2c_read_u8(module, &data, address);
|
||||
if (ret >= 0)
|
||||
ret = data;
|
||||
else
|
||||
dev_err(twl->dev,
|
||||
"readb[0x%x,0x%x] Error %d\n",
|
||||
module, address, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
static int twl6030_set_phy_clk(struct otg_transceiver *x, int on)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
struct device *dev;
|
||||
struct twl4030_usb_data *pdata;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
dev = twl->dev;
|
||||
pdata = dev->platform_data;
|
||||
|
||||
pdata->phy_set_clock(twl->dev, on);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_phy_init(struct otg_transceiver *x)
|
||||
{
|
||||
u8 hw_state;
|
||||
struct twl6030_usb *twl;
|
||||
struct device *dev;
|
||||
struct twl4030_usb_data *pdata;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
dev = twl->dev;
|
||||
pdata = dev->platform_data;
|
||||
|
||||
regulator_enable(twl->usb3v3);
|
||||
|
||||
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
|
||||
|
||||
if (hw_state & STS_USB_ID)
|
||||
pdata->phy_power(twl->dev, 1, 1);
|
||||
else
|
||||
pdata->phy_power(twl->dev, 0, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl6030_phy_shutdown(struct otg_transceiver *x)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
struct device *dev;
|
||||
struct twl4030_usb_data *pdata;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
dev = twl->dev;
|
||||
pdata = dev->platform_data;
|
||||
pdata->phy_power(twl->dev, 0, 0);
|
||||
regulator_disable(twl->usb3v3);
|
||||
}
|
||||
|
||||
static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
|
||||
{
|
||||
|
||||
/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_BACKUP_REG);
|
||||
|
||||
/* Program CFG_LDO_PD2 register and set VUSB bit */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x1, TWL6030_CFG_LDO_PD2);
|
||||
|
||||
/* Program MISC2 register and set bit VUSB_IN_VBAT */
|
||||
twl6030_writeb(twl, TWL6030_MODULE_ID0 , 0x10, TWL6030_MISC2);
|
||||
|
||||
twl->usb3v3 = regulator_get(twl->dev, "vusb");
|
||||
if (IS_ERR(twl->usb3v3))
|
||||
return -ENODEV;
|
||||
|
||||
regulator_enable(twl->usb3v3);
|
||||
|
||||
/* Program the VUSB_CFG_TRANS for ACTIVE state. */
|
||||
twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0x3F,
|
||||
VUSB_CFG_TRANS);
|
||||
|
||||
/* Program the VUSB_CFG_STATE register to ON on all groups. */
|
||||
twl6030_writeb(twl, TWL_MODULE_PM_RECEIVER, 0xE1,
|
||||
VUSB_CFG_STATE);
|
||||
|
||||
/* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
|
||||
|
||||
/*
|
||||
* Program the USB_ID_CTRL_SET register to enable GND drive
|
||||
* and the ID comparators
|
||||
*/
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t twl6030_usb_vbus_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct twl6030_usb *twl = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
int ret = -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&twl->lock, flags);
|
||||
|
||||
switch (twl->linkstat) {
|
||||
case USB_EVENT_VBUS:
|
||||
ret = snprintf(buf, PAGE_SIZE, "vbus\n");
|
||||
break;
|
||||
case USB_EVENT_ID:
|
||||
ret = snprintf(buf, PAGE_SIZE, "id\n");
|
||||
break;
|
||||
case USB_EVENT_NONE:
|
||||
ret = snprintf(buf, PAGE_SIZE, "none\n");
|
||||
break;
|
||||
default:
|
||||
ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&twl->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
|
||||
|
||||
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
|
||||
{
|
||||
struct twl6030_usb *twl = _twl;
|
||||
int status;
|
||||
u8 vbus_state, hw_state;
|
||||
|
||||
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
|
||||
|
||||
vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
|
||||
CONTROLLER_STAT1);
|
||||
if (!(hw_state & STS_USB_ID)) {
|
||||
if (vbus_state & VBUS_DET) {
|
||||
status = USB_EVENT_VBUS;
|
||||
twl->otg.default_a = false;
|
||||
twl->otg.state = OTG_STATE_B_IDLE;
|
||||
} else {
|
||||
status = USB_EVENT_NONE;
|
||||
}
|
||||
if (status >= 0) {
|
||||
twl->linkstat = status;
|
||||
blocking_notifier_call_chain(&twl->otg.notifier,
|
||||
status, twl->otg.gadget);
|
||||
}
|
||||
}
|
||||
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
|
||||
{
|
||||
struct twl6030_usb *twl = _twl;
|
||||
int status = USB_EVENT_NONE;
|
||||
u8 hw_state;
|
||||
|
||||
hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
|
||||
|
||||
if (hw_state & STS_USB_ID) {
|
||||
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR, 0x1);
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
|
||||
0x10);
|
||||
status = USB_EVENT_ID;
|
||||
twl->otg.default_a = true;
|
||||
twl->otg.state = OTG_STATE_A_IDLE;
|
||||
blocking_notifier_call_chain(&twl->otg.notifier, status,
|
||||
twl->otg.gadget);
|
||||
} else {
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
|
||||
0x10);
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
|
||||
0x1);
|
||||
}
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_LATCH_CLR, status);
|
||||
twl->linkstat = status;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int twl6030_set_peripheral(struct otg_transceiver *x,
|
||||
struct usb_gadget *gadget)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
|
||||
if (!x)
|
||||
return -ENODEV;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
twl->otg.gadget = gadget;
|
||||
if (!gadget)
|
||||
twl->otg.state = OTG_STATE_UNDEFINED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_enable_irq(struct otg_transceiver *x)
|
||||
{
|
||||
struct twl6030_usb *twl = xceiv_to_twl(x);
|
||||
|
||||
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1);
|
||||
twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
|
||||
twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
|
||||
|
||||
twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
|
||||
REG_INT_MSK_LINE_C);
|
||||
twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
|
||||
REG_INT_MSK_STS_C);
|
||||
twl6030_usb_irq(twl->irq2, twl);
|
||||
twl6030_usbotg_irq(twl->irq1, twl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
|
||||
{
|
||||
struct twl6030_usb *twl = xceiv_to_twl(x);
|
||||
|
||||
/*
|
||||
* Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
|
||||
* register. This enables boost mode.
|
||||
*/
|
||||
if (enabled)
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x40,
|
||||
CHARGERUSB_CTRL1);
|
||||
else
|
||||
twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE , 0x00,
|
||||
CHARGERUSB_CTRL1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int twl6030_set_host(struct otg_transceiver *x, struct usb_bus *host)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
|
||||
if (!x)
|
||||
return -ENODEV;
|
||||
|
||||
twl = xceiv_to_twl(x);
|
||||
twl->otg.host = host;
|
||||
if (!host)
|
||||
twl->otg.state = OTG_STATE_UNDEFINED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit twl6030_usb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6030_usb *twl;
|
||||
int status, err;
|
||||
struct twl4030_usb_data *pdata;
|
||||
struct device *dev = &pdev->dev;
|
||||
pdata = dev->platform_data;
|
||||
|
||||
twl = kzalloc(sizeof *twl, GFP_KERNEL);
|
||||
if (!twl)
|
||||
return -ENOMEM;
|
||||
|
||||
twl->dev = &pdev->dev;
|
||||
twl->irq1 = platform_get_irq(pdev, 0);
|
||||
twl->irq2 = platform_get_irq(pdev, 1);
|
||||
twl->otg.dev = twl->dev;
|
||||
twl->otg.label = "twl6030";
|
||||
twl->otg.set_host = twl6030_set_host;
|
||||
twl->otg.set_peripheral = twl6030_set_peripheral;
|
||||
twl->otg.set_vbus = twl6030_set_vbus;
|
||||
twl->otg.init = twl6030_phy_init;
|
||||
twl->otg.shutdown = twl6030_phy_shutdown;
|
||||
|
||||
/* init spinlock for workqueue */
|
||||
spin_lock_init(&twl->lock);
|
||||
|
||||
err = twl6030_usb_ldo_init(twl);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "ldo init failed\n");
|
||||
kfree(twl);
|
||||
return err;
|
||||
}
|
||||
otg_set_transceiver(&twl->otg);
|
||||
|
||||
platform_set_drvdata(pdev, twl);
|
||||
if (device_create_file(&pdev->dev, &dev_attr_vbus))
|
||||
dev_warn(&pdev->dev, "could not create sysfs file\n");
|
||||
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
|
||||
|
||||
twl->irq_enabled = true;
|
||||
status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"twl6030_usb", twl);
|
||||
if (status < 0) {
|
||||
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
||||
twl->irq1, status);
|
||||
device_remove_file(twl->dev, &dev_attr_vbus);
|
||||
kfree(twl);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
|
||||
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
|
||||
"twl6030_usb", twl);
|
||||
if (status < 0) {
|
||||
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
|
||||
twl->irq2, status);
|
||||
free_irq(twl->irq1, twl);
|
||||
device_remove_file(twl->dev, &dev_attr_vbus);
|
||||
kfree(twl);
|
||||
return status;
|
||||
}
|
||||
|
||||
pdata->phy_init(dev);
|
||||
twl6030_enable_irq(&twl->otg);
|
||||
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __exit twl6030_usb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct twl6030_usb *twl = platform_get_drvdata(pdev);
|
||||
|
||||
struct twl4030_usb_data *pdata;
|
||||
struct device *dev = &pdev->dev;
|
||||
pdata = dev->platform_data;
|
||||
|
||||
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
|
||||
REG_INT_MSK_LINE_C);
|
||||
twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
|
||||
REG_INT_MSK_STS_C);
|
||||
free_irq(twl->irq1, twl);
|
||||
free_irq(twl->irq2, twl);
|
||||
regulator_put(twl->usb3v3);
|
||||
pdata->phy_exit(twl->dev);
|
||||
device_remove_file(twl->dev, &dev_attr_vbus);
|
||||
kfree(twl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver twl6030_usb_driver = {
|
||||
.probe = twl6030_usb_probe,
|
||||
.remove = __exit_p(twl6030_usb_remove),
|
||||
.driver = {
|
||||
.name = "twl6030_usb",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init twl6030_usb_init(void)
|
||||
{
|
||||
return platform_driver_register(&twl6030_usb_driver);
|
||||
}
|
||||
subsys_initcall(twl6030_usb_init);
|
||||
|
||||
static void __exit twl6030_usb_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&twl6030_usb_driver);
|
||||
}
|
||||
module_exit(twl6030_usb_exit);
|
||||
|
||||
MODULE_ALIAS("platform:twl6030_usb");
|
||||
MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
|
||||
MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -593,6 +593,13 @@ enum twl4030_usb_mode {
|
|||
|
||||
struct twl4030_usb_data {
|
||||
enum twl4030_usb_mode usb_mode;
|
||||
|
||||
int (*phy_init)(struct device *dev);
|
||||
int (*phy_exit)(struct device *dev);
|
||||
/* Power on/off the PHY */
|
||||
int (*phy_power)(struct device *dev, int iD, int on);
|
||||
/* enable/disable phy clocks */
|
||||
int (*phy_set_clock)(struct device *dev, int on);
|
||||
};
|
||||
|
||||
struct twl4030_ins {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Inventra (Multidrop) Highspeed Dual-Role Controllers: (M)HDRC.
|
||||
*
|
||||
* Board initialization should put one of these into dev->platform_data,
|
||||
* probably on some platform_device named "musb_hdrc". It encapsulates
|
||||
* probably on some platform_device named "musb-hdrc". It encapsulates
|
||||
* key configuration differences between boards.
|
||||
*/
|
||||
|
||||
|
@ -118,14 +118,14 @@ struct musb_hdrc_platform_data {
|
|||
/* Power the device on or off */
|
||||
int (*set_power)(int state);
|
||||
|
||||
/* Turn device clock on or off */
|
||||
int (*set_clock)(struct clk *clock, int is_on);
|
||||
|
||||
/* MUSB configuration-specific details */
|
||||
struct musb_hdrc_config *config;
|
||||
|
||||
/* Architecture specific board data */
|
||||
void *board_data;
|
||||
|
||||
/* Platform specific struct musb_ops pointer */
|
||||
const void *platform_ops;
|
||||
};
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue