// SPDX-License-Identifier: GPL-2.0 /* * Common code for Intel Cherry Trail ACPI INT33FE pseudo device drivers * (USB Micro-B and Type-C connector variants). * * Copyright (c) 2019 Yauhen Kharuzhy */ #include #include #include #include #include #include "intel_cht_int33fe_common.h" #define EXPECTED_PTYPE 4 static int cht_int33fe_i2c_res_filter(struct acpi_resource *ares, void *data) { struct acpi_resource_i2c_serialbus *sb; int *count = data; if (i2c_acpi_get_i2c_resource(ares, &sb)) (*count)++; return 1; } static int cht_int33fe_count_i2c_clients(struct device *dev) { struct acpi_device *adev; LIST_HEAD(resource_list); int count = 0; adev = ACPI_COMPANION(dev); if (!adev) return -EINVAL; acpi_dev_get_resources(adev, &resource_list, cht_int33fe_i2c_res_filter, &count); acpi_dev_free_resource_list(&resource_list); return count; } static int cht_int33fe_check_hw_type(struct device *dev) { unsigned long long ptyp; acpi_status status; int ret; status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp); if (ACPI_FAILURE(status)) { dev_err(dev, "Error getting PTYPE\n"); return -ENODEV; } /* * The same ACPI HID is used for different configurations check PTYP * to ensure that we are dealing with the expected config. */ if (ptyp != EXPECTED_PTYPE) return -ENODEV; /* Check presence of INT34D3 (hardware-rev 3) expected for ptype == 4 */ if (!acpi_dev_present("INT34D3", "1", 3)) { dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n", EXPECTED_PTYPE); return -ENODEV; } ret = cht_int33fe_count_i2c_clients(dev); if (ret < 0) return ret; switch (ret) { case 2: return INT33FE_HW_MICROB; case 4: return INT33FE_HW_TYPEC; default: return -ENODEV; } } static int cht_int33fe_probe(struct platform_device *pdev) { struct cht_int33fe_data *data; struct device *dev = &pdev->dev; int ret; ret = cht_int33fe_check_hw_type(dev); if (ret < 0) return ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; data->dev = dev; switch (ret) { case INT33FE_HW_MICROB: data->probe = cht_int33fe_microb_probe; data->remove = cht_int33fe_microb_remove; break; case INT33FE_HW_TYPEC: data->probe = cht_int33fe_typec_probe; data->remove = cht_int33fe_typec_remove; break; } platform_set_drvdata(pdev, data); return data->probe(data); } static int cht_int33fe_remove(struct platform_device *pdev) { struct cht_int33fe_data *data = platform_get_drvdata(pdev); return data->remove(data); } static const struct acpi_device_id cht_int33fe_acpi_ids[] = { { "INT33FE", }, { } }; MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids); static struct platform_driver cht_int33fe_driver = { .driver = { .name = "Intel Cherry Trail ACPI INT33FE driver", .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids), }, .probe = cht_int33fe_probe, .remove = cht_int33fe_remove, }; module_platform_driver(cht_int33fe_driver); MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver"); MODULE_AUTHOR("Yauhen Kharuzhy "); MODULE_LICENSE("GPL v2");