Ejemplo n.º 1
0
static void bcmpmu_otg_xceiv_select_host_mode(struct bcmpmu_otg_xceiv_data
        *xceiv_data, bool enable)
{
    if (enable) {
        dev_info(xceiv_data->dev, "Switching to Host\n");
        xceiv_data->host = true;
        bcm_hsotgctrl_set_phy_off(false);
        msleep(PERIPHERAL_TO_HOST_DELAY_MS);
        bcm_hsotgctrl_phy_set_id_stat(false);
    } else {
        dev_info(xceiv_data->dev, "Switching to Peripheral\n");
        bcm_hsotgctrl_phy_set_id_stat(true);
        if (xceiv_data->host) {
            xceiv_data->host = false;
            msleep(HOST_TO_PERIPHERAL_DELAY_MS);
        }
    }
}
static int bcm_hsotgctrl_probe(struct platform_device *pdev)
{
	int error = 0;
	unsigned int val;
	struct bcm_hsotgctrl_drv_data *hsotgctrl_drvdata;
	struct bcm_hsotgctrl_platform_data *plat_data = NULL;

	if (pdev->dev.platform_data)
		plat_data = (struct bcm_hsotgctrl_platform_data *)
			pdev->dev.platform_data;
	else if (pdev->dev.of_node) {
		int val;
		struct resource *resource;

		plat_data = kzalloc(sizeof(struct bcm_hsotgctrl_platform_data),
				GFP_KERNEL);
		if (!plat_data) {
			dev_err(&pdev->dev,
				"%s: memory allocation failed.", __func__);
			error = -ENOMEM;
			goto err_ret;
		}

		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
		if (resource->start)
			plat_data->hsotgctrl_virtual_mem_base =
				HW_IO_PHYS_TO_VIRT(resource->start);
		else {
			pr_info("Invalid hsotgctrl_virtual_mem_basei from DT\n");
			goto err_read;
		}


		if (of_property_read_u32(pdev->dev.of_node,
				"chipreg-virtual-mem-base", &val)) {
			error = -EINVAL;
			dev_err(&pdev->dev, "chipreg-virtual-mem-base read failed\n");
			goto err_read;
		}
		plat_data->chipreg_virtual_mem_base = HW_IO_PHYS_TO_VIRT(val);

		resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
		if (resource->start)
			plat_data->irq = resource->start;
		else {
			pr_info("Invalid irq from DT\n");
			goto err_read;
		}

		if (of_property_read_string(pdev->dev.of_node,
				"usb-ahb-clk-name",
			&plat_data->usb_ahb_clk_name) != 0) {
			error = -EINVAL;
			dev_err(&pdev->dev, "usb-ahb-clk-name read failed\n");
			goto err_read;
		}

		if (of_property_read_string(pdev->dev.of_node,
				"mdio-mstr-clk-name",
			&plat_data->mdio_mstr_clk_name) != 0) {
			error = -EINVAL;
			dev_err(&pdev->dev, "mdio-mstr-clk-name read failed\n");
			goto err_read;
		}
	}


	if (plat_data == NULL) {
		dev_err(&pdev->dev, "platform_data failed\n");
		return -ENODEV;
	}

	hsotgctrl_drvdata = kzalloc(sizeof(*hsotgctrl_drvdata), GFP_KERNEL);
	if (!hsotgctrl_drvdata) {
		dev_warn(&pdev->dev, "Memory allocation failed\n");
		return -ENOMEM;
	}

	local_hsotgctrl_handle = hsotgctrl_drvdata;

	hsotgctrl_drvdata->hsotg_ctrl_base =
		(void *)plat_data->hsotgctrl_virtual_mem_base;
	if (!hsotgctrl_drvdata->hsotg_ctrl_base) {
		dev_warn(&pdev->dev, "No vaddr for HSOTGCTRL!\n");
		goto error_get_vaddr;
	}

	hsotgctrl_drvdata->chipregs_base =
		(void *)plat_data->chipreg_virtual_mem_base;
	if (!hsotgctrl_drvdata->chipregs_base) {
		dev_warn(&pdev->dev, "No vaddr for CHIPREG!\n");
		goto error_get_vaddr;
	}

	hsotgctrl_drvdata->dev = &pdev->dev;
	hsotgctrl_drvdata->otg_clk = clk_get(NULL,
		plat_data->usb_ahb_clk_name);

	if (IS_ERR(hsotgctrl_drvdata->otg_clk)) {
		error = PTR_ERR(hsotgctrl_drvdata->otg_clk);
		dev_warn(&pdev->dev,
			 "OTG clock allocation failed - %d\n", error);
		goto error_get_otg_clk;
	}

	hsotgctrl_drvdata->mdio_master_clk = clk_get(NULL,
		plat_data->mdio_mstr_clk_name);

	if (IS_ERR(hsotgctrl_drvdata->mdio_master_clk)) {
		error = PTR_ERR(hsotgctrl_drvdata->mdio_master_clk);
		dev_warn(&pdev->dev,
			 "MDIO Mst clk alloc failed - %d\n", error);
		goto error_get_master_clk;
	}

	hsotgctrl_drvdata->allow_suspend = true;
	platform_set_drvdata(pdev, hsotgctrl_drvdata);

	bcm_hsotgctrl_en_clock(true);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* clear bit 15 RDB error */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_USB11_OEB_IS_TXEB_MASK;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* S/W reset Phy, active low */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* bring Phy out of reset */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_PHY_MODE_MASK;
	val |= HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK;
	/* use OTG mode */
	val |= PHY_MODE_OTG << HSOTG_CTRL_PHY_P1CTL_PHY_MODE_SHIFT;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
		HSOTG_CTRL_PHY_P1CTL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* Enable pad, internal PLL etc */
	bcm_hsotgctrl_set_phy_off(false);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/*Come up as device until we check PMU ID status
	 * to avoid turning on Vbus before checking
	 */
	val =	HSOTG_CTRL_USBOTGCONTROL_OTGSTAT_CTRL_MASK |
			HSOTG_CTRL_USBOTGCONTROL_UTMIOTG_IDDIG_SW_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_HCLK_EN_DIRECT_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_ON_IS_HCLK_EN_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_ON_MASK |
			HSOTG_CTRL_USBOTGCONTROL_PRST_N_SW_MASK |
			HSOTG_CTRL_USBOTGCONTROL_HRESET_N_SW_MASK;

	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_USBOTGCONTROL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	error = device_create_file(&pdev->dev, &dev_attr_hsotgctrldump);

	if (error) {
		dev_warn(&pdev->dev, "Failed to create HOST file\n");
		goto Error_bcm_hsotgctrl_probe;
	}


#ifndef CONFIG_USB_OTG_UTILS
	/* Clear non-driving as default in case there
	 * is no transceiver hookup */
	bcm_hsotgctrl_phy_set_non_driving(false);
#endif

#ifdef CONFIG_NOP_USB_XCEIV
	/* Clear non-driving as default in case there
	 * is no transceiver hookup */
	bcm_hsotgctrl_phy_set_non_driving(false);
#endif

	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	hsotgctrl_drvdata->hsotgctrl_irq = platform_get_irq(pdev, 0);

	/* Create a work queue for wakeup work items */
	hsotgctrl_drvdata->bcm_hsotgctrl_work_queue =
		create_workqueue("bcm_hsotgctrl_events");

	if (hsotgctrl_drvdata->bcm_hsotgctrl_work_queue == NULL) {
		dev_warn(&pdev->dev,
			 "BCM HSOTGCTRL events work queue creation failed\n");
		/* Treat this as non-fatal error */
	}

	INIT_DELAYED_WORK(&hsotgctrl_drvdata->wakeup_work,
			  bcm_hsotgctrl_delayed_wakeup_handler);

	/* disable Bvalid interrupt bit
	 * This interrupt is not currently used as the STAT2 detection
	 * happens from the PMU side. Beacsue of not clearing this bit
	 * Master clock gating feature was not working in Java. This
	 * is not a issue in case of Hawaii
	 * */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
				HSOTG_CTRL_USBOTGCONTROL_OFFSET);
	val |= 1 << HSOTG_CTRL_USBOTGCONTROL_BVALID_CLR_SHIFT;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_USBOTGCONTROL_OFFSET);

	bcm_hsotgctrl_en_clock(false);

	/* request_irq enables irq */
	hsotgctrl_drvdata->irq_enabled = true;
	error = request_irq(hsotgctrl_drvdata->hsotgctrl_irq,
			bcm_hsotgctrl_wake_irq,
			IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
			"bcm_hsotgctrl", (void *)hsotgctrl_drvdata);
	if (error) {
		hsotgctrl_drvdata->irq_enabled = false;
		hsotgctrl_drvdata->hsotgctrl_irq = 0;
		dev_warn(&pdev->dev, "Failed to request IRQ for wakeup\n");
	}

	return 0;

