diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/chrome/cros_ec.c | 16 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_usbpd_logger.c | 9 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_usbpd_notify.c | 9 | ||||
-rw-r--r-- | drivers/platform/x86/dell/dell-smbios-base.c | 92 | ||||
-rw-r--r-- | drivers/platform/x86/intel/tpmi.c | 7 | ||||
-rw-r--r-- | drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c | 7 | ||||
-rw-r--r-- | drivers/platform/x86/p2sb.c | 29 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 5 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 36 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/core.c | 8 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/dmi.c | 18 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/lenovo.c | 216 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/x86-android-tablets.h | 1 | ||||
-rw-r--r-- | drivers/platform/x86/xiaomi-wmi.c | 18 |
14 files changed, 380 insertions, 91 deletions
diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c index badc68bbae..47d19f7e29 100644 --- a/drivers/platform/chrome/cros_ec.c +++ b/drivers/platform/chrome/cros_ec.c @@ -432,6 +432,12 @@ static void cros_ec_send_resume_event(struct cros_ec_device *ec_dev) void cros_ec_resume_complete(struct cros_ec_device *ec_dev) { cros_ec_send_resume_event(ec_dev); + + /* + * Let the mfd devices know about events that occur during + * suspend. This way the clients know what to do with them. + */ + cros_ec_report_events_during_suspend(ec_dev); } EXPORT_SYMBOL(cros_ec_resume_complete); @@ -442,12 +448,6 @@ static void cros_ec_enable_irq(struct cros_ec_device *ec_dev) if (ec_dev->wake_enabled) disable_irq_wake(ec_dev->irq); - - /* - * Let the mfd devices know about events that occur during - * suspend. This way the clients know what to do with them. - */ - cros_ec_report_events_during_suspend(ec_dev); } /** @@ -475,8 +475,8 @@ EXPORT_SYMBOL(cros_ec_resume_early); */ int cros_ec_resume(struct cros_ec_device *ec_dev) { - cros_ec_enable_irq(ec_dev); - cros_ec_send_resume_event(ec_dev); + cros_ec_resume_early(ec_dev); + cros_ec_resume_complete(ec_dev); return 0; } EXPORT_SYMBOL(cros_ec_resume); diff --git a/drivers/platform/chrome/cros_usbpd_logger.c b/drivers/platform/chrome/cros_usbpd_logger.c index f618757f8b..930c2f4726 100644 --- a/drivers/platform/chrome/cros_usbpd_logger.c +++ b/drivers/platform/chrome/cros_usbpd_logger.c @@ -7,6 +7,7 @@ #include <linux/ktime.h> #include <linux/math64.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> @@ -249,6 +250,12 @@ static int __maybe_unused cros_usbpd_logger_suspend(struct device *dev) static SIMPLE_DEV_PM_OPS(cros_usbpd_logger_pm_ops, cros_usbpd_logger_suspend, cros_usbpd_logger_resume); +static const struct platform_device_id cros_usbpd_logger_id[] = { + { DRV_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, cros_usbpd_logger_id); + static struct platform_driver cros_usbpd_logger_driver = { .driver = { .name = DRV_NAME, @@ -256,10 +263,10 @@ static struct platform_driver cros_usbpd_logger_driver = { }, .probe = cros_usbpd_logger_probe, .remove_new = cros_usbpd_logger_remove, + .id_table = cros_usbpd_logger_id, }; module_platform_driver(cros_usbpd_logger_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Logging driver for ChromeOS EC USBPD Charger."); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/platform/chrome/cros_usbpd_notify.c b/drivers/platform/chrome/cros_usbpd_notify.c index aacad022f2..c83f81d864 100644 --- a/drivers/platform/chrome/cros_usbpd_notify.c +++ b/drivers/platform/chrome/cros_usbpd_notify.c @@ -6,6 +6,7 @@ */ #include <linux/acpi.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_data/cros_usbpd_notify.h> @@ -218,12 +219,19 @@ static void cros_usbpd_notify_remove_plat(struct platform_device *pdev) &pdnotify->nb); } +static const struct platform_device_id cros_usbpd_notify_id[] = { + { DRV_NAME, 0 }, + {} +}; +MODULE_DEVICE_TABLE(platform, cros_usbpd_notify_id); + static struct platform_driver cros_usbpd_notify_plat_driver = { .driver = { .name = DRV_NAME, }, .probe = cros_usbpd_notify_probe_plat, .remove_new = cros_usbpd_notify_remove_plat, + .id_table = cros_usbpd_notify_id, }; static int __init cros_usbpd_notify_init(void) @@ -258,4 +266,3 @@ module_exit(cros_usbpd_notify_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("ChromeOS power delivery notifier device"); MODULE_AUTHOR("Jon Flatley <jflat@chromium.org>"); -MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/platform/x86/dell/dell-smbios-base.c b/drivers/platform/x86/dell/dell-smbios-base.c index e61bfaf8b5..86b95206cb 100644 --- a/drivers/platform/x86/dell/dell-smbios-base.c +++ b/drivers/platform/x86/dell/dell-smbios-base.c @@ -11,6 +11,7 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/container_of.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/capability.h> @@ -25,11 +26,16 @@ static u32 da_supported_commands; static int da_num_tokens; static struct platform_device *platform_device; static struct calling_interface_token *da_tokens; -static struct device_attribute *token_location_attrs; -static struct device_attribute *token_value_attrs; +static struct token_sysfs_data *token_entries; static struct attribute **token_attrs; static DEFINE_MUTEX(smbios_mutex); +struct token_sysfs_data { + struct device_attribute location_attr; + struct device_attribute value_attr; + struct calling_interface_token *token; +}; + struct smbios_device { struct list_head list; struct device *device; @@ -416,47 +422,26 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy) } } -static int match_attribute(struct device *dev, - struct device_attribute *attr) -{ - int i; - - for (i = 0; i < da_num_tokens * 2; i++) { - if (!token_attrs[i]) - continue; - if (strcmp(token_attrs[i]->name, attr->attr.name) == 0) - return i/2; - } - dev_dbg(dev, "couldn't match: %s\n", attr->attr.name); - return -EINVAL; -} - static ssize_t location_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i; + struct token_sysfs_data *data = container_of(attr, struct token_sysfs_data, location_attr); if (!capable(CAP_SYS_ADMIN)) return -EPERM; - i = match_attribute(dev, attr); - if (i > 0) - return sysfs_emit(buf, "%08x", da_tokens[i].location); - return 0; + return sysfs_emit(buf, "%08x", data->token->location); } static ssize_t value_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i; + struct token_sysfs_data *data = container_of(attr, struct token_sysfs_data, value_attr); if (!capable(CAP_SYS_ADMIN)) return -EPERM; - i = match_attribute(dev, attr); - if (i > 0) - return sysfs_emit(buf, "%08x", da_tokens[i].value); - return 0; + return sysfs_emit(buf, "%08x", data->token->value); } static struct attribute_group smbios_attribute_group = { @@ -473,22 +458,15 @@ static int build_tokens_sysfs(struct platform_device *dev) { char *location_name; char *value_name; - size_t size; int ret; int i, j; - /* (number of tokens + 1 for null terminated */ - size = sizeof(struct device_attribute) * (da_num_tokens + 1); - token_location_attrs = kzalloc(size, GFP_KERNEL); - if (!token_location_attrs) + token_entries = kcalloc(da_num_tokens, sizeof(*token_entries), GFP_KERNEL); + if (!token_entries) return -ENOMEM; - token_value_attrs = kzalloc(size, GFP_KERNEL); - if (!token_value_attrs) - goto out_allocate_value; /* need to store both location and value + terminator*/ - size = sizeof(struct attribute *) * ((2 * da_num_tokens) + 1); - token_attrs = kzalloc(size, GFP_KERNEL); + token_attrs = kcalloc((2 * da_num_tokens) + 1, sizeof(*token_attrs), GFP_KERNEL); if (!token_attrs) goto out_allocate_attrs; @@ -496,27 +474,32 @@ static int build_tokens_sysfs(struct platform_device *dev) /* skip empty */ if (da_tokens[i].tokenID == 0) continue; + + token_entries[i].token = &da_tokens[i]; + /* add location */ location_name = kasprintf(GFP_KERNEL, "%04x_location", da_tokens[i].tokenID); if (location_name == NULL) goto out_unwind_strings; - sysfs_attr_init(&token_location_attrs[i].attr); - token_location_attrs[i].attr.name = location_name; - token_location_attrs[i].attr.mode = 0444; - token_location_attrs[i].show = location_show; - token_attrs[j++] = &token_location_attrs[i].attr; + + sysfs_attr_init(&token_entries[i].location_attr.attr); + token_entries[i].location_attr.attr.name = location_name; + token_entries[i].location_attr.attr.mode = 0444; + token_entries[i].location_attr.show = location_show; + token_attrs[j++] = &token_entries[i].location_attr.attr; /* add value */ value_name = kasprintf(GFP_KERNEL, "%04x_value", da_tokens[i].tokenID); if (value_name == NULL) goto loop_fail_create_value; - sysfs_attr_init(&token_value_attrs[i].attr); - token_value_attrs[i].attr.name = value_name; - token_value_attrs[i].attr.mode = 0444; - token_value_attrs[i].show = value_show; - token_attrs[j++] = &token_value_attrs[i].attr; + + sysfs_attr_init(&token_entries[i].value_attr.attr); + token_entries[i].value_attr.attr.name = value_name; + token_entries[i].value_attr.attr.mode = 0444; + token_entries[i].value_attr.show = value_show; + token_attrs[j++] = &token_entries[i].value_attr.attr; continue; loop_fail_create_value: @@ -532,14 +515,12 @@ loop_fail_create_value: out_unwind_strings: while (i--) { - kfree(token_location_attrs[i].attr.name); - kfree(token_value_attrs[i].attr.name); + kfree(token_entries[i].location_attr.attr.name); + kfree(token_entries[i].value_attr.attr.name); } kfree(token_attrs); out_allocate_attrs: - kfree(token_value_attrs); -out_allocate_value: - kfree(token_location_attrs); + kfree(token_entries); return -ENOMEM; } @@ -551,12 +532,11 @@ static void free_group(struct platform_device *pdev) sysfs_remove_group(&pdev->dev.kobj, &smbios_attribute_group); for (i = 0; i < da_num_tokens; i++) { - kfree(token_location_attrs[i].attr.name); - kfree(token_value_attrs[i].attr.name); + kfree(token_entries[i].location_attr.attr.name); + kfree(token_entries[i].value_attr.attr.name); } kfree(token_attrs); - kfree(token_value_attrs); - kfree(token_location_attrs); + kfree(token_entries); } static int __init dell_smbios_init(void) diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c index 910df7c654..003e765ded 100644 --- a/drivers/platform/x86/intel/tpmi.c +++ b/drivers/platform/x86/intel/tpmi.c @@ -763,8 +763,11 @@ static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev) * when actual device nodes created outside this * loop via tpmi_create_devices(). */ - if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) - tpmi_process_info(tpmi_info, pfs); + if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) { + ret = tpmi_process_info(tpmi_info, pfs); + if (ret) + return ret; + } if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) tpmi_set_control_base(auxdev, tpmi_info, pfs); diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c index ef730200a0..bb8e72deb3 100644 --- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c +++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c @@ -240,6 +240,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ bool read_blocked = 0, write_blocked = 0; struct intel_tpmi_plat_info *plat_info; struct tpmi_uncore_struct *tpmi_uncore; + bool uncore_sysfs_added = false; int ret, i, pkg = 0; int num_resources; @@ -384,9 +385,15 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_ } /* Point to next cluster offset */ cluster_offset >>= UNCORE_MAX_CLUSTER_PER_DOMAIN; + uncore_sysfs_added = true; } } + if (!uncore_sysfs_added) { + ret = -ENODEV; + goto remove_clusters; + } + auxiliary_set_drvdata(auxdev, tpmi_uncore); tpmi_uncore->root_cluster.root_domain = true; diff --git a/drivers/platform/x86/p2sb.c b/drivers/platform/x86/p2sb.c index 3d66e1d4eb..1ac30034f3 100644 --- a/drivers/platform/x86/p2sb.c +++ b/drivers/platform/x86/p2sb.c @@ -56,12 +56,9 @@ static int p2sb_get_devfn(unsigned int *devfn) return 0; } -static bool p2sb_valid_resource(struct resource *res) +static bool p2sb_valid_resource(const struct resource *res) { - if (res->flags) - return true; - - return false; + return res->flags & ~IORESOURCE_UNSET; } /* Copy resource from the first BAR of the device in question */ @@ -220,16 +217,20 @@ EXPORT_SYMBOL_GPL(p2sb_bar); static int __init p2sb_fs_init(void) { - p2sb_cache_resources(); - return 0; + return p2sb_cache_resources(); } /* - * pci_rescan_remove_lock to avoid access to unhidden P2SB devices can - * not be locked in sysfs pci bus rescan path because of deadlock. To - * avoid the deadlock, access to P2SB devices with the lock at an early - * step in kernel initialization and cache required resources. This - * should happen after subsys_initcall which initializes PCI subsystem - * and before device_initcall which requires P2SB resources. + * pci_rescan_remove_lock() can not be locked in sysfs PCI bus rescan path + * because of deadlock. To avoid the deadlock, access P2SB devices with the lock + * at an early step in kernel initialization and cache required resources. + * + * We want to run as early as possible. If the P2SB was assigned a bad BAR, + * we'll need to wait on pcibios_assign_resources() to fix it. So, our list of + * initcall dependencies looks something like this: + * + * ... + * subsys_initcall (pci_subsys_init) + * fs_initcall (pcibios_assign_resources) */ -fs_initcall(p2sb_fs_init); +fs_initcall_sync(p2sb_fs_init); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 82429e5999..87a4a381bd 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3044,10 +3044,9 @@ static void tpacpi_send_radiosw_update(void) static void hotkey_exit(void) { -#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL mutex_lock(&hotkey_mutex); +#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL hotkey_poll_stop_sync(); - mutex_unlock(&hotkey_mutex); #endif dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, "restoring original HKEY status and mask\n"); @@ -3057,6 +3056,8 @@ static void hotkey_exit(void) hotkey_mask_set(hotkey_orig_mask)) | hotkey_status_set(false)) != 0) pr_err("failed to restore hot key mask to BIOS defaults\n"); + + mutex_unlock(&hotkey_mutex); } static void __init hotkey_unmap(const unsigned int scancode) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 77244c9aa6..16e941449b 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -57,6 +57,11 @@ module_param(turn_on_panel_on_resume, int, 0644); MODULE_PARM_DESC(turn_on_panel_on_resume, "Call HCI_PANEL_POWER_ON on resume (-1 = auto, 0 = no, 1 = yes"); +static int hci_hotkey_quickstart = -1; +module_param(hci_hotkey_quickstart, int, 0644); +MODULE_PARM_DESC(hci_hotkey_quickstart, + "Call HCI_HOTKEY_EVENT with value 0x5 for quickstart button support (-1 = auto, 0 = no, 1 = yes"); + #define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100" /* Scan code for Fn key on TOS1900 models */ @@ -136,6 +141,7 @@ MODULE_PARM_DESC(turn_on_panel_on_resume, #define HCI_ACCEL_MASK 0x7fff #define HCI_ACCEL_DIRECTION_MASK 0x8000 #define HCI_HOTKEY_DISABLE 0x0b +#define HCI_HOTKEY_ENABLE_QUICKSTART 0x05 #define HCI_HOTKEY_ENABLE 0x09 #define HCI_HOTKEY_SPECIAL_FUNCTIONS 0x10 #define HCI_LCD_BRIGHTNESS_BITS 3 @@ -2731,10 +2737,15 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev) return -ENODEV; /* + * Enable quickstart buttons if supported. + * * Enable the "Special Functions" mode only if they are * supported and if they are activated. */ - if (dev->kbd_function_keys_supported && dev->special_functions) + if (hci_hotkey_quickstart) + result = hci_write(dev, HCI_HOTKEY_EVENT, + HCI_HOTKEY_ENABLE_QUICKSTART); + else if (dev->kbd_function_keys_supported && dev->special_functions) result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_SPECIAL_FUNCTIONS); else @@ -3258,7 +3269,14 @@ static const char *find_hci_method(acpi_handle handle) * works. toshiba_acpi_resume() uses HCI_PANEL_POWER_ON to avoid changing * the configured brightness level. */ -static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { +#define QUIRK_TURN_ON_PANEL_ON_RESUME BIT(0) +/* + * Some Toshibas use "quickstart" keys. On these, HCI_HOTKEY_EVENT must use + * the value HCI_HOTKEY_ENABLE_QUICKSTART. + */ +#define QUIRK_HCI_HOTKEY_QUICKSTART BIT(1) + +static const struct dmi_system_id toshiba_dmi_quirks[] = { { /* Toshiba Portégé R700 */ /* https://bugzilla.kernel.org/show_bug.cgi?id=21012 */ @@ -3266,6 +3284,7 @@ static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R700"), }, + .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME, }, { /* Toshiba Satellite/Portégé R830 */ @@ -3275,6 +3294,7 @@ static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "R830"), }, + .driver_data = (void *)QUIRK_TURN_ON_PANEL_ON_RESUME, }, { /* Toshiba Satellite/Portégé Z830 */ @@ -3282,6 +3302,7 @@ static const struct dmi_system_id turn_on_panel_on_resume_dmi_ids[] = { DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), DMI_MATCH(DMI_PRODUCT_NAME, "Z830"), }, + .driver_data = (void *)(QUIRK_TURN_ON_PANEL_ON_RESUME | QUIRK_HCI_HOTKEY_QUICKSTART), }, }; @@ -3290,6 +3311,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) struct toshiba_acpi_dev *dev; const char *hci_method; u32 dummy; + const struct dmi_system_id *dmi_id; + long quirks = 0; int ret = 0; if (toshiba_acpi) @@ -3442,8 +3465,15 @@ iio_error: } #endif + dmi_id = dmi_first_match(toshiba_dmi_quirks); + if (dmi_id) + quirks = (long)dmi_id->driver_data; + if (turn_on_panel_on_resume == -1) - turn_on_panel_on_resume = dmi_check_system(turn_on_panel_on_resume_dmi_ids); + turn_on_panel_on_resume = !!(quirks & QUIRK_TURN_ON_PANEL_ON_RESUME); + + if (hci_hotkey_quickstart == -1) + hci_hotkey_quickstart = !!(quirks & QUIRK_HCI_HOTKEY_QUICKSTART); toshiba_wwan_available(dev); if (dev->wwan_supported) diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index a3415f1c0b..6559bb4ea7 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -278,25 +278,25 @@ static void x86_android_tablet_remove(struct platform_device *pdev) { int i; - for (i = 0; i < serdev_count; i++) { + for (i = serdev_count - 1; i >= 0; i--) { if (serdevs[i]) serdev_device_remove(serdevs[i]); } kfree(serdevs); - for (i = 0; i < pdev_count; i++) + for (i = pdev_count - 1; i >= 0; i--) platform_device_unregister(pdevs[i]); kfree(pdevs); kfree(buttons); - for (i = 0; i < spi_dev_count; i++) + for (i = spi_dev_count - 1; i >= 0; i--) spi_unregister_device(spi_devs[i]); kfree(spi_devs); - for (i = 0; i < i2c_client_count; i++) + for (i = i2c_client_count - 1; i >= 0; i--) i2c_unregister_device(i2c_clients[i]); kfree(i2c_clients); diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index 5d6c12494f..141a2d25e8 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -106,6 +106,24 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = { }, { /* + * Lenovo Yoga Tablet 2 Pro 1380F/L (13") This has more or less + * the same BIOS as the 830F/L or 1050F/L (8" and 10") below, + * but unlike the 8" / 10" models which share the same mainboard + * this model has a different mainboard. + * This match for the 13" model MUST come before the 8" + 10" + * match since that one will also match the 13" model! + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), + /* Full match so as to NOT match the 830/1050 BIOS */ + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21.X64.0005.R00.1504101516"), + }, + .driver_data = (void *)&lenovo_yoga_tab2_1380_info, + }, + { + /* * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" * Lenovo Yoga Tablet 2 use the same mainboard) */ diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index c297391955..16fa04d604 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -19,6 +19,7 @@ #include <linux/pinctrl/machine.h> #include <linux/platform_data/lp855x.h> #include <linux/platform_device.h> +#include <linux/power/bq24190_charger.h> #include <linux/reboot.h> #include <linux/rmi.h> #include <linux/spi/spi.h> @@ -565,6 +566,221 @@ static void lenovo_yoga_tab2_830_1050_exit(void) } } +/* + * Lenovo Yoga Tablet 2 Pro 1380F/L + * + * The Lenovo Yoga Tablet 2 Pro 1380F/L mostly has the same design as the 830F/L + * and the 1050F/L so this re-uses some of the handling for that from above. + */ +static const char * const lc824206xa_chg_det_psy[] = { "lc824206xa-charger-detect" }; + +static const struct property_entry lenovo_yoga_tab2_1380_bq24190_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lc824206xa_chg_det_psy), + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), + PROPERTY_ENTRY_BOOL("omit-battery-class"), + PROPERTY_ENTRY_BOOL("disable-reset"), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_bq24190_node = { + .properties = lenovo_yoga_tab2_1380_bq24190_props, +}; + +/* For enabling the bq24190 5V boost based on id-pin */ +static struct regulator_consumer_supply lc824206xa_consumer = { + .supply = "vbus", + .dev_name = "i2c-lc824206xa", +}; + +static const struct regulator_init_data lenovo_yoga_tab2_1380_bq24190_vbus_init_data = { + .constraints = { + .name = "bq24190_vbus", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &lc824206xa_consumer, + .num_consumer_supplies = 1, +}; + +struct bq24190_platform_data lenovo_yoga_tab2_1380_bq24190_pdata = { + .regulator_init_data = &lenovo_yoga_tab2_1380_bq24190_vbus_init_data, +}; + +static const struct property_entry lenovo_yoga_tab2_1380_lc824206xa_props[] = { + PROPERTY_ENTRY_BOOL("onnn,enable-miclr-for-dcp"), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_lc824206xa_node = { + .properties = lenovo_yoga_tab2_1380_lc824206xa_props, +}; + +static const char * const lenovo_yoga_tab2_1380_lms303d_mount_matrix[] = { + "0", "-1", "0", + "-1", "0", "0", + "0", "0", "1" +}; + +static const struct property_entry lenovo_yoga_tab2_1380_lms303d_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", lenovo_yoga_tab2_1380_lms303d_mount_matrix), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_lms303d_node = { + .properties = lenovo_yoga_tab2_1380_lms303d_props, +}; + +static const struct x86_i2c_client_info lenovo_yoga_tab2_1380_i2c_clients[] __initconst = { + { + /* BQ27541 fuel-gauge */ + .board_info = { + .type = "bq27541", + .addr = 0x55, + .dev_name = "bq27541", + .swnode = &fg_bq24190_supply_node, + }, + .adapter_path = "\\_SB_.I2C1", + }, { + /* bq24292i battery charger */ + .board_info = { + .type = "bq24190", + .addr = 0x6b, + .dev_name = "bq24292i", + .swnode = &lenovo_yoga_tab2_1380_bq24190_node, + .platform_data = &lenovo_yoga_tab2_1380_bq24190_pdata, + }, + .adapter_path = "\\_SB_.I2C1", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 2, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + .con_id = "bq24292i_irq", + }, + }, { + /* LP8557 Backlight controller */ + .board_info = { + .type = "lp8557", + .addr = 0x2c, + .dev_name = "lp8557", + .platform_data = &lenovo_lp8557_pwm_and_reg_pdata, + }, + .adapter_path = "\\_SB_.I2C3", + }, { + /* LC824206XA Micro USB Switch */ + .board_info = { + .type = "lc824206xa", + .addr = 0x48, + .dev_name = "lc824206xa", + .swnode = &lenovo_yoga_tab2_1380_lc824206xa_node, + }, + .adapter_path = "\\_SB_.I2C3", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 1, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_LOW, + .con_id = "lc824206xa_irq", + }, + }, { + /* AL3320A ambient light sensor */ + .board_info = { + .type = "al3320a", + .addr = 0x1c, + .dev_name = "al3320a", + }, + .adapter_path = "\\_SB_.I2C5", + }, { + /* LSM303DA accelerometer + magnetometer */ + .board_info = { + .type = "lsm303d", + .addr = 0x1d, + .dev_name = "lsm303d", + .swnode = &lenovo_yoga_tab2_1380_lms303d_node, + }, + .adapter_path = "\\_SB_.I2C5", + }, { + /* Synaptics RMI touchscreen */ + .board_info = { + .type = "rmi4_i2c", + .addr = 0x38, + .dev_name = "rmi4_i2c", + .platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata, + }, + .adapter_path = "\\_SB_.I2C6", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x45, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + } +}; + +static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initconst = { + { + /* For the Tablet 2 Pro 1380's custom fast charging driver */ + .name = "lenovo-yoga-tab2-pro-1380-fastcharger", + .id = PLATFORM_DEVID_NONE, + }, +}; + +const char * const lenovo_yoga_tab2_1380_modules[] __initconst = { + "bq24190_charger", /* For the Vbus regulator for lc824206xa */ + NULL +}; + +static int __init lenovo_yoga_tab2_1380_init(void) +{ + int ret; + + /* To verify that the DMI matching works vs the 830 / 1050 models */ + pr_info("detected Lenovo Yoga Tablet 2 Pro 1380F/L\n"); + + ret = lenovo_yoga_tab2_830_1050_init_codec(); + if (ret) + return ret; + + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ + lenovo_yoga_tab2_830_1050_sys_off_handler = + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1, + lenovo_yoga_tab2_830_1050_power_off, NULL); + if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler)) + return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler); + + return 0; +} + +static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios = { + .dev_id = "serial0-0", + .table = { + GPIO_LOOKUP("INT33FC:00", 57, "uart3_txd", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("INT33FC:00", 61, "uart3_rxd", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] = { + &lenovo_yoga_tab2_830_1050_codec_gpios, + &lenovo_yoga_tab2_1380_fc_gpios, + NULL +}; + +const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { + .i2c_client_info = lenovo_yoga_tab2_1380_i2c_clients, + .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_i2c_clients), + .pdev_info = lenovo_yoga_tab2_1380_pdevs, + .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), + .gpio_button = &lenovo_yoga_tab2_830_1050_lid, + .gpio_button_count = 1, + .gpiod_lookup_tables = lenovo_yoga_tab2_1380_gpios, + .bat_swnode = &generic_lipo_hv_4v35_battery_node, + .modules = lenovo_yoga_tab2_1380_modules, + .init = lenovo_yoga_tab2_1380_init, + .exit = lenovo_yoga_tab2_830_1050_exit, +}; + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ /* diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 468993edfe..821dc094b0 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -112,6 +112,7 @@ extern const struct x86_dev_info czc_p10t; extern const struct x86_dev_info lenovo_yogabook_x90_info; extern const struct x86_dev_info lenovo_yogabook_x91_info; extern const struct x86_dev_info lenovo_yoga_tab2_830_1050_info; +extern const struct x86_dev_info lenovo_yoga_tab2_1380_info; extern const struct x86_dev_info lenovo_yt3_info; extern const struct x86_dev_info medion_lifetab_s10346_info; extern const struct x86_dev_info nextbook_ares8_info; diff --git a/drivers/platform/x86/xiaomi-wmi.c b/drivers/platform/x86/xiaomi-wmi.c index 54a2546bb9..be80f0bda9 100644 --- a/drivers/platform/x86/xiaomi-wmi.c +++ b/drivers/platform/x86/xiaomi-wmi.c @@ -2,8 +2,10 @@ /* WMI driver for Xiaomi Laptops */ #include <linux/acpi.h> +#include <linux/device.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/wmi.h> #include <uapi/linux/input-event-codes.h> @@ -20,12 +22,21 @@ struct xiaomi_wmi { struct input_dev *input_dev; + struct mutex key_lock; /* Protects the key event sequence */ unsigned int key_code; }; +static void xiaomi_mutex_destroy(void *data) +{ + struct mutex *lock = data; + + mutex_destroy(lock); +} + static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context) { struct xiaomi_wmi *data; + int ret; if (wdev == NULL || context == NULL) return -EINVAL; @@ -35,6 +46,11 @@ static int xiaomi_wmi_probe(struct wmi_device *wdev, const void *context) return -ENOMEM; dev_set_drvdata(&wdev->dev, data); + mutex_init(&data->key_lock); + ret = devm_add_action_or_reset(&wdev->dev, xiaomi_mutex_destroy, &data->key_lock); + if (ret < 0) + return ret; + data->input_dev = devm_input_allocate_device(&wdev->dev); if (data->input_dev == NULL) return -ENOMEM; @@ -59,10 +75,12 @@ static void xiaomi_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy) if (data == NULL) return; + mutex_lock(&data->key_lock); input_report_key(data->input_dev, data->key_code, 1); input_sync(data->input_dev); input_report_key(data->input_dev, data->key_code, 0); input_sync(data->input_dev); + mutex_unlock(&data->key_lock); } static const struct wmi_device_id xiaomi_wmi_id_table[] = { |