Lines Matching +full:usb +full:- +full:sdp
1 // SPDX-License-Identifier: GPL-2.0
7 * Copyright (C) 2013-2015 Intel Corporation. All rights reserved.
10 #include <linux/extcon-provider.h>
22 #include <linux/usb/role.h>
24 #include "extcon-intel.h"
67 /* 0 - open drain, 1 - regular push-pull output */
69 /* 0 - pin is controlled by SW, 1 - by HW */
125 * According to the spec. we should read the USB-ID pin ADC value here in cht_wc_extcon_get_id()
126 * to determine the resistance of the used pull-down resister and then in cht_wc_extcon_get_id()
129 * a combination of a charging port with one or more USB-A ports, so in cht_wc_extcon_get_id()
131 * is hard to read / badly-worded so some of them actually indicate in cht_wc_extcon_get_id()
152 ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc); in cht_wc_extcon_get_charger()
154 dev_err(ext->dev, "Error reading usbsrc: %d\n", ret); in cht_wc_extcon_get_charger()
169 dev_warn(ext->dev, "Could not detect charger type\n"); in cht_wc_extcon_get_charger()
171 dev_warn(ext->dev, "Timeout detecting charger type\n"); in cht_wc_extcon_get_charger()
181 dev_warn(ext->dev, in cht_wc_extcon_get_charger()
182 "Unhandled charger type %d, defaulting to SDP\n", in cht_wc_extcon_get_charger()
184 ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; in cht_wc_extcon_get_charger()
189 ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP; in cht_wc_extcon_get_charger()
192 ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP; in cht_wc_extcon_get_charger()
197 ext->usb_type = POWER_SUPPLY_USB_TYPE_DCP; in cht_wc_extcon_get_charger()
200 ext->usb_type = POWER_SUPPLY_USB_TYPE_ACA; in cht_wc_extcon_get_charger()
209 ret = regmap_write(ext->regmap, CHT_WC_PHYCTRL, state); in cht_wc_extcon_set_phymux()
211 dev_err(ext->dev, "Error writing phyctrl: %d\n", ret); in cht_wc_extcon_set_phymux()
227 ret = regmap_write(ext->regmap, CHT_WC_VBUS_GPIO_CTLO, val); in cht_wc_extcon_set_5v_boost()
229 dev_err(ext->dev, "Error writing Vbus GPIO CTLO: %d\n", ret); in cht_wc_extcon_set_5v_boost()
238 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL1, in cht_wc_extcon_set_otgmode()
241 dev_err(ext->dev, "Error updating CHGRCTRL1 reg: %d\n", ret); in cht_wc_extcon_set_otgmode()
243 if (ext->vbus_boost && ext->vbus_boost_enabled != enable) { in cht_wc_extcon_set_otgmode()
245 ret = regulator_enable(ext->vbus_boost); in cht_wc_extcon_set_otgmode()
247 ret = regulator_disable(ext->vbus_boost); in cht_wc_extcon_set_otgmode()
250 dev_err(ext->dev, "Error updating Vbus boost regulator: %d\n", ret); in cht_wc_extcon_set_otgmode()
252 ext->vbus_boost_enabled = enable; in cht_wc_extcon_set_otgmode()
262 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, in cht_wc_extcon_enable_charging()
265 dev_err(ext->dev, "Error updating CHGDISCTRL reg: %d\n", ret); in cht_wc_extcon_enable_charging()
272 extcon_set_state_sync(ext->edev, cable, state); in cht_wc_extcon_set_state()
274 extcon_set_state_sync(ext->edev, EXTCON_USB, state); in cht_wc_extcon_set_state()
282 bool ignore_get_charger_errors = ext->usb_host; in cht_wc_extcon_pwrsrc_event()
285 ext->usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; in cht_wc_extcon_pwrsrc_event()
287 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); in cht_wc_extcon_pwrsrc_event()
289 dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); in cht_wc_extcon_pwrsrc_event()
298 /* The 5v boost causes a false VBUS / SDP detect, skip */ in cht_wc_extcon_pwrsrc_event()
307 /* Route D+ and D- to PMIC for future charger detection */ in cht_wc_extcon_pwrsrc_event()
317 /* Route D+ and D- to SoC for the host or gadget controller */ in cht_wc_extcon_pwrsrc_event()
321 if (cable != ext->previous_cable) { in cht_wc_extcon_pwrsrc_event()
323 cht_wc_extcon_set_state(ext, ext->previous_cable, false); in cht_wc_extcon_pwrsrc_event()
324 ext->previous_cable = cable; in cht_wc_extcon_pwrsrc_event()
327 ext->usb_host = ((id == INTEL_USB_ID_GND) || (id == INTEL_USB_RID_A)); in cht_wc_extcon_pwrsrc_event()
328 extcon_set_state_sync(ext->edev, EXTCON_USB_HOST, ext->usb_host); in cht_wc_extcon_pwrsrc_event()
330 if (ext->usb_host) in cht_wc_extcon_pwrsrc_event()
337 /* Note: this is a no-op when ext->role_sw is NULL */ in cht_wc_extcon_pwrsrc_event()
338 ret = usb_role_switch_set_role(ext->role_sw, role); in cht_wc_extcon_pwrsrc_event()
340 dev_err(ext->dev, "Error setting USB-role: %d\n", ret); in cht_wc_extcon_pwrsrc_event()
342 if (ext->psy) in cht_wc_extcon_pwrsrc_event()
343 power_supply_changed(ext->psy); in cht_wc_extcon_pwrsrc_event()
351 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_IRQ, &irqs); in cht_wc_extcon_isr()
353 dev_err(ext->dev, "Error reading irqs: %d\n", ret); in cht_wc_extcon_isr()
359 ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ, irqs); in cht_wc_extcon_isr()
361 dev_err(ext->dev, "Error writing irqs: %d\n", ret); in cht_wc_extcon_isr()
373 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGDISCTRL, in cht_wc_extcon_sw_control()
376 dev_err(ext->dev, in cht_wc_extcon_sw_control()
382 ret = regmap_update_bits(ext->regmap, CHT_WC_CHGRCTRL0, mask, val); in cht_wc_extcon_sw_control()
384 dev_err(ext->dev, "Error setting sw control: %d\n", ret); in cht_wc_extcon_sw_control()
394 swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); in cht_wc_extcon_find_role_sw()
396 return -EPROBE_DEFER; in cht_wc_extcon_find_role_sw()
399 ext->role_sw = usb_role_switch_find_by_fwnode(fwnode); in cht_wc_extcon_find_role_sw()
402 return ext->role_sw ? 0 : -EPROBE_DEFER; in cht_wc_extcon_find_role_sw()
409 usb_role_switch_put(ext->role_sw); in cht_wc_extcon_put_role_sw()
412 /* Some boards require controlling the role-sw and Vbus based on the id-pin */
421 ret = devm_add_action_or_reset(ext->dev, cht_wc_extcon_put_role_sw, ext); in cht_wc_extcon_get_role_sw_and_regulator()
426 * On x86/ACPI platforms the regulator <-> consumer link is provided in cht_wc_extcon_get_role_sw_and_regulator()
432 ext->vbus_boost = devm_regulator_get_optional(ext->dev, "vbus"); in cht_wc_extcon_get_role_sw_and_regulator()
433 if (IS_ERR(ext->vbus_boost)) { in cht_wc_extcon_get_role_sw_and_regulator()
434 ret = PTR_ERR(ext->vbus_boost); in cht_wc_extcon_get_role_sw_and_regulator()
435 if (ret == -ENODEV) in cht_wc_extcon_get_role_sw_and_regulator()
436 ret = -EPROBE_DEFER; in cht_wc_extcon_get_role_sw_and_regulator()
438 return dev_err_probe(ext->dev, ret, "getting Vbus regulator"); in cht_wc_extcon_get_role_sw_and_regulator()
452 val->intval = ext->usb_type; in cht_wc_extcon_psy_get_prop()
455 val->intval = ext->usb_type ? 1 : 0; in cht_wc_extcon_psy_get_prop()
458 return -EINVAL; in cht_wc_extcon_psy_get_prop()
486 ext->psy = devm_power_supply_register(ext->dev, in cht_wc_extcon_register_psy()
489 return PTR_ERR_OR_ZERO(ext->psy); in cht_wc_extcon_register_psy()
494 struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); in cht_wc_extcon_probe()
504 ext = devm_kzalloc(&pdev->dev, sizeof(*ext), GFP_KERNEL); in cht_wc_extcon_probe()
506 return -ENOMEM; in cht_wc_extcon_probe()
508 ext->dev = &pdev->dev; in cht_wc_extcon_probe()
509 ext->regmap = pmic->regmap; in cht_wc_extcon_probe()
510 ext->previous_cable = EXTCON_NONE; in cht_wc_extcon_probe()
513 ext->edev = devm_extcon_dev_allocate(ext->dev, cht_wc_extcon_cables); in cht_wc_extcon_probe()
514 if (IS_ERR(ext->edev)) in cht_wc_extcon_probe()
515 return PTR_ERR(ext->edev); in cht_wc_extcon_probe()
517 switch (pmic->cht_wc_model) { in cht_wc_extcon_probe()
520 * When a host-cable is detected the BIOS enables an external 5v boost in cht_wc_extcon_probe()
525 * (and unless we drive the external-charger-disable pin high it in cht_wc_extcon_probe()
527 * 2) This gets seen by the pwrsrc block as a SDP USB Vbus supply in cht_wc_extcon_probe()
536 /* Do this first, as it may very well return -EPROBE_DEFER. */ in cht_wc_extcon_probe()
541 * The bq25890 used here relies on this driver's BC-1.2 charger in cht_wc_extcon_probe()
544 * models the detected charger (idem to how the Type-C TCPM code in cht_wc_extcon_probe()
569 ret = devm_extcon_dev_register(ext->dev, ext->edev); in cht_wc_extcon_probe()
571 dev_err(ext->dev, "Error registering extcon device: %d\n", ret); in cht_wc_extcon_probe()
575 ret = regmap_read(ext->regmap, CHT_WC_PWRSRC_STS, &pwrsrc_sts); in cht_wc_extcon_probe()
577 dev_err(ext->dev, "Error reading pwrsrc status: %d\n", ret); in cht_wc_extcon_probe()
582 * If no USB host or device connected, route D+ and D- to PMIC for in cht_wc_extcon_probe()
592 ret = devm_request_threaded_irq(ext->dev, irq, NULL, cht_wc_extcon_isr, in cht_wc_extcon_probe()
593 IRQF_ONESHOT, pdev->name, ext); in cht_wc_extcon_probe()
595 dev_err(ext->dev, "Error requesting interrupt: %d\n", ret); in cht_wc_extcon_probe()
600 ret = regmap_write(ext->regmap, CHT_WC_PWRSRC_IRQ_MASK, mask); in cht_wc_extcon_probe()
602 dev_err(ext->dev, "Error writing irq-mask: %d\n", ret); in cht_wc_extcon_probe()