static void bcm_hsotgctrl_delayed_wakeup_handler(struct work_struct *work)
{
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		container_of(work, struct bcm_hsotgctrl_drv_data,
			 wakeup_work.work);

	if (NULL == local_hsotgctrl_handle)
		return;

	if (bcm_hsotgctrl_handle !=	local_hsotgctrl_handle) {
		dev_warn(local_hsotgctrl_handle->dev,
			"Invalid HSOTGCTRL wakeup handler");
		return;
	}

	dev_info(bcm_hsotgctrl_handle->dev, "Do HSOTGCTRL wakeup\n");

	/* Enable OTG AHB clock */
	bcm_hsotgctrl_en_clock(true);
	
	/* Use the PHY-core wakeup sequence */
	bcm_hsotgctrl_wakeup_core();

	bcm_hsotgctrl_en_clock(false);
}
int bcm_hsotgctrl_bc_enable_sw_ovwr(void)
{
	int val;
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		local_hsotgctrl_handle;

	if (NULL == local_hsotgctrl_handle) {
		dev_warn(bcm_hsotgctrl_handle->dev,
		  "%s: error invalid handle\n", __func__);
		return -ENODEV;
	}
	bcm_hsotgctrl_en_clock(true);

	val = readl(bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	/* Clear overwrite key */
	val &= ~(HSOTG_CTRL_BC_CFG_BC_OVWR_KEY_MASK |
		HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK);

	/*We need this key written for this register access*/
	val |= (BCCFG_SW_OVERWRITE_KEY |
			HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK);

	/*Enable SW overwrite*/
	writel(val, bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	msleep_interruptible(BC_CONFIG_DELAY_MS);

	bcm_hsotgctrl_en_clock(false);
	return 0;
}
static ssize_t dump_hsotgctrl(struct device *dev,
	struct device_attribute *attr,
	char *buf)
{
	struct bcm_hsotgctrl_drv_data *hsotgctrl_drvdata = dev_get_drvdata(dev);
	void __iomem *hsotg_ctrl_base = hsotgctrl_drvdata->hsotg_ctrl_base;
	int clk_cnt = clk_get_usage(hsotgctrl_drvdata->otg_clk);

	/* This could be done after USB is unplugged
	 * Turn on AHB clock so registers
	 * can be read even when USB is unplugged
	 */
	if (!clk_cnt)
		bcm_hsotgctrl_en_clock(true);

	pr_info("\nusbotgcontrol: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_USBOTGCONTROL_OFFSET));
	pr_info("\nphy_cfg: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_PHY_CFG_OFFSET));
	pr_info("\nphy_p1ctl: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_PHY_P1CTL_OFFSET));
	pr_info("\nbc11_status: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_BC_STATUS_OFFSET));
	pr_info("\nbc11_cfg: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_BC_CFG_OFFSET));
	pr_info("\ntp_in: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_TP_IN_OFFSET));
	pr_info("\ntp_out: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_TP_OUT_OFFSET));
	pr_info("\nphy_ctrl: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_PHY_CTRL_OFFSET));
	pr_info("\nusbreg: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_USBREG_OFFSET));
	pr_info("\nusbproben: 0x%08X",
		readl(hsotg_ctrl_base +
		    HSOTG_CTRL_USBPROBEN_OFFSET));

	/* We turned on the clock so turn it off */
	if (!clk_cnt)
		bcm_hsotgctrl_en_clock(false);

	return sprintf(buf, "hsotgctrl register dump\n");
}
int bcm_hsotgctrl_bc_reset(void)
{
	int val;
	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;

	bcm_hsotgctrl_en_clock(true);

	val = readl(bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	/* Clear overwrite key */
	val &= ~(HSOTG_CTRL_BC_CFG_BC_OVWR_KEY_MASK |
		HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK);
	/*We need this key written for this register access*/
	val |= (BCCFG_SW_OVERWRITE_KEY |
			HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK);
	val |= HSOTG_CTRL_BC_CFG_SW_RST_MASK;

	/*Reset BC1.1 state machine */
	writel(val, bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	msleep_interruptible(BC_CONFIG_DELAY_MS);

	val &= ~HSOTG_CTRL_BC_CFG_SW_RST_MASK;
	writel(val, bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET); /*Clear reset*/

	val = readl(bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	/* Clear overwrite key so we don't accidently write to these bits */
	val &= ~(HSOTG_CTRL_BC_CFG_BC_OVWR_KEY_MASK |
			HSOTG_CTRL_BC_CFG_SW_OVWR_EN_MASK);
	writel(val, bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);

	val = readl(bcm_hsotgctrl_handle->hsotg_ctrl_base +
			HSOTG_CTRL_BC_CFG_OFFSET);
	bcm_hsotgctrl_en_clock(false);
	return 0;
}
예제 #5
0
static int bcmpmu_otg_xceiv_a_invalid_notif_handler(
	struct notifier_block *nb, unsigned long value, void *data)
{
	struct bcmpmu_otg_xceiv_data *xceiv_data =
	    container_of(nb, struct bcmpmu_otg_xceiv_data,
			 bcm_otg_vbus_a_invalid_notifier);
	bool suspend_allowed = false;

	if (!xceiv_data)
		return -EINVAL;

	/* Check if system suspend is allowed */
	bcm_hsotgctrl_is_suspend_allowed(&suspend_allowed);

	if (suspend_allowed) {
		/* Clock must be off. Enable OTG AHB clock */
		bcm_hsotgctrl_en_clock(true);
	}

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

	/* This triggers shutdown that will turn off the clock */
	atomic_notifier_call_chain(&xceiv_data->otg_xceiver.
				   xceiver.notifier,
				   USB_EVENT_NONE, NULL);

	return 0;
}
static void enable_bc_clock(struct bcmpmu_accy *paccy, bool en)
{
	if (paccy->bc == BCMPMU_BC_BB_BC12) {
		bcm_hsotgctrl_en_clock(en);
		paccy->clock_en = en;
		pr_accy(FLOW, "======<%s> paccy clock %x\n"
			, __func__, paccy->clock_en);
	}
}
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);

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

	if (!bcm_hsotgctrl_get_clk_count())
		bcm_hsotgctrl_en_clock(true);

	/* 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);
		} else if (!bcmpmu_otg_xceiv_check_id_rid_a(xceiv_data)) {
			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);
		}
	} 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);
		}
	}
}
void bcm_hsotgctrl_wakeup_core(void)
{
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		local_hsotgctrl_handle;

	if (NULL == local_hsotgctrl_handle)
		return;

	bcm_hsotgctrl_handle->usb_active = true;

	/* Enable OTG AHB clock */
	bcm_hsotgctrl_en_clock(true);

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

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

	/* PHY isolation */
	bcm_hsotgctrl_set_phy_iso(true);

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

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

	/* De-assert PHY reset */
	bcm_hsotgctrl_set_phy_resetb(true);

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

	/* Request PHY clock */
	bcm_hsotgctrl_set_phy_clk_request(true);
	mdelay(PHY_PM_DELAY_IN_MS);

	/* Do MDIO init values after PHY is up */
	bcm_hsotgctrl_phy_mdio_initialization();

	if (local_wakeup_core_cb) {
		local_wakeup_core_cb();
		local_wakeup_core_cb = NULL;
	}

}
int bcm_hsotgctrl_handle_bus_suspend(send_core_event_cb_t suspend_core_cb,
		send_core_event_cb_t wakeup_core_cb)
{
	struct bcm_hsotgctrl_drv_data *bcm_hsotgctrl_handle =
		local_hsotgctrl_handle;

	if (NULL == local_hsotgctrl_handle)
		return -ENODEV;

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

	if (suspend_core_cb)
		suspend_core_cb();
	if (wakeup_core_cb)
		local_wakeup_core_cb = wakeup_core_cb;

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

	/* PHY isolation */
	bcm_hsotgctrl_set_phy_iso(true);
	mdelay(PHY_PM_DELAY_IN_MS);

	/* Clear PHY clock request */
	bcm_hsotgctrl_set_phy_clk_request(true);

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

	/* Enable wakeup interrupt */
	bcm_hsotgctrl_phy_wakeup_condition(true);

	/* Disable OTG AHB clock */
	bcm_hsotgctrl_handle->usb_active = false;
	bcm_hsotgctrl_en_clock(false);

	if (bcm_hsotgctrl_handle->irq_enabled == false) {
		/* Enable wake IRQ */
		bcm_hsotgctrl_handle->irq_enabled = true;
		enable_irq(bcm_hsotgctrl_handle->hsotgctrl_irq);
	}

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

}
예제 #13
0
/**
 * Set the register offset for the next Register Access          Read/Write
 */
static ssize_t regoffset_store(struct device *_dev,
			       struct device_attribute *attr,
			       const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)

	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t offset = simple_strtoul(buf, NULL, 16);

#if defined(PCI_INTERFACE)
	if (offset < 0x00040000) {
#else
	if (offset < SZ_256K) {
#endif
		otg_dev->reg_offset = offset;
	} else {
		dev_err(_dev, "invalid offset\n");
	}

	return count;
}

DEVICE_ATTR(regoffset, S_IRUGO | S_IWUSR, regoffset_show, regoffset_store);

/**
 * Show the value of the register at the offset in the reg_offset
 * attribute.
 */
static ssize_t regvalue_show(struct device *_dev,
			     struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val;
	volatile uint32_t *addr;

	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t *)(otg_dev->reg_offset +
				    (uint8_t *)otg_dev->base);
		val = dwc_read_reg32(addr);
		return snprintf(buf,
				sizeof("Reg@0xFFFFFFFF = 0xFFFFFFFF\n") + 1,
				"Reg@0x%06x = 0x%08x\n", otg_dev->reg_offset,
				val);
	} else {
		dev_err(_dev, "Invalid offset (0x%0x)\n", otg_dev->reg_offset);
		return sprintf(buf, "invalid offset\n");
	}
}

/**
 * Store the value in the register at the offset in the reg_offset
 * attribute.
 *
 */
static ssize_t regvalue_store(struct device *_dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)

	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	volatile uint32_t *addr;
	uint32_t val = simple_strtoul(buf, NULL, 16);
	/* dev_dbg(_dev, "Offset=0x%08x Val=0x%08x\n", otg_dev->reg_offset, val); */
	if (otg_dev->reg_offset != 0xFFFFFFFF && 0 != otg_dev->base) {
		/* Calculate the address */
		addr = (uint32_t *)(otg_dev->reg_offset +
				    (uint8_t *)otg_dev->base);
		dwc_write_reg32(addr, val);
	} else {
		dev_err(_dev, "Invalid Register Offset (0x%08x)\n",
			otg_dev->reg_offset);
	}
	return count;
}

DEVICE_ATTR(regvalue, S_IRUGO | S_IWUSR, regvalue_show, regvalue_store);

/*
 * Attributes
 */
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(mode, "Mode");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hnpcapable, "HNPCapable");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(srpcapable, "SRPCapable");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(hsic_connect, "HSIC Connect");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(inv_sel_hsic, "Invert Select HSIC");

/* DWC_OTG_DEVICE_ATTR_BITFIELD_RW(buspower,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); */
/* DWC_OTG_DEVICE_ATTR_BITFIELD_RW(bussuspend,&(otg_dev->core_if->core_global_regs->gotgctl),(1<<8),8,"Mode"); */
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(busconnected, "Bus Connected");

DWC_OTG_DEVICE_ATTR_REG32_RW(gotgctl, 0, "GOTGCTL");
DWC_OTG_DEVICE_ATTR_REG32_RW(gusbcfg,
			     &(otg_dev->core_if->core_global_regs->gusbcfg),
			     "GUSBCFG");
DWC_OTG_DEVICE_ATTR_REG32_RW(grxfsiz,
			     &(otg_dev->core_if->core_global_regs->grxfsiz),
			     "GRXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(gnptxfsiz,
			     &(otg_dev->core_if->core_global_regs->gnptxfsiz),
			     "GNPTXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(gpvndctl,
			     &(otg_dev->core_if->core_global_regs->gpvndctl),
			     "GPVNDCTL");
DWC_OTG_DEVICE_ATTR_REG32_RW(ggpio,
			     &(otg_dev->core_if->core_global_regs->ggpio),
			     "GGPIO");
DWC_OTG_DEVICE_ATTR_REG32_RW(guid, &(otg_dev->core_if->core_global_regs->guid),
			     "GUID");
DWC_OTG_DEVICE_ATTR_REG32_RO(gsnpsid,
			     &(otg_dev->core_if->core_global_regs->gsnpsid),
			     "GSNPSID");
DWC_OTG_DEVICE_ATTR_BITFIELD_RW(devspeed, "Device Speed");
DWC_OTG_DEVICE_ATTR_BITFIELD_RO(enumspeed, "Device Enumeration Speed");

DWC_OTG_DEVICE_ATTR_REG32_RO(hptxfsiz,
			     &(otg_dev->core_if->core_global_regs->hptxfsiz),
			     "HPTXFSIZ");
DWC_OTG_DEVICE_ATTR_REG32_RW(hprt0, otg_dev->core_if->host_if->hprt0, "HPRT0");

/**
 * @todo Add code to initiate the HNP.
 */
/**
 * Show the HNP status bit
 */
static ssize_t hnp_show(struct device *_dev,
			struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "HstNegScs = 0x%x\n",
		       dwc_otg_get_hnpstatus(otg_dev->core_if));
}

/**
 * Set the HNP Request bit
 */
static ssize_t hnp_store(struct device *_dev,
			 struct device_attribute *attr,
			 const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t in = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_hnpreq(otg_dev->core_if, in);
	return count;
}

DEVICE_ATTR(hnp, 0644, hnp_show, hnp_store);

/**
 * @todo Add code to initiate the SRP.
 */
/**
 * Show the SRP status bit
 */
static ssize_t srp_show(struct device *_dev,
			struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "SesReqScs = 0x%x\n",
		       dwc_otg_get_srpstatus(otg_dev->core_if));
#else
	return sprintf(buf, "Host Only Mode!\n");
#endif
}

/**
 * Set the SRP Request bit
 */
static ssize_t srp_store(struct device *_dev,
			 struct device_attribute *attr,
			 const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	if (NULL != otg_dev->pcd)
		dwc_otg_pcd_initiate_srp(otg_dev->pcd);
#endif
	return count;
}

DEVICE_ATTR(srp, 0644, srp_show, srp_store);

/**
 * @todo Need to do more for power on/off?
 */
/**
 * Show the Bus Power status
 */
static ssize_t buspower_show(struct device *_dev,
			     struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	return sprintf(buf, "Bus Power = 0x%x\n",
		       dwc_otg_get_prtpower(otg_dev->core_if));
}

/**
 * Set the Bus Power status
 */
static ssize_t buspower_store(struct device *_dev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t on = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_prtpower(otg_dev->core_if, on);
	return count;
}

DEVICE_ATTR(buspower, 0644, buspower_show, buspower_store);

/**
 * @todo Need to do more for suspend?
 */
/**
 * Show the Bus Suspend status
 */
static ssize_t bussuspend_show(struct device *_dev,
			       struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Bus Suspend = 0x%x\n",
		       dwc_otg_get_prtsuspend(otg_dev->core_if));
}

/**
 * Set the Bus Suspend status
 */
static ssize_t bussuspend_store(struct device *_dev,
				struct device_attribute *attr,
				const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t in = simple_strtoul(buf, NULL, 16);
	dwc_otg_set_prtsuspend(otg_dev->core_if, in);
	return count;
}

DEVICE_ATTR(bussuspend, 0644, bussuspend_show, bussuspend_store);

/**
 * Show the status of Remote Wakeup.
 */
static ssize_t remote_wakeup_show(struct device *_dev,
				  struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf,
		       "Remote Wakeup Sig = %d Enabled = %d LPM Remote Wakeup = %d\n",
		       dwc_otg_get_remotewakesig(otg_dev->core_if),
		       dwc_otg_pcd_get_rmwkup_enable(otg_dev->pcd),
		       dwc_otg_get_lpm_remotewakeenabled(otg_dev->core_if));
#else
	return sprintf(buf, "Host Only Mode!\n");
#endif /* DWC_HOST_ONLY */
}

/**
 * Initiate a remote wakeup of the host.  The Device control register
 * Remote Wakeup Signal bit is written if the PCD Remote wakeup enable
 * flag is set.
 *
 */
static ssize_t remote_wakeup_store(struct device *_dev,
				   struct device_attribute *attr,
				   const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val = simple_strtoul(buf, NULL, 16);

	if (val & 1)
		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 1);
	else
		dwc_otg_pcd_remote_wakeup(otg_dev->pcd, 0);
#endif /* DWC_HOST_ONLY */
	return count;
}

DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR, remote_wakeup_show,
	    remote_wakeup_store);

/**
 * Show the whether core is hibernated or not.
 */
static ssize_t rem_wakeup_pwrdn_show(struct device *_dev,
				     struct device_attribute *attr, char *buf)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	if (dwc_otg_get_core_state(otg_dev->core_if))
		DWC_PRINTF("Core is in hibernation\n");
	else
		DWC_PRINTF("Core is not in hibernation\n");
#endif /* DWC_HOST_ONLY */
	return 0;
}

/**
 * Initiate a remote wakeup of the device to exit from hibernation.
 */
static ssize_t rem_wakeup_pwrdn_store(struct device *_dev,
				      struct device_attribute *attr,
				      const char *buf, size_t count)
{
#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	dwc_otg_device_hibernation_restore(otg_dev->core_if, 1, 0);
#endif
	return count;
}

DEVICE_ATTR(rem_wakeup_pwrdn, S_IRUGO | S_IWUSR, rem_wakeup_pwrdn_show,
	    rem_wakeup_pwrdn_store);

static ssize_t disconnect_us(struct device *_dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{

#ifndef DWC_HOST_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif
	uint32_t val = simple_strtoul(buf, NULL, 16);
	DWC_PRINTF("The Passed value is %04x\n", val);

	dwc_otg_pcd_disconnect_us(otg_dev->pcd, 50);

#endif /* DWC_HOST_ONLY */
	return count;
}

DEVICE_ATTR(disconnect_us, S_IWUSR, 0, disconnect_us);

/**
 * Dump global registers and either host or device registers (depending on the
 * current mode of the core).
 */
static ssize_t regdump_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

#ifdef CONFIG_KONA_USB_CONTROL
	/* We want to be able to do this with and without
	 * USB-PMU-xceiver interface so use direct API
	 */
	bcm_hsotgctrl_en_clock(true);
	dwc_otg_dump_global_registers(otg_dev->core_if);
	if (dwc_otg_is_host_mode(otg_dev->core_if))
		dwc_otg_dump_host_registers(otg_dev->core_if);
	else
		dwc_otg_dump_dev_registers(otg_dev->core_if);

	bcm_hsotgctrl_en_clock(false);
#else
	dwc_otg_dump_global_registers(otg_dev->core_if);
	if (dwc_otg_is_host_mode(otg_dev->core_if))
		dwc_otg_dump_host_registers(otg_dev->core_if);
	else
		dwc_otg_dump_dev_registers(otg_dev->core_if);
#endif

	return sprintf(buf, "Register Dump\n");
}

DEVICE_ATTR(regdump, S_IRUGO | S_IWUSR, regdump_show, 0);

/**
 * Dump global registers and either host or device registers (depending on the
 * current mode of the core).
 */
static ssize_t spramdump_show(struct device *_dev,
			      struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_dump_spram(otg_dev->core_if);

	return sprintf(buf, "SPRAM Dump\n");
}

DEVICE_ATTR(spramdump, S_IRUGO | S_IWUSR, spramdump_show, 0);

/**
 * Dump the current hcd state.
 */
static ssize_t hcddump_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_hcd_dump_state(otg_dev->hcd);
#endif /* DWC_DEVICE_ONLY */
	return sprintf(buf, "HCD Dump\n");
}

