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>
52 /* BC USB status register */
136 ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val); in axp288_extcon_log_rsi()
138 dev_err(info->dev, "failed to read reset source indicator\n"); in axp288_extcon_log_rsi()
142 bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0); in axp288_extcon_log_rsi()
144 dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]); in axp288_extcon_log_rsi()
148 regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); in axp288_extcon_log_rsi()
152 * The below code to control the USB role-switch on devices with an AXP288
154 * to control the USB role-switch on such devices:
155 * 1) On many devices the USB role is controlled by AML code, but the AML code
164 /* Returns the id-pin value, note pulled low / false == host-mode */
169 if (info->id_extcon) in axp288_get_id_pin()
170 return extcon_get_state(info->id_extcon, EXTCON_USB_HOST) <= 0; in axp288_get_id_pin()
172 /* We cannot access the id-pin, see what mode the AML code has set */ in axp288_get_id_pin()
173 role = usb_role_switch_get_role(info->role_sw); in axp288_get_id_pin()
188 else if (info->vbus_attach) in axp288_usb_role_work()
193 ret = usb_role_switch_set_role(info->role_sw, role); in axp288_usb_role_work()
195 dev_err(info->dev, "failed to set role: %d\n", ret); in axp288_usb_role_work()
202 ret = regmap_read(info->regmap, AXP288_PS_STAT_REG, &pwr_stat); in axp288_get_vbus_attach()
204 dev_err(info->dev, "failed to read vbus status\n"); in axp288_get_vbus_attach()
215 unsigned int cable = info->previous_cable; in axp288_handle_chrg_det_event()
223 ret = regmap_read(info->regmap, AXP288_BC_GLOBAL_REG, &cfg); in axp288_handle_chrg_det_event()
227 dev_dbg(info->dev, "can't complete the charger detection\n"); in axp288_handle_chrg_det_event()
231 ret = regmap_read(info->regmap, AXP288_BC_DET_STAT_REG, &stat); in axp288_handle_chrg_det_event()
239 dev_dbg(info->dev, "sdp cable is connected\n"); in axp288_handle_chrg_det_event()
243 dev_dbg(info->dev, "cdp cable is connected\n"); in axp288_handle_chrg_det_event()
247 dev_dbg(info->dev, "dcp cable is connected\n"); in axp288_handle_chrg_det_event()
251 dev_warn(info->dev, "unknown (reserved) bc detect result\n"); in axp288_handle_chrg_det_event()
256 extcon_set_state_sync(info->edev, info->previous_cable, false); in axp288_handle_chrg_det_event()
257 if (info->previous_cable == EXTCON_CHG_USB_SDP) in axp288_handle_chrg_det_event()
258 extcon_set_state_sync(info->edev, EXTCON_USB, false); in axp288_handle_chrg_det_event()
261 extcon_set_state_sync(info->edev, cable, vbus_attach); in axp288_handle_chrg_det_event()
263 extcon_set_state_sync(info->edev, EXTCON_USB, in axp288_handle_chrg_det_event()
266 info->previous_cable = cable; in axp288_handle_chrg_det_event()
269 if (info->role_sw && info->vbus_attach != vbus_attach) { in axp288_handle_chrg_det_event()
270 info->vbus_attach = vbus_attach; in axp288_handle_chrg_det_event()
272 queue_work(system_long_wq, &info->role_work); in axp288_handle_chrg_det_event()
279 dev_err(info->dev, "failed to detect BC Mod\n"); in axp288_handle_chrg_det_event()
291 queue_work(system_long_wq, &info->role_work); in axp288_extcon_id_evt()
303 dev_err(info->dev, "failed to handle the interrupt\n"); in axp288_extcon_isr()
310 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, in axp288_extcon_enable()
313 regmap_update_bits(info->regmap, AXP288_BC_GLOBAL_REG, in axp288_extcon_enable()
321 cancel_work_sync(&info->role_work); in axp288_put_role_sw()
322 usb_role_switch_put(info->role_sw); in axp288_put_role_sw()
333 swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); in axp288_extcon_find_role_sw()
335 return -EPROBE_DEFER; in axp288_extcon_find_role_sw()
338 info->role_sw = usb_role_switch_find_by_fwnode(fwnode); in axp288_extcon_find_role_sw()
341 return info->role_sw ? 0 : -EPROBE_DEFER; in axp288_extcon_find_role_sw()
347 struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); in axp288_extcon_probe()
348 struct device *dev = &pdev->dev; in axp288_extcon_probe()
352 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); in axp288_extcon_probe()
354 return -ENOMEM; in axp288_extcon_probe()
356 info->dev = &pdev->dev; in axp288_extcon_probe()
357 info->regmap = axp20x->regmap; in axp288_extcon_probe()
358 info->regmap_irqc = axp20x->regmap_irqc; in axp288_extcon_probe()
359 info->previous_cable = EXTCON_NONE; in axp288_extcon_probe()
360 INIT_WORK(&info->role_work, axp288_usb_role_work); in axp288_extcon_probe()
361 info->id_nb.notifier_call = axp288_extcon_id_evt; in axp288_extcon_probe()
369 if (info->role_sw) { in axp288_extcon_probe()
374 adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1); in axp288_extcon_probe()
376 info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev)); in axp288_extcon_probe()
377 put_device(&adev->dev); in axp288_extcon_probe()
378 if (!info->id_extcon) in axp288_extcon_probe()
379 return -EPROBE_DEFER; in axp288_extcon_probe()
381 dev_info(dev, "controlling USB role\n"); in axp288_extcon_probe()
383 dev_info(dev, "controlling USB role based on Vbus presence\n"); in axp288_extcon_probe()
387 info->vbus_attach = axp288_get_vbus_attach(info); in axp288_extcon_probe()
392 info->edev = devm_extcon_dev_allocate(&pdev->dev, in axp288_extcon_probe()
394 if (IS_ERR(info->edev)) { in axp288_extcon_probe()
395 dev_err(&pdev->dev, "failed to allocate memory for extcon\n"); in axp288_extcon_probe()
396 return PTR_ERR(info->edev); in axp288_extcon_probe()
400 ret = devm_extcon_dev_register(&pdev->dev, info->edev); in axp288_extcon_probe()
402 dev_err(&pdev->dev, "failed to register extcon device\n"); in axp288_extcon_probe()
411 info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); in axp288_extcon_probe()
412 if (info->irq[i] < 0) { in axp288_extcon_probe()
413 dev_err(&pdev->dev, in axp288_extcon_probe()
415 ret = info->irq[i]; in axp288_extcon_probe()
419 ret = devm_request_threaded_irq(&pdev->dev, info->irq[i], in axp288_extcon_probe()
422 pdev->name, info); in axp288_extcon_probe()
424 dev_err(&pdev->dev, "failed to request interrupt=%d\n", in axp288_extcon_probe()
425 info->irq[i]); in axp288_extcon_probe()
430 if (info->id_extcon) { in axp288_extcon_probe()
431 ret = devm_extcon_register_notifier_all(dev, info->id_extcon, in axp288_extcon_probe()
432 &info->id_nb); in axp288_extcon_probe()
437 /* Make sure the role-sw is set correctly before doing BC detection */ in axp288_extcon_probe()
438 if (info->role_sw) { in axp288_extcon_probe()
439 queue_work(system_long_wq, &info->role_work); in axp288_extcon_probe()
440 flush_work(&info->role_work); in axp288_extcon_probe()
457 enable_irq_wake(info->irq[VBUS_RISING_IRQ]); in axp288_extcon_suspend()
467 * Wakeup when a charger is connected to do charger-type in axp288_extcon_resume()
472 disable_irq_wake(info->irq[VBUS_RISING_IRQ]); in axp288_extcon_resume()
498 MODULE_DESCRIPTION("X-Powers AXP288 extcon driver");