Lines Matching +full:usb +full:- +full:sdp

1 // SPDX-License-Identifier: GPL-2.0-only
3 * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver
5 * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com>
19 #include <linux/extcon-provider.h>
22 #include <linux/usb/role.h>
26 #include <asm/intel-family.h>
53 /* BC USB status register */
137 ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val); in axp288_extcon_log_rsi()
139 dev_err(info->dev, "failed to read reset source indicator\n"); in axp288_extcon_log_rsi()
143 bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0); in axp288_extcon_log_rsi()
145 dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]); in axp288_extcon_log_rsi()
149 regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); in axp288_extcon_log_rsi()
153 * The below code to control the USB role-switch on devices with an AXP288
155 * to control the USB role-switch on such devices:
156 * 1) On many devices the USB role is controlled by AML code, but the AML code
165 /* Returns the id-pin value, note pulled low / false == host-mode */
170 if (info->id_extcon) in axp288_get_id_pin()
171 return extcon_get_state(info->id_extcon, EXTCON_USB_HOST) <= 0; in axp288_get_id_pin()
173 /* We cannot access the id-pin, see what mode the AML code has set */ in axp288_get_id_pin()
174 role = usb_role_switch_get_role(info->role_sw); in axp288_get_id_pin()
189 else if (info->vbus_attach) in axp288_usb_role_work()
194 ret = usb_role_switch_set_role(info->role_sw, role); in axp288_usb_role_work()
196 dev_err(info->dev, "failed to set role: %d\n", ret); in axp288_usb_role_work()
203 ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat); in axp288_get_vbus_attach()
205 dev_err(info->dev, "failed to read vbus status\n"); in axp288_get_vbus_attach()
216 unsigned int cable = info->previous_cable; in axp288_handle_chrg_det_event()
228 ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg); in axp288_handle_chrg_det_event()
232 dev_dbg(info->dev, "can't complete the charger detection\n"); in axp288_handle_chrg_det_event()
236 ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat); in axp288_handle_chrg_det_event()
244 dev_dbg(info->dev, "sdp cable is connected\n"); in axp288_handle_chrg_det_event()
248 dev_dbg(info->dev, "cdp cable is connected\n"); in axp288_handle_chrg_det_event()
252 dev_dbg(info->dev, "dcp cable is connected\n"); in axp288_handle_chrg_det_event()
256 dev_warn(info->dev, "unknown (reserved) bc detect result\n"); in axp288_handle_chrg_det_event()
263 extcon_set_state_sync(info->edev, info->previous_cable, false); in axp288_handle_chrg_det_event()
264 if (info->previous_cable == EXTCON_CHG_USB_SDP) in axp288_handle_chrg_det_event()
265 extcon_set_state_sync(info->edev, EXTCON_USB, false); in axp288_handle_chrg_det_event()
268 extcon_set_state_sync(info->edev, cable, vbus_attach); in axp288_handle_chrg_det_event()
270 extcon_set_state_sync(info->edev, EXTCON_USB, in axp288_handle_chrg_det_event()
273 info->previous_cable = cable; in axp288_handle_chrg_det_event()
276 if (info->role_sw && info->vbus_attach != vbus_attach) { in axp288_handle_chrg_det_event()
277 info->vbus_attach = vbus_attach; in axp288_handle_chrg_det_event()
279 queue_work(system_long_wq, &info->role_work); in axp288_handle_chrg_det_event()
288 dev_err(info->dev, "failed to detect BC Mod\n"); in axp288_handle_chrg_det_event()
300 queue_work(system_long_wq, &info->role_work); in axp288_extcon_id_evt()
312 dev_err(info->dev, "failed to handle the interrupt\n"); in axp288_extcon_isr()
325 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, in axp288_extcon_enable()
328 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, in axp288_extcon_enable()
340 cancel_work_sync(&info->role_work); in axp288_put_role_sw()
341 usb_role_switch_put(info->role_sw); in axp288_put_role_sw()
352 swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); in axp288_extcon_find_role_sw()
354 return -EPROBE_DEFER; in axp288_extcon_find_role_sw()
357 info->role_sw = usb_role_switch_find_by_fwnode(fwnode); in axp288_extcon_find_role_sw()
360 return info->role_sw ? 0 : -EPROBE_DEFER; in axp288_extcon_find_role_sw()
366 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp288_extcon_probe()
367 struct device *dev = &pdev->dev; in axp288_extcon_probe()
371 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in axp288_extcon_probe()
373 return -ENOMEM; in axp288_extcon_probe()
375 info->dev = &pdev->dev; in axp288_extcon_probe()
376 info->regmap = axp20x->regmap; in axp288_extcon_probe()
377 info->regmap_irqc = axp20x->regmap_irqc; in axp288_extcon_probe()
378 info->previous_cable = EXTCON_NONE; in axp288_extcon_probe()
379 INIT_WORK(&info->role_work, axp288_usb_role_work); in axp288_extcon_probe()
380 info->id_nb.notifier_call = axp288_extcon_id_evt; in axp288_extcon_probe()
388 if (info->role_sw) { in axp288_extcon_probe()
393 adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1); in axp288_extcon_probe()
395 info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev)); in axp288_extcon_probe()
397 if (IS_ERR(info->id_extcon)) in axp288_extcon_probe()
398 return PTR_ERR(info->id_extcon); in axp288_extcon_probe()
400 dev_info(dev, "controlling USB role\n"); in axp288_extcon_probe()
402 dev_info(dev, "controlling USB role based on Vbus presence\n"); in axp288_extcon_probe()
410 info->vbus_attach = axp288_get_vbus_attach(info); in axp288_extcon_probe()
417 info->edev = devm_extcon_dev_allocate(&pdev->dev, in axp288_extcon_probe()
419 if (IS_ERR(info->edev)) { in axp288_extcon_probe()
420 dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); in axp288_extcon_probe()
421 return PTR_ERR(info->edev); in axp288_extcon_probe()
425 ret = devm_extcon_dev_register(&pdev->dev, info->edev); in axp288_extcon_probe()
427 dev_err(&pdev->dev, "failed to register extcon device\n"); in axp288_extcon_probe()
436 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); in axp288_extcon_probe()
437 if (info->irq[i] < 0) { in axp288_extcon_probe()
438 dev_err(&pdev->dev, in axp288_extcon_probe()
440 ret = info->irq[i]; in axp288_extcon_probe()
444 ret = devm_request_threaded_irq(&pdev->dev, info->irq[i], in axp288_extcon_probe()
447 pdev->name, info); in axp288_extcon_probe()
449 dev_err(&pdev->dev, "failed to request interrupt=%d\n", in axp288_extcon_probe()
450 info->irq[i]); in axp288_extcon_probe()
455 if (info->id_extcon) { in axp288_extcon_probe()
456 ret = devm_extcon_register_notifier_all(dev, info->id_extcon, in axp288_extcon_probe()
457 &info->id_nb); in axp288_extcon_probe()
462 /* Make sure the role-sw is set correctly before doing BC detection */ in axp288_extcon_probe()
463 if (info->role_sw) { in axp288_extcon_probe()
464 queue_work(system_long_wq, &info->role_work); in axp288_extcon_probe()
465 flush_work(&info->role_work); in axp288_extcon_probe()
484 enable_irq_wake(info->irq[VBUS_RISING_IRQ]); in axp288_extcon_suspend()
494 * Wakeup when a charger is connected to do charger-type in axp288_extcon_resume()
499 disable_irq_wake(info->irq[VBUS_RISING_IRQ]); in axp288_extcon_resume()
525 MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");