aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/intel_cht_int33fe.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-18 10:26:57 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-18 10:26:57 -0800
commit07c455ee222f3ad219c2835d05a175a326a138fb (patch)
treec3fdcd89a4fe87877963162de8bc428bb265bb8e /drivers/platform/x86/intel_cht_int33fe.c
parentMerge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc (diff)
parentplatform/x86: silead_dmi: Add silead, home-button property to some tablets (diff)
downloadlinux-dev-07c455ee222f3ad219c2835d05a175a326a138fb.tar.xz
linux-dev-07c455ee222f3ad219c2835d05a175a326a138fb.zip
Merge tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Andy Shevchenko: "Here is the collected material against Platform Drivers x86 subsystem. It's rather bit busy cycle for PDx86, mostly due to Dell SMBIOS driver activity For this cycle we have quite an update for the Dell SMBIOS driver including WMI work to provide an interface for SMBIOS tokens via sysfs and WMI support for 2017+ Dell laptop models. SMM dispatcher code is split into a separate driver followed by a new WMI dispatcher. The latter provides a character device interface to user space. The git history also contains a merge of immutable branch from Wolfram Sang in order to apply a dependent fix to the Intel CherryTrail Battery Management driver. Other Intel drivers got a lot of cleanups. The Turbo Boost Max 3.0 support is added for Intel Skylake. Peaq WMI hotkeys driver gets its own maintainer and white list of supported models. Silead DMI is expanded to support few additional platforms. Tablet mode via GMMS ACPI method is added to support some ThinkPad tablets. new driver: - Add driver to force WMI Thunderbolt controller power status asus-wmi: - Add lightbar led support dell-laptop: - Allocate buffer before rfkill use dell-smbios: - fix string overflow - Add filtering support - Introduce dispatcher for SMM calls - Add a sysfs interface for SMBIOS tokens - only run if proper oem string is detected - Prefix class/select with cmd_ - Add pr_fmt definition to driver dell-smbios-smm: - test for WSMT dell-smbios-wmi: - release mutex lock on WMI call failure - introduce userspace interface - Add new WMI dispatcher driver dell-smo8800: - remove redundant assignments to byte_data dell-wmi: - don't check length returned - clean up wmi descriptor check - increase severity of some failures - Do not match on descriptor GUID modalias - Label driver as handling notifications dell-*wmi*: - Relay failed initial probe to dependent drivers dell-wmi-descriptor: - check if memory was allocated - split WMI descriptor into it's own driver fujitsu-laptop: - Fix radio LED detection - Don't oops when FUJ02E3 is not presnt hp_accel: - Add quirk for HP ProBook 440 G4 hp-wmi: - Fix tablet mode detection for convertibles ideapad-laptop: - Add Lenovo Yoga 920-13IKB to no_hw_rfkill dmi list intel_cht_int33fe: - Update fusb302 type string, add properties - make a couple of local functions static - Work around BIOS bug on some devices intel-hid: - Power button suspend on Dell Latitude 7275 intel_ips: - Convert timers to use timer_setup() - Remove FSF address from GPL notice - Remove unneeded fields and label - Keep pointer to struct device - Use PCI_VDEVICE() macro - Switch to new PCI IRQ allocation API - Simplify error handling via devres API intel_pmc_ipc: - Revert Use MFD framework to create dependent devices - Use MFD framework to create dependent devices - Use spin_lock to protect GCR updates - Use devm_* calls in driver probe function intel_punit_ipc: - Fix resource ioremap warning intel_telemetry: - Remove useless default in Kconfig - Add needed inclusion - cleanup redundant headers - Fix typos - Fix load failure info intel_telemetry_debugfs: - Use standard ARRAY_SIZE() macro intel_turbo_max_3: - Add Skylake platform intel-wmi-thunderbolt: - Silence error cases mlx-platform: - make a couple of structures static peaq_wmi: - Fix missing terminating entry for peaq_dmi_table peaq-wmi: - Remove unnecessary checks from peaq_wmi_exit - Add DMI check before binding to the WMI interface - Revert Blacklist Lenovo ideapad 700-15ISK - Blacklist Lenovo ideapad 700-15ISK silead_dmi: - Add silead, home-button property to some tablets - Add entry for the Digma e200 tablet - Fix GP-electronic T701 entry - Add entry for the Chuwi Hi8 Pro tablet sony-laptop: - Drop variable assignment in sony_nc_setup_rfkill() - Fix error handling in sony_nc_setup_rfkill() thinkpad_acpi: - Implement tablet mode using GMMS method tools/wmi: - add a sample for dell smbios communication over WMI wmi: - release mutex on module acquistion failure - create userspace interface for drivers - Don't allow drivers to get each other's GUIDs - Add new method wmidev_evaluate_method - Destroy on cleanup rather than unregister - Cleanup exit routine in reverse order of init - Sort include list" * tag 'platform-drivers-x86-v4.15-1' of git://git.infradead.org/linux-platform-drivers-x86: (74 commits) platform/x86: silead_dmi: Add silead, home-button property to some tablets platform/x86: dell-laptop: Allocate buffer before rfkill use platform/x86: dell-*wmi*: Relay failed initial probe to dependent drivers platform/x86: dell-wmi-descriptor: check if memory was allocated platform/x86: Revert intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: dell-smbios-wmi: release mutex lock on WMI call failure platform/x86: wmi: release mutex on module acquistion failure platform/x86: dell-smbios: fix string overflow platform/x86: intel_pmc_ipc: Use MFD framework to create dependent devices platform/x86: intel_punit_ipc: Fix resource ioremap warning platform/x86: dell-smo8800: remove redundant assignments to byte_data platform/x86: hp-wmi: Fix tablet mode detection for convertibles platform/x86: intel_ips: Convert timers to use timer_setup() platform/x86: sony-laptop: Drop variable assignment in sony_nc_setup_rfkill() platform/x86: sony-laptop: Fix error handling in sony_nc_setup_rfkill() tools/wmi: add a sample for dell smbios communication over WMI platform/x86: dell-smbios-wmi: introduce userspace interface platform/x86: wmi: create userspace interface for drivers platform/x86: dell-smbios: Add filtering support platform/x86: dell-smbios-smm: test for WSMT ...
Diffstat (limited to 'drivers/platform/x86/intel_cht_int33fe.c')
-rw-r--r--drivers/platform/x86/intel_cht_int33fe.c114
1 files changed, 104 insertions, 10 deletions
diff --git a/drivers/platform/x86/intel_cht_int33fe.c b/drivers/platform/x86/intel_cht_int33fe.c
index da706e2c4232..380ef7ec094f 100644
--- a/drivers/platform/x86/intel_cht_int33fe.c
+++ b/drivers/platform/x86/intel_cht_int33fe.c
@@ -24,6 +24,7 @@
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define EXPECTED_PTYPE 4
@@ -34,6 +35,42 @@ struct cht_int33fe_data {
struct i2c_client *pi3usb30532;
};
+/*
+ * Grrr I severly 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 i2c-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;
+ const char *hid;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return 0;
+
+ hid = acpi_device_hid(adev);
+
+ /* The MAX17047 ACPI node doesn't have an UID, so we don't check that */
+ if (strcmp(hid, "MAX17047"))
+ return 0;
+
+ *max17047 = to_i2c_client(dev);
+ return 1;
+}
+
+static struct i2c_client *cht_int33fe_find_max17047(void)
+{
+ struct i2c_client *max17047 = NULL;
+
+ i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
+ return max17047;
+}
+
static const char * const max17047_suppliers[] = { "bq24190-charger" };
static const struct property_entry max17047_props[] = {
@@ -41,14 +78,25 @@ static const struct property_entry max17047_props[] = {
{ }
};
+static const struct property_entry fusb302_props[] = {
+ PROPERTY_ENTRY_STRING("fcs,extcon-name", "cht_wcove_pwrsrc"),
+ PROPERTY_ENTRY_U32("fcs,max-sink-microvolt", 12000000),
+ PROPERTY_ENTRY_U32("fcs,max-sink-microamp", 3000000),
+ PROPERTY_ENTRY_U32("fcs,max-sink-microwatt", 36000000),
+ { }
+};
+
static int cht_int33fe_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct i2c_board_info board_info;
struct cht_int33fe_data *data;
+ struct i2c_client *max17047;
+ struct regulator *regulator;
unsigned long long ptyp;
acpi_status status;
int fusb302_irq;
+ int ret;
status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
if (ACPI_FAILURE(status)) {
@@ -63,6 +111,34 @@ static int cht_int33fe_probe(struct i2c_client *client)
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;
+ }
+
+ /*
+ * 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 i2c-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) {
@@ -75,16 +151,31 @@ static int cht_int33fe_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
- memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
- board_info.properties = max17047_props;
-
- data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
- if (!data->max17047)
- return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
+ /* Work around BIOS bug, see comment on cht_int33fe_find_max17047 */
+ max17047 = cht_int33fe_find_max17047();
+ if (max17047) {
+ /* Pre-existing i2c-client for the max17047, add device-props */
+ ret = device_add_properties(&max17047->dev, max17047_props);
+ if (ret)
+ return ret;
+ /* And re-probe to get the new device-props applied. */
+ ret = device_reprobe(&max17047->dev);
+ if (ret)
+ dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
+ } else {
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
+ board_info.dev_name = "max17047";
+ board_info.properties = max17047_props;
+ data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
+ if (!data->max17047)
+ return -EPROBE_DEFER; /* Wait for i2c-adapter to load */
+ }
memset(&board_info, 0, sizeof(board_info));
- strlcpy(board_info.type, "fusb302", I2C_NAME_SIZE);
+ strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
+ board_info.dev_name = "fusb302";
+ board_info.properties = fusb302_props;
board_info.irq = fusb302_irq;
data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
@@ -92,6 +183,7 @@ static int cht_int33fe_probe(struct i2c_client *client)
goto out_unregister_max17047;
memset(&board_info, 0, sizeof(board_info));
+ board_info.dev_name = "pi3usb30532";
strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
@@ -106,7 +198,8 @@ out_unregister_fusb302:
i2c_unregister_device(data->fusb302);
out_unregister_max17047:
- i2c_unregister_device(data->max17047);
+ if (data->max17047)
+ i2c_unregister_device(data->max17047);
return -EPROBE_DEFER; /* Wait for the i2c-adapter to load */
}
@@ -117,7 +210,8 @@ static int cht_int33fe_remove(struct i2c_client *i2c)
i2c_unregister_device(data->pi3usb30532);
i2c_unregister_device(data->fusb302);
- i2c_unregister_device(data->max17047);
+ if (data->max17047)
+ i2c_unregister_device(data->max17047);
return 0;
}