Error_bcm_hsotgctrl_probe:
	clk_put(hsotgctrl_drvdata->mdio_master_clk);
	bcm_hsotgctrl_en_clock(false);
error_get_master_clk:
	clk_put(hsotgctrl_drvdata->otg_clk);
error_get_otg_clk:
error_get_vaddr:
	kfree(hsotgctrl_drvdata);
err_read:
	if (pdev->dev.of_node)
		kfree(plat_data);
err_ret:
	pr_err("%s probe failed\n", __func__);
	return error;
}
int bcm_hsotgctrl_phy_deinit(void)
{
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		local_hsotgctrl_handle;

	if (NULL == local_hsotgctrl_handle)
		return -ENODEV;

	if (!bcm_hsotgctrl_handle->dev)
		return -EIO;

	if (bcm_hsotgctrl_handle->irq_enabled) {

		/* We are shutting down USB so ensure wake IRQ
		 * is disabled
		 */
		disable_irq(bcm_hsotgctrl_handle->hsotgctrl_irq);
		bcm_hsotgctrl_handle->irq_enabled = false;

	}

	if (work_pending(&bcm_hsotgctrl_handle->wakeup_work.work)) {

		/* Cancel scheduled work */
		cancel_delayed_work(&bcm_hsotgctrl_handle->
			wakeup_work);

		/* Make sure work queue is flushed */
		flush_workqueue(bcm_hsotgctrl_handle->
			bcm_hsotgctrl_work_queue);

	}

	/* Disable wakeup condition */
	bcm_hsotgctrl_phy_wakeup_condition(false);

	/* Stay disconnected */
	bcm_hsotgctrl_wakeup_core();
	bcm_hsotgctrl_phy_set_non_driving(true);

	/* Disable pad, internal PLL etc. */
	bcm_hsotgctrl_set_phy_off(true);

	/* Enable software control of PHY-PM */
	bcm_hsotgctrl_set_soft_ldo_pwrdn(true);

	/* Isolate PHY */
	bcm_hsotgctrl_set_phy_iso(true);

	/* Power down ALDO */
	bcm_hsotgctrl_set_aldo_pdn(false);

	/* Clear PHY reference clock request */
	bcm_hsotgctrl_set_phy_clk_request(false);

	/* Clear Vbus valid state */
	bcm_hsotgctrl_phy_set_vbus_stat(false);

	/* Disable the OTG core AHB clock */
	bcm_hsotgctrl_en_clock(false);
	return 0;
}
int bcm_hsotgctrl_phy_init(bool id_device)
{
	int val;
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		local_hsotgctrl_handle;

	if (NULL == local_hsotgctrl_handle)
		return -ENODEV;

	if ((!bcm_hsotgctrl_handle->hsotg_ctrl_base) ||
		  (!bcm_hsotgctrl_handle->dev))
		return -EIO;

	bcm_hsotgctrl_en_clock(true);
	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);
	/* clear bit 15 RDB error */
	val = readl(bcm_hsotgctrl_handle->hsotg_ctrl_base +
		HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_USB11_OEB_IS_TXEB_MASK;
	writel(val, bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* Enable software control of PHY-PM */
	bcm_hsotgctrl_set_soft_ldo_pwrdn(true);

	/* Put PHY in reset state */
	bcm_hsotgctrl_set_phy_resetb(false);

	/* Reset PHY and AHB clock domain */
	bcm_hsotgctrl_reset_clk_domain();

	/* Power up ALDO */
	bcm_hsotgctrl_set_aldo_pdn(true);
	mdelay(PHY_PM_DELAY_IN_MS);

	/* Enable pad, internal PLL etc */
	bcm_hsotgctrl_set_phy_off(false);

	bcm_hsotgctrl_set_ldo_suspend_mask();

	/* Remove PHY isolation */
	bcm_hsotgctrl_set_phy_iso(false);
	mdelay(PHY_PM_DELAY_IN_MS);

	/* PHY clock request */
	bcm_hsotgctrl_set_phy_clk_request(true);
	mdelay(PHY_PLL_DELAY_MS);

	/* Bring Put PHY out of reset state */
	bcm_hsotgctrl_set_phy_resetb(true);

	/* Don't disable software control of PHY-PM
	 * We want to control the PHY LDOs from software
	 */
	bcm_hsotgctrl_phy_mdio_initialization();

	if (id_device) {
		/* Set correct ID value */
		bcm_hsotgctrl_phy_set_id_stat(true);

		/* Set Vbus valid state */
		bcm_hsotgctrl_phy_set_vbus_stat(true);
	} else {
		/* Set correct ID value */
		bcm_hsotgctrl_phy_set_id_stat(false);
		/* Clear non-driving */
		bcm_hsotgctrl_phy_set_non_driving(false);
	}

	msleep(HSOTGCTRL_ID_CHANGE_DELAY_IN_MS);

	return 0;

}
static int __devinit bcm_hsotgctrl_probe(struct platform_device *pdev)
{
	int error = 0;
	int val;
	struct bcm_hsotgctrl_drv_data *hsotgctrl_drvdata;
	struct bcm_hsotgctrl_platform_data *plat_data =
	  (struct bcm_hsotgctrl_platform_data *)pdev->dev.platform_data;

	if (plat_data == NULL) {
		dev_err(&pdev->dev, "platform_data failed\n");
		return -ENODEV;
	}

	hsotgctrl_drvdata = kzalloc(sizeof(*hsotgctrl_drvdata), GFP_KERNEL);
	if (!hsotgctrl_drvdata) {
		dev_warn(&pdev->dev, "Memory allocation failed\n");
		return -ENOMEM;
	}

	local_hsotgctrl_handle = hsotgctrl_drvdata;

	hsotgctrl_drvdata->hsotg_ctrl_base =
		(void *)plat_data->hsotgctrl_virtual_mem_base;
	if (!hsotgctrl_drvdata->hsotg_ctrl_base) {
		dev_warn(&pdev->dev, "No vaddr for HSOTGCTRL!\n");
		kfree(hsotgctrl_drvdata);
		return -ENOMEM;
	}

	hsotgctrl_drvdata->chipregs_base =
		(void *)plat_data->chipreg_virtual_mem_base;
	if (!hsotgctrl_drvdata->chipregs_base) {
		dev_warn(&pdev->dev, "No vaddr for CHIPREG!\n");
		kfree(hsotgctrl_drvdata);
		return -ENOMEM;
	}

	hsotgctrl_drvdata->dev = &pdev->dev;
	hsotgctrl_drvdata->otg_clk = clk_get(NULL,
		plat_data->usb_ahb_clk_name);

	if (IS_ERR(hsotgctrl_drvdata->otg_clk)) {
		error = PTR_ERR(hsotgctrl_drvdata->otg_clk);
		dev_warn(&pdev->dev, "OTG clock allocation failed\n");
		kfree(hsotgctrl_drvdata);
		return error;
	}

	hsotgctrl_drvdata->mdio_master_clk = clk_get(NULL,
		plat_data->mdio_mstr_clk_name);

	if (IS_ERR(hsotgctrl_drvdata->mdio_master_clk)) {
		error = PTR_ERR(hsotgctrl_drvdata->mdio_master_clk);
		dev_warn(&pdev->dev, "MDIO Mst clk alloc failed\n");
		kfree(hsotgctrl_drvdata);
		return error;
	}

	hsotgctrl_drvdata->allow_suspend = true;
	platform_set_drvdata(pdev, hsotgctrl_drvdata);

	/* Init the PHY */
	hsotgctrl_drvdata->usb_active = true;
	bcm_hsotgctrl_en_clock(true);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* clear bit 15 RDB error */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_USB11_OEB_IS_TXEB_MASK;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* S/W reset Phy, active low */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* bring Phy out of reset */
	val = readl(hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_PHY_P1CTL_OFFSET);
	val &= ~HSOTG_CTRL_PHY_P1CTL_PHY_MODE_MASK;
	val |= HSOTG_CTRL_PHY_P1CTL_SOFT_RESET_MASK;
	/* use OTG mode */
	val |= PHY_MODE_OTG << HSOTG_CTRL_PHY_P1CTL_PHY_MODE_SHIFT;
	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
		HSOTG_CTRL_PHY_P1CTL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/* Enable pad, internal PLL etc */
	bcm_hsotgctrl_set_phy_off(false);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	/*Come up as device until we check PMU ID status
	 * to avoid turning on Vbus before checking
	 */
	val =	HSOTG_CTRL_USBOTGCONTROL_OTGSTAT_CTRL_MASK |
			HSOTG_CTRL_USBOTGCONTROL_UTMIOTG_IDDIG_SW_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_HCLK_EN_DIRECT_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_ON_IS_HCLK_EN_MASK |
			HSOTG_CTRL_USBOTGCONTROL_USB_ON_MASK |
			HSOTG_CTRL_USBOTGCONTROL_PRST_N_SW_MASK |
			HSOTG_CTRL_USBOTGCONTROL_HRESET_N_SW_MASK;

	writel(val, hsotgctrl_drvdata->hsotg_ctrl_base +
			HSOTG_CTRL_USBOTGCONTROL_OFFSET);

	mdelay(HSOTGCTRL_STEP_DELAY_IN_MS);

	error = device_create_file(&pdev->dev, &dev_attr_hsotgctrldump);

	if (error) {
		dev_warn(&pdev->dev, "Failed to create HOST file\n");
		goto Error_bcm_hsotgctrl_probe;
	}


#ifndef CONFIG_USB_OTG_UTILS
	/* Clear non-driving as default in case there
	 * is no transceiver hookup */
	bcm_hsotgctrl_phy_set_non_driving(false);
#endif

#ifdef CONFIG_NOP_USB_XCEIV
	/* Clear non-driving as default in case there
	 * is no transceiver hookup */
	bcm_hsotgctrl_phy_set_non_driving(false);
#endif

	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	hsotgctrl_drvdata->hsotgctrl_irq = platform_get_irq(pdev, 0);

	/* Create a work queue for wakeup work items */
	hsotgctrl_drvdata->bcm_hsotgctrl_work_queue =
		create_workqueue("bcm_hsotgctrl_events");

	if (hsotgctrl_drvdata->bcm_hsotgctrl_work_queue == NULL) {
		dev_warn(&pdev->dev,
			 "BCM HSOTGCTRL events work queue creation failed\n");
		/* Treat this as non-fatal error */
	}

	INIT_DELAYED_WORK(&hsotgctrl_drvdata->wakeup_work,
			  bcm_hsotgctrl_delayed_wakeup_handler);

	/* request_irq enables irq */
	hsotgctrl_drvdata->irq_enabled = true;
	error = request_irq(hsotgctrl_drvdata->hsotgctrl_irq,
			bcm_hsotgctrl_wake_irq,
			IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND,
			"bcm_hsotgctrl", (void *)hsotgctrl_drvdata);
	if (error) {
		hsotgctrl_drvdata->irq_enabled = false;
		hsotgctrl_drvdata->hsotgctrl_irq = 0;
		dev_warn(&pdev->dev, "Failed to request IRQ for wakeup\n");
	}

	local_wakeup_core_cb = NULL;
	return 0;

Error_bcm_hsotgctrl_probe:
	clk_put(hsotgctrl_drvdata->otg_clk);
	clk_put(hsotgctrl_drvdata->mdio_master_clk);
	kfree(hsotgctrl_drvdata);
	return error;
}