DEVICE_ATTR(hcddump, S_IRUGO | S_IWUSR, hcddump_show, 0);

/**
 * Dump the average frame remaining at SOF. This can be used to
 * determine average interrupt latency. Frame remaining is also shown for
 * start transfer and two additional sample points.
 */
static ssize_t hcd_frrem_show(struct device *_dev,
			      struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_hcd_dump_frrem(otg_dev->hcd);
#endif /* DWC_DEVICE_ONLY */
	return sprintf(buf, "HCD Dump Frame Remaining\n");
}

DEVICE_ATTR(hcd_frrem, S_IRUGO | S_IWUSR, hcd_frrem_show, 0);

/**
 * Displays the time required to read the GNPTXFSIZ register many times (the
 * output shows the number of times the register is read).
 */
#define RW_REG_COUNT 10000000
#define MSEC_PER_JIFFIE (1000/HZ)
static ssize_t rd_reg_test_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	int i;
	int time;
	int start_jiffies;

	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
		HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++)
		dwc_otg_get_gnptxfsiz(otg_dev->core_if);

	time = jiffies - start_jiffies;
	return sprintf(buf,
		       "Time to read GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}

DEVICE_ATTR(rd_reg_test, S_IRUGO | S_IWUSR, rd_reg_test_show, 0);

/**
 * Displays the time required to write the GNPTXFSIZ register many times (the
 * output shows the number of times the register is written).
 */
static ssize_t wr_reg_test_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t reg_val;
	int i;
	int time;
	int start_jiffies;

	pr_info("HZ %d, MSEC_PER_JIFFIE %d, loops_per_jiffy %lu\n",
		HZ, MSEC_PER_JIFFIE, loops_per_jiffy);
	reg_val = dwc_otg_get_gnptxfsiz(otg_dev->core_if);
	start_jiffies = jiffies;
	for (i = 0; i < RW_REG_COUNT; i++)
		dwc_otg_set_gnptxfsiz(otg_dev->core_if, reg_val);

	time = jiffies - start_jiffies;
	return sprintf(buf,
		       "Time to write GNPTXFSIZ reg %d times: %d msecs (%d jiffies)\n",
		       RW_REG_COUNT, time * MSEC_PER_JIFFIE, time);
}

