Пример #1
0
void bcmpmu_otg_xceiv_do_srp(struct bcmpmu_otg_xceiv_data *xceiv_data)
{
#ifdef CONFIG_USB_OTG
    if (xceiv_data->otg_xceiver.xceiver.gadget && xceiv_data->otg_xceiver.xceiver.gadget->ops &&
            xceiv_data->otg_xceiver.xceiver.gadget->ops->wakeup &&
            xceiv_data->otg_enabled) {

        bool vbus_status = 0;

        bcmpmu_usb_get(xceiv_data->bcmpmu,
                       BCMPMU_USB_CTRL_GET_VBUS_STATUS, &vbus_status);

        /* Should do SRP only if Vbus is not valid */
        if (!vbus_status) {
            bcm_hsotgctrl_phy_set_non_driving(false);
            /* Do SRP */
            xceiv_data->otg_xceiver.xceiver.gadget->
            ops->wakeup(xceiv_data->otg_xceiver.xceiver.gadget);
            /* Start SRP failure timer to do ADP probes
             * if it expires
             */
            xceiv_data->otg_xceiver.srp_failure_timer.expires =
                jiffies +
                msecs_to_jiffies(T_SRP_FAILURE_MAX_IN_MS);
            add_timer(&xceiv_data->otg_xceiver.srp_failure_timer);

            /* SRP initiated. Clear the flag */
            xceiv_data->otg_xceiver.otg_srp_reqd = false;
        }
    }
#endif
}
Пример #2
0
static void bcmpmu_otg_xceiv_chg_detect_handler(struct work_struct *work)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data =
        container_of(work, struct bcmpmu_otg_xceiv_data,
                     bcm_otg_chg_detect_work);

    dev_info(xceiv_data->dev, "Charger detect event\n");

    /* Read and save USB charger type */
    bcmpmu_usb_get(xceiv_data->bcmpmu,
                   BCMPMU_USB_CTRL_GET_USB_TYPE,
                   (void *)&xceiv_data->usb_charger_type);

    if (xceiv_data->otg_enabled) {
        /* Core is already up so just set the Vbus status */
        bcm_hsotgctrl_phy_set_vbus_stat(true);

        /* Vbus is up so allow the core to connect */
        bcm_hsotgctrl_phy_set_non_driving(false);
    } else {
        bool id_default_host = false;

        id_default_host =
            bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
            bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);

        if (!id_default_host && xceiv_data->otg_xceiver.xceiver.gadget)
            atomic_notifier_call_chain(&xceiv_data->otg_xceiver.
                                       xceiver.notifier,
                                       USB_EVENT_VBUS, NULL);
    }
}
Пример #3
0
static int bcmpmu_otg_xceiv_set_host(struct otg_transceiver *otg,
                                     struct usb_bus *host)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);
    int status = 0;

    dev_dbg(xceiv_data->dev, "Setting Host\n");
    otg->host = host;

    if (host) {
        if (xceiv_data->otg_enabled) {
            /* Wake lock forever in OTG build */
            wake_lock(&xceiv_data->otg_xceiver.xceiver_wake_lock);
            /* Do calibration probe */
            bcm_otg_do_adp_calibration_probe(xceiv_data);
        }

        if (bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
                bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data)) {
            bcm_hsotgctrl_phy_set_id_stat(false);
            bcm_hsotgctrl_phy_set_non_driving(false);
        } else
            bcm_hsotgctrl_phy_set_id_stat(true);
    }
    return status;
}
Пример #4
0
static int bcmpmu_otg_xceiv_pullup_on(struct otg_transceiver *otg, bool on)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);

    if (!xceiv_data)
        return -EINVAL;

    bcm_hsotgctrl_phy_set_non_driving(!on);

    return 0;
}
static int bcmpmu_otg_xceiv_set_peripheral(struct otg_transceiver *otg,
					   struct usb_gadget *gadget)
{
	struct bcmpmu_otg_xceiv_data *xceiv_data = dev_get_drvdata(otg->dev);
	int status = 0;
	bool id_default_host = false;

