USB: EHCI: Configure HSIC host<->hub<->Conventional USB devices
SMSC hub must be configured so that Conventional USB
devices can be connected to SMSC hub on 8960 liquid.
Change-Id: I261798de153d3c37f2fa2c4d7e15d96bb81c432f
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm8960-regulator.c b/arch/arm/mach-msm/board-msm8960-regulator.c
index e98f364..29b7460 100644
--- a/arch/arm/mach-msm/board-msm8960-regulator.c
+++ b/arch/arm/mach-msm/board-msm8960-regulator.c
@@ -164,6 +164,7 @@
REGULATOR_SUPPLY("CDC_VDDA_TX", "tabla2x-slim"),
REGULATOR_SUPPLY("CDC_VDDA_RX", "tabla2x-slim"),
REGULATOR_SUPPLY("vcc_i2c", "3-005b"),
+ REGULATOR_SUPPLY("EXT_HUB_VDDIO", "msm_hsic_host"),
};
VREG_CONSUMERS(S5) = {
REGULATOR_SUPPLY("8921_s5", NULL),
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 53fd4f3..3412539 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -731,6 +731,12 @@
.pull = GPIOMUX_PULL_DOWN,
};
+static struct gpiomux_setting hsic_hub_act_cfg = {
+ .func = GPIOMUX_FUNC_GPIO,
+ .drv = GPIOMUX_DRV_2MA,
+ .pull = GPIOMUX_PULL_NONE,
+};
+
static struct msm_gpiomux_config msm8960_hsic_configs[] = {
{
.gpio = 150, /*HSIC_STROBE */
@@ -746,6 +752,13 @@
[GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
},
},
+ {
+ .gpio = 91, /* HSIC_HUB_RESET */
+ .settings = {
+ [GPIOMUX_ACTIVE] = &hsic_hub_act_cfg,
+ [GPIOMUX_SUSPENDED] = &hsic_sus_cfg,
+ },
+ },
};
#endif
@@ -3091,6 +3104,7 @@
#endif
#ifdef CONFIG_USB_EHCI_MSM_HSIC
+#define HSIC_HUB_RESET_GPIO 91
static struct msm_hsic_host_platform_data msm_hsic_pdata = {
.strobe = 150,
.data = 151,
@@ -4610,6 +4624,12 @@
msm8960_device_otg.dev.platform_data = &msm_otg_pdata;
msm8960_device_gadget_peripheral.dev.parent = &msm8960_device_otg.dev;
msm_device_hsusb_host.dev.parent = &msm8960_device_otg.dev;
+#ifdef CONFIG_USB_EHCI_MSM_HSIC
+ if (machine_is_msm8960_liquid()) {
+ if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2)
+ msm_hsic_pdata.hub_reset = HSIC_HUB_RESET_GPIO;
+ }
+#endif
msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
gpiomux_init();
if (machine_is_msm8960_cdp())
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 1b8b5d6..093a170 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -34,6 +34,7 @@
#include <linux/gpio.h>
#include <mach/clk.h>
#include <mach/msm_iomap.h>
+#include <mach/msm_xo.h>
#define MSM_USB_BASE (hcd->regs)
@@ -48,6 +49,7 @@
struct regulator *hsic_vddcx;
bool async_int;
atomic_t in_lpm;
+ struct msm_xo_voter *xo_handle;
struct wake_lock wlock;
};
@@ -145,6 +147,81 @@
return 0;
}
+#define HSIC_HUB_VDD_VOL_MIN 1650000 /* uV */
+#define HSIC_HUB_VDD_VOL_MAX 1950000 /* uV */
+#define HSIC_HUB_VDD_LOAD 36000 /* uA */
+static int msm_hsic_config_hub(struct msm_hsic_hcd *mehci, int init)
+{
+ int ret = 0;
+ struct msm_hsic_host_platform_data *pdata;
+ static struct regulator *hsic_hub_reg;
+
+ pdata = mehci->dev->platform_data;
+ if (!pdata->hub_reset)
+ return ret;
+
+ if (!init)
+ goto disable_reg;
+
+ hsic_hub_reg = regulator_get(mehci->dev, "EXT_HUB_VDDIO");
+ if (IS_ERR(hsic_hub_reg)) {
+ dev_err(mehci->dev, "unable to get ext hub vddcx\n");
+ return PTR_ERR(hsic_hub_reg);
+ }
+
+ ret = gpio_request(pdata->hub_reset, "HSIC_HUB_RESET_GPIO");
+ if (ret < 0) {
+ dev_err(mehci->dev, "gpio request failed for GPIO%d\n",
+ pdata->hub_reset);
+ goto gpio_req_fail;
+ }
+
+ ret = regulator_set_voltage(hsic_hub_reg,
+ HSIC_HUB_VDD_VOL_MIN,
+ HSIC_HUB_VDD_VOL_MAX);
+ if (ret) {
+ dev_err(mehci->dev, "unable to set the voltage"
+ "for hsic hub reg\n");
+ goto reg_set_voltage_fail;
+ }
+
+ ret = regulator_set_optimum_mode(hsic_hub_reg,
+ HSIC_HUB_VDD_LOAD);
+ if (ret < 0) {
+ pr_err("%s: Unable to set optimum mode of the regulator:"
+ "VDDCX\n", __func__);
+ goto reg_optimum_mode_fail;
+ }
+
+ ret = regulator_enable(hsic_hub_reg);
+ if (ret) {
+ dev_err(mehci->dev, "unable to enable ext hub vddcx\n");
+ goto reg_enable_fail;
+ }
+
+ gpio_direction_output(pdata->hub_reset, 0);
+ /* Hub reset should be asserted for minimum 2usec before deasserting */
+ udelay(5);
+ gpio_direction_output(pdata->hub_reset, 1);
+
+ return 0;
+
+disable_reg:
+ regulator_disable(hsic_hub_reg);
+reg_enable_fail:
+ regulator_set_optimum_mode(hsic_hub_reg, 0);
+reg_optimum_mode_fail:
+ regulator_set_voltage(hsic_hub_reg, 0,
+ HSIC_HUB_VDD_VOL_MIN);
+reg_set_voltage_fail:
+ gpio_free(pdata->hub_reset);
+gpio_req_fail:
+ regulator_put(hsic_hub_reg);
+
+ return ret;
+
+}
+
static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en)
{
int rc = 0;
@@ -294,8 +371,9 @@
static int msm_hsic_suspend(struct msm_hsic_hcd *mehci)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
- int cnt = 0;
+ int cnt = 0, ret;
u32 val;
+ struct msm_hsic_host_platform_data *pdata;
if (atomic_read(&mehci->in_lpm)) {
dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
@@ -345,6 +423,13 @@
clk_disable(mehci->hsic_clk);
clk_disable(mehci->cal_clk);
clk_disable(mehci->ahb_clk);
+ pdata = mehci->dev->platform_data;
+ if (pdata->hub_reset) {
+ ret = msm_xo_mode_vote(mehci->xo_handle, MSM_XO_MODE_OFF);
+ if (ret)
+ pr_err("%s failed to devote for"
+ "TCXO D1 buffer%d\n", __func__, ret);
+ }
atomic_set(&mehci->in_lpm, 1);
enable_irq(hcd->irq);
@@ -358,8 +443,9 @@
static int msm_hsic_resume(struct msm_hsic_hcd *mehci)
{
struct usb_hcd *hcd = hsic_to_hcd(mehci);
- int cnt = 0;
+ int cnt = 0, ret;
unsigned temp;
+ struct msm_hsic_host_platform_data *pdata;
if (!atomic_read(&mehci->in_lpm)) {
dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
@@ -368,6 +454,13 @@
wake_lock(&mehci->wlock);
+ pdata = mehci->dev->platform_data;
+ if (pdata->hub_reset) {
+ ret = msm_xo_mode_vote(mehci->xo_handle, MSM_XO_MODE_ON);
+ if (ret)
+ pr_err("%s failed to vote for"
+ "TCXO D1 buffer%d\n", __func__, ret);
+ }
clk_enable(mehci->sys_clk);
clk_enable(mehci->hsic_clk);
clk_enable(mehci->cal_clk);
@@ -598,6 +691,7 @@
struct usb_hcd *hcd;
struct resource *res;
struct msm_hsic_hcd *mehci;
+ struct msm_hsic_host_platform_data *pdata;
int ret;
dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");
@@ -649,10 +743,34 @@
goto deinit_clocks;
}
+ pdata = mehci->dev->platform_data;
+ if (pdata->hub_reset) {
+ mehci->xo_handle = msm_xo_get(MSM_XO_TCXO_D1, "hsic");
+ if (IS_ERR(mehci->xo_handle)) {
+ pr_err(" %s not able to get the handle"
+ "to vote for TCXO D1 buffer\n", __func__);
+ ret = PTR_ERR(mehci->xo_handle);
+ goto deinit_vddcx;
+ }
+
+ ret = msm_xo_mode_vote(mehci->xo_handle, MSM_XO_MODE_ON);
+ if (ret) {
+ pr_err("%s failed to vote for TCXO"
+ "D1 buffer%d\n", __func__, ret);
+ goto free_xo_handle;
+ }
+ }
+
+ ret = msm_hsic_config_hub(mehci, 1);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to initialize hsic hub");
+ goto free_xo_handle;
+ }
+
ret = msm_hsic_reset(mehci);
if (ret) {
dev_err(&pdev->dev, "unable to initialize PHY\n");
- goto deinit_vddcx;
+ goto deinit_hub;
}
ret = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
@@ -676,6 +794,11 @@
unconfig_gpio:
msm_hsic_config_gpios(mehci, 0);
+deinit_hub:
+ msm_hsic_config_hub(mehci, 0);
+free_xo_handle:
+ if (pdata->hub_reset)
+ msm_xo_put(mehci->xo_handle);
deinit_vddcx:
msm_hsic_init_vddcx(mehci, 0);
deinit_clocks:
@@ -692,6 +815,7 @@
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
+ struct msm_hsic_host_platform_data *pdata;
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
@@ -699,6 +823,10 @@
usb_remove_hcd(hcd);
msm_hsic_config_gpios(mehci, 0);
+ msm_hsic_config_hub(mehci, 0);
+ pdata = mehci->dev->platform_data;
+ if (pdata->hub_reset)
+ msm_xo_put(mehci->xo_handle);
msm_hsic_init_vddcx(mehci, 0);
msm_hsic_init_clocks(mehci, 0);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index d776718..62d58de 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -240,6 +240,7 @@
struct msm_hsic_host_platform_data {
unsigned strobe;
unsigned data;
+ unsigned hub_reset;
};
#endif