DEVICE_ATTR(wr_reg_test, S_IRUGO | S_IWUSR, wr_reg_test_show, 0);

#ifdef CONFIG_USB_DWC_OTG_LPM

/**
* Show the lpm_response attribute.
*/
static ssize_t lpmresp_show(struct device *_dev,
			    struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
		return sprintf(buf, "** LPM is DISABLED **\n");

	if (!dwc_otg_is_device_mode(otg_dev->core_if))
		return sprintf(buf, "** Current mode is not device mode\n");

	return sprintf(buf, "lpm_response = %d\n",
		       dwc_otg_get_lpmresponse(otg_dev->core_if));
}

/**
* Store the lpm_response attribute.
*/
static ssize_t lpmresp_store(struct device *_dev,
			     struct device_attribute *attr,
			     const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	uint32_t val = simple_strtoul(buf, NULL, 16);

	if (!dwc_otg_get_param_lpm_enable(otg_dev->core_if))
		return 0;

	if (!dwc_otg_is_device_mode(otg_dev->core_if))
		return 0;

	dwc_otg_set_lpmresponse(otg_dev->core_if, val);
	return count;
}

DEVICE_ATTR(lpm_response, S_IRUGO | S_IWUSR, lpmresp_show, lpmresp_store);

/**
* Show the sleep_status attribute.
*/
static ssize_t sleepstatus_show(struct device *_dev,
				struct device_attribute *attr, char *buf)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Sleep Status = %d\n",
		       dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if));
}

