/* * In case the fsl,usbmisc property is not present this device doesn't * need usbmisc. Return NULL (which is no error here)
*/ if (!of_property_present(np, "fsl,usbmisc")) return NULL;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return ERR_PTR(-ENOMEM);
ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
0, &args); if (ret) {
dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
ret); return ERR_PTR(ret);
}
if (!platform_get_drvdata(misc_pdev)) {
put_device(&misc_pdev->dev); return ERR_PTR(-EPROBE_DEFER);
}
data->dev = &misc_pdev->dev;
/* * Check the various over current related properties. If over current * detection is disabled we're not interested in the polarity.
*/ if (of_property_read_bool(np, "disable-over-current")) {
data->disable_oc = 1;
} elseif (of_property_read_bool(np, "over-current-active-high")) {
data->oc_pol_active_low = 0;
data->oc_pol_configured = 1;
} elseif (of_property_read_bool(np, "over-current-active-low")) {
data->oc_pol_active_low = 1;
data->oc_pol_configured = 1;
} else {
dev_warn(dev, "No over current polarity defined\n");
}
if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
data->ulpi = 1;
if (of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control",
&data->emp_curr_control))
data->emp_curr_control = -1; if (of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust",
&data->dc_vol_level_adjust))
data->dc_vol_level_adjust = -1; if (of_property_read_u32(np, "fsl,picophy-rise-fall-time-adjust",
&data->rise_fall_time_adjust))
data->rise_fall_time_adjust = -1;
return data;
}
/* End of common functions shared by usbmisc drivers*/ staticint imx_get_clks(struct device *dev)
{ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret = 0;
data->clk_ipg = devm_clk_get(dev, "ipg"); if (IS_ERR(data->clk_ipg)) { /* If the platform only needs one primary clock */
data->clk = devm_clk_get(dev, NULL); if (IS_ERR(data->clk)) {
ret = PTR_ERR(data->clk);
dev_err(dev, "Failed to get clks, err=%ld,%ld\n",
PTR_ERR(data->clk), PTR_ERR(data->clk_ipg)); return ret;
} /* Get wakeup clock. Not all of the platforms need to * handle this clock. So make it optional.
*/
data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup"); if (IS_ERR(data->clk_wakeup))
ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup), "Failed to get wakeup clk\n"); return ret;
}
data->clk_ahb = devm_clk_get(dev, "ahb"); if (IS_ERR(data->clk_ahb)) {
ret = PTR_ERR(data->clk_ahb);
dev_err(dev, "Failed to get ahb clock, err=%d\n", ret); return ret;
}
data->clk_per = devm_clk_get(dev, "per"); if (IS_ERR(data->clk_per)) {
ret = PTR_ERR(data->clk_per);
dev_err(dev, "Failed to get per clock, err=%d\n", ret); return ret;
}
data->need_three_clks = true; return ret;
}
staticint imx_prepare_enable_clks(struct device *dev)
{ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev); int ret = 0;
if (data->need_three_clks) {
ret = clk_prepare_enable(data->clk_ipg); if (ret) {
dev_err(dev, "Failed to prepare/enable ipg clk, err=%d\n",
ret); return ret;
}
ret = clk_prepare_enable(data->clk_ahb); if (ret) {
dev_err(dev, "Failed to prepare/enable ahb clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ipg); return ret;
}
ret = clk_prepare_enable(data->clk_per); if (ret) {
dev_err(dev, "Failed to prepare/enable per clk, err=%d\n",
ret);
clk_disable_unprepare(data->clk_ahb);
clk_disable_unprepare(data->clk_ipg); return ret;
}
} else {
ret = clk_prepare_enable(data->clk); if (ret) {
dev_err(dev, "Failed to prepare/enable clk, err=%d\n",
ret); return ret;
}
}
switch (event) { case CI_HDRC_IMX_HSIC_ACTIVE_EVENT: if (data->pinctrl) {
ret = pinctrl_select_state(data->pinctrl,
data->pinctrl_hsic_active); if (ret)
dev_err(dev, "hsic_active select failed, err=%d\n",
ret);
} break; case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
ret = imx_usbmisc_hsic_set_connect(mdata); if (ret)
dev_err(dev, "hsic_set_connect failed, err=%d\n", ret); break; case CI_HDRC_CONTROLLER_VBUS_EVENT: if (ci->vbus_active)
ret = imx_usbmisc_charger_detection(mdata, true); else
ret = imx_usbmisc_charger_detection(mdata, false); if (ci->usb_phy)
schedule_work(&ci->usb_phy->chg_work); break; case CI_HDRC_CONTROLLER_PULLUP_EVENT: if (ci->role == CI_ROLE_GADGET &&
ci->gadget.speed == USB_SPEED_HIGH)
imx_usbmisc_pullup(data->usbmisc_data,
ci->gadget.connected); break; default: break;
}
if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC)
&& data->usbmisc_data) {
pdata.flags |= CI_HDRC_IMX_IS_HSIC;
data->usbmisc_data->hsic = 1;
data->pinctrl = devm_pinctrl_get(dev); if (PTR_ERR(data->pinctrl) == -ENODEV)
data->pinctrl = NULL; elseif (IS_ERR(data->pinctrl)) {
ret = dev_err_probe(dev, PTR_ERR(data->pinctrl), "pinctrl get failed\n"); goto err_put;
}
data->hsic_pad_regulator =
devm_regulator_get_optional(dev, "hsic"); if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) { /* no pad regulator is needed */
data->hsic_pad_regulator = NULL;
} elseif (IS_ERR(data->hsic_pad_regulator)) {
ret = dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator), "Get HSIC pad regulator error\n"); goto err_put;
}
if (data->hsic_pad_regulator) {
ret = regulator_enable(data->hsic_pad_regulator); if (ret) {
dev_err(dev, "Failed to enable HSIC pad regulator\n"); goto err_put;
}
ret = devm_add_action_or_reset(dev,
ci_hdrc_imx_disable_regulator, data); if (ret) {
dev_err(dev, "Failed to add regulator devm action\n"); goto err_put;
}
}
}
if (data->supports_runtime_pm) {
pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
} if (data->ci_pdev)
ci_hdrc_remove_device(data->ci_pdev); if (data->override_phy_control)
usb_phy_shutdown(data->phy); if (data->ci_pdev) {
imx_disable_unprepare_clks(&pdev->dev);
clk_disable_unprepare(data->clk_wakeup); if (data->plat_data->flags & CI_HDRC_PMQOS)
cpu_latency_qos_remove_request(&data->pm_qos_req);
} if (data->usbmisc_data)
put_device(data->usbmisc_data->dev);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.