staticvoid ab8500_usb_regulator_enable(struct ab8500_usb *ab)
{ int ret, volt;
ret = regulator_enable(ab->v_ape); if (ret)
dev_err(ab->dev, "Failed to enable v-ape\n");
if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) {
ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi); if (ab->saved_v_ulpi < 0)
dev_err(ab->dev, "Failed to get v_ulpi voltage\n");
ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000); if (ret < 0)
dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n",
ret);
ret = regulator_set_load(ab->v_ulpi, 28000); if (ret < 0)
dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
ret);
}
ret = regulator_enable(ab->v_ulpi); if (ret)
dev_err(ab->dev, "Failed to enable vddulpivio18\n");
if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) {
volt = regulator_get_voltage(ab->v_ulpi); if ((volt != 1300000) && (volt != 1350000))
dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n",
volt);
}
ret = regulator_enable(ab->v_musb); if (ret)
dev_err(ab->dev, "Failed to enable musb_1v8\n");
}
staticvoid ab8500_usb_regulator_disable(struct ab8500_usb *ab)
{ int ret;
regulator_disable(ab->v_musb);
regulator_disable(ab->v_ulpi);
/* USB is not the only consumer of Vintcore, restore old settings */ if (ab->flags & AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE) { if (ab->saved_v_ulpi > 0) {
ret = regulator_set_voltage(ab->v_ulpi,
ab->saved_v_ulpi, ab->saved_v_ulpi); if (ret < 0)
dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n",
ab->saved_v_ulpi, ret);
}
ret = regulator_set_load(ab->v_ulpi, 0); if (ret < 0)
dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n",
ret);
}
/* mux and configure USB pins to DEFAULT state */
ab->pinctrl = pinctrl_get_select(ab->dev, PINCTRL_STATE_DEFAULT); if (IS_ERR(ab->pinctrl))
dev_err(ab->dev, "could not get/set default pinstate\n");
if (clk_prepare_enable(ab->sysclk))
dev_err(ab->dev, "can't prepare/enable clock\n");
/* Needed to disable the phy.*/
ab8500_usb_wd_workaround(ab);
clk_disable_unprepare(ab->sysclk);
ab8500_usb_regulator_disable(ab);
if (!IS_ERR(ab->pinctrl)) { /* configure USB pins to SLEEP state */
ab->pins_sleep = pinctrl_lookup_state(ab->pinctrl,
PINCTRL_STATE_SLEEP);
if (IS_ERR(ab->pins_sleep))
dev_dbg(ab->dev, "could not get sleep pinstate\n"); elseif (pinctrl_select_state(ab->pinctrl, ab->pins_sleep))
dev_err(ab->dev, "could not set pins to sleep state\n");
/* * as USB pins are shared with iddet, release them to allow * iddet to request them
*/
pinctrl_put(ab->pinctrl);
}
}
/* * Spurious link_status interrupts are seen at the time of * disconnection of a device in RIDA state
*/ if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8505 &&
(lsts == USB_LINK_STD_HOST_NC_8505)) return 0;
ab->previous_link_status_state = lsts;
switch (lsts) { case USB_LINK_ACA_RID_B_8505:
event = UX500_MUSB_RIDB;
fallthrough; case USB_LINK_NOT_CONFIGURED_8505: case USB_LINK_RESERVED0_8505: case USB_LINK_RESERVED1_8505: case USB_LINK_RESERVED2_8505: case USB_LINK_RESERVED3_8505:
ab->mode = USB_IDLE;
ab->phy.otg->default_a = false;
ab->vbus_draw = 0; if (event != UX500_MUSB_RIDB)
event = UX500_MUSB_NONE; /* * Fallback to default B_IDLE as nothing * is connected
*/
ab->phy.otg->state = OTG_STATE_B_IDLE;
usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break;
case USB_LINK_ACA_RID_C_NM_8505:
event = UX500_MUSB_RIDC;
fallthrough; case USB_LINK_STD_HOST_NC_8505: case USB_LINK_STD_HOST_C_NS_8505: case USB_LINK_STD_HOST_C_S_8505: case USB_LINK_CDP_8505: if (ab->mode == USB_IDLE) {
ab->mode = USB_PERIPHERAL;
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
} if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS; break;
case USB_LINK_ACA_RID_A_8505: case USB_LINK_ACA_DOCK_CHGR_8505:
event = UX500_MUSB_RIDA;
fallthrough; case USB_LINK_HM_IDGND_8505: if (ab->mode == USB_IDLE) {
ab->mode = USB_HOST;
ab8500_usb_host_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
}
ab->phy.otg->default_a = true; if (event != UX500_MUSB_RIDA)
event = UX500_MUSB_ID;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw); break;
/* * FIXME: For now we rely on the boot firmware to set up the necessary * PHY/pin configuration for UART mode. * * AB8505 does not seem to report any status change for UART cables, * possibly because it cannot detect them autonomously. * We may need to measure the ID resistance manually to reliably * detect UART cables after bootup.
*/ case USB_LINK_SAMSUNG_UART_CBL_PHY_EN_8505: case USB_LINK_SAMSUNG_UART_CBL_PHY_DISB_8505: if (ab->mode == USB_IDLE) {
ab->mode = USB_UART;
ab8500_usb_peri_phy_en(ab);
}
/* * Spurious link_status interrupts are seen in case of a * disconnection of a device in IDGND and RIDA stage
*/ if (ab->previous_link_status_state == USB_LINK_HM_IDGND_8500 &&
(lsts == USB_LINK_STD_HOST_C_NS_8500 ||
lsts == USB_LINK_STD_HOST_NC_8500)) return 0;
if (ab->previous_link_status_state == USB_LINK_ACA_RID_A_8500 &&
lsts == USB_LINK_STD_HOST_NC_8500) return 0;
ab->previous_link_status_state = lsts;
switch (lsts) { case USB_LINK_ACA_RID_B_8500:
event = UX500_MUSB_RIDB;
fallthrough; case USB_LINK_NOT_CONFIGURED_8500: case USB_LINK_NOT_VALID_LINK_8500:
ab->mode = USB_IDLE;
ab->phy.otg->default_a = false;
ab->vbus_draw = 0; if (event != UX500_MUSB_RIDB)
event = UX500_MUSB_NONE; /* Fallback to default B_IDLE as nothing is connected */
ab->phy.otg->state = OTG_STATE_B_IDLE;
usb_phy_set_event(&ab->phy, USB_EVENT_NONE); break;
case USB_LINK_ACA_RID_C_NM_8500: case USB_LINK_ACA_RID_C_HS_8500: case USB_LINK_ACA_RID_C_HS_CHIRP_8500:
event = UX500_MUSB_RIDC;
fallthrough; case USB_LINK_STD_HOST_NC_8500: case USB_LINK_STD_HOST_C_NS_8500: case USB_LINK_STD_HOST_C_S_8500: case USB_LINK_HOST_CHG_NM_8500: case USB_LINK_HOST_CHG_HS_8500: case USB_LINK_HOST_CHG_HS_CHIRP_8500: if (ab->mode == USB_IDLE) {
ab->mode = USB_PERIPHERAL;
ab8500_usb_peri_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
usb_phy_set_event(&ab->phy, USB_EVENT_ENUMERATED);
} if (event != UX500_MUSB_RIDC)
event = UX500_MUSB_VBUS; break;
case USB_LINK_ACA_RID_A_8500:
event = UX500_MUSB_RIDA;
fallthrough; case USB_LINK_HM_IDGND_8500: if (ab->mode == USB_IDLE) {
ab->mode = USB_HOST;
ab8500_usb_host_phy_en(ab);
atomic_notifier_call_chain(&ab->phy.notifier,
UX500_MUSB_PREPARE, &ab->vbus_draw);
}
ab->phy.otg->default_a = true; if (event != UX500_MUSB_RIDA)
event = UX500_MUSB_ID;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw); break;
/* Link status will not be updated till phy is disabled. */ if (ab->mode == USB_HOST) {
ab->phy.otg->default_a = false;
ab->vbus_draw = 0;
atomic_notifier_call_chain(&ab->phy.notifier,
event, &ab->vbus_draw);
ab8500_usb_host_phy_dis(ab);
ab->mode = USB_IDLE;
}
/* Disable regulator voltage setting for AB8500 <= v2.0 */ if (is_ab8500_2p0_or_earlier(ab->ab8500))
ab->flags &= ~AB8500_USB_FLAG_REGULATOR_SET_VOLTAGE;
platform_set_drvdata(pdev, ab);
/* all: Disable phy when called from set_host and set_peripheral */
INIT_WORK(&ab->phy_dis_work, ab8500_usb_phy_disable_work);
err = ab8500_usb_regulator_get(ab); if (err) return err;
ab->sysclk = devm_clk_get(ab->dev, "sysclk"); if (IS_ERR(ab->sysclk)) {
dev_err(ab->dev, "Could not get sysclk.\n"); return PTR_ERR(ab->sysclk);
}
err = ab8500_usb_irq_setup(pdev, ab); if (err < 0) return err;
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.