/**
 * Store the sleep_status attribure.
 */
static ssize_t sleepstatus_store(struct device *_dev,
				 struct device_attribute *attr,
				 const char *buf, size_t count)
{
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	dwc_otg_core_if_t *core_if = otg_dev->core_if;

	if (dwc_otg_get_lpm_portsleepstatus(otg_dev->core_if)) {
		if (dwc_otg_is_host_mode(core_if)) {

			DWC_PRINTF("Host initiated resume\n");
			dwc_otg_set_prtresume(otg_dev->core_if, 1);
		}
	}

	return count;
}

DEVICE_ATTR(sleep_status, S_IRUGO | S_IWUSR, sleepstatus_show,
	    sleepstatus_store);

#endif /* CONFIG_USB_DWC_OTG_LPM_ENABLE */

/**
 * Show the value of Host mode Connection Timeout.
 */
static ssize_t h_conn_wait_tmout_show(struct device *_dev,
				      struct device_attribute *attr, char *buf)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	return sprintf(buf, "Connection wait timeout in ms = %d\n",
		       otg_dev->hcd->conn_wait_timeout);
#else
	return sprintf(buf, "Device Only Mode!\n");
#endif /* #ifndef DWC_DEVICE_ONLY */
}

/**
 * Set the value of host mode connection timeout
 *
 */
