| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * extcon-axp288.c - X-Power AXP288 PMIC extcon cable detection driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2017-2018 Hans de Goede <hdegoede@redhat.com> |
|---|
| 5 | 6 | * Copyright (C) 2015 Intel Corporation |
|---|
| 6 | 7 | * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 10 | | - * published by the Free Software Foundation. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | 8 | */ |
|---|
| 17 | 9 | |
|---|
| 18 | 10 | #include <linux/acpi.h> |
|---|
| .. | .. |
|---|
| 115 | 107 | }; |
|---|
| 116 | 108 | |
|---|
| 117 | 109 | static const struct x86_cpu_id cherry_trail_cpu_ids[] = { |
|---|
| 118 | | - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT, X86_FEATURE_ANY }, |
|---|
| 110 | + X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, NULL), |
|---|
| 119 | 111 | {} |
|---|
| 120 | 112 | }; |
|---|
| 121 | 113 | |
|---|
| .. | .. |
|---|
| 129 | 121 | "Last shutdown caused by PMIC UVLO threshold", |
|---|
| 130 | 122 | "Last shutdown caused by SOC initiated cold off", |
|---|
| 131 | 123 | "Last shutdown caused by user pressing the power button", |
|---|
| 132 | | - NULL, |
|---|
| 133 | 124 | }; |
|---|
| 134 | 125 | |
|---|
| 135 | 126 | /* |
|---|
| .. | .. |
|---|
| 138 | 129 | */ |
|---|
| 139 | 130 | static void axp288_extcon_log_rsi(struct axp288_extcon_info *info) |
|---|
| 140 | 131 | { |
|---|
| 141 | | - const char * const *rsi; |
|---|
| 142 | 132 | unsigned int val, i, clear_mask = 0; |
|---|
| 133 | + unsigned long bits; |
|---|
| 143 | 134 | int ret; |
|---|
| 144 | 135 | |
|---|
| 145 | 136 | ret = regmap_read(info->regmap, AXP288_PS_BOOT_REASON_REG, &val); |
|---|
| 146 | | - for (i = 0, rsi = axp288_pwr_up_down_info; *rsi; rsi++, i++) { |
|---|
| 147 | | - if (val & BIT(i)) { |
|---|
| 148 | | - dev_dbg(info->dev, "%s\n", *rsi); |
|---|
| 149 | | - clear_mask |= BIT(i); |
|---|
| 150 | | - } |
|---|
| 137 | + if (ret < 0) { |
|---|
| 138 | + dev_err(info->dev, "failed to read reset source indicator\n"); |
|---|
| 139 | + return; |
|---|
| 151 | 140 | } |
|---|
| 141 | + |
|---|
| 142 | + bits = val & GENMASK(ARRAY_SIZE(axp288_pwr_up_down_info) - 1, 0); |
|---|
| 143 | + for_each_set_bit(i, &bits, ARRAY_SIZE(axp288_pwr_up_down_info)) |
|---|
| 144 | + dev_dbg(info->dev, "%s\n", axp288_pwr_up_down_info[i]); |
|---|
| 145 | + clear_mask = bits; |
|---|
| 152 | 146 | |
|---|
| 153 | 147 | /* Clear the register value for next reboot (write 1 to clear bit) */ |
|---|
| 154 | 148 | regmap_write(info->regmap, AXP288_PS_BOOT_REASON_REG, clear_mask); |
|---|
| .. | .. |
|---|
| 328 | 322 | usb_role_switch_put(info->role_sw); |
|---|
| 329 | 323 | } |
|---|
| 330 | 324 | |
|---|
| 325 | +static int axp288_extcon_find_role_sw(struct axp288_extcon_info *info) |
|---|
| 326 | +{ |
|---|
| 327 | + const struct software_node *swnode; |
|---|
| 328 | + struct fwnode_handle *fwnode; |
|---|
| 329 | + |
|---|
| 330 | + if (!x86_match_cpu(cherry_trail_cpu_ids)) |
|---|
| 331 | + return 0; |
|---|
| 332 | + |
|---|
| 333 | + swnode = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); |
|---|
| 334 | + if (!swnode) |
|---|
| 335 | + return -EPROBE_DEFER; |
|---|
| 336 | + |
|---|
| 337 | + fwnode = software_node_fwnode(swnode); |
|---|
| 338 | + info->role_sw = usb_role_switch_find_by_fwnode(fwnode); |
|---|
| 339 | + fwnode_handle_put(fwnode); |
|---|
| 340 | + |
|---|
| 341 | + return info->role_sw ? 0 : -EPROBE_DEFER; |
|---|
| 342 | +} |
|---|
| 343 | + |
|---|
| 331 | 344 | static int axp288_extcon_probe(struct platform_device *pdev) |
|---|
| 332 | 345 | { |
|---|
| 333 | 346 | struct axp288_extcon_info *info; |
|---|
| 334 | 347 | struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); |
|---|
| 335 | 348 | struct device *dev = &pdev->dev; |
|---|
| 336 | | - const char *name; |
|---|
| 349 | + struct acpi_device *adev; |
|---|
| 337 | 350 | int ret, i, pirq; |
|---|
| 338 | 351 | |
|---|
| 339 | 352 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 349 | 362 | |
|---|
| 350 | 363 | platform_set_drvdata(pdev, info); |
|---|
| 351 | 364 | |
|---|
| 352 | | - info->role_sw = usb_role_switch_get(dev); |
|---|
| 353 | | - if (IS_ERR(info->role_sw)) |
|---|
| 354 | | - return PTR_ERR(info->role_sw); |
|---|
| 365 | + ret = axp288_extcon_find_role_sw(info); |
|---|
| 366 | + if (ret) |
|---|
| 367 | + return ret; |
|---|
| 368 | + |
|---|
| 355 | 369 | if (info->role_sw) { |
|---|
| 356 | 370 | ret = devm_add_action_or_reset(dev, axp288_put_role_sw, info); |
|---|
| 357 | 371 | if (ret) |
|---|
| 358 | 372 | return ret; |
|---|
| 359 | 373 | |
|---|
| 360 | | - name = acpi_dev_get_first_match_name("INT3496", NULL, -1); |
|---|
| 361 | | - if (name) { |
|---|
| 362 | | - info->id_extcon = extcon_get_extcon_dev(name); |
|---|
| 374 | + adev = acpi_dev_get_first_match_dev("INT3496", NULL, -1); |
|---|
| 375 | + if (adev) { |
|---|
| 376 | + info->id_extcon = extcon_get_extcon_dev(acpi_dev_name(adev)); |
|---|
| 377 | + put_device(&adev->dev); |
|---|
| 363 | 378 | if (!info->id_extcon) |
|---|
| 364 | 379 | return -EPROBE_DEFER; |
|---|
| 365 | 380 | |
|---|
| .. | .. |
|---|
| 476 | 491 | .pm = &axp288_extcon_pm_ops, |
|---|
| 477 | 492 | }, |
|---|
| 478 | 493 | }; |
|---|
| 479 | | - |
|---|
| 480 | | -static struct device_connection axp288_extcon_role_sw_conn = { |
|---|
| 481 | | - .endpoint[0] = "axp288_extcon", |
|---|
| 482 | | - .endpoint[1] = "intel_xhci_usb_sw-role-switch", |
|---|
| 483 | | - .id = "usb-role-switch", |
|---|
| 484 | | -}; |
|---|
| 485 | | - |
|---|
| 486 | | -static int __init axp288_extcon_init(void) |
|---|
| 487 | | -{ |
|---|
| 488 | | - if (x86_match_cpu(cherry_trail_cpu_ids)) |
|---|
| 489 | | - device_connection_add(&axp288_extcon_role_sw_conn); |
|---|
| 490 | | - |
|---|
| 491 | | - return platform_driver_register(&axp288_extcon_driver); |
|---|
| 492 | | -} |
|---|
| 493 | | -module_init(axp288_extcon_init); |
|---|
| 494 | | - |
|---|
| 495 | | -static void __exit axp288_extcon_exit(void) |
|---|
| 496 | | -{ |
|---|
| 497 | | - if (x86_match_cpu(cherry_trail_cpu_ids)) |
|---|
| 498 | | - device_connection_remove(&axp288_extcon_role_sw_conn); |
|---|
| 499 | | - |
|---|
| 500 | | - platform_driver_unregister(&axp288_extcon_driver); |
|---|
| 501 | | -} |
|---|
| 502 | | -module_exit(axp288_extcon_exit); |
|---|
| 494 | +module_platform_driver(axp288_extcon_driver); |
|---|
| 503 | 495 | |
|---|
| 504 | 496 | MODULE_AUTHOR("Ramakrishna Pallala <ramakrishna.pallala@intel.com>"); |
|---|
| 505 | 497 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); |
|---|