	dev_dbg(xceiv_data->dev, "Setting Peripheral\n");
	otg->gadget = gadget;

	id_default_host = bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
		  bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);

	if (!id_default_host) {
		if (xceiv_data->otg_enabled &&
			(bcmpmu_otg_xceiv_check_id_rid_b(xceiv_data) ==
			    false)) { /* No SRP if RID_B */
			/* REVISIT. Shutdown uses sequence for lowest power
			 * and does not meet timing so don't do that in OTG mode
			 * for now. Just do SRP for ADP startup */
			bcmpmu_otg_xceiv_do_srp(xceiv_data);
		} else {
			int data;
			bcmpmu_usb_get(xceiv_data->bcmpmu,
				       BCMPMU_USB_CTRL_GET_USB_TYPE, &data);
			if ((data != PMU_USB_TYPE_SDP)
			    && (data != PMU_USB_TYPE_CDP)) {
				/* Shutdown the core */
				atomic_notifier_call_chain(&xceiv_data->
							   otg_xceiver.xceiver.
							   notifier,
							   USB_EVENT_NONE,
							   NULL);
			}
		}

	} else {
		bcm_hsotgctrl_phy_set_id_stat(false);
		/* Come up connected  */
		bcm_hsotgctrl_phy_set_non_driving(false);
	}

	return status;
}
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;

}
Пример #9
0
static void bcmpmu_otg_xceiv_vbus_a_invalid_handler(struct work_struct *work)
{
    struct bcmpmu_otg_xceiv_data *xceiv_data =
        container_of(work, struct bcmpmu_otg_xceiv_data,
                     bcm_otg_vbus_a_invalid_work);
    int bcm_hsotgctrl_status;

    /* dev_info(xceiv_data->dev, "A session invalid\n"); */

    fsa9485_vbus_check(0);

    if ( !(bcm_hsotgctrl_status = bcm_hsotgctrl_get_clk_count()) )
        bcm_hsotgctrl_en_clock(true);
    else if (-ENODEV == bcm_hsotgctrl_status || -EIO == bcm_hsotgctrl_status )
        return ;

    /* Inform the core of session invalid level  */
    bcm_hsotgctrl_phy_set_vbus_stat(false);

    if (xceiv_data->otg_enabled) {
        /* Stop Vbus discharge */
        bcmpmu_usb_set(xceiv_data->bcmpmu, BCMPMU_USB_CTRL_DISCHRG_VBUS, 0);

        if (bcmpmu_otg_xceiv_check_id_gnd(xceiv_data)) {
            /* Use n-1 method for ADP rise time comparison */
            bcmpmu_usb_set(xceiv_data->bcmpmu, BCMPMU_USB_CTRL_SET_ADP_COMP_METHOD, 1);
            if (xceiv_data->otg_xceiver.otg_vbus_off)
                schedule_delayed_work(&xceiv_data->
                                      bcm_otg_delayed_adp_work,
                                      msecs_to_jiffies
                                      (T_NO_ADP_DELAY_MIN_IN_MS));
            else
                bcm_otg_do_adp_probe(xceiv_data, true);
        } else if (!bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data)) {

            /* Vbus is off now so don't allow
             * core to connect
             */
            bcm_hsotgctrl_phy_set_non_driving(true);

            if (xceiv_data->otg_xceiver.otg_srp_reqd) {
                /* Start Session End SRP timer */
                xceiv_data->otg_xceiver.sess_end_srp_timer.expires =
                    jiffies +
                    msecs_to_jiffies(T_SESS_END_SRP_START_IN_MS);
                add_timer(&xceiv_data->otg_xceiver.sess_end_srp_timer);
            }
            else
                bcm_otg_do_adp_sense(xceiv_data, true);
        }
    } else {
        bool id_default_host = false;

        id_default_host =
            bcmpmu_otg_xceiv_check_id_gnd(xceiv_data) ||
            bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data);

        if (!id_default_host) {
            atomic_notifier_call_chain(&xceiv_data->otg_xceiver.
                                       xceiver.notifier,
                                       USB_EVENT_NONE, NULL);
        }
    }
}
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;
}