static ssize_t h_conn_wait_tmout_store(struct device *_dev,
				       struct device_attribute *attr,
				       const char *buf, size_t count)
{
#ifndef DWC_DEVICE_ONLY
#ifdef LM_INTERFACE
	struct lm_device *lm_dev = container_of(_dev, struct lm_device, dev);
	dwc_otg_device_t *otg_dev = lm_get_drvdata(lm_dev);
#elif defined(PCI_INTERFACE)
	dwc_otg_device_t *otg_dev = dev_get_drvdata(_dev);
#else
	struct platform_device *platform_dev =
	    container_of(_dev, struct platform_device, dev);
	dwc_otg_device_t *otg_dev = platform_get_drvdata(platform_dev);
#endif

	otg_dev->hcd->conn_wait_timeout = simple_strtoul(buf, NULL, 10);
#endif
	return count;
}

DEVICE_ATTR(h_conn_wait_tmout, S_IRUGO | S_IWUSR, h_conn_wait_tmout_show,
	    h_conn_wait_tmout_store);

/**@}*/

/**
 * Create the device files
 */
void dwc_otg_attr_create(
#ifdef LM_INTERFACE
				struct lm_device *dev
#elif defined(PCI_INTERFACE)
				struct pci_dev *dev
#else
				struct platform_device *dev
#endif
    )
{
	int error;

	error = device_create_file(&dev->dev, &dev_attr_regoffset);
	error = device_create_file(&dev->dev, &dev_attr_regvalue);
	error = device_create_file(&dev->dev, &dev_attr_mode);
	error = device_create_file(&dev->dev, &dev_attr_hnpcapable);
	error = device_create_file(&dev->dev, &dev_attr_srpcapable);
	error = device_create_file(&dev->dev, &dev_attr_hsic_connect);
	error = device_create_file(&dev->dev, &dev_attr_inv_sel_hsic);
	error = device_create_file(&dev->dev, &dev_attr_hnp);
	error = device_create_file(&dev->dev, &dev_attr_srp);
	error = device_create_file(&dev->dev, &dev_attr_buspower);
	error = device_create_file(&dev->dev, &dev_attr_bussuspend);
	error = device_create_file(&dev->dev, &dev_attr_busconnected);
	error = device_create_file(&dev->dev, &dev_attr_gotgctl);
	error = device_create_file(&dev->dev, &dev_attr_gusbcfg);
	error = device_create_file(&dev->dev, &dev_attr_grxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_gnptxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_gpvndctl);
	error = device_create_file(&dev->dev, &dev_attr_ggpio);
	error = device_create_file(&dev->dev, &dev_attr_guid);
	error = device_create_file(&dev->dev, &dev_attr_gsnpsid);
	error = device_create_file(&dev->dev, &dev_attr_devspeed);
	error = device_create_file(&dev->dev, &dev_attr_enumspeed);
	error = device_create_file(&dev->dev, &dev_attr_hptxfsiz);
	error = device_create_file(&dev->dev, &dev_attr_hprt0);
	error = device_create_file(&dev->dev, &dev_attr_remote_wakeup);
	error = device_create_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
	error = device_create_file(&dev->dev, &dev_attr_disconnect_us);
	error = device_create_file(&dev->dev, &dev_attr_regdump);
	error = device_create_file(&dev->dev, &dev_attr_spramdump);
	error = device_create_file(&dev->dev, &dev_attr_hcddump);
	error = device_create_file(&dev->dev, &dev_attr_hcd_frrem);
	error = device_create_file(&dev->dev, &dev_attr_rd_reg_test);
	error = device_create_file(&dev->dev, &dev_attr_wr_reg_test);
#ifdef CONFIG_USB_DWC_OTG_LPM
	error = device_create_file(&dev->dev, &dev_attr_lpm_response);
	error = device_create_file(&dev->dev, &dev_attr_sleep_status);
#endif
	error = device_create_file(&dev->dev, &dev_attr_h_conn_wait_tmout);
}

