예제 #1
0
static void tegra_change_otg_state(struct tegra_otg_data *tegra,
				enum usb_otg_state to)
{
	struct otg_transceiver *otg = &tegra->otg;
	enum usb_otg_state from = otg->state;

	if(!tegra->interrupt_mode){
		DBG("OTG: Vbus detection is disabled");
		return;
	}

	DBG("%s(%d) requested otg state %s-->%s\n", __func__,
		__LINE__, tegra_state_name(from), tegra_state_name(to));

	if (to != OTG_STATE_UNDEFINED && from != to) {
		otg->state = to;
		/*dev_info(tegra->otg.dev, "%s --> %s\n", tegra_state_name(from),
					      tegra_state_name(to));*/
		USBH_INFO("%s --> %s\n", tegra_state_name(from), tegra_state_name(to));

		if (from == OTG_STATE_A_SUSPEND) {
			if (to == OTG_STATE_B_PERIPHERAL && otg->gadget) {
				usb_gadget_vbus_connect(otg->gadget);
#ifdef CONFIG_USB_ANDROID_PROJECTOR
				if (check_htc_mode_status() != NOT_ON_AUTOBOT) {
					htc_mode_enable(0);
					android_switch_default();
				}
#endif
			} else if (to == OTG_STATE_A_HOST) {
				tegra_start_host(tegra);
				dump_otg_state();
			}
		} else if (from == OTG_STATE_A_HOST) {
			if (to == OTG_STATE_A_SUSPEND)
				tegra_stop_host(tegra);
		} else if (from == OTG_STATE_B_PERIPHERAL && otg->gadget) {
			if (to == OTG_STATE_A_SUSPEND)
				usb_gadget_vbus_disconnect(otg->gadget);
		}
	} else if (to != OTG_STATE_UNDEFINED && from == to) {
		USBH_INFO("%s --> %s (%d)\n", tegra_state_name(from), tegra_state_name(to), USB_disabled);
		if (USB_disabled) {
			usb_gadget_disconnect(otg->gadget);
		} else if (to == OTG_STATE_B_PERIPHERAL) {
			usb_gadget_vbus_connect(otg->gadget);
			usb_gadget_connect(otg->gadget);
		} else {
			usb_gadget_connect(otg->gadget);
		}
	}
}
예제 #2
0
static void dump_otg_state(void)
{
	unsigned long flags;
	unsigned long status;
	unsigned long val;
	if (!tegra_clone)
		return;
	status = tegra_clone->int_status;

	/* Debug prints */
	USBH_INFO("%s(%d) status = 0x%x\n", __func__, __LINE__, status);
	if ((status & USB_ID_INT_STATUS) &&
			(status & USB_VBUS_INT_STATUS))
		USBH_INFO("%s(%d) got vbus & id interrupt\n", __func__, __LINE__);
	else {
		if (status & USB_ID_INT_STATUS)
			USBH_INFO("%s(%d) got id interrupt\n", __func__, __LINE__);
		if (status & USB_VBUS_INT_STATUS)
			USBH_INFO("%s(%d) got vbus interrupt\n", __func__, __LINE__);
	}

	spin_lock_irqsave(&tegra_clone->lock, flags);
	val = otg_readl(tegra_clone, USB_PHY_WAKEUP);
	spin_unlock_irqrestore(&tegra_clone->lock, flags);
	USBH_INFO("%s(%d) USB_PHY_WAKEUP val = 0x%x\n", __func__, __LINE__, val);
	if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) {
		USBH_INFO("%s(%d) PHY_WAKEUP = 0x%x\n", __func__, __LINE__, val);
	}


}
예제 #3
0
static int ehci_msm_run(struct usb_hcd *hcd)
{
	struct ehci_hcd *ehci  = hcd_to_ehci(hcd);
	struct msmusb_hcd *mhcd = hcd_to_mhcd(hcd);
	int             retval = 0;
	int     	port   = HCS_N_PORTS(ehci->hcs_params);
	u32 __iomem     *reg_ptr;
	u32             hcc_params;
	struct msm_usb_host_platform_data *pdata = mhcd->pdata;

	hcd->uses_new_polling = 1;
	hcd->poll_rh = 0;

	USBH_INFO("%s\n", __func__);
	/* set hostmode */
	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
	ehci_writel(ehci, (USBMODE_VBUS | USBMODE_SDIS), reg_ptr);

	/* port configuration - phy, port speed, port power, port enable */
	while (port--)
		ehci_writel(ehci, (PTS_VAL(pdata->phy_info) | PORT_POWER |
				PORT_PE), &ehci->regs->port_status[port]);

	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);

	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
	if (HCC_64BIT_ADDR(hcc_params))
		ehci_writel(ehci, 0, &ehci->regs->segment);

	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
	ehci->command |= CMD_RUN;
	ehci_writel(ehci, ehci->command, &ehci->regs->command);
	ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */

	hcd->state = HC_STATE_RUNNING;

	/*Enable appropriate Interrupts*/
	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);

	return retval;
}
예제 #4
0
static ssize_t store_host_en(struct device *dev, struct device_attribute *attr,
				const char *buf, size_t count)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct tegra_otg_data *tegra = platform_get_drvdata(pdev);
	unsigned long host;

	if (sscanf(buf, "%d", &host) != 1 || host < 0 || host > 1)
		return -EINVAL;

	USBH_INFO("%s %d ", __func__, host);
	if (host) {
		enable_interrupt(tegra, false);
		tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
		tegra_change_otg_state(tegra, OTG_STATE_A_HOST);
		tegra->interrupt_mode = false;
	} else {
		tegra->interrupt_mode = true;
		tegra_change_otg_state(tegra, OTG_STATE_A_SUSPEND);
		enable_interrupt(tegra, true);
	}

	return count;
}
예제 #5
0
static int __devinit ehci_msm_probe(struct platform_device *pdev)
{
	struct usb_hcd *hcd;
	struct resource *res;
	struct msm_usb_host_platform_data *pdata;
	int retval;
	struct msmusb_hcd *mhcd;

	USBH_INFO("%s\n", __func__);
	hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev, dev_name(&pdev->dev));
	if (!hcd)
		return  -ENOMEM;

	hcd->irq = platform_get_irq(pdev, 0);
	if (hcd->irq < 0) {
		usb_put_hcd(hcd);
		return hcd->irq;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		usb_put_hcd(hcd);
		return -ENODEV;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);

	mhcd = hcd_to_mhcd(hcd);
	spin_lock_init(&mhcd->lock);
	mhcd->in_lpm = 0;
	mhcd->running = 0;
	device_init_wakeup(&pdev->dev, 1);

	pdata = pdev->dev.platform_data;
	if (PHY_TYPE(pdata->phy_info) == USB_PHY_UNDEFINED) {
		usb_put_hcd(hcd);
		return -ENODEV;
	}
	hcd->power_budget = pdata->power_budget;
	mhcd->pdata = pdata;
	INIT_WORK(&mhcd->lpm_exit_work, usb_lpm_exit_w);

	wake_lock_init(&mhcd->wlock, WAKE_LOCK_SUSPEND, dev_name(&pdev->dev));
	pdata->ebi1_clk = clk_get(NULL, "ebi1_usb_clk");
	if (IS_ERR(pdata->ebi1_clk))
		pdata->ebi1_clk = NULL;
	else
		clk_set_rate(pdata->ebi1_clk, INT_MAX);

	retval = msm_xusb_init_host(mhcd);

	if (retval < 0) {
		usb_put_hcd(hcd);
		wake_lock_destroy(&mhcd->wlock);
		clk_put(pdata->ebi1_clk);
	}

	pm_runtime_enable(&pdev->dev);

	USBH_INFO("%s: success\n", __func__);
	return retval;
}
예제 #6
0
static void msm_hsusb_request_host(void *handle, int request)
{
	struct msmusb_hcd *mhcd = handle;
	struct usb_hcd *hcd = mhcd_to_hcd(mhcd);
	struct msm_usb_host_platform_data *pdata = mhcd->pdata;
	struct msm_otg *otg = container_of(mhcd->xceiv, struct msm_otg, otg);
	struct usb_device *udev = hcd->self.root_hub;
	struct device *dev = hcd->self.controller;

	USBH_INFO("%s: %d\n", __func__, request);
	switch (request) {
#ifdef CONFIG_USB_OTG
	case REQUEST_HNP_SUSPEND:
		/* disable Root hub auto suspend. As hardware is configured
		 * for peripheral mode, mark hardware is not available.
		 */
		if (PHY_TYPE(pdata->phy_info) == USB_PHY_INTEGRATED) {
			pm_runtime_disable(&udev->dev);
			/* Mark root hub as disconnected. This would
			 * protect suspend/resume via sysfs.
			 */
			udev->state = USB_STATE_NOTATTACHED;
			clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
			hcd->state = HC_STATE_HALT;
			pm_runtime_put_noidle(dev);
			pm_runtime_suspend(dev);
		}
		break;
	case REQUEST_HNP_RESUME:
		if (PHY_TYPE(pdata->phy_info) == USB_PHY_INTEGRATED) {
			pm_runtime_get_noresume(dev);
			pm_runtime_resume(dev);
			disable_irq(hcd->irq);
			ehci_msm_reset(hcd);
			ehci_msm_run(hcd);
			set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
			pm_runtime_enable(&udev->dev);
			udev->state = USB_STATE_CONFIGURED;
			enable_irq(hcd->irq);
		}
		break;
#endif
	case REQUEST_RESUME:
		usb_hcd_resume_root_hub(hcd);
		break;
	case REQUEST_START:
		if (mhcd->running)
			break;
		pm_runtime_get_noresume(dev);
		pm_runtime_resume(dev);
		wake_lock(&mhcd->wlock);
		msm_xusb_pm_qos_update(mhcd, 1);
		msm_xusb_enable_clks(mhcd);
		if (PHY_TYPE(pdata->phy_info) == USB_PHY_INTEGRATED)
			if (otg->set_clk)
				otg->set_clk(mhcd->xceiv, 1);
		if (pdata->vbus_power)
			pdata->vbus_power(pdata->phy_info, 1);
		if (pdata->config_gpio)
			pdata->config_gpio(1);
		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
		mhcd->running = 1;
		if (PHY_TYPE(pdata->phy_info) == USB_PHY_INTEGRATED)
			if (otg->set_clk)
				otg->set_clk(mhcd->xceiv, 0);
		break;
	case REQUEST_STOP:
		if (!mhcd->running)
			break;
		mhcd->running = 0;
		/* come out of lpm before deregistration */
		if (PHY_TYPE(pdata->phy_info) == USB_PHY_SERIAL_PMIC) {
			usb_lpm_exit(hcd);
			if (cancel_work_sync(&(mhcd->lpm_exit_work)))
				usb_lpm_exit_w(&mhcd->lpm_exit_work);
		}
		usb_remove_hcd(hcd);
		if (pdata->config_gpio)
			pdata->config_gpio(0);
		if (pdata->vbus_power)
			pdata->vbus_power(pdata->phy_info, 0);
		msm_xusb_disable_clks(mhcd);
		wake_lock_timeout(&mhcd->wlock, HZ/2);
		msm_xusb_pm_qos_update(mhcd, 0);
		pm_runtime_put_noidle(dev);
		pm_runtime_suspend(dev);
		break;
	}
}
예제 #7
0
static int tegra_otg_probe(struct platform_device *pdev)
{
	struct tegra_otg_data *tegra;
	struct resource *res;
	struct tegra_usb_otg_data *pdata = dev_get_platdata(&pdev->dev);
	int err;

	tegra = kzalloc(sizeof(struct tegra_otg_data), GFP_KERNEL);
	if (!tegra)
		return -ENOMEM;

	tegra->otg.dev = &pdev->dev;
	tegra->otg.label = "tegra-otg";
	tegra->otg.state = OTG_STATE_UNDEFINED;
	tegra->otg.set_host = tegra_otg_set_host;
	tegra->otg.set_peripheral = tegra_otg_set_peripheral;
	tegra->otg.set_suspend = tegra_otg_set_suspend;
	tegra->otg.set_power = tegra_otg_set_power;
	spin_lock_init(&tegra->lock);

	if (pdata) {
		tegra->builtin_host = !pdata->ehci_pdata->builtin_host_disabled;
	}

	platform_set_drvdata(pdev, tegra);
	tegra_clone = tegra;
	tegra->interrupt_mode = true;
	tegra->suspended = false;

	tegra->clk = clk_get(&pdev->dev, NULL);
	if (IS_ERR(tegra->clk)) {
		dev_err(&pdev->dev, "Can't get otg clock\n");
		err = PTR_ERR(tegra->clk);
		goto err_clk;
	}

	err = clk_enable(tegra->clk);
	if (err)
		goto err_clken;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "Failed to get I/O memory\n");
		err = -ENXIO;
		goto err_io;
	}
	tegra->regs = ioremap(res->start, resource_size(res));
	if (!tegra->regs) {
		err = -ENOMEM;
		goto err_io;
	}

	tegra->otg.state = OTG_STATE_A_SUSPEND;

	err = otg_set_transceiver(&tegra->otg);
	if (err) {
		dev_err(&pdev->dev, "can't register transceiver (%d)\n", err);
		goto err_otg;
	}

	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(&pdev->dev, "Failed to get IRQ\n");
		err = -ENXIO;
		goto err_irq;
	}

	tegra->irq = res->start;
	err = request_threaded_irq(tegra->irq, tegra_otg_irq,
				   NULL,
				   IRQF_SHARED | IRQF_TRIGGER_HIGH,
				   "tegra-otg", tegra);
	if (err) {
		dev_err(&pdev->dev, "Failed to register IRQ\n");
		goto err_irq;
	}

	err = enable_irq_wake(tegra->irq);
	if (err < 0) {
		dev_warn(&pdev->dev,
			"Couldn't enable USB otg mode wakeup, irq=%d, error=%d\n",
			tegra->irq, err);
		err = 0;
	}

	INIT_WORK(&tegra->work, irq_work);

	dev_info(&pdev->dev, "otg transceiver registered\n");

	err = device_create_file(&pdev->dev, &dev_attr_enable_host);
	if (err) {
		dev_warn(&pdev->dev, "Can't register sysfs attribute\n");
		goto err_irq;
	}

	clk_disable(tegra->clk);
#if (defined(CONFIG_USB_OTG) && defined(CONFIG_USB_OTG_HOST))
	usb_host_detect_register_notifier(&usb_host_status_notifier);
#endif

	USBH_INFO("%s done!\n", __func__);
	return 0;

err_irq:
	otg_set_transceiver(NULL);
err_otg:
	iounmap(tegra->regs);
err_io:
	clk_disable(tegra->clk);
err_clken:
	clk_put(tegra->clk);
err_clk:
	platform_set_drvdata(pdev, NULL);
	kfree(tegra);
	return err;
}