From: Andy Shevchenko Date: Fri, 18 Jun 2021 12:55:16 +0000 (+0300) Subject: platform/x86: intel_cht_int33fe: Move to its own subfolder X-Git-Tag: microblaze-v5.15~133^2~6 X-Git-Url: http://git.monstr.eu/?a=commitdiff_plain;h=72fbcac2f40e690e1a5584358750e546a2678c2c;p=linux-2.6-microblaze.git platform/x86: intel_cht_int33fe: Move to its own subfolder Since we have started collecting Intel x86 specific drivers in their own folder, move intel_cht_int33fe to its own subfolder there. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20210618125516.53510-8-andriy.shevchenko@linux.intel.com Signed-off-by: Hans de Goede --- diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 79d095c0ab61..7d385c3b2239 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -687,30 +687,6 @@ config INTEL_ATOMISP2_PM To compile this driver as a module, choose M here: the module will be called intel_atomisp2_pm. -config INTEL_CHT_INT33FE - tristate "Intel Cherry Trail ACPI INT33FE Driver" - depends on X86 && ACPI && I2C && REGULATOR - depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) - depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) - depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) - help - This driver add support for the INT33FE ACPI device found on - some Intel Cherry Trail devices. - - There are two kinds of INT33FE ACPI device possible: for hardware - with USB Type-C and Micro-B connectors. This driver supports both. - - The INT33FE ACPI device has a CRS table with I2cSerialBusV2 - resources for Fuel Gauge Controller and (in the Type-C variant) - FUSB302 USB Type-C Controller and PI3USB30532 USB switch. - This driver instantiates i2c-clients for these, so that standard - i2c drivers for these chips can bind to the them. - - If you enable this driver it is advised to also select - CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B - device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m - for Type-C device. - config INTEL_HID_EVENT tristate "INTEL HID Event" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index e03b59ce3f9f..7ee369aab10d 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -70,10 +70,6 @@ obj-$(CONFIG_X86_PLATFORM_DRIVERS_INTEL) += intel/ obj-$(CONFIG_INTEL_ATOMISP2_LED) += intel_atomisp2_led.o obj-$(CONFIG_INTEL_ATOMISP2_PM) += intel_atomisp2_pm.o -obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o -intel_cht_int33fe-objs := intel_cht_int33fe_common.o \ - intel_cht_int33fe_typec.o \ - intel_cht_int33fe_microb.o obj-$(CONFIG_INTEL_HID_EVENT) += intel-hid.o obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig index 33f2dab03d3d..f2eef337eb98 100644 --- a/drivers/platform/x86/intel/Kconfig +++ b/drivers/platform/x86/intel/Kconfig @@ -16,6 +16,7 @@ menuconfig X86_PLATFORM_DRIVERS_INTEL if X86_PLATFORM_DRIVERS_INTEL +source "drivers/platform/x86/intel/int33fe/Kconfig" source "drivers/platform/x86/intel/int3472/Kconfig" endif # X86_PLATFORM_DRIVERS_INTEL diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile index 3ac795d810f1..0653055942d5 100644 --- a/drivers/platform/x86/intel/Makefile +++ b/drivers/platform/x86/intel/Makefile @@ -4,4 +4,5 @@ # Intel x86 Platform-Specific Drivers # +obj-$(CONFIG_INTEL_CHT_INT33FE) += int33fe/ obj-$(CONFIG_INTEL_SKL_INT3472) += int3472/ diff --git a/drivers/platform/x86/intel/int33fe/Kconfig b/drivers/platform/x86/intel/int33fe/Kconfig new file mode 100644 index 000000000000..2f7329a2e399 --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/Kconfig @@ -0,0 +1,24 @@ +# SPDX-License-Identifier: GPL-2.0-only +config INTEL_CHT_INT33FE + tristate "Intel Cherry Trail ACPI INT33FE Driver" + depends on X86 && ACPI && I2C && REGULATOR + depends on CHARGER_BQ24190=y || (CHARGER_BQ24190=m && m) + depends on USB_ROLES_INTEL_XHCI=y || (USB_ROLES_INTEL_XHCI=m && m) + depends on TYPEC_MUX_PI3USB30532=y || (TYPEC_MUX_PI3USB30532=m && m) + help + This driver add support for the INT33FE ACPI device found on + some Intel Cherry Trail devices. + + There are two kinds of INT33FE ACPI device possible: for hardware + with USB Type-C and Micro-B connectors. This driver supports both. + + The INT33FE ACPI device has a CRS table with I2cSerialBusV2 + resources for Fuel Gauge Controller and (in the Type-C variant) + FUSB302 USB Type-C Controller and PI3USB30532 USB switch. + This driver instantiates i2c-clients for these, so that standard + i2c drivers for these chips can bind to the them. + + If you enable this driver it is advised to also select + CONFIG_BATTERY_BQ27XXX=m or CONFIG_BATTERY_BQ27XXX_I2C=m for Micro-B + device and CONFIG_TYPEC_FUSB302=m and CONFIG_BATTERY_MAX17042=m + for Type-C device. diff --git a/drivers/platform/x86/intel/int33fe/Makefile b/drivers/platform/x86/intel/int33fe/Makefile new file mode 100644 index 000000000000..cc11183ce179 --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_INTEL_CHT_INT33FE) += intel_cht_int33fe.o +intel_cht_int33fe-objs := intel_cht_int33fe_common.o \ + intel_cht_int33fe_typec.o \ + intel_cht_int33fe_microb.o diff --git a/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c new file mode 100644 index 000000000000..251ed9bac789 --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.c @@ -0,0 +1,145 @@ +// 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 = ACPI_COMPANION(dev); + LIST_HEAD(resource_list); + int count = 0; + int ret; + + ret = acpi_dev_get_resources(adev, &resource_list, + cht_int33fe_i2c_res_filter, &count); + acpi_dev_free_resource_list(&resource_list); + if (ret < 0) + return ret; + + 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"); diff --git a/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h new file mode 100644 index 000000000000..03cd45f4e8cb --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_common.h @@ -0,0 +1,41 @@ +/* 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), header file + * + * Copyright (c) 2019 Yauhen Kharuzhy + */ + +#ifndef _INTEL_CHT_INT33FE_COMMON_H +#define _INTEL_CHT_INT33FE_COMMON_H + +#include +#include +#include + +enum int33fe_hw_type { + INT33FE_HW_MICROB, + INT33FE_HW_TYPEC, +}; + +struct cht_int33fe_data { + struct device *dev; + + int (*probe)(struct cht_int33fe_data *data); + int (*remove)(struct cht_int33fe_data *data); + + struct i2c_client *battery_fg; + + /* Type-C only */ + struct i2c_client *fusb302; + struct i2c_client *pi3usb30532; + + struct fwnode_handle *dp; +}; + +int cht_int33fe_microb_probe(struct cht_int33fe_data *data); +int cht_int33fe_microb_remove(struct cht_int33fe_data *data); +int cht_int33fe_typec_probe(struct cht_int33fe_data *data); +int cht_int33fe_typec_remove(struct cht_int33fe_data *data); + +#endif /* _INTEL_CHT_INT33FE_COMMON_H */ diff --git a/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c new file mode 100644 index 000000000000..673f41cd14b5 --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_microb.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Cherry Trail ACPI INT33FE pseudo device driver for devices with + * USB Micro-B connector (e.g. without of FUSB302 USB Type-C controller) + * + * Copyright (C) 2019 Yauhen Kharuzhy + * + * At least one Intel Cherry Trail based device which ship with Windows 10 + * (Lenovo YogaBook YB1-X91L/F tablet), have this weird INT33FE ACPI device + * with a CRS table with 2 I2cSerialBusV2 resources, for 2 different chips + * attached to various i2c busses: + * 1. The Whiskey Cove PMIC, which is also described by the INT34D3 ACPI device + * 2. TI BQ27542 Fuel Gauge Controller + * + * So this driver is a stub / pseudo driver whose only purpose is to + * instantiate i2c-client for battery fuel gauge, so that standard i2c driver + * for these chip can bind to the it. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intel_cht_int33fe_common.h" + +static const char * const bq27xxx_suppliers[] = { "bq25890-charger" }; + +static const struct property_entry bq27xxx_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27xxx_suppliers), + { } +}; + +static const struct software_node bq27xxx_node = { + .properties = bq27xxx_props, +}; + +int cht_int33fe_microb_probe(struct cht_int33fe_data *data) +{ + struct device *dev = data->dev; + struct i2c_board_info board_info; + + memset(&board_info, 0, sizeof(board_info)); + strscpy(board_info.type, "bq27542", ARRAY_SIZE(board_info.type)); + board_info.dev_name = "bq27542"; + board_info.swnode = &bq27xxx_node; + data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); + + return PTR_ERR_OR_ZERO(data->battery_fg); +} + +int cht_int33fe_microb_remove(struct cht_int33fe_data *data) +{ + i2c_unregister_device(data->battery_fg); + + return 0; +} diff --git a/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c new file mode 100644 index 000000000000..d59544167430 --- /dev/null +++ b/drivers/platform/x86/intel/int33fe/intel_cht_int33fe_typec.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Intel Cherry Trail ACPI INT33FE pseudo device driver + * + * Copyright (C) 2017 Hans de Goede + * + * Some Intel Cherry Trail based device which ship with Windows 10, have + * this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2 + * resources, for 4 different chips attached to various I²C buses: + * 1. The Whiskey Cove PMIC, which is also described by the INT34D3 ACPI device + * 2. Maxim MAX17047 Fuel Gauge Controller + * 3. FUSB302 USB Type-C Controller + * 4. PI3USB30532 USB switch + * + * So this driver is a stub / pseudo driver whose only purpose is to + * instantiate I²C clients for chips 2 - 4, so that standard I²C drivers + * for these chips can bind to the them. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intel_cht_int33fe_common.h" + +/* + * Grrr, I severely dislike buggy BIOS-es. At least one BIOS enumerates + * the max17047 both through the INT33FE ACPI device (it is right there + * in the resources table) as well as through a separate MAX17047 device. + * + * These helpers are used to work around this by checking if an I²C client + * for the max17047 has already been registered. + */ +static int cht_int33fe_check_for_max17047(struct device *dev, void *data) +{ + struct i2c_client **max17047 = data; + struct acpi_device *adev; + + adev = ACPI_COMPANION(dev); + if (!adev) + return 0; + + /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */ + if (!acpi_dev_hid_uid_match(adev, "MAX17047", NULL)) + return 0; + + *max17047 = to_i2c_client(dev); + return 1; +} + +static const char * const max17047_suppliers[] = { "bq24190-charger" }; + +static const struct property_entry max17047_properties[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers), + { } +}; + +static const struct software_node max17047_node = { + .name = "max17047", + .properties = max17047_properties, +}; + +/* + * We are not using inline property here because those are constant, + * and we need to adjust this one at runtime to point to real + * software node. + */ +static struct software_node_ref_args fusb302_mux_refs[] = { + { .node = NULL }, +}; + +static const struct property_entry fusb302_properties[] = { + PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"), + PROPERTY_ENTRY_REF_ARRAY("usb-role-switch", fusb302_mux_refs), + { } +}; + +static const struct software_node fusb302_node = { + .name = "fusb302", + .properties = fusb302_properties, +}; + +#define PDO_FIXED_FLAGS \ + (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM) + +static const u32 src_pdo[] = { + PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), +}; + +static const u32 snk_pdo[] = { + PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), + PDO_VAR(5000, 12000, 3000), +}; + +static const struct software_node pi3usb30532_node = { + .name = "pi3usb30532", +}; + +static const struct software_node displayport_node = { + .name = "displayport", +}; + +static const struct property_entry usb_connector_properties[] = { + PROPERTY_ENTRY_STRING("data-role", "dual"), + PROPERTY_ENTRY_STRING("power-role", "dual"), + PROPERTY_ENTRY_STRING("try-power-role", "sink"), + PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo), + PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo), + PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000), + PROPERTY_ENTRY_REF("orientation-switch", &pi3usb30532_node), + PROPERTY_ENTRY_REF("mode-switch", &pi3usb30532_node), + PROPERTY_ENTRY_REF("displayport", &displayport_node), + { } +}; + +static const struct software_node usb_connector_node = { + .name = "connector", + .parent = &fusb302_node, + .properties = usb_connector_properties, +}; + +static const struct software_node altmodes_node = { + .name = "altmodes", + .parent = &usb_connector_node, +}; + +static const struct property_entry dp_altmode_properties[] = { + PROPERTY_ENTRY_U32("svid", 0xff01), + PROPERTY_ENTRY_U32("vdo", 0x0c0086), + { } +}; + +static const struct software_node dp_altmode_node = { + .name = "displayport-altmode", + .parent = &altmodes_node, + .properties = dp_altmode_properties, +}; + +static const struct software_node *node_group[] = { + &fusb302_node, + &max17047_node, + &pi3usb30532_node, + &displayport_node, + &usb_connector_node, + &altmodes_node, + &dp_altmode_node, + NULL +}; + +static int cht_int33fe_setup_dp(struct cht_int33fe_data *data) +{ + struct fwnode_handle *fwnode; + struct pci_dev *pdev; + + fwnode = software_node_fwnode(&displayport_node); + if (!fwnode) + return -ENODEV; + + /* First let's find the GPU PCI device */ + pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); + if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) { + pci_dev_put(pdev); + return -ENODEV; + } + + /* Then the DP-2 child device node */ + data->dp = device_get_named_child_node(&pdev->dev, "DD04"); + pci_dev_put(pdev); + if (!data->dp) + return -ENODEV; + + fwnode->secondary = ERR_PTR(-ENODEV); + data->dp->secondary = fwnode; + + return 0; +} + +static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) +{ + software_node_unregister_node_group(node_group); + + if (fusb302_mux_refs[0].node) { + fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node)); + fusb302_mux_refs[0].node = NULL; + } + + if (data->dp) { + data->dp->secondary = NULL; + fwnode_handle_put(data->dp); + data->dp = NULL; + } +} + +static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) +{ + const struct software_node *mux_ref_node; + int ret; + + /* + * There is no ACPI device node for the USB role mux, so we need to wait + * until the mux driver has created software node for the mux device. + * It means we depend on the mux driver. This function will return + * -EPROBE_DEFER until the mux device is registered. + */ + mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); + if (!mux_ref_node) + return -EPROBE_DEFER; + + /* + * Update node used in "usb-role-switch" property. Note that we + * rely on software_node_register_nodes() to use the original + * instance of properties instead of copying them. + */ + fusb302_mux_refs[0].node = mux_ref_node; + + ret = software_node_register_node_group(node_group); + if (ret) + return ret; + + /* The devices that are not created in this driver need extra steps. */ + + /* + * The DP connector does have ACPI device node. In this case we can just + * find that ACPI node and assign our node as the secondary node to it. + */ + ret = cht_int33fe_setup_dp(data); + if (ret) + goto err_remove_nodes; + + return 0; + +err_remove_nodes: + cht_int33fe_remove_nodes(data); + + return ret; +} + +static int +cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data) +{ + struct i2c_client *max17047 = NULL; + struct i2c_board_info board_info; + struct fwnode_handle *fwnode; + int ret; + + fwnode = software_node_fwnode(&max17047_node); + if (!fwnode) + return -ENODEV; + + i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); + if (max17047) { + /* Pre-existing I²C client for the max17047, add device properties */ + set_secondary_fwnode(&max17047->dev, fwnode); + /* And re-probe to get the new device properties applied */ + ret = device_reprobe(&max17047->dev); + if (ret) + dev_warn(dev, "Reprobing max17047 error: %d\n", ret); + return 0; + } + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); + board_info.dev_name = "max17047"; + board_info.fwnode = fwnode; + data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); + + return PTR_ERR_OR_ZERO(data->battery_fg); +} + +int cht_int33fe_typec_probe(struct cht_int33fe_data *data) +{ + struct device *dev = data->dev; + struct i2c_board_info board_info; + struct fwnode_handle *fwnode; + struct regulator *regulator; + int fusb302_irq; + int ret; + + /* + * We expect the WC PMIC to be paired with a TI bq24292i charger-IC. + * We check for the bq24292i vbus regulator here, this has 2 purposes: + * 1) The bq24292i allows charging with up to 12V, setting the fusb302's + * max-snk voltage to 12V with another charger-IC is not good. + * 2) For the fusb302 driver to get the bq24292i vbus regulator, the + * regulator-map, which is part of the bq24292i regulator_init_data, + * must be registered before the fusb302 is instantiated, otherwise + * it will end up with a dummy-regulator. + * Note "cht_wc_usb_typec_vbus" comes from the regulator_init_data + * which is defined in i2c-cht-wc.c from where the bq24292i I²C client + * gets instantiated. We use regulator_get_optional here so that we + * don't end up getting a dummy-regulator ourselves. + */ + regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus"); + if (IS_ERR(regulator)) { + ret = PTR_ERR(regulator); + return (ret == -ENODEV) ? -EPROBE_DEFER : ret; + } + regulator_put(regulator); + + /* The FUSB302 uses the IRQ at index 1 and is the only IRQ user */ + fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1); + if (fusb302_irq < 0) { + if (fusb302_irq != -EPROBE_DEFER) + dev_err(dev, "Error getting FUSB302 irq\n"); + return fusb302_irq; + } + + ret = cht_int33fe_add_nodes(data); + if (ret) + return ret; + + /* Work around BIOS bug, see comment on cht_int33fe_check_for_max17047() */ + ret = cht_int33fe_register_max17047(dev, data); + if (ret) + goto out_remove_nodes; + + fwnode = software_node_fwnode(&fusb302_node); + if (!fwnode) { + ret = -ENODEV; + goto out_unregister_max17047; + } + + memset(&board_info, 0, sizeof(board_info)); + strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); + board_info.dev_name = "fusb302"; + board_info.fwnode = fwnode; + board_info.irq = fusb302_irq; + + data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); + if (IS_ERR(data->fusb302)) { + ret = PTR_ERR(data->fusb302); + goto out_unregister_max17047; + } + + fwnode = software_node_fwnode(&pi3usb30532_node); + if (!fwnode) { + ret = -ENODEV; + goto out_unregister_fusb302; + } + + memset(&board_info, 0, sizeof(board_info)); + board_info.dev_name = "pi3usb30532"; + board_info.fwnode = fwnode; + strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); + + data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); + if (IS_ERR(data->pi3usb30532)) { + ret = PTR_ERR(data->pi3usb30532); + goto out_unregister_fusb302; + } + + return 0; + +out_unregister_fusb302: + i2c_unregister_device(data->fusb302); + +out_unregister_max17047: + i2c_unregister_device(data->battery_fg); + +out_remove_nodes: + cht_int33fe_remove_nodes(data); + + return ret; +} + +int cht_int33fe_typec_remove(struct cht_int33fe_data *data) +{ + i2c_unregister_device(data->pi3usb30532); + i2c_unregister_device(data->fusb302); + i2c_unregister_device(data->battery_fg); + + cht_int33fe_remove_nodes(data); + + return 0; +} diff --git a/drivers/platform/x86/intel_cht_int33fe_common.c b/drivers/platform/x86/intel_cht_int33fe_common.c deleted file mode 100644 index 251ed9bac789..000000000000 --- a/drivers/platform/x86/intel_cht_int33fe_common.c +++ /dev/null @@ -1,145 +0,0 @@ -// 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 = ACPI_COMPANION(dev); - LIST_HEAD(resource_list); - int count = 0; - int ret; - - ret = acpi_dev_get_resources(adev, &resource_list, - cht_int33fe_i2c_res_filter, &count); - acpi_dev_free_resource_list(&resource_list); - if (ret < 0) - return ret; - - 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"); diff --git a/drivers/platform/x86/intel_cht_int33fe_common.h b/drivers/platform/x86/intel_cht_int33fe_common.h deleted file mode 100644 index 03cd45f4e8cb..000000000000 --- a/drivers/platform/x86/intel_cht_int33fe_common.h +++ /dev/null @@ -1,41 +0,0 @@ -/* 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), header file - * - * Copyright (c) 2019 Yauhen Kharuzhy - */ - -#ifndef _INTEL_CHT_INT33FE_COMMON_H -#define _INTEL_CHT_INT33FE_COMMON_H - -#include -#include -#include - -enum int33fe_hw_type { - INT33FE_HW_MICROB, - INT33FE_HW_TYPEC, -}; - -struct cht_int33fe_data { - struct device *dev; - - int (*probe)(struct cht_int33fe_data *data); - int (*remove)(struct cht_int33fe_data *data); - - struct i2c_client *battery_fg; - - /* Type-C only */ - struct i2c_client *fusb302; - struct i2c_client *pi3usb30532; - - struct fwnode_handle *dp; -}; - -int cht_int33fe_microb_probe(struct cht_int33fe_data *data); -int cht_int33fe_microb_remove(struct cht_int33fe_data *data); -int cht_int33fe_typec_probe(struct cht_int33fe_data *data); -int cht_int33fe_typec_remove(struct cht_int33fe_data *data); - -#endif /* _INTEL_CHT_INT33FE_COMMON_H */ diff --git a/drivers/platform/x86/intel_cht_int33fe_microb.c b/drivers/platform/x86/intel_cht_int33fe_microb.c deleted file mode 100644 index 673f41cd14b5..000000000000 --- a/drivers/platform/x86/intel_cht_int33fe_microb.c +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Cherry Trail ACPI INT33FE pseudo device driver for devices with - * USB Micro-B connector (e.g. without of FUSB302 USB Type-C controller) - * - * Copyright (C) 2019 Yauhen Kharuzhy - * - * At least one Intel Cherry Trail based device which ship with Windows 10 - * (Lenovo YogaBook YB1-X91L/F tablet), have this weird INT33FE ACPI device - * with a CRS table with 2 I2cSerialBusV2 resources, for 2 different chips - * attached to various i2c busses: - * 1. The Whiskey Cove PMIC, which is also described by the INT34D3 ACPI device - * 2. TI BQ27542 Fuel Gauge Controller - * - * So this driver is a stub / pseudo driver whose only purpose is to - * instantiate i2c-client for battery fuel gauge, so that standard i2c driver - * for these chip can bind to the it. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intel_cht_int33fe_common.h" - -static const char * const bq27xxx_suppliers[] = { "bq25890-charger" }; - -static const struct property_entry bq27xxx_props[] = { - PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq27xxx_suppliers), - { } -}; - -static const struct software_node bq27xxx_node = { - .properties = bq27xxx_props, -}; - -int cht_int33fe_microb_probe(struct cht_int33fe_data *data) -{ - struct device *dev = data->dev; - struct i2c_board_info board_info; - - memset(&board_info, 0, sizeof(board_info)); - strscpy(board_info.type, "bq27542", ARRAY_SIZE(board_info.type)); - board_info.dev_name = "bq27542"; - board_info.swnode = &bq27xxx_node; - data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); - - return PTR_ERR_OR_ZERO(data->battery_fg); -} - -int cht_int33fe_microb_remove(struct cht_int33fe_data *data) -{ - i2c_unregister_device(data->battery_fg); - - return 0; -} diff --git a/drivers/platform/x86/intel_cht_int33fe_typec.c b/drivers/platform/x86/intel_cht_int33fe_typec.c deleted file mode 100644 index d59544167430..000000000000 --- a/drivers/platform/x86/intel_cht_int33fe_typec.c +++ /dev/null @@ -1,380 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Intel Cherry Trail ACPI INT33FE pseudo device driver - * - * Copyright (C) 2017 Hans de Goede - * - * Some Intel Cherry Trail based device which ship with Windows 10, have - * this weird INT33FE ACPI device with a CRS table with 4 I2cSerialBusV2 - * resources, for 4 different chips attached to various I²C buses: - * 1. The Whiskey Cove PMIC, which is also described by the INT34D3 ACPI device - * 2. Maxim MAX17047 Fuel Gauge Controller - * 3. FUSB302 USB Type-C Controller - * 4. PI3USB30532 USB switch - * - * So this driver is a stub / pseudo driver whose only purpose is to - * instantiate I²C clients for chips 2 - 4, so that standard I²C drivers - * for these chips can bind to the them. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "intel_cht_int33fe_common.h" - -/* - * Grrr, I severely dislike buggy BIOS-es. At least one BIOS enumerates - * the max17047 both through the INT33FE ACPI device (it is right there - * in the resources table) as well as through a separate MAX17047 device. - * - * These helpers are used to work around this by checking if an I²C client - * for the max17047 has already been registered. - */ -static int cht_int33fe_check_for_max17047(struct device *dev, void *data) -{ - struct i2c_client **max17047 = data; - struct acpi_device *adev; - - adev = ACPI_COMPANION(dev); - if (!adev) - return 0; - - /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */ - if (!acpi_dev_hid_uid_match(adev, "MAX17047", NULL)) - return 0; - - *max17047 = to_i2c_client(dev); - return 1; -} - -static const char * const max17047_suppliers[] = { "bq24190-charger" }; - -static const struct property_entry max17047_properties[] = { - PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers), - { } -}; - -static const struct software_node max17047_node = { - .name = "max17047", - .properties = max17047_properties, -}; - -/* - * We are not using inline property here because those are constant, - * and we need to adjust this one at runtime to point to real - * software node. - */ -static struct software_node_ref_args fusb302_mux_refs[] = { - { .node = NULL }, -}; - -static const struct property_entry fusb302_properties[] = { - PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"), - PROPERTY_ENTRY_REF_ARRAY("usb-role-switch", fusb302_mux_refs), - { } -}; - -static const struct software_node fusb302_node = { - .name = "fusb302", - .properties = fusb302_properties, -}; - -#define PDO_FIXED_FLAGS \ - (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM) - -static const u32 src_pdo[] = { - PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS), -}; - -static const u32 snk_pdo[] = { - PDO_FIXED(5000, 400, PDO_FIXED_FLAGS), - PDO_VAR(5000, 12000, 3000), -}; - -static const struct software_node pi3usb30532_node = { - .name = "pi3usb30532", -}; - -static const struct software_node displayport_node = { - .name = "displayport", -}; - -static const struct property_entry usb_connector_properties[] = { - PROPERTY_ENTRY_STRING("data-role", "dual"), - PROPERTY_ENTRY_STRING("power-role", "dual"), - PROPERTY_ENTRY_STRING("try-power-role", "sink"), - PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo), - PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo), - PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000), - PROPERTY_ENTRY_REF("orientation-switch", &pi3usb30532_node), - PROPERTY_ENTRY_REF("mode-switch", &pi3usb30532_node), - PROPERTY_ENTRY_REF("displayport", &displayport_node), - { } -}; - -static const struct software_node usb_connector_node = { - .name = "connector", - .parent = &fusb302_node, - .properties = usb_connector_properties, -}; - -static const struct software_node altmodes_node = { - .name = "altmodes", - .parent = &usb_connector_node, -}; - -static const struct property_entry dp_altmode_properties[] = { - PROPERTY_ENTRY_U32("svid", 0xff01), - PROPERTY_ENTRY_U32("vdo", 0x0c0086), - { } -}; - -static const struct software_node dp_altmode_node = { - .name = "displayport-altmode", - .parent = &altmodes_node, - .properties = dp_altmode_properties, -}; - -static const struct software_node *node_group[] = { - &fusb302_node, - &max17047_node, - &pi3usb30532_node, - &displayport_node, - &usb_connector_node, - &altmodes_node, - &dp_altmode_node, - NULL -}; - -static int cht_int33fe_setup_dp(struct cht_int33fe_data *data) -{ - struct fwnode_handle *fwnode; - struct pci_dev *pdev; - - fwnode = software_node_fwnode(&displayport_node); - if (!fwnode) - return -ENODEV; - - /* First let's find the GPU PCI device */ - pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL); - if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) { - pci_dev_put(pdev); - return -ENODEV; - } - - /* Then the DP-2 child device node */ - data->dp = device_get_named_child_node(&pdev->dev, "DD04"); - pci_dev_put(pdev); - if (!data->dp) - return -ENODEV; - - fwnode->secondary = ERR_PTR(-ENODEV); - data->dp->secondary = fwnode; - - return 0; -} - -static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data) -{ - software_node_unregister_node_group(node_group); - - if (fusb302_mux_refs[0].node) { - fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node)); - fusb302_mux_refs[0].node = NULL; - } - - if (data->dp) { - data->dp->secondary = NULL; - fwnode_handle_put(data->dp); - data->dp = NULL; - } -} - -static int cht_int33fe_add_nodes(struct cht_int33fe_data *data) -{ - const struct software_node *mux_ref_node; - int ret; - - /* - * There is no ACPI device node for the USB role mux, so we need to wait - * until the mux driver has created software node for the mux device. - * It means we depend on the mux driver. This function will return - * -EPROBE_DEFER until the mux device is registered. - */ - mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw"); - if (!mux_ref_node) - return -EPROBE_DEFER; - - /* - * Update node used in "usb-role-switch" property. Note that we - * rely on software_node_register_nodes() to use the original - * instance of properties instead of copying them. - */ - fusb302_mux_refs[0].node = mux_ref_node; - - ret = software_node_register_node_group(node_group); - if (ret) - return ret; - - /* The devices that are not created in this driver need extra steps. */ - - /* - * The DP connector does have ACPI device node. In this case we can just - * find that ACPI node and assign our node as the secondary node to it. - */ - ret = cht_int33fe_setup_dp(data); - if (ret) - goto err_remove_nodes; - - return 0; - -err_remove_nodes: - cht_int33fe_remove_nodes(data); - - return ret; -} - -static int -cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data) -{ - struct i2c_client *max17047 = NULL; - struct i2c_board_info board_info; - struct fwnode_handle *fwnode; - int ret; - - fwnode = software_node_fwnode(&max17047_node); - if (!fwnode) - return -ENODEV; - - i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047); - if (max17047) { - /* Pre-existing I²C client for the max17047, add device properties */ - set_secondary_fwnode(&max17047->dev, fwnode); - /* And re-probe to get the new device properties applied */ - ret = device_reprobe(&max17047->dev); - if (ret) - dev_warn(dev, "Reprobing max17047 error: %d\n", ret); - return 0; - } - - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "max17047", I2C_NAME_SIZE); - board_info.dev_name = "max17047"; - board_info.fwnode = fwnode; - data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info); - - return PTR_ERR_OR_ZERO(data->battery_fg); -} - -int cht_int33fe_typec_probe(struct cht_int33fe_data *data) -{ - struct device *dev = data->dev; - struct i2c_board_info board_info; - struct fwnode_handle *fwnode; - struct regulator *regulator; - int fusb302_irq; - int ret; - - /* - * We expect the WC PMIC to be paired with a TI bq24292i charger-IC. - * We check for the bq24292i vbus regulator here, this has 2 purposes: - * 1) The bq24292i allows charging with up to 12V, setting the fusb302's - * max-snk voltage to 12V with another charger-IC is not good. - * 2) For the fusb302 driver to get the bq24292i vbus regulator, the - * regulator-map, which is part of the bq24292i regulator_init_data, - * must be registered before the fusb302 is instantiated, otherwise - * it will end up with a dummy-regulator. - * Note "cht_wc_usb_typec_vbus" comes from the regulator_init_data - * which is defined in i2c-cht-wc.c from where the bq24292i I²C client - * gets instantiated. We use regulator_get_optional here so that we - * don't end up getting a dummy-regulator ourselves. - */ - regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus"); - if (IS_ERR(regulator)) { - ret = PTR_ERR(regulator); - return (ret == -ENODEV) ? -EPROBE_DEFER : ret; - } - regulator_put(regulator); - - /* The FUSB302 uses the IRQ at index 1 and is the only IRQ user */ - fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1); - if (fusb302_irq < 0) { - if (fusb302_irq != -EPROBE_DEFER) - dev_err(dev, "Error getting FUSB302 irq\n"); - return fusb302_irq; - } - - ret = cht_int33fe_add_nodes(data); - if (ret) - return ret; - - /* Work around BIOS bug, see comment on cht_int33fe_check_for_max17047() */ - ret = cht_int33fe_register_max17047(dev, data); - if (ret) - goto out_remove_nodes; - - fwnode = software_node_fwnode(&fusb302_node); - if (!fwnode) { - ret = -ENODEV; - goto out_unregister_max17047; - } - - memset(&board_info, 0, sizeof(board_info)); - strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE); - board_info.dev_name = "fusb302"; - board_info.fwnode = fwnode; - board_info.irq = fusb302_irq; - - data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info); - if (IS_ERR(data->fusb302)) { - ret = PTR_ERR(data->fusb302); - goto out_unregister_max17047; - } - - fwnode = software_node_fwnode(&pi3usb30532_node); - if (!fwnode) { - ret = -ENODEV; - goto out_unregister_fusb302; - } - - memset(&board_info, 0, sizeof(board_info)); - board_info.dev_name = "pi3usb30532"; - board_info.fwnode = fwnode; - strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE); - - data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info); - if (IS_ERR(data->pi3usb30532)) { - ret = PTR_ERR(data->pi3usb30532); - goto out_unregister_fusb302; - } - - return 0; - -out_unregister_fusb302: - i2c_unregister_device(data->fusb302); - -out_unregister_max17047: - i2c_unregister_device(data->battery_fg); - -out_remove_nodes: - cht_int33fe_remove_nodes(data); - - return ret; -} - -int cht_int33fe_typec_remove(struct cht_int33fe_data *data) -{ - i2c_unregister_device(data->pi3usb30532); - i2c_unregister_device(data->fusb302); - i2c_unregister_device(data->battery_fg); - - cht_int33fe_remove_nodes(data); - - return 0; -}