/**
 * Remove the device files
 */
void dwc_otg_attr_remove(
#ifdef LM_INTERFACE
				struct lm_device *dev
#elif defined(PCI_INTERFACE)
				struct pci_dev *dev
#else
				struct platform_device *dev
#endif
    )
{
	device_remove_file(&dev->dev, &dev_attr_regoffset);
	device_remove_file(&dev->dev, &dev_attr_regvalue);
	device_remove_file(&dev->dev, &dev_attr_mode);
	device_remove_file(&dev->dev, &dev_attr_hnpcapable);
	device_remove_file(&dev->dev, &dev_attr_srpcapable);
	device_remove_file(&dev->dev, &dev_attr_hsic_connect);
	device_remove_file(&dev->dev, &dev_attr_inv_sel_hsic);
	device_remove_file(&dev->dev, &dev_attr_hnp);
	device_remove_file(&dev->dev, &dev_attr_srp);
	device_remove_file(&dev->dev, &dev_attr_buspower);
	device_remove_file(&dev->dev, &dev_attr_bussuspend);
	device_remove_file(&dev->dev, &dev_attr_busconnected);
	device_remove_file(&dev->dev, &dev_attr_gotgctl);
	device_remove_file(&dev->dev, &dev_attr_gusbcfg);
	device_remove_file(&dev->dev, &dev_attr_grxfsiz);
	device_remove_file(&dev->dev, &dev_attr_gnptxfsiz);
	device_remove_file(&dev->dev, &dev_attr_gpvndctl);
	device_remove_file(&dev->dev, &dev_attr_ggpio);
	device_remove_file(&dev->dev, &dev_attr_guid);
	device_remove_file(&dev->dev, &dev_attr_gsnpsid);
	device_remove_file(&dev->dev, &dev_attr_devspeed);
	device_remove_file(&dev->dev, &dev_attr_enumspeed);
	device_remove_file(&dev->dev, &dev_attr_hptxfsiz);
	device_remove_file(&dev->dev, &dev_attr_hprt0);
	device_remove_file(&dev->dev, &dev_attr_remote_wakeup);
	device_remove_file(&dev->dev, &dev_attr_rem_wakeup_pwrdn);
	device_remove_file(&dev->dev, &dev_attr_disconnect_us);
	device_remove_file(&dev->dev, &dev_attr_regdump);
	device_remove_file(&dev->dev, &dev_attr_spramdump);
	device_remove_file(&dev->dev, &dev_attr_hcddump);
	device_remove_file(&dev->dev, &dev_attr_hcd_frrem);
	device_remove_file(&dev->dev, &dev_attr_rd_reg_test);
	device_remove_file(&dev->dev, &dev_attr_wr_reg_test);
#ifdef CONFIG_USB_DWC_OTG_LPM
	device_remove_file(&dev->dev, &dev_attr_lpm_response);
	device_remove_file(&dev->dev, &dev_attr_sleep_status);
#endif
	device_remove_file(&dev->dev, &dev_attr_h_conn_wait_tmout);
}
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;
}
static void enable_bc_clock(struct accy_det *accy_d, bool en)
{
	bcm_hsotgctrl_en_clock(en);
	pr_acd(VERBOSE, "======<%s> paccy clock %x\n"
		, __func__, en);
}