From 5f25b0054f08be0914528a18bbac5e95eb5ed921 Mon Sep 17 00:00:00 2001 From: Micha? K?pie? Date: Fri, 16 Dec 2016 15:46:03 +0100 Subject: platform/x86: fujitsu-laptop: set default trigger for radio LED to rfkill-any MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "radio components indicator" LED present in Lifebook E734/E744/E754 should be lit when any radio transmitter is enabled, so set its default trigger to rfkill-any. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Andy Shevchenko --- drivers/platform/x86/fujitsu-laptop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 82d67715ce76..b725a907a91f 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -202,6 +202,7 @@ static int radio_led_set(struct led_classdev *cdev, static struct led_classdev radio_led = { .name = "fujitsu::radio_led", + .default_trigger = "rfkill-any", .brightness_get = radio_led_get, .brightness_set_blocking = radio_led_set }; -- cgit v1.2.3 From 98d610c3739ac354319a6590b915f4624d9151e6 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Thu, 3 Nov 2016 08:18:52 +0800 Subject: platform/x86: acer-wmi: setup accelerometer when machine has appropriate notify event MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The accelerometer event relies on the ACERWMID_EVENT_GUID notify. So, this patch changes the codes to setup accelerometer input device when detected ACERWMID_EVENT_GUID. It avoids that the accel input device created on every Acer machines. In addition, patch adds a clearly parsing logic of accelerometer hid to acer_wmi_get_handle_cb callback function. It is positive matching the "SENR" name with "BST0001" device to avoid non-supported hardware. Reported-by: Bjørn Mork Cc: Darren Hart Signed-off-by: Lee, Chun-Yi [andy: slightly massage commit message] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index a66192f692e3..c29b9b611ab2 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -1846,11 +1846,24 @@ static int __init acer_wmi_enable_lm(void) return status; } +#define ACER_WMID_ACCEL_HID "BST0001" + static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, void *ctx, void **retval) { + struct acpi_device *dev; + + if (!strcmp(ctx, "SENR")) { + if (acpi_bus_get_device(ah, &dev)) + return AE_OK; + if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev))) + return AE_OK; + } else + return AE_OK; + *(acpi_handle *)retval = ah; - return AE_OK; + + return AE_CTRL_TERMINATE; } static int __init acer_wmi_get_handle(const char *name, const char *prop, @@ -1877,7 +1890,7 @@ static int __init acer_wmi_accel_setup(void) { int err; - err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle); + err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle); if (err) return err; @@ -2233,10 +2246,11 @@ static int __init acer_wmi_init(void) err = acer_wmi_input_setup(); if (err) return err; + err = acer_wmi_accel_setup(); + if (err) + return err; } - acer_wmi_accel_setup(); - err = platform_driver_register(&acer_platform_driver); if (err) { pr_err("Unable to register platform driver\n"); -- cgit v1.2.3 From 3e491607600aacab5d9cc13aabb9c8b07b0c0909 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Wed, 21 Dec 2016 10:55:53 +0100 Subject: platform/x86: hp_accel: Add support for HP ZBook 17 HP ZBook 17 laptop needs a non-standard mapping (xy_swap_yz_inverted). Signed-off-by: Ladislav Michl Signed-off-by: Andy Shevchenko --- drivers/platform/x86/hp_accel.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index 09356684c32f..493d8910a74e 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -251,6 +251,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = { AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap), AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted), AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted), + AXIS_DMI_MATCH("HPZBook17", "HP ZBook 17", xy_swap_yz_inverted), { NULL, } /* Laptop models without axis info (yet): * "NC6910" "HP Compaq 6910" -- cgit v1.2.3 From 9a38b67c9877a7371a250454bbbbf521d02fded5 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Wed, 14 Dec 2016 12:05:15 +0000 Subject: platform/x86: mlx-platform: mlxcpld-hotplug driver style fixes The patch contains several styling fixes: - Make names of hotplug devices shorter; - Change register offset assignment to defines; - Add defines for the all event masks; - Use PLATFORM_DEVID_NONE instead of -1; Signed-off-by: Vadim Pasternak Signed-off-by: Andy Shevchenko --- drivers/platform/x86/mlx-platform.c | 84 ++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 34 deletions(-) diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 25f15df5c2d7..8f98c211b440 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -45,6 +45,10 @@ /* LPC bus IO offsets */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +#define MLXPLAT_CPLD_LPC_REG_AGGR_ADRR 0x253a +#define MLXPLAT_CPLD_LPC_REG_PSU_ADRR 0x2558 +#define MLXPLAT_CPLD_LPC_REG_PWR_ADRR 0x2564 +#define MLXPLAT_CPLD_LPC_REG_FAN_ADRR 0x2588 #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda @@ -56,6 +60,17 @@ MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ MLXPLAT_CPLD_LPC_PIO_OFFSET) +/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ +#define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 +#define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 +#define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 +#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ + MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) +#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 +#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) +#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) +#define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) + /* Start channel numbers */ #define MLXPLAT_CPLD_CH1 2 #define MLXPLAT_CPLD_CH2 10 @@ -123,7 +138,7 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { }; /* Platform hotplug devices */ -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = { +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_psu[] = { { .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, .bus = 10, @@ -134,7 +149,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = { }, }; -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = { +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_pwr[] = { { .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, .bus = 10, @@ -145,7 +160,7 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = { }, }; -static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = { +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_fan[] = { { .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, .bus = 11, @@ -166,38 +181,38 @@ static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = { /* Platform hotplug default data */ static -struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = { - .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), - .top_aggr_mask = 0x48, - .top_aggr_psu_mask = 0x08, - .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58), - .psu_mask = 0x03, - .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu), - .psu = mlxplat_mlxcpld_hotplug_psu, - .top_aggr_pwr_mask = 0x08, - .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), - .pwr_mask = 0x03, - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), - .pwr = mlxplat_mlxcpld_hotplug_pwr, - .top_aggr_fan_mask = 0x40, - .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88), - .fan_mask = 0x0f, - .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan), - .fan = mlxplat_mlxcpld_hotplug_fan, +struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_default_data = { + .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, + .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_DEF, + .top_aggr_psu_mask = MLXPLAT_CPLD_AGGR_PSU_MASK_DEF, + .psu_reg_offset = MLXPLAT_CPLD_LPC_REG_PSU_ADRR, + .psu_mask = MLXPLAT_CPLD_PSU_MASK, + .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_psu), + .psu = mlxplat_mlxcpld_psu, + .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_PWR_MASK_DEF, + .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, + .pwr_mask = MLXPLAT_CPLD_PWR_MASK, + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), + .pwr = mlxplat_mlxcpld_pwr, + .top_aggr_fan_mask = MLXPLAT_CPLD_AGGR_FAN_MASK_DEF, + .fan_reg_offset = MLXPLAT_CPLD_LPC_REG_FAN_ADRR, + .fan_mask = MLXPLAT_CPLD_FAN_MASK, + .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_fan), + .fan = mlxplat_mlxcpld_fan, }; /* Platform hotplug MSN21xx system family data */ static -struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = { - .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), - .top_aggr_mask = 0x04, - .top_aggr_pwr_mask = 0x04, - .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), - .pwr_mask = 0x03, - .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), +struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_msn21xx_data = { + .top_aggr_offset = MLXPLAT_CPLD_LPC_REG_AGGR_ADRR, + .top_aggr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, + .top_aggr_pwr_mask = MLXPLAT_CPLD_AGGR_MASK_MSN21XX, + .pwr_reg_offset = MLXPLAT_CPLD_LPC_REG_PWR_ADRR, + .pwr_mask = MLXPLAT_CPLD_PWR_MASK, + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_pwr), }; -static struct resource mlxplat_mlxcpld_hotplug_resources[] = { +static struct resource mlxplat_mlxcpld_resources[] = { [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), }; @@ -213,7 +228,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_mux_data[i].n_values = ARRAY_SIZE(mlxplat_default_channels[i]); } - mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data; + mlxplat_hotplug = &mlxplat_mlxcpld_default_data; return 1; }; @@ -227,7 +242,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_mux_data[i].n_values = ARRAY_SIZE(mlxplat_msn21xx_channels); } - mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data; + mlxplat_hotplug = &mlxplat_mlxcpld_msn21xx_data; return 1; }; @@ -314,9 +329,10 @@ static int __init mlxplat_init(void) } priv->pdev_hotplug = platform_device_register_resndata( - &mlxplat_dev->dev, "mlxcpld-hotplug", -1, - mlxplat_mlxcpld_hotplug_resources, - ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources), + &mlxplat_dev->dev, "mlxcpld-hotplug", + PLATFORM_DEVID_NONE, + mlxplat_mlxcpld_resources, + ARRAY_SIZE(mlxplat_mlxcpld_resources), mlxplat_hotplug, sizeof(*mlxplat_hotplug)); if (IS_ERR(priv->pdev_hotplug)) { err = PTR_ERR(priv->pdev_hotplug); -- cgit v1.2.3 From 275721585b34e0104ccdeee21ffe4668da9b5fd3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 2 Jan 2017 12:20:55 -0300 Subject: platform/x86: intel_mid_thermal: Remove duplicated platform device ID Commit 3fca3d3d5075 ("platform-x86: intel_mid_thermal: add msic_thermal alias") added a "msic_thermal" entry to the driver's platform device ID table since that was the platform dev name registered in some platforms and the only dev in the platform table was "msic_sensor" (DRIVER_NAME). But then commit 634830704d80 ("x86/mid/thermal: Add msic_thermal alias") changed DRIVER_NAME from "msic_sensor" to "msic_thermal", and so there's now duplicated entries in the platform device ID table. Signed-off-by: Javier Martinez Canillas Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_thermal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 0df3c9d37509..05ac7203806d 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -549,7 +549,6 @@ static int mid_thermal_remove(struct platform_device *pdev) static const struct platform_device_id therm_id_table[] = { { DRIVER_NAME, 1 }, - { "msic_thermal", 1 }, { } }; -- cgit v1.2.3 From a93151a72061e944a4915458b1b1d6d505c03bbf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 2 Jan 2017 12:20:56 -0300 Subject: platform/x86: intel_mid_thermal: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/platform/x86/intel_mid_thermal.ko | grep alias $ After this patch: $ modinfo drivers/platform/x86/intel_mid_thermal.ko | grep alias alias: platform:msic_thermal Signed-off-by: Javier Martinez Canillas Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_thermal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 05ac7203806d..008a76903cbf 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -551,6 +551,7 @@ static const struct platform_device_id therm_id_table[] = { { DRIVER_NAME, 1 }, { } }; +MODULE_DEVICE_TABLE(platform, therm_id_table); static struct platform_driver mid_thermal_driver = { .driver = { -- cgit v1.2.3 From 596c12423264917bb1086ab11571a5c884a70e9c Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 3 Jan 2017 06:46:14 -0800 Subject: platform/x86: intel_pmc_ipc: Remove unused iTCO_version variable iTCO_version was there since the driver was introduced but never used. Drop it. Signed-off-by: Guenter Roeck Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_ipc.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 0bf51d574fa9..59a86121105b 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -97,8 +97,6 @@ #define TCO_PMC_OFFSET 0x8 #define TCO_PMC_SIZE 0x4 -static const int iTCO_version = 3; - static struct intel_pmc_ipc_dev { struct device *dev; void __iomem *ipc_base; -- cgit v1.2.3 From 9893ae86066cf0a59a6beb3908b9cdac4c1347f3 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 5 Jan 2017 09:14:43 +0100 Subject: platform/x86: dell-smbios: Auto-select as needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dell-smbios is a helper module, it serves no purpose on its own, so do not present it as an option to the user. Instead, select it automatically whenever a driver which needs it is selected. Also select DCDBAS as needed, instead of depending on it, so that the Dell driver options are always visible. As a clean-up, I removed the "default n" statements as they are not needed (n is the default default.) Signed-off-by: Jean Delvare Cc: Michał Kępień Cc: Pali Rohár Cc: Darren Hart Cc: Andy Shevchenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 59aa8e302bc3..e4758d7ab602 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -92,9 +92,8 @@ config ASUS_LAPTOP If you have an ACPI-compatible ASUS laptop, say Y or M here. config DELL_SMBIOS - tristate "Dell SMBIOS Support" - depends on DCDBAS - default n + tristate + select DCDBAS ---help--- This module provides common functions for kernel modules using Dell SMBIOS. @@ -103,16 +102,15 @@ config DELL_SMBIOS config DELL_LAPTOP tristate "Dell Laptop Extras" - depends on DELL_SMBIOS depends on DMI depends on BACKLIGHT_CLASS_DEVICE depends on ACPI_VIDEO || ACPI_VIDEO = n depends on RFKILL || RFKILL = n depends on SERIO_I8042 + select DELL_SMBIOS select POWER_SUPPLY select LEDS_CLASS select NEW_LEDS - default n ---help--- This driver adds support for rfkill and backlight control to Dell laptops (except for some models covered by the Compal driver). @@ -123,7 +121,7 @@ config DELL_WMI depends on DMI depends on INPUT depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on DELL_SMBIOS + select DELL_SMBIOS select INPUT_SPARSEKMAP ---help--- Say Y here if you want to support WMI-based hotkeys on Dell laptops. -- cgit v1.2.3 From dcb50b351646c3549fc28b5857d1414ec6487615 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Mon, 9 Jan 2017 14:14:16 +0100 Subject: platform/x86: fujitsu-laptop: rework logolamp_set() to properly handle errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Potential errors returned by some call_fext_func() calls inside logolamp_set() are currently ignored. Rework logolamp_set() to properly handle them. This causes one more call_fext_func() call to be made in the LED_OFF case, though one could argue that this is logically the right thing to do (even though the extra call is not needed to shut the LED off). Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Andy Shevchenko --- drivers/platform/x86/fujitsu-laptop.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index b725a907a91f..34b8481fb0ed 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -271,15 +271,20 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness) { - if (brightness >= LED_FULL) { - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); - } else if (brightness >= LED_HALF) { - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); - } else { - return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); - } + int poweron = FUNC_LED_ON, always = FUNC_LED_ON; + int ret; + + if (brightness < LED_HALF) + poweron = FUNC_LED_OFF; + + if (brightness < LED_FULL) + always = FUNC_LED_OFF; + + ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); + if (ret < 0) + return ret; + + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); } static int kblamps_set(struct led_classdev *cdev, -- cgit v1.2.3 From 5c461e8e74a6a67cbd31ce0c9db5f8d0a41dccdd Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Mon, 9 Jan 2017 14:14:17 +0100 Subject: platform/x86: fujitsu-laptop: simplify logolamp_get() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that call_fext_func() is invoked by logolamp_set() for both LOGOLAMP_POWERON and LOGOLAMP_ALWAYS for every brightness value, logolamp_get() can be simplified to decrease indentation and number of local variables. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Andy Shevchenko --- drivers/platform/x86/fujitsu-laptop.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 34b8481fb0ed..7fa082558a42 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -319,17 +319,17 @@ static int eco_led_set(struct led_classdev *cdev, static enum led_brightness logolamp_get(struct led_classdev *cdev) { - enum led_brightness brightness = LED_OFF; - int poweron, always; - - poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); - if (poweron == FUNC_LED_ON) { - brightness = LED_HALF; - always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); - if (always == FUNC_LED_ON) - brightness = LED_FULL; - } - return brightness; + int ret; + + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + if (ret == FUNC_LED_ON) + return LED_FULL; + + ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + if (ret == FUNC_LED_ON) + return LED_HALF; + + return LED_OFF; } static enum led_brightness kblamps_get(struct led_classdev *cdev) -- cgit v1.2.3 From eb357cbaf7018342699386e93d292233181e8262 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Wed, 11 Jan 2017 09:59:30 +0100 Subject: platform/x86: fujitsu-laptop: decrease indentation in acpi_fujitsu_hotkey_notify() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_fujitsu_hotkey_notify() is pretty deeply nested, which hurts readability. Strip off one level of indentation by returning early when the event code supplied as argument is not ACPI_FUJITSU_NOTIFY_CODE1. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 152 +++++++++++++++++----------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 7fa082558a42..de89fc8135fb 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1044,98 +1044,96 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) input = fujitsu_hotkey->input; + if (event != ACPI_FUJITSU_NOTIFY_CODE1) { + keycode = KEY_UNKNOWN; + vdbg_printk(FUJLAPTOP_DBG_WARN, + "Unsupported event [0x%x]\n", event); + input_report_key(input, keycode, 1); + input_sync(input); + input_report_key(input, keycode, 0); + input_sync(input); + return; + } + if (fujitsu_hotkey->rfkill_supported) fujitsu_hotkey->rfkill_state = call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); - switch (event) { - case ACPI_FUJITSU_NOTIFY_CODE1: - i = 0; - while ((irb = - call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { - switch (irb & 0x4ff) { - case KEY1_CODE: - keycode = fujitsu->keycode1; - break; - case KEY2_CODE: - keycode = fujitsu->keycode2; - break; - case KEY3_CODE: - keycode = fujitsu->keycode3; - break; - case KEY4_CODE: - keycode = fujitsu->keycode4; - break; - case KEY5_CODE: - keycode = fujitsu->keycode5; - break; - case 0: - keycode = 0; - break; - default: + i = 0; + while ((irb = + call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { + switch (irb & 0x4ff) { + case KEY1_CODE: + keycode = fujitsu->keycode1; + break; + case KEY2_CODE: + keycode = fujitsu->keycode2; + break; + case KEY3_CODE: + keycode = fujitsu->keycode3; + break; + case KEY4_CODE: + keycode = fujitsu->keycode4; + break; + case KEY5_CODE: + keycode = fujitsu->keycode5; + break; + case 0: + keycode = 0; + break; + default: + vdbg_printk(FUJLAPTOP_DBG_WARN, + "Unknown GIRB result [%x]\n", irb); + keycode = -1; + break; + } + if (keycode > 0) { + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "Push keycode into ringbuffer [%d]\n", + keycode); + status = kfifo_in_locked(&fujitsu_hotkey->fifo, + (unsigned char *)&keycode, + sizeof(keycode), + &fujitsu_hotkey->fifo_lock); + if (status != sizeof(keycode)) { vdbg_printk(FUJLAPTOP_DBG_WARN, - "Unknown GIRB result [%x]\n", irb); - keycode = -1; - break; + "Could not push keycode [0x%x]\n", + keycode); + } else { + input_report_key(input, keycode, 1); + input_sync(input); } - if (keycode > 0) { + } else if (keycode == 0) { + while ((status = + kfifo_out_locked( + &fujitsu_hotkey->fifo, + (unsigned char *) &keycode_r, + sizeof(keycode_r), + &fujitsu_hotkey->fifo_lock)) + == sizeof(keycode_r)) { + input_report_key(input, keycode_r, 0); + input_sync(input); vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Push keycode into ringbuffer [%d]\n", - keycode); - status = kfifo_in_locked(&fujitsu_hotkey->fifo, - (unsigned char *)&keycode, - sizeof(keycode), - &fujitsu_hotkey->fifo_lock); - if (status != sizeof(keycode)) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Could not push keycode [0x%x]\n", - keycode); - } else { - input_report_key(input, keycode, 1); - input_sync(input); - } - } else if (keycode == 0) { - while ((status = - kfifo_out_locked( - &fujitsu_hotkey->fifo, - (unsigned char *) &keycode_r, - sizeof(keycode_r), - &fujitsu_hotkey->fifo_lock)) - == sizeof(keycode_r)) { - input_report_key(input, keycode_r, 0); - input_sync(input); - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Pop keycode from ringbuffer [%d]\n", - keycode_r); - } + "Pop keycode from ringbuffer [%d]\n", + keycode_r); } } + } - /* On some models (first seen on the Skylake-based Lifebook - * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is - * handled in software; its state is queried using FUNC_RFKILL - */ - if ((fujitsu_hotkey->rfkill_supported & BIT(26)) && - (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) { - keycode = KEY_TOUCHPAD_TOGGLE; - input_report_key(input, keycode, 1); - input_sync(input); - input_report_key(input, keycode, 0); - input_sync(input); - } - - break; - default: - keycode = KEY_UNKNOWN; - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Unsupported event [0x%x]\n", event); + /* On some models (first seen on the Skylake-based Lifebook + * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is + * handled in software; its state is queried using FUNC_RFKILL + */ + if ((fujitsu_hotkey->rfkill_supported & BIT(26)) && + (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) { + keycode = KEY_TOUCHPAD_TOGGLE; input_report_key(input, keycode, 1); input_sync(input); input_report_key(input, keycode, 0); input_sync(input); - break; } + } /* Initialization */ -- cgit v1.2.3 From 2451d19d5d6a4659e5345024efdef3fc5336938a Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Wed, 11 Jan 2017 09:59:31 +0100 Subject: platform/x86: fujitsu-laptop: move keycode processing to separate functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_fujitsu_hotkey_notify() is pretty deeply nested, which hurts readability. Move the keycode processing part to two separate functions to make the code easier to understand and save a few line breaks. Rename variable keycode_r to keycode as there is no longer any need to differentiate between the two. Tweak indentations to make checkpatch happy. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 76 ++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index de89fc8135fb..f46ef5782e04 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1035,12 +1035,48 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device) return 0; } +static void acpi_fujitsu_hotkey_press(int keycode) +{ + struct input_dev *input = fujitsu_hotkey->input; + int status; + + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "Push keycode into ringbuffer [%d]\n", keycode); + status = kfifo_in_locked(&fujitsu_hotkey->fifo, + (unsigned char *)&keycode, sizeof(keycode), + &fujitsu_hotkey->fifo_lock); + if (status != sizeof(keycode)) { + vdbg_printk(FUJLAPTOP_DBG_WARN, + "Could not push keycode [0x%x]\n", keycode); + } else { + input_report_key(input, keycode, 1); + input_sync(input); + } +} + +static void acpi_fujitsu_hotkey_release(void) +{ + struct input_dev *input = fujitsu_hotkey->input; + int keycode, status; + + while ((status = kfifo_out_locked(&fujitsu_hotkey->fifo, + (unsigned char *)&keycode, + sizeof(keycode), + &fujitsu_hotkey->fifo_lock)) + == sizeof(keycode)) { + input_report_key(input, keycode, 0); + input_sync(input); + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "Pop keycode from ringbuffer [%d]\n", keycode); + } +} + static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) { struct input_dev *input; - int keycode, keycode_r; + int keycode; unsigned int irb = 1; - int i, status; + int i; input = fujitsu_hotkey->input; @@ -1088,37 +1124,11 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) keycode = -1; break; } - if (keycode > 0) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Push keycode into ringbuffer [%d]\n", - keycode); - status = kfifo_in_locked(&fujitsu_hotkey->fifo, - (unsigned char *)&keycode, - sizeof(keycode), - &fujitsu_hotkey->fifo_lock); - if (status != sizeof(keycode)) { - vdbg_printk(FUJLAPTOP_DBG_WARN, - "Could not push keycode [0x%x]\n", - keycode); - } else { - input_report_key(input, keycode, 1); - input_sync(input); - } - } else if (keycode == 0) { - while ((status = - kfifo_out_locked( - &fujitsu_hotkey->fifo, - (unsigned char *) &keycode_r, - sizeof(keycode_r), - &fujitsu_hotkey->fifo_lock)) - == sizeof(keycode_r)) { - input_report_key(input, keycode_r, 0); - input_sync(input); - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Pop keycode from ringbuffer [%d]\n", - keycode_r); - } - } + + if (keycode > 0) + acpi_fujitsu_hotkey_press(keycode); + else if (keycode == 0) + acpi_fujitsu_hotkey_release(); } /* On some models (first seen on the Skylake-based Lifebook -- cgit v1.2.3 From 29544f03e52b2a6670ae1f1331033feefa216536 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Wed, 11 Jan 2017 09:59:32 +0100 Subject: platform/x86: fujitsu-laptop: break up complex loop condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The loop condition in acpi_fujitsu_hotkey_release() includes an assignment, a four-argument function call and a comparison, making it hard to read. Separate the assignment from the comparison to improve readability. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f46ef5782e04..1e54dddf51de 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1059,11 +1059,13 @@ static void acpi_fujitsu_hotkey_release(void) struct input_dev *input = fujitsu_hotkey->input; int keycode, status; - while ((status = kfifo_out_locked(&fujitsu_hotkey->fifo, + while (true) { + status = kfifo_out_locked(&fujitsu_hotkey->fifo, (unsigned char *)&keycode, sizeof(keycode), - &fujitsu_hotkey->fifo_lock)) - == sizeof(keycode)) { + &fujitsu_hotkey->fifo_lock); + if (status != sizeof(keycode)) + return; input_report_key(input, keycode, 0); input_sync(input); vdbg_printk(FUJLAPTOP_DBG_TRACE, -- cgit v1.2.3 From a28c7e93bf26f16948065dbbf4cbe3c457386f41 Mon Sep 17 00:00:00 2001 From: Michał Kępień Date: Wed, 11 Jan 2017 09:59:33 +0100 Subject: platform/x86: fujitsu-laptop: make hotkey handling functions more similar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make two minor tweaks to acpi_fujitsu_hotkey_press() to make it more similar to acpi_fujitsu_hotkey_release(): * call vdbg_printk() after reporting the input event, * return immediately when kfifo_in_locked() fails. Signed-off-by: Michał Kępień Acked-by: Jonathan Woithe Signed-off-by: Darren Hart --- drivers/platform/x86/fujitsu-laptop.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1e54dddf51de..2b218b1d13e5 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -1040,18 +1040,18 @@ static void acpi_fujitsu_hotkey_press(int keycode) struct input_dev *input = fujitsu_hotkey->input; int status; - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "Push keycode into ringbuffer [%d]\n", keycode); status = kfifo_in_locked(&fujitsu_hotkey->fifo, (unsigned char *)&keycode, sizeof(keycode), &fujitsu_hotkey->fifo_lock); if (status != sizeof(keycode)) { vdbg_printk(FUJLAPTOP_DBG_WARN, "Could not push keycode [0x%x]\n", keycode); - } else { - input_report_key(input, keycode, 1); - input_sync(input); + return; } + input_report_key(input, keycode, 1); + input_sync(input); + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "Push keycode into ringbuffer [%d]\n", keycode); } static void acpi_fujitsu_hotkey_release(void) -- cgit v1.2.3 From 4ec567b8dda20d0129b60da63a472246f09e03d4 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 18 Jan 2017 10:29:15 -0800 Subject: platform/x86: Support Turbo Boost Max 3.0 for non HWP systems MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On platforms supporting Intel Turbo Boost Max Technology 3.0, the maximum turbo frequencies (turbo ratio) of some cores in a CPU package may be higher than the other cores in the same package. In that case, better performance can be achieved by making the scheduler prefer to run tasks on the CPUs with higher max turbo frequencies. On Intel® Broadwell Xeon systems, it is optional to turn on HWP (Hardware P-States). When HWP is not turned on, the BIOS doesn't present required CPPC (Collaborative Processor Performance Control) tables. This table is used to get the per CPU core maximum performance ratio and inform scheduler (in cpufreq/intel_pstate driver). On such systems the maximum performance ratio can be read via over clocking (OC) mailbox interface for each CPU. This interface is not architectural and can change for every model of processors. This driver reads maximum performance ratio of each CPU and set up the scheduler priority metrics. In this way scheduler can prefer CPU with higher performance to schedule tasks. Signed-off-by: Srinivas Pandruvada Signed-off-by: Darren Hart --- drivers/platform/x86/Kconfig | 10 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_turbo_max_3.c | 152 +++++++++++++++++++++++++++++++ 3 files changed, 163 insertions(+) create mode 100644 drivers/platform/x86/intel_turbo_max_3.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index e4758d7ab602..d9748a881798 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1074,4 +1074,14 @@ config MLX_CPLD_PLATFORM This driver handles hot-plug events for the power suppliers, power cables and fans on the wide range Mellanox IB and Ethernet systems. +config INTEL_TURBO_MAX_3 + bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" + depends on X86_64 && SCHED_MC_PRIO + ---help--- + This driver reads maximum performance ratio of each CPU and set up + the scheduler priority metrics. In this way scheduler can prefer + CPU with higher performance to schedule tasks. + This driver is only required when the system is not using Hardware + P-States (HWP). In HWP mode, priority can be read from ACPI tables. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d4111f0f8a78..cde7b4fdf5d6 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -76,3 +76,4 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o +obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o diff --git a/drivers/platform/x86/intel_turbo_max_3.c b/drivers/platform/x86/intel_turbo_max_3.c new file mode 100644 index 000000000000..0103f5b32e34 --- /dev/null +++ b/drivers/platform/x86/intel_turbo_max_3.c @@ -0,0 +1,152 @@ +/* + * Intel Turbo Boost Max Technology 3.0 legacy (non HWP) enumeration driver + * Copyright (c) 2017, Intel Corporation. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define MSR_OC_MAILBOX 0x150 +#define MSR_OC_MAILBOX_CMD_OFFSET 32 +#define MSR_OC_MAILBOX_RSP_OFFSET 32 +#define MSR_OC_MAILBOX_BUSY_BIT 63 +#define OC_MAILBOX_FC_CONTROL_CMD 0x1C + +/* + * Typical latency to get mail box response is ~3us, It takes +3 us to + * process reading mailbox after issuing mailbox write on a Broadwell 3.4 GHz + * system. So for most of the time, the first mailbox read should have the + * response, but to avoid some boundary cases retry twice. + */ +#define OC_MAILBOX_RETRY_COUNT 2 + +static int get_oc_core_priority(unsigned int cpu) +{ + u64 value, cmd = OC_MAILBOX_FC_CONTROL_CMD; + int ret, i; + + /* Issue favored core read command */ + value = cmd << MSR_OC_MAILBOX_CMD_OFFSET; + /* Set the busy bit to indicate OS is trying to issue command */ + value |= BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT); + ret = wrmsrl_safe(MSR_OC_MAILBOX, value); + if (ret) { + pr_debug("cpu %d OC mailbox write failed\n", cpu); + return ret; + } + + for (i = 0; i < OC_MAILBOX_RETRY_COUNT; ++i) { + ret = rdmsrl_safe(MSR_OC_MAILBOX, &value); + if (ret) { + pr_debug("cpu %d OC mailbox read failed\n", cpu); + break; + } + + if (value & BIT_ULL(MSR_OC_MAILBOX_BUSY_BIT)) { + pr_debug("cpu %d OC mailbox still processing\n", cpu); + ret = -EBUSY; + continue; + } + + if ((value >> MSR_OC_MAILBOX_RSP_OFFSET) & 0xff) { + pr_debug("cpu %d OC mailbox cmd failed\n", cpu); + ret = -ENXIO; + break; + } + + ret = value & 0xff; + pr_debug("cpu %d max_ratio %d\n", cpu, ret); + break; + } + + return ret; +} + +/* + * The work item is needed to avoid CPU hotplug locking issues. The function + * itmt_legacy_set_priority() is called from CPU online callback, so can't + * call sched_set_itmt_support() from there as this function will aquire + * hotplug locks in its path. + */ +static void itmt_legacy_work_fn(struct work_struct *work) +{ + sched_set_itmt_support(); +} + +static DECLARE_WORK(sched_itmt_work, itmt_legacy_work_fn); + +static int itmt_legacy_cpu_online(unsigned int cpu) +{ + static u32 max_highest_perf = 0, min_highest_perf = U32_MAX; + int priority; + + priority = get_oc_core_priority(cpu); + if (priority < 0) + return 0; + + sched_set_itmt_core_prio(priority, cpu); + + /* Enable ITMT feature when a core with different priority is found */ + if (max_highest_perf <= min_highest_perf) { + if (priority > max_highest_perf) + max_highest_perf = priority; + + if (priority < min_highest_perf) + min_highest_perf = priority; + + if (max_highest_perf > min_highest_perf) + schedule_work(&sched_itmt_work); + } + + return 0; +} + +#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, } + +static const struct x86_cpu_id itmt_legacy_cpu_ids[] = { + ICPU(INTEL_FAM6_BROADWELL_X), + {} +}; +MODULE_DEVICE_TABLE(x86cpu, itmt_legacy_cpu_ids); + +static int __init itmt_legacy_init(void) +{ + const struct x86_cpu_id *id; + int ret; + + id = x86_match_cpu(itmt_legacy_cpu_ids); + if (!id) + return -ENODEV; + + if (boot_cpu_has(X86_FEATURE_HWP)) + return -ENODEV; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, + "platform/x86/turbo_max_3:online", + itmt_legacy_cpu_online, NULL); + if (ret < 0) + return ret; + + return 0; +} +late_initcall(itmt_legacy_init) + +MODULE_DESCRIPTION("Intel Turbo Boost Max 3.0 enumeration driver"); +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 07d9089d3989150a80ff2083799929354d7e6c53 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:41 +0200 Subject: platform/x86: intel_mid_powerbtn: Convert to use devm_*() Convert driver to use managed resources. This eliminates error path boilerplate and makes code neat. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 361770568ad0..05c52cc87852 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -66,7 +66,7 @@ static int mfld_pb_probe(struct platform_device *pdev) if (irq < 0) return -EINVAL; - input = input_allocate_device(); + input = devm_input_allocate_device(&pdev->dev); if (!input) return -ENOMEM; @@ -77,22 +77,19 @@ static int mfld_pb_probe(struct platform_device *pdev) input_set_capability(input, EV_KEY, KEY_POWER); - error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT, - DRIVER_NAME, input); + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mfld_pb_isr, + IRQF_ONESHOT, DRIVER_NAME, input); if (error) { dev_err(&pdev->dev, "Unable to request irq %d for mfld power" "button\n", irq); - goto err_free_input; + return error; } - device_init_wakeup(&pdev->dev, true); - dev_pm_set_wake_irq(&pdev->dev, irq); - error = input_register_device(input); if (error) { dev_err(&pdev->dev, "Unable to register input dev, error " "%d\n", error); - goto err_free_irq; + return error; } platform_set_drvdata(pdev, input); @@ -111,27 +108,19 @@ static int mfld_pb_probe(struct platform_device *pdev) if (error) { dev_err(&pdev->dev, "Unable to clear power button interrupt, " "error: %d\n", error); - goto err_free_irq; + return error; } - return 0; + device_init_wakeup(&pdev->dev, true); + dev_pm_set_wake_irq(&pdev->dev, irq); -err_free_irq: - free_irq(irq, input); -err_free_input: - input_free_device(input); - return error; + return 0; } static int mfld_pb_remove(struct platform_device *pdev) { - struct input_dev *input = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); - free_irq(irq, input); - input_unregister_device(input); return 0; } -- cgit v1.2.3 From 48b44529d35f715362ea93f070ca1ac938e205e3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:42 +0200 Subject: platform/x86: intel_mid_powerbtn: Substitute mfld by mid Replace all occurrences of mfld by mid to emphasize that driver is used for Intel MID platforms. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 05c52cc87852..3ab134ba832e 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -1,5 +1,5 @@ /* - * Power button driver for Medfield. + * Power button driver for Intel MID platforms. * * Copyright (C) 2010 Intel Corp * @@ -36,7 +36,7 @@ */ #define MSIC_PWRBTNM (1 << 0) -static irqreturn_t mfld_pb_isr(int irq, void *dev_id) +static irqreturn_t mid_pb_isr(int irq, void *dev_id) { struct input_dev *input = dev_id; int ret; @@ -57,7 +57,7 @@ static irqreturn_t mfld_pb_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static int mfld_pb_probe(struct platform_device *pdev) +static int mid_pb_probe(struct platform_device *pdev) { struct input_dev *input; int irq = platform_get_irq(pdev, 0); @@ -77,10 +77,10 @@ static int mfld_pb_probe(struct platform_device *pdev) input_set_capability(input, EV_KEY, KEY_POWER); - error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mfld_pb_isr, + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, IRQF_ONESHOT, DRIVER_NAME, input); if (error) { - dev_err(&pdev->dev, "Unable to request irq %d for mfld power" + dev_err(&pdev->dev, "Unable to request irq %d for MID power" "button\n", irq); return error; } @@ -117,7 +117,7 @@ static int mfld_pb_probe(struct platform_device *pdev) return 0; } -static int mfld_pb_remove(struct platform_device *pdev) +static int mid_pb_remove(struct platform_device *pdev) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); @@ -125,17 +125,17 @@ static int mfld_pb_remove(struct platform_device *pdev) return 0; } -static struct platform_driver mfld_pb_driver = { +static struct platform_driver mid_pb_driver = { .driver = { .name = DRIVER_NAME, }, - .probe = mfld_pb_probe, - .remove = mfld_pb_remove, + .probe = mid_pb_probe, + .remove = mid_pb_remove, }; -module_platform_driver(mfld_pb_driver); +module_platform_driver(mid_pb_driver); MODULE_AUTHOR("Hong Liu "); -MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); +MODULE_DESCRIPTION("Intel MID Power Button Driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3 From 18934eceed987432ec90db46196e9653fe704d80 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:43 +0200 Subject: platform/x86: intel_mid_powerbtn: Introduce driver data This is preparatory patch to extend the driver in order to support other Intel MID platform. Here the new driver data structure is introduced with split of ->pbstat() callback. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 62 ++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 3ab134ba832e..bce8653cc345 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -26,6 +26,9 @@ #include #include +#include +#include + #define DRIVER_NAME "msic_power_btn" #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ @@ -36,33 +39,72 @@ */ #define MSIC_PWRBTNM (1 << 0) -static irqreturn_t mid_pb_isr(int irq, void *dev_id) +struct mid_pb_ddata { + struct device *dev; + int irq; + struct input_dev *input; + int (*pbstat)(struct mid_pb_ddata *ddata, int *value); +}; + +static int mfld_pbstat(struct mid_pb_ddata *ddata, int *value) { - struct input_dev *input = dev_id; + struct input_dev *input = ddata->input; int ret; u8 pbstat; ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat); + if (ret) + return ret; + dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); + *value = !(pbstat & MSIC_PB_LEVEL); + return 0; +} + +static irqreturn_t mid_pb_isr(int irq, void *dev_id) +{ + struct mid_pb_ddata *ddata = dev_id; + struct input_dev *input = ddata->input; + int value; + int ret; + + ret = ddata->pbstat(ddata, &value); if (ret < 0) { dev_err(input->dev.parent, "Read error %d while reading" " MSIC_PB_STATUS\n", ret); } else { - input_event(input, EV_KEY, KEY_POWER, - !(pbstat & MSIC_PB_LEVEL)); + input_event(input, EV_KEY, KEY_POWER, value); input_sync(input); } return IRQ_HANDLED; } +static struct mid_pb_ddata mfld_ddata = { + .pbstat = mfld_pbstat, +}; + +#define ICPU(model, ddata) \ + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata } + +static const struct x86_cpu_id mid_pb_cpu_ids[] = { + ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata), + {} +}; + static int mid_pb_probe(struct platform_device *pdev) { + const struct x86_cpu_id *id; + struct mid_pb_ddata *ddata; struct input_dev *input; int irq = platform_get_irq(pdev, 0); int error; + id = x86_match_cpu(mid_pb_cpu_ids); + if (!id) + return -ENODEV; + if (irq < 0) return -EINVAL; @@ -77,8 +119,16 @@ static int mid_pb_probe(struct platform_device *pdev) input_set_capability(input, EV_KEY, KEY_POWER); + ddata = (struct mid_pb_ddata *)id->driver_data; + if (!ddata) + return -ENODATA; + + ddata->dev = &pdev->dev; + ddata->irq = irq; + ddata->input = input; + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, - IRQF_ONESHOT, DRIVER_NAME, input); + IRQF_ONESHOT, DRIVER_NAME, ddata); if (error) { dev_err(&pdev->dev, "Unable to request irq %d for MID power" "button\n", irq); @@ -92,7 +142,7 @@ static int mid_pb_probe(struct platform_device *pdev) return error; } - platform_set_drvdata(pdev, input); + platform_set_drvdata(pdev, ddata); /* * SCU firmware might send power button interrupts to IA core before -- cgit v1.2.3 From 4b819c6d5f3c9f9efb8ab334f735f6a223e84d14 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:44 +0200 Subject: platform/x86: intel_mid_powerbtn: Factor out mfld_ack() Move Intel Medfield specific code to another callback, which will be used later. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index bce8653cc345..596ac9f3e89d 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -44,6 +44,7 @@ struct mid_pb_ddata { int irq; struct input_dev *input; int (*pbstat)(struct mid_pb_ddata *ddata, int *value); + int (*ack)(struct mid_pb_ddata *ddata); }; static int mfld_pbstat(struct mid_pb_ddata *ddata, int *value) @@ -62,6 +63,21 @@ static int mfld_pbstat(struct mid_pb_ddata *ddata, int *value) return 0; } +static int mfld_ack(struct mid_pb_ddata *ddata) +{ + /* + * SCU firmware might send power button interrupts to IA core before + * kernel boots and doesn't get EOI from IA core. The first bit of + * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new + * power interrupt to Android kernel. Unmask the bit when probing + * power button in kernel. + * There is a very narrow race between irq handler and power button + * initialization. The race happens rarely. So we needn't worry + * about it. + */ + return intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); +} + static irqreturn_t mid_pb_isr(int irq, void *dev_id) { struct mid_pb_ddata *ddata = dev_id; @@ -83,6 +99,7 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) static struct mid_pb_ddata mfld_ddata = { .pbstat = mfld_pbstat, + .ack = mfld_ack, }; #define ICPU(model, ddata) \ @@ -144,17 +161,7 @@ static int mid_pb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); - /* - * SCU firmware might send power button interrupts to IA core before - * kernel boots and doesn't get EOI from IA core. The first bit of - * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new - * power interrupt to Android kernel. Unmask the bit when probing - * power button in kernel. - * There is a very narrow race between irq handler and power button - * initialization. The race happens rarely. So we needn't worry - * about it. - */ - error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); + error = ddata->ack(ddata); if (error) { dev_err(&pdev->dev, "Unable to clear power button interrupt, " "error: %d\n", error); -- cgit v1.2.3 From 553e9c1861b7f91492eb6e209adff81507624fa6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:45 +0200 Subject: platform/x86: intel_mid_powerbtn: Acknowledge interrupts Some platforms require interrupt to be acknowledged by clearing MSIC_PWRBTNM bit in interrupt level 1 mask register. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 596ac9f3e89d..ac02a0b8bef3 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -94,6 +94,7 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) input_sync(input); } + ddata->ack(ddata); return IRQ_HANDLED; } -- cgit v1.2.3 From 6a0f998856383f4becfef585c18bb8949c34a1f0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:46 +0200 Subject: platform/x86: intel_mid_powerbtn: Enable driver for Merrifield Enable this driver to handle events from Basin Cove PMIC, which is installed on Intel Merrifield platform. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index ac02a0b8bef3..12fbf400f228 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -28,6 +28,7 @@ #include #include +#include #define DRIVER_NAME "msic_power_btn" @@ -39,12 +40,23 @@ */ #define MSIC_PWRBTNM (1 << 0) +/* Intel Tangier */ +#define MRFLD_PBSTAT_ADDR 0xfffff61a +#define MRFLD_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */ + +/* Basin Cove PMIC */ +#define BCOVE_PBIRQ 0x02 +#define BCOVE_IRQLVL1MSK 0x0c +#define BCOVE_PBIRQMASK 0x0d + struct mid_pb_ddata { struct device *dev; + void __iomem *reg; int irq; struct input_dev *input; int (*pbstat)(struct mid_pb_ddata *ddata, int *value); int (*ack)(struct mid_pb_ddata *ddata); + int (*setup)(struct mid_pb_ddata *ddata); }; static int mfld_pbstat(struct mid_pb_ddata *ddata, int *value) @@ -78,6 +90,37 @@ static int mfld_ack(struct mid_pb_ddata *ddata) return intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); } +static int mrfld_pbstat(struct mid_pb_ddata *ddata, int *value) +{ + struct input_dev *input = ddata->input; + u8 pbstat; + + pbstat = readb(ddata->reg); + + dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); + + *value = !(pbstat & MRFLD_PB_LEVEL); + return 0; +} + +static int mrfld_ack(struct mid_pb_ddata *ddata) +{ + return intel_scu_ipc_update_register(BCOVE_IRQLVL1MSK, 0, MSIC_PWRBTNM); +} + +static int mrfld_setup(struct mid_pb_ddata *ddata) +{ + ddata->reg = devm_ioremap_nocache(ddata->dev, MRFLD_PBSTAT_ADDR, 1); + if (!ddata->reg) + return -ENOMEM; + + /* Unmask the PBIRQ and MPBIRQ on Tangier */ + intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM); + intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); + + return 0; +} + static irqreturn_t mid_pb_isr(int irq, void *dev_id) { struct mid_pb_ddata *ddata = dev_id; @@ -103,11 +146,18 @@ static struct mid_pb_ddata mfld_ddata = { .ack = mfld_ack, }; +static struct mid_pb_ddata mrfld_ddata = { + .pbstat = mrfld_pbstat, + .ack = mrfld_ack, + .setup = mrfld_setup, +}; + #define ICPU(model, ddata) \ { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (kernel_ulong_t)&ddata } static const struct x86_cpu_id mid_pb_cpu_ids[] = { ICPU(INTEL_FAM6_ATOM_PENWELL, mfld_ddata), + ICPU(INTEL_FAM6_ATOM_MERRIFIELD, mrfld_ddata), {} }; @@ -145,6 +195,12 @@ static int mid_pb_probe(struct platform_device *pdev) ddata->irq = irq; ddata->input = input; + if (ddata->setup) { + error = ddata->setup(ddata); + if (error) + return error; + } + error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, IRQF_ONESHOT, DRIVER_NAME, ddata); if (error) { -- cgit v1.2.3 From fdde1a82265ba635284c27f3ab65be461487ff00 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:47 +0200 Subject: platform/x86: intel_mid_powerbtn: Join string literals There is no need and bad practice for debugging to split string literals. Join them back. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 12fbf400f228..9b718cf237ee 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -130,8 +130,8 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) ret = ddata->pbstat(ddata, &value); if (ret < 0) { - dev_err(input->dev.parent, "Read error %d while reading" - " MSIC_PB_STATUS\n", ret); + dev_err(input->dev.parent, + "Read error %d while reading MSIC_PB_STATUS\n", ret); } else { input_event(input, EV_KEY, KEY_POWER, value); input_sync(input); @@ -204,15 +204,15 @@ static int mid_pb_probe(struct platform_device *pdev) error = devm_request_threaded_irq(&pdev->dev, irq, NULL, mid_pb_isr, IRQF_ONESHOT, DRIVER_NAME, ddata); if (error) { - dev_err(&pdev->dev, "Unable to request irq %d for MID power" - "button\n", irq); + dev_err(&pdev->dev, + "Unable to request irq %d for MID power button\n", irq); return error; } error = input_register_device(input); if (error) { - dev_err(&pdev->dev, "Unable to register input dev, error " - "%d\n", error); + dev_err(&pdev->dev, + "Unable to register input dev, error %d\n", error); return error; } @@ -220,8 +220,9 @@ static int mid_pb_probe(struct platform_device *pdev) error = ddata->ack(ddata); if (error) { - dev_err(&pdev->dev, "Unable to clear power button interrupt, " - "error: %d\n", error); + dev_err(&pdev->dev, + "Unable to clear power button interrupt, error: %d\n", + error); return error; } -- cgit v1.2.3 From 7591b9f52d6d119fe53fa80ae9e9943a45c28f15 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:48 +0200 Subject: platform/x86: intel_mid_powerbtn: Sort headers alphabetically Sort header inclusion block in alphabetical order. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 9b718cf237ee..63ffd1ce3d1c 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -17,14 +17,14 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include #include -#include -#include -#include #include +#include #include +#include +#include #include +#include #include #include -- cgit v1.2.3 From 1cfd3ba0c146a165951cedf293929a4983a45ae3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 19 Jan 2017 18:39:49 +0200 Subject: platform/x86: intel_mid_powerbtn: Remove snail address The snail address is subject to change. This already happened once. Remove the address completely from the file to avoid potential noise when update. While here, adjust copyright years and list authors. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 63ffd1ce3d1c..1d30b3549748 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -1,7 +1,10 @@ /* * Power button driver for Intel MID platforms. * - * Copyright (C) 2010 Intel Corp + * Copyright (C) 2010,2017 Intel Corp + * + * Author: Hong Liu + * Author: Andy Shevchenko * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -11,10 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include -- cgit v1.2.3 From cef9dd85acd79449d1a5a65543d10f18cb68e56c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 23 Jan 2017 18:35:30 +0100 Subject: platform/x86: add support for devices with Silead touchscreens On ACPI based tablets, the ACPI touchscreen node only contains info on the gpio and the irq, and is missing any info on the axis. This info is expected to be built into the tablet model specific version of the driver shipped with the os-image for the device. Add support for getting the missing info from a table built into the driver, using dmi data to identify which entry of the table to use and add info for the CUBE iwork8 Air and Jumper EZpad mini3 tablets on which this code was tested / developed. BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=187531 Signed-off-by: Hans de Goede [dmitry.torokhov@gmail.com: Move to platform/x86] Signed-off-by: Dmitry Torokhov Acked-by: Andy Shevchenko [andy: fixed merge conflict] Signed-off-by: Andy Shevchenko --- MAINTAINERS | 8 +++ drivers/platform/x86/Kconfig | 11 +++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/silead_dmi.c | 136 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 drivers/platform/x86/silead_dmi.c diff --git a/MAINTAINERS b/MAINTAINERS index 5f10c28b2e15..88cbc17d71c8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11271,6 +11271,14 @@ F: drivers/media/usb/siano/ F: drivers/media/usb/siano/ F: drivers/media/mmc/siano/ +SILEAD TOUCHSCREEN DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +L: platform-driver-x86@vger.kernel.org +S: Maintained +F: drivers/input/touchscreen/silead.c +F: drivers/platform/x86/silead_dmi.c + SIMPLEFB FB DRIVER M: Hans de Goede L: linux-fbdev@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index d9748a881798..cfa842daa270 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1084,4 +1084,15 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. +config SILEAD_DMI + bool "Tablets with Silead touchscreens" + depends on ACPI && DMI && I2C && INPUT + ---help--- + Certain ACPI based tablets with Silead touchscreens do not have + enough data in ACPI tables for the touchscreen driver to handle + the touchscreen properly, as OEMs expected the data to be baked + into the tablet model specific version of the driver shipped + with the OS-image for the device. This option supplies the missing + information. Enable this for x86 tablets with Silead touchscreens. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index cde7b4fdf5d6..b689be13ade0 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o +obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/silead_dmi.c new file mode 100644 index 000000000000..02e11fdbf375 --- /dev/null +++ b/drivers/platform/x86/silead_dmi.c @@ -0,0 +1,136 @@ +/* + * Silead touchscreen driver DMI based configuration code + * + * Copyright (c) 2017 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Red Hat authors: + * Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include + +struct silead_ts_dmi_data { + const char *acpi_name; + struct property_entry *properties; +}; + +static struct property_entry cube_iwork8_air_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 900), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data cube_iwork8_air_data = { + .acpi_name = "MSSL1680:00", + .properties = cube_iwork8_air_props, +}; + +static struct property_entry jumper_ezpad_mini3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { + .acpi_name = "MSSL1680:00", + .properties = jumper_ezpad_mini3_props, +}; + +static const struct dmi_system_id silead_ts_dmi_table[] = { + { + /* CUBE iwork8 Air */ + .driver_data = (void *)&cube_iwork8_air_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "cube"), + DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, + { + /* Jumper EZpad mini3 */ + .driver_data = (void *)&jumper_ezpad_mini3_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ + DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), + }, + }, + { }, +}; + +static void silead_ts_dmi_add_props(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + const struct dmi_system_id *dmi_id; + const struct silead_ts_dmi_data *ts_data; + int error; + + dmi_id = dmi_first_match(silead_ts_dmi_table); + if (!dmi_id) + return; + + ts_data = dmi_id->driver_data; + if (has_acpi_companion(dev) && + !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { + error = device_add_properties(dev, ts_data->properties); + if (error) + dev_err(dev, "failed to add properties: %d\n", error); + } +} + +static int silead_ts_dmi_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + + switch (action) { + case BUS_NOTIFY_ADD_DEVICE: + silead_ts_dmi_add_props(dev); + break; + + default: + break; + } + + return 0; +} + +static struct notifier_block silead_ts_dmi_notifier = { + .notifier_call = silead_ts_dmi_notifier_call, +}; + +static int __init silead_ts_dmi_init(void) +{ + int error; + + error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier); + if (error) + pr_err("%s: failed to register i2c bus notifier: %d\n", + __func__, error); + + return error; +} + +/* + * We are registering out notifier after i2c core is initialized and i2c bus + * itself is ready (which happens at postcore initcall level), but before + * ACPI starts enumerating devices (at subsys initcall level). + */ +arch_initcall(silead_ts_dmi_init); -- cgit v1.2.3 From be2eba5810db19a3f752430cd1b03e9457c2959c Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 2 Feb 2017 15:25:57 +0100 Subject: platform/x86: silead depends on I2C being built-in The new driver cannot be a loadable module, so if I2C is loadable, we get this link error: drivers/platform/built-in.o: In function `silead_ts_dmi_init': silead_dmi.c:(.init.text+0x2ef): undefined reference to `i2c_bus_type' This makes the Kconfig dependency stricter to require I2C=y. Fixes: 9eeda3897a85 ("platform/x86: add support for devices with Silead touchscreens") Signed-off-by: Arnd Bergmann Acked-by: Hans de Goede Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index cfa842daa270..d6fbfc0fd2de 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1086,7 +1086,7 @@ config INTEL_TURBO_MAX_3 config SILEAD_DMI bool "Tablets with Silead touchscreens" - depends on ACPI && DMI && I2C && INPUT + depends on ACPI && DMI && I2C=y && INPUT ---help--- Certain ACPI based tablets with Silead touchscreens do not have enough data in ACPI tables for the touchscreen driver to handle -- cgit v1.2.3 From 4f24ecff0153047a4a8b53c31d8001ee79e1cab7 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Thu, 26 Jan 2017 17:27:23 +0300 Subject: platform/x86: intel_pmc_core: fix out-of-bounds accesses on stack pmc_core_mtpmc_link_status() an pmc_core_check_read_lock_bit() use test_bit() on local 32-bit variable. This causes out-of-bounds access since test_bit() expects object at least of 'unsigned long' size: BUG: KASAN: stack-out-of-bounds in pmc_core_probe+0x3aa/0x3b0 Call Trace: __asan_report_load_n_noabort+0x5c/0x80 pmc_core_probe+0x3aa/0x3b0 local_pci_probe+0xf9/0x1e0 pci_device_probe+0x27b/0x350 driver_probe_device+0x419/0x830 __driver_attach+0x15f/0x1d0 bus_for_each_dev+0x129/0x1d0 driver_attach+0x42/0x70 bus_add_driver+0x385/0x690 driver_register+0x1a9/0x3d0 __pci_register_driver+0x1a2/0x290 intel_pmc_core_driver_init+0x19/0x1b do_one_initcall+0x12e/0x280 kernel_init_freeable+0x57c/0x623 kernel_init+0x13/0x140 ret_from_fork+0x2e/0x40 Fix this by open coding bit test. While at it, also refactor this code a little bit. Fixes: 173943b3dae5 ("platform/x86: intel_pmc_core: ModPhy core lanes pg status") Signed-off-by: Andrey Ryabinin [andy: reverted not related changes, used BIT() macro] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index b130b8c9b9d7..914bcd2edbde 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -188,8 +188,7 @@ static int pmc_core_check_read_lock_bit(void) u32 value; value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET); - return test_bit(SPT_PMC_READ_DISABLE_BIT, - (unsigned long *)&value); + return value & BIT(SPT_PMC_READ_DISABLE_BIT); } #if IS_ENABLED(CONFIG_DEBUG_FS) @@ -238,8 +237,7 @@ static int pmc_core_mtpmc_link_status(void) u32 value; value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET); - return test_bit(SPT_PMC_MSG_FULL_STS_BIT, - (unsigned long *)&value); + return value & BIT(SPT_PMC_MSG_FULL_STS_BIT); } static int pmc_core_send_msg(u32 *addr_xram) -- cgit v1.2.3 From b30f3f8e109698f79ab1cdd30d6386d92338eb15 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Feb 2017 19:54:26 +0200 Subject: platform/x86: intel_mid_powerbtn: Unify PBSTATUS access The status register on Intel Merrifield can be read in the similar way it's done for previous MID platforms. Unify access to PBSTATUS register via SCU IPC. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 41 ++++++++++--------------------- 1 file changed, 13 insertions(+), 28 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 1d30b3549748..594d503ca6fe 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -40,37 +40,37 @@ #define MSIC_PWRBTNM (1 << 0) /* Intel Tangier */ -#define MRFLD_PBSTAT_ADDR 0xfffff61a -#define MRFLD_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */ +#define BCOVE_PB_LEVEL (1 << 4) /* 1 - release, 0 - press */ /* Basin Cove PMIC */ #define BCOVE_PBIRQ 0x02 #define BCOVE_IRQLVL1MSK 0x0c #define BCOVE_PBIRQMASK 0x0d +#define BCOVE_PBSTATUS 0x27 struct mid_pb_ddata { struct device *dev; - void __iomem *reg; int irq; struct input_dev *input; - int (*pbstat)(struct mid_pb_ddata *ddata, int *value); + unsigned short pbstat_addr; + u8 pbstat_mask; int (*ack)(struct mid_pb_ddata *ddata); int (*setup)(struct mid_pb_ddata *ddata); }; -static int mfld_pbstat(struct mid_pb_ddata *ddata, int *value) +static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) { struct input_dev *input = ddata->input; int ret; u8 pbstat; - ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat); + ret = intel_msic_reg_read(ddata->pbstat_addr, &pbstat); if (ret) return ret; dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); - *value = !(pbstat & MSIC_PB_LEVEL); + *value = !(pbstat & ddata->pbstat_mask); return 0; } @@ -89,19 +89,6 @@ static int mfld_ack(struct mid_pb_ddata *ddata) return intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); } -static int mrfld_pbstat(struct mid_pb_ddata *ddata, int *value) -{ - struct input_dev *input = ddata->input; - u8 pbstat; - - pbstat = readb(ddata->reg); - - dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); - - *value = !(pbstat & MRFLD_PB_LEVEL); - return 0; -} - static int mrfld_ack(struct mid_pb_ddata *ddata) { return intel_scu_ipc_update_register(BCOVE_IRQLVL1MSK, 0, MSIC_PWRBTNM); @@ -109,10 +96,6 @@ static int mrfld_ack(struct mid_pb_ddata *ddata) static int mrfld_setup(struct mid_pb_ddata *ddata) { - ddata->reg = devm_ioremap_nocache(ddata->dev, MRFLD_PBSTAT_ADDR, 1); - if (!ddata->reg) - return -ENOMEM; - /* Unmask the PBIRQ and MPBIRQ on Tangier */ intel_scu_ipc_update_register(BCOVE_PBIRQ, 0, MSIC_PWRBTNM); intel_scu_ipc_update_register(BCOVE_PBIRQMASK, 0, MSIC_PWRBTNM); @@ -124,10 +107,10 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) { struct mid_pb_ddata *ddata = dev_id; struct input_dev *input = ddata->input; - int value; + int value = 0; int ret; - ret = ddata->pbstat(ddata, &value); + ret = mid_pbstat(ddata, &value); if (ret < 0) { dev_err(input->dev.parent, "Read error %d while reading MSIC_PB_STATUS\n", ret); @@ -141,12 +124,14 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) } static struct mid_pb_ddata mfld_ddata = { - .pbstat = mfld_pbstat, + .pbstat_addr = INTEL_MSIC_PBSTATUS, + .pbstat_mask = MSIC_PB_LEVEL, .ack = mfld_ack, }; static struct mid_pb_ddata mrfld_ddata = { - .pbstat = mrfld_pbstat, + .pbstat_addr = BCOVE_PBSTATUS, + .pbstat_mask = BCOVE_PB_LEVEL, .ack = mrfld_ack, .setup = mrfld_setup, }; -- cgit v1.2.3 From 5cb44ee2f4dde68d83a3e17c3333bc4099003669 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Feb 2017 19:54:27 +0200 Subject: platform/x86: intel_mid_powerbtn: Move comment to where it belongs The comments is about initial interrupt acknowledgment only. So, move it back to where it belongs. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 594d503ca6fe..de40c71883f8 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -76,16 +76,6 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) static int mfld_ack(struct mid_pb_ddata *ddata) { - /* - * SCU firmware might send power button interrupts to IA core before - * kernel boots and doesn't get EOI from IA core. The first bit of - * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new - * power interrupt to Android kernel. Unmask the bit when probing - * power button in kernel. - * There is a very narrow race between irq handler and power button - * initialization. The race happens rarely. So we needn't worry - * about it. - */ return intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); } @@ -202,6 +192,16 @@ static int mid_pb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); + /* + * SCU firmware might send power button interrupts to IA core before + * kernel boots and doesn't get EOI from IA core. The first bit of + * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new + * power interrupt to Android kernel. Unmask the bit when probing + * power button in kernel. + * There is a very narrow race between irq handler and power button + * initialization. The race happens rarely. So we needn't worry + * about it. + */ error = ddata->ack(ddata); if (error) { dev_err(&pdev->dev, -- cgit v1.2.3 From ca45ba06885f9f3fa9a7e70296f99d9a4899dbf4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Feb 2017 19:54:28 +0200 Subject: platform/x86: intel_mid_powerbtn: Unify IRQ acknowledgment The IRQ on Intel Merrifield can be acknowledged in the similar way it's done for previous MID platforms. Unify acknowledgment via SCU IPC. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index de40c71883f8..38844f765345 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -52,9 +52,9 @@ struct mid_pb_ddata { struct device *dev; int irq; struct input_dev *input; + unsigned short mirqlvl1_addr; unsigned short pbstat_addr; u8 pbstat_mask; - int (*ack)(struct mid_pb_ddata *ddata); int (*setup)(struct mid_pb_ddata *ddata); }; @@ -74,14 +74,9 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) return 0; } -static int mfld_ack(struct mid_pb_ddata *ddata) +static int mid_irq_ack(struct mid_pb_ddata *ddata) { - return intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); -} - -static int mrfld_ack(struct mid_pb_ddata *ddata) -{ - return intel_scu_ipc_update_register(BCOVE_IRQLVL1MSK, 0, MSIC_PWRBTNM); + return intel_msic_reg_update(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM); } static int mrfld_setup(struct mid_pb_ddata *ddata) @@ -109,20 +104,20 @@ static irqreturn_t mid_pb_isr(int irq, void *dev_id) input_sync(input); } - ddata->ack(ddata); + mid_irq_ack(ddata); return IRQ_HANDLED; } static struct mid_pb_ddata mfld_ddata = { + .mirqlvl1_addr = INTEL_MSIC_IRQLVL1MSK, .pbstat_addr = INTEL_MSIC_PBSTATUS, .pbstat_mask = MSIC_PB_LEVEL, - .ack = mfld_ack, }; static struct mid_pb_ddata mrfld_ddata = { + .mirqlvl1_addr = BCOVE_IRQLVL1MSK, .pbstat_addr = BCOVE_PBSTATUS, .pbstat_mask = BCOVE_PB_LEVEL, - .ack = mrfld_ack, .setup = mrfld_setup, }; @@ -202,7 +197,7 @@ static int mid_pb_probe(struct platform_device *pdev) * initialization. The race happens rarely. So we needn't worry * about it. */ - error = ddata->ack(ddata); + error = mid_irq_ack(ddata); if (error) { dev_err(&pdev->dev, "Unable to clear power button interrupt, error: %d\n", -- cgit v1.2.3 From 25b4a38fcf1be7f425b3a9eb94998c35f5b763ee Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 Feb 2017 19:03:19 +0200 Subject: platform/x86: intel_mid_powerbtn: Use SCU IPC directly On older Intel MID platforms is using SCU IPC library beneath MSIC calls. To make access unified between old and new platforms use SCU IPC library directly. It's safe since serialization is done in the library. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_powerbtn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 38844f765345..871cfa682519 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -64,7 +64,7 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) int ret; u8 pbstat; - ret = intel_msic_reg_read(ddata->pbstat_addr, &pbstat); + ret = intel_scu_ipc_ioread8(ddata->pbstat_addr, &pbstat); if (ret) return ret; @@ -76,7 +76,7 @@ static int mid_pbstat(struct mid_pb_ddata *ddata, int *value) static int mid_irq_ack(struct mid_pb_ddata *ddata) { - return intel_msic_reg_update(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM); + return intel_scu_ipc_update_register(ddata->mirqlvl1_addr, 0, MSIC_PWRBTNM); } static int mrfld_setup(struct mid_pb_ddata *ddata) -- cgit v1.2.3 From 8e4b8c7d7df78a2c8fe4ba0daf12fc877f353f5c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 8 Feb 2017 17:33:01 +0200 Subject: platform/x86: alienware-wmi: Remove header duplicate No need to #include twice. Remove second occurrence. Signed-off-by: Andy Shevchenko --- drivers/platform/x86/alienware-wmi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 005629447b0c..d6b34923fb4e 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492" -- cgit v1.2.3 From 76062b4ae2ea54fcfb8fce6940921a90f33f38da Mon Sep 17 00:00:00 2001 From: Shanth Murthy Date: Mon, 13 Feb 2017 04:02:52 -0800 Subject: platform/x86: intel_pmc_ipc: read s0ix residency API This patch adds a new API to indicate S0ix residency in usec. It utilizes the PMC Global Control Registers (GCR) to read deep and shallow S0ix residency. PMC MMIO resources: o Lower 4kB: IPC1 (PMC inter-processor communication) interface o Upper 4kB: GCR (Global Control Registers) This enables the power management framework to take corrective actions when the platform fails to enter S0ix after kernel freeze as part of the suspend to idle flow. (echo freeze > /sys/power/state). This is expected to be used with a S0ix failsafe framework such as: [rajneesh: folded in "fix division in 32-bit case" from Andy Shevchenko] Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Shanth Murthy [andy: fixed kbuild error, removed "total" from variables, fixed macro] Signed-off-by: Andy Shevchenko --- arch/x86/include/asm/intel_pmc_ipc.h | 6 ++++ drivers/platform/x86/intel_pmc_ipc.c | 64 ++++++++++++++++++++++++++++++++---- 2 files changed, 64 insertions(+), 6 deletions(-) diff --git a/arch/x86/include/asm/intel_pmc_ipc.h b/arch/x86/include/asm/intel_pmc_ipc.h index cd0310e186f4..4291b6a5ddf7 100644 --- a/arch/x86/include/asm/intel_pmc_ipc.h +++ b/arch/x86/include/asm/intel_pmc_ipc.h @@ -30,6 +30,7 @@ int intel_pmc_ipc_raw_cmd(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, u32 outlen, u32 dptr, u32 sptr); int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, u32 *out, u32 outlen); +int intel_pmc_s0ix_counter_read(u64 *data); #else @@ -50,6 +51,11 @@ static inline int intel_pmc_ipc_command(u32 cmd, u32 sub, u8 *in, u32 inlen, return -EINVAL; } +static inline int intel_pmc_s0ix_counter_read(u64 *data) +{ + return -EINVAL; +} + #endif /*CONFIG_INTEL_PMC_IPC*/ #endif diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 59a86121105b..9dae8434bd78 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -32,7 +32,10 @@ #include #include #include +#include + #include + #include /* @@ -54,6 +57,18 @@ #define IPC_WRITE_BUFFER 0x80 #define IPC_READ_BUFFER 0x90 +/* PMC Global Control Registers */ +#define GCR_TELEM_DEEP_S0IX_OFFSET 0x1078 +#define GCR_TELEM_SHLW_S0IX_OFFSET 0x1080 + +/* Residency with clock rate at 19.2MHz to usecs */ +#define S0IX_RESIDENCY_IN_USECS(d, s) \ +({ \ + u64 result = 10ull * ((d) + (s)); \ + do_div(result, 192); \ + result; \ +}) + /* * 16-byte buffer for sending data associated with IPC command. */ @@ -68,7 +83,7 @@ #define PLAT_RESOURCE_IPC_INDEX 0 #define PLAT_RESOURCE_IPC_SIZE 0x1000 #define PLAT_RESOURCE_GCR_OFFSET 0x1008 -#define PLAT_RESOURCE_GCR_SIZE 0x4 +#define PLAT_RESOURCE_GCR_SIZE 0x1000 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 @@ -113,6 +128,7 @@ static struct intel_pmc_ipc_dev { /* gcr */ resource_size_t gcr_base; int gcr_size; + bool has_gcr_regs; /* punit */ struct platform_device *punit_dev; @@ -178,6 +194,11 @@ static inline u32 ipc_data_readl(u32 offset) return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); } +static inline u64 gcr_data_readq(u32 offset) +{ + return readq(ipcdev.ipc_base + offset); +} + static int intel_pmc_ipc_check_status(void) { int status; @@ -710,7 +731,8 @@ static int ipc_plat_get_res(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to get ipc resource\n"); return -ENXIO; } - size = PLAT_RESOURCE_IPC_SIZE; + size = PLAT_RESOURCE_IPC_SIZE + PLAT_RESOURCE_GCR_SIZE; + if (!request_mem_region(res->start, size, pdev->name)) { dev_err(&pdev->dev, "Failed to request ipc resource\n"); return -EBUSY; @@ -746,6 +768,28 @@ static int ipc_plat_get_res(struct platform_device *pdev) return 0; } +/** + * intel_pmc_s0ix_counter_read() - Read S0ix residency. + * @data: Out param that contains current S0ix residency count. + * + * Return: an error code or 0 on success. + */ +int intel_pmc_s0ix_counter_read(u64 *data) +{ + u64 deep, shlw; + + if (!ipcdev.has_gcr_regs) + return -EACCES; + + deep = gcr_data_readq(GCR_TELEM_DEEP_S0IX_OFFSET); + shlw = gcr_data_readq(GCR_TELEM_SHLW_S0IX_OFFSET); + + *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); + #ifdef CONFIG_ACPI static const struct acpi_device_id ipc_acpi_ids[] = { { "INT34D2", 0}, @@ -795,6 +839,8 @@ static int ipc_plat_probe(struct platform_device *pdev) goto err_sys; } + ipcdev.has_gcr_regs = true; + return 0; err_sys: free_irq(ipcdev.irq, &ipcdev); @@ -806,8 +852,11 @@ err_device: iounmap(ipcdev.ipc_base); res = platform_get_resource(pdev, IORESOURCE_MEM, PLAT_RESOURCE_IPC_INDEX); - if (res) - release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); + if (res) { + release_mem_region(res->start, + PLAT_RESOURCE_IPC_SIZE + + PLAT_RESOURCE_GCR_SIZE); + } return ret; } @@ -823,8 +872,11 @@ static int ipc_plat_remove(struct platform_device *pdev) iounmap(ipcdev.ipc_base); res = platform_get_resource(pdev, IORESOURCE_MEM, PLAT_RESOURCE_IPC_INDEX); - if (res) - release_mem_region(res->start, PLAT_RESOURCE_IPC_SIZE); + if (res) { + release_mem_region(res->start, + PLAT_RESOURCE_IPC_SIZE + + PLAT_RESOURCE_GCR_SIZE); + } ipcdev.dev = NULL; return 0; } -- cgit v1.2.3 From 23e775db8cb90a3bde18d7c5e3bcc90a59395978 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Mon, 13 Feb 2017 16:11:47 +0530 Subject: platform/x86: intel_pmc_ipc: Add APL PMC PCI Id This patch adds the PCI Device id for Power Management Controller on Intel Apollo Lake platforms. Intel PMC IPC Driver loads as a platform driver on Apollo Lake platforms since Intel BIOS hides the PCI Configuration space for 0:13:1 and re-enumerates it as ACPI device (INT34D2). The correct PCI Device ID should be added if some platform firmware choses to enumerate the device via PCI space. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_pmc_ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 9dae8434bd78..0651d47b8eeb 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c @@ -408,6 +408,7 @@ static void ipc_pci_remove(struct pci_dev *pdev) static const struct pci_device_id ipc_pci_ids[] = { {PCI_VDEVICE(INTEL, 0x0a94), 0}, {PCI_VDEVICE(INTEL, 0x1a94), 0}, + {PCI_VDEVICE(INTEL, 0x5a94), 0}, { 0,} }; MODULE_DEVICE_TABLE(pci, ipc_pci_ids); -- cgit v1.2.3 From 4b7fb9fcf917f7eda8da8f2bf335539067772c4d Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Tue, 7 Feb 2017 16:45:10 -0500 Subject: platform/x86: asus-wireless: Use per-HID HSWC parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some Asus machines use 0x4/0x5 as their LED on/off values, while others use 0x0/0x1, as shown in the DSDT excerpts below. Luckily it seems this behavior is tied to different HIDs, after looking at 44 DSDTs from different Asus models. Another small difference is that a few of them call GWBL instead of OWGS, and SWBL instead of OWGD. That does not seem to make a difference for asus-wireless, and is additional reasoning to not try to call these methods directly. Device (ASHS) | Device (ASHS) { | { Name (_HID, "ATK4002") | Name (_HID, "ATK4001") Method (HSWC, 1, Serialized) | Method (HSWC, 1, Serialized) { | { If ((Arg0 < 0x02)) | If ((Arg0 < 0x02)) { | { OWGD (Arg0) | OWGD (Arg0) Return (One) | Return (One) } | } If ((Arg0 == 0x02)) | { | If ((Arg0 == 0x02)) Local0 = OWGS () | { If (Local0) | Return (OWGS ()) { | } Return (0x05) | } | If ((Arg0 == 0x03)) Else | { { | Return (0xFF) Return (0x04) | } } | } | If ((Arg0 == 0x80)) If ((Arg0 == 0x03)) | { { | Return (One) Return (0xFF) | } } | } If ((Arg0 == 0x04)) | Method (_STA, 0, NotSerialized) { | { OWGD (Zero) | If ((MSOS () >= OSW8)) Return (One) | { } | Return (0x0F) If ((Arg0 == 0x05)) | } { | Else OWGD (One) | { Return (One) | Return (Zero) } | } If ((Arg0 == 0x80)) | } { | } Return (One) | } | } | Method (_STA, 0, NotSerialized) | { | If ((MSOS () >= OSW8)) | { | Return (0x0F) | } | Else | { | Return (Zero) | } | } | } | Signed-off-by: João Paulo Rechi Vita Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-wireless.c | 57 ++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 9f31bc1a47d0..9fd43b75339d 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -17,19 +17,41 @@ #include #include -#define ASUS_WIRELESS_LED_STATUS 0x2 -#define ASUS_WIRELESS_LED_OFF 0x4 -#define ASUS_WIRELESS_LED_ON 0x5 +struct hswc_params { + u8 on; + u8 off; + u8 status; +}; struct asus_wireless_data { struct input_dev *idev; struct acpi_device *adev; + const struct hswc_params *hswc_params; struct workqueue_struct *wq; struct work_struct led_work; struct led_classdev led; int led_state; }; +static const struct hswc_params atk4001_id_params = { + .on = 0x0, + .off = 0x1, + .status = 0x2, +}; + +static const struct hswc_params atk4002_id_params = { + .on = 0x5, + .off = 0x4, + .status = 0x2, +}; + +static const struct acpi_device_id device_ids[] = { + {"ATK4001", (kernel_ulong_t)&atk4001_id_params}, + {"ATK4002", (kernel_ulong_t)&atk4002_id_params}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, device_ids); + static u64 asus_wireless_method(acpi_handle handle, const char *method, int param) { @@ -61,8 +83,8 @@ static enum led_brightness led_state_get(struct led_classdev *led) data = container_of(led, struct asus_wireless_data, led); s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC", - ASUS_WIRELESS_LED_STATUS); - if (s == ASUS_WIRELESS_LED_ON) + data->hswc_params->status); + if (s == data->hswc_params->on) return LED_FULL; return LED_OFF; } @@ -82,8 +104,8 @@ static void led_state_set(struct led_classdev *led, struct asus_wireless_data *data; data = container_of(led, struct asus_wireless_data, led); - data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF : - ASUS_WIRELESS_LED_ON; + data->led_state = value == LED_OFF ? data->hswc_params->off : + data->hswc_params->on; queue_work(data->wq, &data->led_work); } @@ -104,12 +126,14 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event) static int asus_wireless_add(struct acpi_device *adev) { struct asus_wireless_data *data; + const struct acpi_device_id *id; int err; data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; adev->driver_data = data; + data->adev = adev; data->idev = devm_input_allocate_device(&adev->dev); if (!data->idev) @@ -124,7 +148,16 @@ static int asus_wireless_add(struct acpi_device *adev) if (err) return err; - data->adev = adev; + for (id = device_ids; id->id[0]; id++) { + if (!strcmp((char *) id->id, acpi_device_hid(adev))) { + data->hswc_params = + (const struct hswc_params *)id->driver_data; + break; + } + } + if (!data->hswc_params) + return 0; + data->wq = create_singlethread_workqueue("asus_wireless_workqueue"); if (!data->wq) return -ENOMEM; @@ -137,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev) err = devm_led_classdev_register(&adev->dev, &data->led); if (err) destroy_workqueue(data->wq); + return err; } @@ -149,13 +183,6 @@ static int asus_wireless_remove(struct acpi_device *adev) return 0; } -static const struct acpi_device_id device_ids[] = { - {"ATK4001", 0}, - {"ATK4002", 0}, - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, device_ids); - static struct acpi_driver asus_wireless_driver = { .name = "Asus Wireless Radio Control Driver", .class = "hotkey", -- cgit v1.2.3 From 4ac20e62efc6b8a63a1a534ddf236af7fe8849b5 Mon Sep 17 00:00:00 2001 From: João Paulo Rechi Vita Date: Mon, 6 Feb 2017 10:20:21 -0500 Subject: platform/x86: asus-wireless: Fix indentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix indentation problem introduced when this driver was first merged into the kernel. Signed-off-by: João Paulo Rechi Vita Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-wireless.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 9fd43b75339d..f3796164329e 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -98,8 +98,7 @@ static void led_state_update(struct work_struct *work) data->led_state); } -static void led_state_set(struct led_classdev *led, - enum led_brightness value) +static void led_state_set(struct led_classdev *led, enum led_brightness value) { struct asus_wireless_data *data; -- cgit v1.2.3 From 280642c3c8dda79da39e056fd5480d1c3942524e Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 8 Feb 2017 07:51:40 -0600 Subject: platform/x86: acer-wmi: Inform firmware that RF Button Driver is active The same method to activate LM(Launch Manager) can also be used to activate the RF Button driver with different bit toggled in the same lm_status. To express that many functions this byte field can achieve, rename the lm_status to app_status. And also the app_mask is the bit mask which specifically indicate which bits are going to be changed. This solves a problem where the AR9565 wifi included in the Acer Aspire ES1-421 is permanently hard blocked according to the rfkill GPIO read by ath9k. Signed-off-by: Chris Chiu Signed-off-by: Daniel Drake Reviewed-by: Lee, Chun-Yi Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 74 ++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c29b9b611ab2..4f633570531a 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -150,15 +150,30 @@ struct event_return_value { #define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */ #define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */ -struct lm_input_params { +/* Hotkey Customized Setting and Acer Application Status. + * Set Device Default Value and Report Acer Application Status. + * When Acer Application starts, it will run this method to inform + * BIOS/EC that Acer Application is on. + * App Status + * Bit[0]: Launch Manager Status + * Bit[1]: ePM Status + * Bit[2]: Device Control Status + * Bit[3]: Acer Power Button Utility Status + * Bit[4]: RF Button Status + * Bit[5]: ODD PM Status + * Bit[6]: Device Default Value Control + * Bit[7]: Hall Sensor Application Status + */ +struct func_input_params { u8 function_num; /* Function Number */ u16 commun_devices; /* Communication type devices default status */ u16 devices; /* Other type devices default status */ - u8 lm_status; /* Launch Manager Status */ - u16 reserved; + u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */ + u8 app_mask; /* Bit mask to app_status */ + u8 reserved; } __attribute__((packed)); -struct lm_return_value { +struct func_return_value { u8 error_code; /* Error Code */ u8 ec_return_value; /* EC Return Value */ u16 reserved; @@ -1769,13 +1784,13 @@ static void acer_wmi_notify(u32 value, void *context) } static acpi_status __init -wmid3_set_lm_mode(struct lm_input_params *params, - struct lm_return_value *return_value) +wmid3_set_function_mode(struct func_input_params *params, + struct func_return_value *return_value) { acpi_status status; union acpi_object *obj; - struct acpi_buffer input = { sizeof(struct lm_input_params), params }; + struct acpi_buffer input = { sizeof(struct func_input_params), params }; struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output); @@ -1796,7 +1811,7 @@ wmid3_set_lm_mode(struct lm_input_params *params, return AE_ERROR; } - *return_value = *((struct lm_return_value *)obj->buffer.pointer); + *return_value = *((struct func_return_value *)obj->buffer.pointer); kfree(obj); return status; @@ -1804,16 +1819,17 @@ wmid3_set_lm_mode(struct lm_input_params *params, static int __init acer_wmi_enable_ec_raw(void) { - struct lm_return_value return_value; + struct func_return_value return_value; acpi_status status; - struct lm_input_params params = { + struct func_input_params params = { .function_num = 0x1, .commun_devices = 0xFFFF, .devices = 0xFFFF, - .lm_status = 0x00, /* Launch Manager Deactive */ + .app_status = 0x00, /* Launch Manager Deactive */ + .app_mask = 0x01, }; - status = wmid3_set_lm_mode(¶ms, &return_value); + status = wmid3_set_function_mode(¶ms, &return_value); if (return_value.error_code || return_value.ec_return_value) pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n", @@ -1827,16 +1843,17 @@ static int __init acer_wmi_enable_ec_raw(void) static int __init acer_wmi_enable_lm(void) { - struct lm_return_value return_value; + struct func_return_value return_value; acpi_status status; - struct lm_input_params params = { + struct func_input_params params = { .function_num = 0x1, .commun_devices = 0xFFFF, .devices = 0xFFFF, - .lm_status = 0x01, /* Launch Manager Active */ + .app_status = 0x01, /* Launch Manager Active */ + .app_mask = 0x01, }; - status = wmid3_set_lm_mode(¶ms, &return_value); + status = wmid3_set_function_mode(¶ms, &return_value); if (return_value.error_code || return_value.ec_return_value) pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n", @@ -1846,6 +1863,28 @@ static int __init acer_wmi_enable_lm(void) return status; } +static int __init acer_wmi_enable_rf_button(void) +{ + struct func_return_value return_value; + acpi_status status; + struct func_input_params params = { + .function_num = 0x1, + .commun_devices = 0xFFFF, + .devices = 0xFFFF, + .app_status = 0x10, /* RF Button Active */ + .app_mask = 0x10, + }; + + status = wmid3_set_function_mode(¶ms, &return_value); + + if (return_value.error_code || return_value.ec_return_value) + pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n", + return_value.error_code, + return_value.ec_return_value); + + return status; +} + #define ACER_WMID_ACCEL_HID "BST0001" static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level, @@ -2229,6 +2268,9 @@ static int __init acer_wmi_init(void) interface->capability &= ~ACER_CAP_BRIGHTNESS; if (wmi_has_guid(WMID_GUID3)) { + if (ACPI_FAILURE(acer_wmi_enable_rf_button())) + pr_warn("Cannot enable RF Button Driver\n"); + if (ec_raw_mode) { if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { pr_err("Cannot enable EC raw mode\n"); -- cgit v1.2.3 From 5ffa572a431ff3fd6175419656603519fa471c27 Mon Sep 17 00:00:00 2001 From: Chris Chiu Date: Wed, 8 Feb 2017 07:51:41 -0600 Subject: platform/x86: acer-wmi: add another KEY_WLAN keycode Now that we have informed the firmware that the RF Button driver is active, laptops such as the Acer TravelMate P238-M will generate a WMI key event with code 0x86 when the Fn+F3 airplane mode key is pressed. Add this keycode to the table so that it is converted to an appropriate input event. Signed-off-by: Chris Chiu Signed-off-by: Daniel Drake Signed-off-by: Andy Shevchenko --- drivers/platform/x86/acer-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 4f633570531a..dac0fbe87460 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -128,6 +128,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = { {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} }, {KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} }, {KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} }, + {KE_KEY, 0x86, {KEY_WLAN} }, {KE_END, 0} }; -- cgit v1.2.3 From b8c5099b0027f013dad115b8d00f36f12cb13bb4 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 29 Jan 2017 14:42:52 +0100 Subject: leds: class: Add new optional brightness_hw_changed attribute Some LEDs may have their brightness level changed autonomously (outside of kernel control) by hardware / firmware. This commit adds support for an optional brightness_hw_changed attribute to signal such changes to userspace (if a driver can detect them): What: /sys/class/leds//brightness_hw_changed Date: January 2017 KernelVersion: 4.11 Description: Last hardware set brightness level for this LED. Some LEDs may be changed autonomously by hardware/firmware. Only LEDs where this happens and the driver can detect this, will have this file. This file supports poll() to detect when the hardware changes the brightness. Reading this file will return the last brightness level set by the hardware, this may be different from the current brightness. Drivers which want to support this, simply add LED_BRIGHT_HW_CHANGED to their flags field and call led_classdev_notify_brightness_hw_changed() with the hardware set brightness when they detect a hardware / firmware triggered brightness change. Signed-off-by: Hans de Goede Acked-by: Pavel Machek Signed-off-by: Jacek Anaszewski --- Documentation/ABI/testing/sysfs-class-led | 17 +++++++ Documentation/leds/leds-class.txt | 15 ++++++ drivers/leds/Kconfig | 9 ++++ drivers/leds/led-class.c | 76 +++++++++++++++++++++++++++++++ include/linux/leds.h | 15 ++++++ 5 files changed, 132 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led index 491cdeedc195..5f67f7ab277b 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -23,6 +23,23 @@ Description: If the LED does not support different brightness levels, this should be 1. +What: /sys/class/leds//brightness_hw_changed +Date: January 2017 +KernelVersion: 4.11 +Description: + Last hardware set brightness level for this LED. Some LEDs + may be changed autonomously by hardware/firmware. Only LEDs + where this happens and the driver can detect this, will have + this file. + + This file supports poll() to detect when the hardware changes + the brightness. + + Reading this file will return the last brightness level set + by the hardware, this may be different from the current + brightness. Reading this file when no hw brightness change + event has happened will return an ENODATA error. + What: /sys/class/leds//trigger Date: March 2006 KernelVersion: 2.6.17 diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt index f1f7ec9f5cc5..836cb16d6f09 100644 --- a/Documentation/leds/leds-class.txt +++ b/Documentation/leds/leds-class.txt @@ -65,6 +65,21 @@ LED subsystem core exposes following API for setting brightness: blinking, returns -EBUSY if software blink fallback is enabled. +LED registration API +==================== + +A driver wanting to register a LED classdev for use by other drivers / +userspace needs to allocate and fill a led_classdev struct and then call +[devm_]led_classdev_register. If the non devm version is used the driver +must call led_classdev_unregister from its remove function before +free-ing the led_classdev struct. + +If the driver can detect hardware initiated brightness changes and thus +wants to have a brightness_hw_changed attribute then the LED_BRIGHT_HW_CHANGED +flag must be set in flags before registering. Calling +led_classdev_notify_brightness_hw_changed on a classdev not registered with +the LED_BRIGHT_HW_CHANGED flag is a bug and will trigger a WARN_ON. + Hardware accelerated blink of LEDs ================================== diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c621cbbb5768..275f467956ee 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -29,6 +29,15 @@ config LEDS_CLASS_FLASH for the flash related features of a LED device. It can be built as a module. +config LEDS_BRIGHTNESS_HW_CHANGED + bool "LED Class brightness_hw_changed attribute support" + depends on LEDS_CLASS + help + This option enables support for the brightness_hw_changed attribute + for led sysfs class devices under /sys/class/leds. + + See Documentation/ABI/testing/sysfs-class-led for details. + comment "LED drivers" config LEDS_88PM860X diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 326ee6e925a2..f2b0a80a62b4 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -103,6 +103,68 @@ static const struct attribute_group *led_groups[] = { NULL, }; +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED +static ssize_t brightness_hw_changed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (led_cdev->brightness_hw_changed == -1) + return -ENODATA; + + return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed); +} + +static DEVICE_ATTR_RO(brightness_hw_changed); + +static int led_add_brightness_hw_changed(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev; + int ret; + + ret = device_create_file(dev, &dev_attr_brightness_hw_changed); + if (ret) { + dev_err(dev, "Error creating brightness_hw_changed\n"); + return ret; + } + + led_cdev->brightness_hw_changed_kn = + sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed"); + if (!led_cdev->brightness_hw_changed_kn) { + dev_err(dev, "Error getting brightness_hw_changed kn\n"); + device_remove_file(dev, &dev_attr_brightness_hw_changed); + return -ENXIO; + } + + return 0; +} + +static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev) +{ + sysfs_put(led_cdev->brightness_hw_changed_kn); + device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed); +} + +void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + if (WARN_ON(!led_cdev->brightness_hw_changed_kn)) + return; + + led_cdev->brightness_hw_changed = brightness; + sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn); +} +EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed); +#else +static int led_add_brightness_hw_changed(struct led_classdev *led_cdev) +{ + return 0; +} +static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev) +{ +} +#endif + /** * led_classdev_suspend - suspend an led_classdev. * @led_cdev: the led_classdev to suspend. @@ -204,9 +266,20 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) dev_warn(parent, "Led %s renamed to %s due to name collision", led_cdev->name, dev_name(led_cdev->dev)); + if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) { + ret = led_add_brightness_hw_changed(led_cdev); + if (ret) { + device_unregister(led_cdev->dev); + return ret; + } + } + led_cdev->work_flags = 0; #ifdef CONFIG_LEDS_TRIGGERS init_rwsem(&led_cdev->trigger_lock); +#endif +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED + led_cdev->brightness_hw_changed = -1; #endif mutex_init(&led_cdev->led_access); /* add to the list of leds */ @@ -256,6 +329,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev) flush_work(&led_cdev->set_brightness_work); + if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) + led_remove_brightness_hw_changed(led_cdev); + device_unregister(led_cdev->dev); down_write(&leds_list_lock); diff --git a/include/linux/leds.h b/include/linux/leds.h index 569cb531094c..c7711539888b 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -13,6 +13,7 @@ #define __LINUX_LEDS_H_INCLUDED #include +#include #include #include #include @@ -46,6 +47,7 @@ struct led_classdev { #define LED_DEV_CAP_FLASH (1 << 18) #define LED_HW_PLUGGABLE (1 << 19) #define LED_PANIC_INDICATOR (1 << 20) +#define LED_BRIGHT_HW_CHANGED (1 << 21) /* set_brightness_work / blink_timer flags, atomic, private. */ unsigned long work_flags; @@ -110,6 +112,11 @@ struct led_classdev { bool activated; #endif +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED + int brightness_hw_changed; + struct kernfs_node *brightness_hw_changed_kn; +#endif + /* Ensures consistent access to the LED Flash Class device */ struct mutex led_access; }; @@ -422,4 +429,12 @@ static inline void ledtrig_cpu(enum cpu_led_event evt) } #endif +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED +extern void led_classdev_notify_brightness_hw_changed( + struct led_classdev *led_cdev, enum led_brightness brightness); +#else +static inline void led_classdev_notify_brightness_hw_changed( + struct led_classdev *led_cdev, enum led_brightness brightness) { } +#endif + #endif /* __LINUX_LEDS_H_INCLUDED */ -- cgit v1.2.3 From 06da5325d02ed3e9be9fbc7d0d621a04efc96961 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Feb 2017 16:44:11 +0100 Subject: platform/x86: thinkpad_acpi: Stop setting led_classdev brightness directly There is no need to set the led_classdev's brightness value from its set_brightness callback, this is taken care of by the led-core and thinkpad_acpi really should not be mucking with it. Note that kbdlight_set_level_and_update() is still used by the old thinpad_acpi specific sysfs interface for the led, so we cannot remove it. Signed-off-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko Acked-by: Pavel Machek --- drivers/platform/x86/thinkpad_acpi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cacb43fb1df7..0680bb395204 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -5095,8 +5095,6 @@ static int kbdlight_set_level(int level) return 0; } -static int kbdlight_set_level_and_update(int level); - static int kbdlight_get_level(void) { int status = 0; @@ -5164,7 +5162,7 @@ static void kbdlight_set_worker(struct work_struct *work) container_of(work, struct tpacpi_led_classdev, work); if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) - kbdlight_set_level_and_update(data->new_state); + kbdlight_set_level(data->new_state); } static void kbdlight_sysfs_set(struct led_classdev *led_cdev, -- cgit v1.2.3 From 86ec0c2c0b527dc1574e5e95436bec5499102a3d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Feb 2017 16:44:12 +0100 Subject: platform/x86: thinkpad_acpi: Use brightness_set_blocking callback for LEDs Now a days the LED core can take care of executing brightness_set from a workqueue if it needs to sleep, make use of this and remove a bunch of DIY code for this. Since this commit removes the workqueue usage for LEDs, the led_sysfs_blink_set callback may now also sleep, this is fine. Signed-off-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko Acked-by: Pavel Machek --- drivers/platform/x86/thinkpad_acpi.c | 80 ++++++++---------------------------- 1 file changed, 16 insertions(+), 64 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 0680bb395204..f51833f79297 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -372,11 +372,9 @@ enum led_status_t { TPACPI_LED_BLINK, }; -/* Special LED class that can defer work */ +/* tpacpi LED class */ struct tpacpi_led_classdev { struct led_classdev led_classdev; - struct work_struct work; - enum led_status_t new_state; int led; }; @@ -5156,24 +5154,10 @@ static bool kbdlight_is_supported(void) return status & BIT(9); } -static void kbdlight_set_worker(struct work_struct *work) -{ - struct tpacpi_led_classdev *data = - container_of(work, struct tpacpi_led_classdev, work); - - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) - kbdlight_set_level(data->new_state); -} - -static void kbdlight_sysfs_set(struct led_classdev *led_cdev, +static int kbdlight_sysfs_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct tpacpi_led_classdev *data = - container_of(led_cdev, - struct tpacpi_led_classdev, - led_classdev); - data->new_state = brightness; - queue_work(tpacpi_wq, &data->work); + return kbdlight_set_level(brightness); } static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev) @@ -5191,7 +5175,7 @@ static struct tpacpi_led_classdev tpacpi_led_kbdlight = { .led_classdev = { .name = "tpacpi::kbd_backlight", .max_brightness = 2, - .brightness_set = &kbdlight_sysfs_set, + .brightness_set_blocking = &kbdlight_sysfs_set, .brightness_get = &kbdlight_sysfs_get, } }; @@ -5203,7 +5187,6 @@ static int __init kbdlight_init(struct ibm_init_struct *iibm) vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n"); TPACPI_ACPIHANDLE_INIT(hkey); - INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker); if (!kbdlight_is_supported()) { tp_features.kbdlight = 0; @@ -5227,7 +5210,6 @@ static void kbdlight_exit(void) { if (tp_features.kbdlight) led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev); - flush_workqueue(tpacpi_wq); } static int kbdlight_set_level_and_update(int level) @@ -5356,25 +5338,11 @@ static int light_set_status(int status) return -ENXIO; } -static void light_set_status_worker(struct work_struct *work) -{ - struct tpacpi_led_classdev *data = - container_of(work, struct tpacpi_led_classdev, work); - - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) - light_set_status((data->new_state != TPACPI_LED_OFF)); -} - -static void light_sysfs_set(struct led_classdev *led_cdev, +static int light_sysfs_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct tpacpi_led_classdev *data = - container_of(led_cdev, - struct tpacpi_led_classdev, - led_classdev); - data->new_state = (brightness != LED_OFF) ? - TPACPI_LED_ON : TPACPI_LED_OFF; - queue_work(tpacpi_wq, &data->work); + return light_set_status((brightness != LED_OFF) ? + TPACPI_LED_ON : TPACPI_LED_OFF); } static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) @@ -5385,7 +5353,7 @@ static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev) static struct tpacpi_led_classdev tpacpi_led_thinklight = { .led_classdev = { .name = "tpacpi::thinklight", - .brightness_set = &light_sysfs_set, + .brightness_set_blocking = &light_sysfs_set, .brightness_get = &light_sysfs_get, } }; @@ -5401,7 +5369,6 @@ static int __init light_init(struct ibm_init_struct *iibm) TPACPI_ACPIHANDLE_INIT(lght); } TPACPI_ACPIHANDLE_INIT(cmos); - INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker); /* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */ tp_features.light = (cmos_handle || lght_handle) && !ledb_handle; @@ -5435,7 +5402,6 @@ static int __init light_init(struct ibm_init_struct *iibm) static void light_exit(void) { led_classdev_unregister(&tpacpi_led_thinklight.led_classdev); - flush_workqueue(tpacpi_wq); } static int light_read(struct seq_file *m) @@ -5702,29 +5668,21 @@ static int led_set_status(const unsigned int led, return rc; } -static void led_set_status_worker(struct work_struct *work) -{ - struct tpacpi_led_classdev *data = - container_of(work, struct tpacpi_led_classdev, work); - - if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) - led_set_status(data->led, data->new_state); -} - -static void led_sysfs_set(struct led_classdev *led_cdev, +static int led_sysfs_set(struct led_classdev *led_cdev, enum led_brightness brightness) { struct tpacpi_led_classdev *data = container_of(led_cdev, struct tpacpi_led_classdev, led_classdev); + enum led_status_t new_state; if (brightness == LED_OFF) - data->new_state = TPACPI_LED_OFF; + new_state = TPACPI_LED_OFF; else if (tpacpi_led_state_cache[data->led] != TPACPI_LED_BLINK) - data->new_state = TPACPI_LED_ON; + new_state = TPACPI_LED_ON; else - data->new_state = TPACPI_LED_BLINK; + new_state = TPACPI_LED_BLINK; - queue_work(tpacpi_wq, &data->work); + return led_set_status(data->led, new_state); } static int led_sysfs_blink_set(struct led_classdev *led_cdev, @@ -5741,10 +5699,7 @@ static int led_sysfs_blink_set(struct led_classdev *led_cdev, } else if ((*delay_on != 500) || (*delay_off != 500)) return -EINVAL; - data->new_state = TPACPI_LED_BLINK; - queue_work(tpacpi_wq, &data->work); - - return 0; + return led_set_status(data->led, TPACPI_LED_BLINK); } static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev) @@ -5773,7 +5728,6 @@ static void led_exit(void) led_classdev_unregister(&tpacpi_leds[i].led_classdev); } - flush_workqueue(tpacpi_wq); kfree(tpacpi_leds); } @@ -5787,7 +5741,7 @@ static int __init tpacpi_init_led(unsigned int led) if (!tpacpi_led_names[led]) return 0; - tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; + tpacpi_leds[led].led_classdev.brightness_set_blocking = &led_sysfs_set; tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; if (led_supported == TPACPI_LED_570) tpacpi_leds[led].led_classdev.brightness_get = @@ -5795,8 +5749,6 @@ static int __init tpacpi_init_led(unsigned int led) tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; - INIT_WORK(&tpacpi_leds[led].work, led_set_status_worker); - rc = led_classdev_register(&tpacpi_pdev->dev, &tpacpi_leds[led].led_classdev); if (rc < 0) -- cgit v1.2.3 From c685e20df5cfa11cee0954be70456872c4f670f0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 9 Feb 2017 16:44:13 +0100 Subject: platform/x86: thinkpad_acpi: Call led_classdev_notify_brightness_hw_changed on kbd brightness change Make thinkpad_acpi call led_classdev_notify_brightness_hw_changed on the kbd_led led_classdev registered by thinkpad_acpi when the kbd backlight brightness is changed through the hotkey. This will allow userspace to monitor (poll) for brightness changes on these LEDs caused by the hotkey. Signed-off-by: Hans de Goede Acked-by: Henrique de Moraes Holschuh Signed-off-by: Andy Shevchenko Acked-by: Pavel Machek --- drivers/platform/x86/thinkpad_acpi.c | 42 ++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f51833f79297..1d18b32628ec 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -163,6 +163,7 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_HOTKEY_BASE = 0x1001, /* first hotkey (FN+F1) */ TP_HKEY_EV_BRGHT_UP = 0x1010, /* Brightness up */ TP_HKEY_EV_BRGHT_DOWN = 0x1011, /* Brightness down */ + TP_HKEY_EV_KBD_LIGHT = 0x1012, /* Thinklight/kbd backlight */ TP_HKEY_EV_VOL_UP = 0x1015, /* Volume up or unmute */ TP_HKEY_EV_VOL_DOWN = 0x1016, /* Volume down or unmute */ TP_HKEY_EV_VOL_MUTE = 0x1017, /* Mixer output mute */ @@ -1957,7 +1958,7 @@ enum { /* Positions of some of the keys in hotkey masks */ TP_ACPI_HKEY_HIBERNATE_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNF12, TP_ACPI_HKEY_BRGHTUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNHOME, TP_ACPI_HKEY_BRGHTDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNEND, - TP_ACPI_HKEY_THNKLGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, + TP_ACPI_HKEY_KBD_LIGHT_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNPAGEUP, TP_ACPI_HKEY_ZOOM_MASK = 1 << TP_ACPI_HOTKEYSCAN_FNSPACE, TP_ACPI_HKEY_VOLUP_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEUP, TP_ACPI_HKEY_VOLDWN_MASK = 1 << TP_ACPI_HOTKEYSCAN_VOLUMEDOWN, @@ -2342,7 +2343,7 @@ static void hotkey_read_nvram(struct tp_nvram_state *n, const u32 m) n->display_toggle = !!(d & TP_NVRAM_MASK_HKT_DISPLAY); n->hibernate_toggle = !!(d & TP_NVRAM_MASK_HKT_HIBERNATE); } - if (m & TP_ACPI_HKEY_THNKLGHT_MASK) { + if (m & TP_ACPI_HKEY_KBD_LIGHT_MASK) { d = nvram_read_byte(TP_NVRAM_ADDR_THINKLIGHT); n->thinklight_toggle = !!(d & TP_NVRAM_MASK_THINKLIGHT); } @@ -5082,15 +5083,26 @@ static struct ibm_struct video_driver_data = { * Keyboard backlight subdriver */ +static enum led_brightness kbdlight_brightness; +static DEFINE_MUTEX(kbdlight_mutex); + static int kbdlight_set_level(int level) { + int ret = 0; + if (!hkey_handle) return -ENXIO; + mutex_lock(&kbdlight_mutex); + if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level)) - return -EIO; + ret = -EIO; + else + kbdlight_brightness = level; - return 0; + mutex_unlock(&kbdlight_mutex); + + return ret; } static int kbdlight_get_level(void) @@ -5175,6 +5187,7 @@ static struct tpacpi_led_classdev tpacpi_led_kbdlight = { .led_classdev = { .name = "tpacpi::kbd_backlight", .max_brightness = 2, + .flags = LED_BRIGHT_HW_CHANGED, .brightness_set_blocking = &kbdlight_sysfs_set, .brightness_get = &kbdlight_sysfs_get, } @@ -5194,6 +5207,7 @@ static int __init kbdlight_init(struct ibm_init_struct *iibm) return 1; } + kbdlight_brightness = kbdlight_sysfs_get(NULL); tp_features.kbdlight = 1; rc = led_classdev_register(&tpacpi_pdev->dev, @@ -5203,6 +5217,8 @@ static int __init kbdlight_init(struct ibm_init_struct *iibm) return rc; } + tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | + TP_ACPI_HKEY_KBD_LIGHT_MASK); return 0; } @@ -9119,6 +9135,24 @@ static void tpacpi_driver_event(const unsigned int hkey_event) volume_alsa_notify_change(); } } + if (tp_features.kbdlight && hkey_event == TP_HKEY_EV_KBD_LIGHT) { + enum led_brightness brightness; + + mutex_lock(&kbdlight_mutex); + + /* + * Check the brightness actually changed, setting the brightness + * through kbdlight_set_level() also triggers this event. + */ + brightness = kbdlight_sysfs_get(NULL); + if (kbdlight_brightness != brightness) { + kbdlight_brightness = brightness; + led_classdev_notify_brightness_hw_changed( + &tpacpi_led_kbdlight.led_classdev, brightness); + } + + mutex_unlock(&kbdlight_mutex); + } } static void hotkey_driver_event(const unsigned int scancode) -- cgit v1.2.3 From bd5762a0c1c9ae66bd0ece6959bbc5013ab95dcd Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Tue, 14 Feb 2017 15:20:34 +0800 Subject: platform/x86: intel-hid: Support 5 button array MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New firmwares include a feature called 5 button array that supports super key, volume up/down, rotation lock and power button. Support for this feature is required to fix power button on some recent systems. This patch was tested on a Dell Latitude 7480. Signed-off-by: Alex Hung Reviewed-by: Michał Kępień Signed-off-by: Darren Hart --- drivers/platform/x86/intel-hid.c | 96 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 5 deletions(-) diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index cb3ab2b212b1..bcf438f38781 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -1,5 +1,5 @@ /* - * Intel HID event driver for Windows 8 + * Intel HID event & 5 button array driver * * Copyright (C) 2015 Alex Hung * Copyright (C) 2015 Andrew Lutomirski @@ -57,8 +57,24 @@ static const struct key_entry intel_hid_keymap[] = { { KE_END }, }; +/* 5 button array notification value. */ +static const struct key_entry intel_array_keymap[] = { + { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* Press */ + { KE_IGNORE, 0xC3, { KEY_LEFTMETA } }, /* Release */ + { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* Press */ + { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* Release */ + { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* Press */ + { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* Release */ + { KE_SW, 0xC8, { .sw = { SW_ROTATE_LOCK, 1 } } }, /* Press */ + { KE_SW, 0xC9, { .sw = { SW_ROTATE_LOCK, 0 } } }, /* Release */ + { KE_KEY, 0xCE, { KEY_POWER } }, /* Press */ + { KE_IGNORE, 0xCF, { KEY_POWER } }, /* Release */ + { KE_END }, +}; + struct intel_hid_priv { struct input_dev *input_dev; + struct input_dev *array; }; static int intel_hid_set_enable(struct device *device, int enable) @@ -78,15 +94,43 @@ static int intel_hid_set_enable(struct device *device, int enable) return 0; } +static void intel_button_array_enable(struct device *device, bool enable) +{ + struct intel_hid_priv *priv = dev_get_drvdata(device); + acpi_handle handle = ACPI_HANDLE(device); + unsigned long long button_cap; + acpi_status status; + + if (!priv->array) + return; + + /* Query supported platform features */ + status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap); + if (ACPI_FAILURE(status)) { + dev_warn(device, "failed to get button capability\n"); + return; + } + + /* Enable|disable features - power button is always enabled */ + status = acpi_execute_simple_method(handle, "BTNE", + enable ? button_cap : 1); + if (ACPI_FAILURE(status)) + dev_warn(device, "failed to set button capability\n"); +} + static int intel_hid_pl_suspend_handler(struct device *device) { intel_hid_set_enable(device, 0); + intel_button_array_enable(device, false); + return 0; } static int intel_hid_pl_resume_handler(struct device *device) { intel_hid_set_enable(device, 1); + intel_button_array_enable(device, true); + return 0; } @@ -126,6 +170,27 @@ err_free_device: return ret; } +static int intel_button_array_input_setup(struct platform_device *device) +{ + struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); + int ret; + + /* Setup input device for 5 button array */ + priv->array = devm_input_allocate_device(&device->dev); + if (!priv->array) + return -ENOMEM; + + ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL); + if (ret) + return ret; + + priv->array->dev.parent = &device->dev; + priv->array->name = "Intel HID 5 button array"; + priv->array->id.bustype = BUS_HOST; + + return input_register_device(priv->array); +} + static void intel_hid_input_destroy(struct platform_device *device) { struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); @@ -140,10 +205,11 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) unsigned long long ev_index; acpi_status status; - /* The platform spec only defines one event code: 0xC0. */ + /* 0xC0 is for HID events, other values are for 5 button array */ if (event != 0xc0) { - dev_warn(&device->dev, "received unknown event (0x%x)\n", - event); + if (!priv->array || + !sparse_keymap_report_event(priv->array, event, 1, true)) + dev_info(&device->dev, "unknown event 0x%x\n", event); return; } @@ -161,8 +227,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) static int intel_hid_probe(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); + unsigned long long event_cap, mode; struct intel_hid_priv *priv; - unsigned long long mode; acpi_status status; int err; @@ -193,6 +259,15 @@ static int intel_hid_probe(struct platform_device *device) return err; } + /* Setup 5 button array */ + status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); + if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) { + dev_info(&device->dev, "platform supports 5 button array\n"); + err = intel_button_array_input_setup(device); + if (err) + pr_err("Failed to setup Intel 5 button array hotkeys\n"); + } + status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler, @@ -206,6 +281,16 @@ static int intel_hid_probe(struct platform_device *device) if (err) goto err_remove_notify; + if (priv->array) { + intel_button_array_enable(&device->dev, true); + + /* Call button load method to enable HID power button */ + status = acpi_evaluate_object(handle, "BTNL", NULL, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&device->dev, + "failed to enable HID power button\n"); + } + return 0; err_remove_notify: @@ -224,6 +309,7 @@ static int intel_hid_remove(struct platform_device *device) acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); intel_hid_input_destroy(device); intel_hid_set_enable(&device->dev, 0); + intel_button_array_enable(&device->dev, false); /* * Even if we failed to shut off the event stream, we can still -- cgit v1.2.3 From 8d2c4538dbc7154c4aed1364db127a0e51dbd459 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 16 Feb 2017 20:58:03 +0800 Subject: platform/x86: dell-laptop: Add Latitude 7480 and others to the DMI whitelist MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to support Latitude 7480 and many other newer Dell laptops. Signed-off-by: Alex Hung Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 14392a01ab36..f57dd282a002 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -105,6 +105,12 @@ static const struct dmi_system_id dell_device_table[] __initconst = { DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/ }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/ + }, + }, { .ident = "Dell Computer Corporation", .matches = { -- cgit v1.2.3 From af050abb5c2e5e7d3e1368475d63cbac597dc34f Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 13 Feb 2017 19:37:00 -0500 Subject: platform/x86: intel_turbo_max_3: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/platform/x86/Kconfig:config INTEL_TURBO_MAX_3 drivers/platform/x86/Kconfig: bool "Intel Turbo Boost Max Technology 3.0 enumeration driver" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. We do uncover some implicit includes during build coverage that were hidden behind the module.h which pulls in a lot of dependants. Cc: Andy Shevchenko Cc: Srinivas Pandruvada Cc: platform-driver-x86@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Darren Hart --- drivers/platform/x86/intel_turbo_max_3.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/intel_turbo_max_3.c b/drivers/platform/x86/intel_turbo_max_3.c index 0103f5b32e34..4f60d8e32a0a 100644 --- a/drivers/platform/x86/intel_turbo_max_3.c +++ b/drivers/platform/x86/intel_turbo_max_3.c @@ -3,6 +3,8 @@ * Copyright (c) 2017, Intel Corporation. * All rights reserved. * + * Author: Srinivas Pandruvada + * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. @@ -16,7 +18,9 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include +#include +#include +#include #include #include #include @@ -123,7 +127,6 @@ static const struct x86_cpu_id itmt_legacy_cpu_ids[] = { ICPU(INTEL_FAM6_BROADWELL_X), {} }; -MODULE_DEVICE_TABLE(x86cpu, itmt_legacy_cpu_ids); static int __init itmt_legacy_init(void) { @@ -146,7 +149,3 @@ static int __init itmt_legacy_init(void) return 0; } late_initcall(itmt_legacy_init) - -MODULE_DESCRIPTION("Intel Turbo Boost Max 3.0 enumeration driver"); -MODULE_AUTHOR("Srinivas Pandruvada "); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3