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; }
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; }
/** * 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); }