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:
Greg Kroah-Hartman 2010-12-15 09:29:38 -08:00
commit 5cdc5bd8b2
42 changed files with 2537 additions and 640 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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) {

View file

@ -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 = {

View file

@ -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)

View file

@ -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),
};
/*

View file

@ -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),

View file

@ -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),
};

View file

@ -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),

View file

@ -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;
}

View file

@ -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()) {

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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).

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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__ */

View file

@ -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

View file

@ -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)

View file

@ -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:

View file

@ -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);

View file

@ -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);

216
drivers/usb/musb/ux500.c Normal file
View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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");

View file

@ -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 {

View file

@ -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;
};