aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 16:31:25 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-15 16:31:25 -0500
commite18bf801f1501e15830db5fa927a6e2832d49d7b (patch)
tree6880011bae0d372770c43fdbb7bcedf959d6d868
parent8600b697cd4787ac3ce053d48ca7301836fd0c55 (diff)
parentcb2bf25145e0d2abef20f47dd2ae55bff97fd9cb (diff)
Merge tag 'platform-drivers-x86-v4.10-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darrent Hart: "Introduce one new driver for Mellanox platforms. Add support for various new models to existing drivers via quirks, hotkeys, etc. Significant updates to intel_pmc_core in support of Kabylake and Sunrise Point PCH power management debug. Some cleanup and refactoring across various drivers. Detailed summary: dell-laptop: - Use brightness_set_blocking for kbd_led_level_set thinkpad_acpi: - Initialize local in_tablet_mode and type - Fix old style declaration GCC warning - Adding new hotkey ID for Lenovo thinkpad - Add support for X1 Yoga (2016) Tablet Mode - Move tablet detection into separate function asus-nb-wmi: - Add X45U quirk - Make use of dmi->ident asus-wmi: - Set specified XUSB2PR value for X550LB intel_mid_thermal: - Fix suspend handlers unused warning intel-vbtn: - Switch to use devm_input_allocate_device dell-wmi: - Add events created by Dell Rugged 2-in-1s - Adjust wifi catcher to emit KEY_WLAN intel_pmc_core: - Add KBL CPUID support - Add LTR IGNORE debug feature - Add MPHY PLL clock gating status - ModPhy core lanes pg status - Add PCH IP Power Gating Status - Fix PWRMBASE mask and mmio reg len acer-wmi: - Only supports AMW0_GUID1 on acer family mlx-platform: - Introduce support for Mellanox hotplug driver platform/x86: - Use ACPI_FAILURE at appropriate places" * tag 'platform-drivers-x86-v4.10-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (22 commits) platform/x86: thinkpad_acpi: Initialize local in_tablet_mode and type platform/x86: dell-laptop: Use brightness_set_blocking for kbd_led_level_set platform/x86: thinkpad_acpi: Fix old style declaration GCC warning platform/x86: thinkpad_acpi: Adding new hotkey ID for Lenovo thinkpad platform/x86: thinkpad_acpi: Add support for X1 Yoga (2016) Tablet Mode platform/x86: thinkpad_acpi: Move tablet detection into separate function platform/x86: asus-nb-wmi.c: Add X45U quirk platform/x86: asus-nb-wmi: Make use of dmi->ident platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB platform/x86: intel_mid_thermal: Fix suspend handlers unused warning platform/x86: intel-vbtn: Switch to use devm_input_allocate_device platform/x86: Use ACPI_FAILURE at appropriate places platform/x86: dell-wmi: Add events created by Dell Rugged 2-in-1s platform/x86: dell-wmi: Adjust wifi catcher to emit KEY_WLAN platform/x86: intel_pmc_core: Add KBL CPUID support platform/x86: intel_pmc_core: Add LTR IGNORE debug feature platform/x86: intel_pmc_core: Add MPHY PLL clock gating status platform/x86: intel_pmc_core: ModPhy core lanes pg status platform/x86: intel_pmc_core: Add PCH IP Power Gating Status platform/x86: intel_pmc_core: Fix PWRMBASE mask and mmio reg len ...
-rw-r--r--Documentation/laptops/thinkpad-acpi.txt1
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/platform/x86/Kconfig11
-rw-r--r--drivers/platform/x86/Makefile1
-rw-r--r--drivers/platform/x86/acer-wmi.c56
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c23
-rw-r--r--drivers/platform/x86/asus-wmi.c29
-rw-r--r--drivers/platform/x86/asus-wmi.h1
-rw-r--r--drivers/platform/x86/dell-laptop.c26
-rw-r--r--drivers/platform/x86/dell-wmi.c12
-rw-r--r--drivers/platform/x86/intel-hid.c6
-rw-r--r--drivers/platform/x86/intel-smartconnect.c2
-rw-r--r--drivers/platform/x86/intel-vbtn.c35
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c2
-rw-r--r--drivers/platform/x86/intel_pmc_core.c386
-rw-r--r--drivers/platform/x86/intel_pmc_core.h110
-rw-r--r--drivers/platform/x86/mlxcpld-hotplug.c515
-rw-r--r--drivers/platform/x86/panasonic-laptop.c2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c95
-rw-r--r--include/linux/platform_data/mlxcpld-hotplug.h99
20 files changed, 1346 insertions, 73 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 72a150d8f3df..ba2e7d254842 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -540,6 +540,7 @@ Events that are propagated by the driver to userspace:
5400x6022 ALARM: a sensor is extremely hot 5400x6022 ALARM: a sensor is extremely hot
5410x6030 System thermal table changed 5410x6030 System thermal table changed
5420x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED) 5420x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED)
5430x60C0 X1 Yoga 2016, Tablet mode status changed
543 544
544Battery nearly empty alarms are a last resort attempt to get the 545Battery nearly empty alarms are a last resort attempt to get the
545operating system to hibernate or shutdown cleanly (0x2313), or shutdown 546operating system to hibernate or shutdown cleanly (0x2313), or shutdown
diff --git a/MAINTAINERS b/MAINTAINERS
index 86f9583393ba..9d73040b846d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8045,6 +8045,13 @@ L: platform-driver-x86@vger.kernel.org
8045S: Supported 8045S: Supported
8046F: arch/x86/platform/mellanox/mlx-platform.c 8046F: arch/x86/platform/mellanox/mlx-platform.c
8047 8047
8048MELLANOX MLX CPLD HOTPLUG DRIVER
8049M: Vadim Pasternak <vadimp@mellanox.com>
8050L: platform-driver-x86@vger.kernel.org
8051S: Supported
8052F: drivers/platform/x86/mlxcpld-hotplug.c
8053F: include/linux/platform_data/mlxcpld-hotplug.h
8054
8048SOFT-ROCE DRIVER (rxe) 8055SOFT-ROCE DRIVER (rxe)
8049M: Moni Shoua <monis@mellanox.com> 8056M: Moni Shoua <monis@mellanox.com>
8050L: linux-rdma@vger.kernel.org 8057L: linux-rdma@vger.kernel.org
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index b8a21d7b25d4..185376901d9c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1027,4 +1027,15 @@ config INTEL_TELEMETRY
1027 used to get various SoC events and parameters 1027 used to get various SoC events and parameters
1028 directly via debugfs files. Various tools may use 1028 directly via debugfs files. Various tools may use
1029 this interface for SoC state monitoring. 1029 this interface for SoC state monitoring.
1030
1031config MLX_CPLD_PLATFORM
1032 tristate "Mellanox platform hotplug driver support"
1033 default n
1034 depends on MLX_PLATFORM
1035 select HWMON
1036 select I2C
1037 ---help---
1038 This driver handles hot-plug events for the power suppliers, power
1039 cables and fans on the wide range Mellanox IB and Ethernet systems.
1040
1030endif # X86_PLATFORM_DEVICES 1041endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 2efa86d2a1a7..1f06b6339cf7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -71,3 +71,4 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
71 intel_telemetry_pltdrv.o \ 71 intel_telemetry_pltdrv.o \
72 intel_telemetry_debugfs.o 72 intel_telemetry_debugfs.o
73obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o 73obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
74obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 79d64ea00bfb..a66192f692e3 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -355,6 +355,32 @@ static const struct dmi_system_id acer_blacklist[] __initconst = {
355 {} 355 {}
356}; 356};
357 357
358static const struct dmi_system_id amw0_whitelist[] __initconst = {
359 {
360 .ident = "Acer",
361 .matches = {
362 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
363 },
364 },
365 {
366 .ident = "Gateway",
367 .matches = {
368 DMI_MATCH(DMI_SYS_VENDOR, "Gateway"),
369 },
370 },
371 {
372 .ident = "Packard Bell",
373 .matches = {
374 DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"),
375 },
376 },
377 {}
378};
379
380/*
381 * This quirk table is only for Acer/Gateway/Packard Bell family
382 * that those machines are supported by acer-wmi driver.
383 */
358static const struct dmi_system_id acer_quirks[] __initconst = { 384static const struct dmi_system_id acer_quirks[] __initconst = {
359 { 385 {
360 .callback = dmi_matched, 386 .callback = dmi_matched,
@@ -464,6 +490,17 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
464 }, 490 },
465 .driver_data = &quirk_acer_travelmate_2490, 491 .driver_data = &quirk_acer_travelmate_2490,
466 }, 492 },
493 {}
494};
495
496/*
497 * This quirk list is for those non-acer machines that have AMW0_GUID1
498 * but supported by acer-wmi in past days. Keeping this quirk list here
499 * is only for backward compatible. Please do not add new machine to
500 * here anymore. Those non-acer machines should be supported by
501 * appropriate wmi drivers.
502 */
503static const struct dmi_system_id non_acer_quirks[] __initconst = {
467 { 504 {
468 .callback = dmi_matched, 505 .callback = dmi_matched,
469 .ident = "Fujitsu Siemens Amilo Li 1718", 506 .ident = "Fujitsu Siemens Amilo Li 1718",
@@ -598,6 +635,7 @@ static void __init find_quirks(void)
598{ 635{
599 if (!force_series) { 636 if (!force_series) {
600 dmi_check_system(acer_quirks); 637 dmi_check_system(acer_quirks);
638 dmi_check_system(non_acer_quirks);
601 } else if (force_series == 2490) { 639 } else if (force_series == 2490) {
602 quirks = &quirk_acer_travelmate_2490; 640 quirks = &quirk_acer_travelmate_2490;
603 } 641 }
@@ -2108,6 +2146,24 @@ static int __init acer_wmi_init(void)
2108 find_quirks(); 2146 find_quirks();
2109 2147
2110 /* 2148 /*
2149 * The AMW0_GUID1 wmi is not only found on Acer family but also other
2150 * machines like Lenovo, Fujitsu and Medion. In the past days,
2151 * acer-wmi driver handled those non-Acer machines by quirks list.
2152 * But actually acer-wmi driver was loaded on any machines that have
2153 * AMW0_GUID1. This behavior is strange because those machines should
2154 * be supported by appropriate wmi drivers. e.g. fujitsu-laptop,
2155 * ideapad-laptop. So, here checks the machine that has AMW0_GUID1
2156 * should be in Acer/Gateway/Packard Bell white list, or it's already
2157 * in the past quirk list.
2158 */
2159 if (wmi_has_guid(AMW0_GUID1) &&
2160 !dmi_check_system(amw0_whitelist) &&
2161 quirks == &quirk_unknown) {
2162 pr_err("Unsupported machine has AMW0_GUID1, unable to load\n");
2163 return -ENODEV;
2164 }
2165
2166 /*
2111 * Detect which ACPI-WMI interface we're using. 2167 * Detect which ACPI-WMI interface we're using.
2112 */ 2168 */
2113 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1)) 2169 if (wmi_has_guid(AMW0_GUID1) && wmi_has_guid(WMID_GUID1))
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 26e4cbc34db8..5be4783e40d4 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -116,8 +116,13 @@ static struct quirk_entry quirk_asus_ux303ub = {
116 .wmi_backlight_native = true, 116 .wmi_backlight_native = true,
117}; 117};
118 118
119static struct quirk_entry quirk_asus_x550lb = {
120 .xusb2pr = 0x01D9,
121};
122
119static int dmi_matched(const struct dmi_system_id *dmi) 123static int dmi_matched(const struct dmi_system_id *dmi)
120{ 124{
125 pr_info("Identified laptop model '%s'\n", dmi->ident);
121 quirks = dmi->driver_data; 126 quirks = dmi->driver_data;
122 return 1; 127 return 1;
123} 128}
@@ -175,6 +180,15 @@ static const struct dmi_system_id asus_quirks[] = {
175 }, 180 },
176 { 181 {
177 .callback = dmi_matched, 182 .callback = dmi_matched,
183 .ident = "ASUSTeK COMPUTER INC. X45U",
184 .matches = {
185 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
186 DMI_MATCH(DMI_PRODUCT_NAME, "X45U"),
187 },
188 .driver_data = &quirk_asus_wapf4,
189 },
190 {
191 .callback = dmi_matched,
178 .ident = "ASUSTeK COMPUTER INC. X456UA", 192 .ident = "ASUSTeK COMPUTER INC. X456UA",
179 .matches = { 193 .matches = {
180 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 194 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
@@ -398,6 +412,15 @@ static const struct dmi_system_id asus_quirks[] = {
398 }, 412 },
399 .driver_data = &quirk_asus_ux303ub, 413 .driver_data = &quirk_asus_ux303ub,
400 }, 414 },
415 {
416 .callback = dmi_matched,
417 .ident = "ASUSTeK COMPUTER INC. X550LB",
418 .matches = {
419 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
420 DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"),
421 },
422 .driver_data = &quirk_asus_x550lb,
423 },
401 {}, 424 {},
402}; 425};
403 426
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index ce6ca31a2d09..43cb680adbb4 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -156,6 +156,9 @@ MODULE_LICENSE("GPL");
156#define ASUS_FAN_CTRL_MANUAL 1 156#define ASUS_FAN_CTRL_MANUAL 1
157#define ASUS_FAN_CTRL_AUTO 2 157#define ASUS_FAN_CTRL_AUTO 2
158 158
159#define USB_INTEL_XUSB2PR 0xD0
160#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
161
159struct bios_args { 162struct bios_args {
160 u32 arg0; 163 u32 arg0;
161 u32 arg1; 164 u32 arg1;
@@ -1080,6 +1083,29 @@ exit:
1080 return result; 1083 return result;
1081} 1084}
1082 1085
1086static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
1087{
1088 struct pci_dev *xhci_pdev;
1089 u32 orig_ports_available;
1090 u32 ports_available = asus->driver->quirks->xusb2pr;
1091
1092 xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
1093 PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI,
1094 NULL);
1095
1096 if (!xhci_pdev)
1097 return;
1098
1099 pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
1100 &orig_ports_available);
1101
1102 pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
1103 cpu_to_le32(ports_available));
1104
1105 pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
1106 orig_ports_available, ports_available);
1107}
1108
1083/* 1109/*
1084 * Hwmon device 1110 * Hwmon device
1085 */ 1111 */
@@ -2087,6 +2113,9 @@ static int asus_wmi_add(struct platform_device *pdev)
2087 if (asus->driver->quirks->wmi_backlight_native) 2113 if (asus->driver->quirks->wmi_backlight_native)
2088 acpi_video_set_dmi_backlight_type(acpi_backlight_native); 2114 acpi_video_set_dmi_backlight_type(acpi_backlight_native);
2089 2115
2116 if (asus->driver->quirks->xusb2pr)
2117 asus_wmi_set_xusb2pr(asus);
2118
2090 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 2119 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
2091 err = asus_wmi_backlight_init(asus); 2120 err = asus_wmi_backlight_init(asus);
2092 if (err && err != -ENODEV) 2121 if (err && err != -ENODEV)
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 0e19014e9f54..fdff626c3b51 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -53,6 +53,7 @@ struct quirk_entry {
53 * and let the ACPI interrupt to send out the key event. 53 * and let the ACPI interrupt to send out the key event.
54 */ 54 */
55 int no_display_toggle; 55 int no_display_toggle;
56 u32 xusb2pr;
56 57
57 bool (*i8042_filter)(unsigned char data, unsigned char str, 58 bool (*i8042_filter)(unsigned char data, unsigned char str,
58 struct serio *serio); 59 struct serio *serio);
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 2c2f02b2e08a..14392a01ab36 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -1904,38 +1904,40 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev)
1904 return 0; 1904 return 0;
1905} 1905}
1906 1906
1907static void kbd_led_level_set(struct led_classdev *led_cdev, 1907static int kbd_led_level_set(struct led_classdev *led_cdev,
1908 enum led_brightness value) 1908 enum led_brightness value)
1909{ 1909{
1910 struct kbd_state state; 1910 struct kbd_state state;
1911 struct kbd_state new_state; 1911 struct kbd_state new_state;
1912 u16 num; 1912 u16 num;
1913 int ret;
1913 1914
1914 if (kbd_get_max_level()) { 1915 if (kbd_get_max_level()) {
1915 if (kbd_get_state(&state)) 1916 ret = kbd_get_state(&state);
1916 return; 1917 if (ret)
1918 return ret;
1917 new_state = state; 1919 new_state = state;
1918 if (kbd_set_level(&new_state, value)) 1920 ret = kbd_set_level(&new_state, value);
1919 return; 1921 if (ret)
1920 kbd_set_state_safe(&new_state, &state); 1922 return ret;
1921 return; 1923 return kbd_set_state_safe(&new_state, &state);
1922 } 1924 }
1923 1925
1924 if (kbd_get_valid_token_counts()) { 1926 if (kbd_get_valid_token_counts()) {
1925 for (num = kbd_token_bits; num != 0 && value > 0; --value) 1927 for (num = kbd_token_bits; num != 0 && value > 0; --value)
1926 num &= num - 1; /* clear the first bit set */ 1928 num &= num - 1; /* clear the first bit set */
1927 if (num == 0) 1929 if (num == 0)
1928 return; 1930 return 0;
1929 kbd_set_token_bit(ffs(num) - 1); 1931 return kbd_set_token_bit(ffs(num) - 1);
1930 return;
1931 } 1932 }
1932 1933
1933 pr_warn("Keyboard brightness level control not supported\n"); 1934 pr_warn("Keyboard brightness level control not supported\n");
1935 return -ENXIO;
1934} 1936}
1935 1937
1936static struct led_classdev kbd_led = { 1938static struct led_classdev kbd_led = {
1937 .name = "dell::kbd_backlight", 1939 .name = "dell::kbd_backlight",
1938 .brightness_set = kbd_led_level_set, 1940 .brightness_set_blocking = kbd_led_level_set,
1939 .brightness_get = kbd_led_level_get, 1941 .brightness_get = kbd_led_level_get,
1940 .groups = kbd_led_groups, 1942 .groups = kbd_led_groups,
1941}; 1943};
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c
index da2fe18162e1..75e637047d36 100644
--- a/drivers/platform/x86/dell-wmi.c
+++ b/drivers/platform/x86/dell-wmi.c
@@ -114,7 +114,7 @@ static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = {
114 { KE_IGNORE, 0xe00e, { KEY_RESERVED } }, 114 { KE_IGNORE, 0xe00e, { KEY_RESERVED } },
115 115
116 /* Wifi Catcher */ 116 /* Wifi Catcher */
117 { KE_KEY, 0xe011, { KEY_PROG2 } }, 117 { KE_KEY, 0xe011, { KEY_WLAN } },
118 118
119 /* Ambient light sensor toggle */ 119 /* Ambient light sensor toggle */
120 { KE_IGNORE, 0xe013, { KEY_RESERVED } }, 120 { KE_IGNORE, 0xe013, { KEY_RESERVED } },
@@ -274,6 +274,16 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = {
274 274
275 /* Stealth mode toggle */ 275 /* Stealth mode toggle */
276 { KE_IGNORE, 0x155, { KEY_RESERVED } }, 276 { KE_IGNORE, 0x155, { KEY_RESERVED } },
277
278 /* Rugged magnetic dock attach/detach events */
279 { KE_IGNORE, 0x156, { KEY_RESERVED } },
280 { KE_IGNORE, 0x157, { KEY_RESERVED } },
281
282 /* Rugged programmable (P1/P2/P3 keys) */
283 { KE_KEY, 0x850, { KEY_PROG1 } },
284 { KE_KEY, 0x851, { KEY_PROG2 } },
285 { KE_KEY, 0x852, { KEY_PROG3 } },
286
277}; 287};
278 288
279/* 289/*
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index 12dbb5063376..cb3ab2b212b1 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -69,7 +69,7 @@ static int intel_hid_set_enable(struct device *device, int enable)
69 69
70 arg0.integer.value = enable; 70 arg0.integer.value = enable;
71 status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL); 71 status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL);
72 if (!ACPI_SUCCESS(status)) { 72 if (ACPI_FAILURE(status)) {
73 dev_warn(device, "failed to %sable hotkeys\n", 73 dev_warn(device, "failed to %sable hotkeys\n",
74 enable ? "en" : "dis"); 74 enable ? "en" : "dis");
75 return -EIO; 75 return -EIO;
@@ -148,7 +148,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
148 } 148 }
149 149
150 status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index); 150 status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index);
151 if (!ACPI_SUCCESS(status)) { 151 if (ACPI_FAILURE(status)) {
152 dev_warn(&device->dev, "failed to get event index\n"); 152 dev_warn(&device->dev, "failed to get event index\n");
153 return; 153 return;
154 } 154 }
@@ -167,7 +167,7 @@ static int intel_hid_probe(struct platform_device *device)
167 int err; 167 int err;
168 168
169 status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode); 169 status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode);
170 if (!ACPI_SUCCESS(status)) { 170 if (ACPI_FAILURE(status)) {
171 dev_warn(&device->dev, "failed to read mode\n"); 171 dev_warn(&device->dev, "failed to read mode\n");
172 return -ENODEV; 172 return -ENODEV;
173 } 173 }
diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c
index 04cf5dffdfd9..bbe4c06c769f 100644
--- a/drivers/platform/x86/intel-smartconnect.c
+++ b/drivers/platform/x86/intel-smartconnect.c
@@ -29,7 +29,7 @@ static int smartconnect_acpi_init(struct acpi_device *acpi)
29 acpi_status status; 29 acpi_status status;
30 30
31 status = acpi_evaluate_integer(acpi->handle, "GAOS", NULL, &value); 31 status = acpi_evaluate_integer(acpi->handle, "GAOS", NULL, &value);
32 if (!ACPI_SUCCESS(status)) 32 if (ACPI_FAILURE(status))
33 return -EINVAL; 33 return -EINVAL;
34 34
35 if (value & 0x1) { 35 if (value & 0x1) {
diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
index 78080763df51..554e82ebe83c 100644
--- a/drivers/platform/x86/intel-vbtn.c
+++ b/drivers/platform/x86/intel-vbtn.c
@@ -49,34 +49,19 @@ static int intel_vbtn_input_setup(struct platform_device *device)
49 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); 49 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
50 int ret; 50 int ret;
51 51
52 priv->input_dev = input_allocate_device(); 52 priv->input_dev = devm_input_allocate_device(&device->dev);
53 if (!priv->input_dev) 53 if (!priv->input_dev)
54 return -ENOMEM; 54 return -ENOMEM;
55 55
56 ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL); 56 ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL);
57 if (ret) 57 if (ret)
58 goto err_free_device; 58 return ret;
59 59
60 priv->input_dev->dev.parent = &device->dev; 60 priv->input_dev->dev.parent = &device->dev;
61 priv->input_dev->name = "Intel Virtual Button driver"; 61 priv->input_dev->name = "Intel Virtual Button driver";
62 priv->input_dev->id.bustype = BUS_HOST; 62 priv->input_dev->id.bustype = BUS_HOST;
63 63
64 ret = input_register_device(priv->input_dev); 64 return input_register_device(priv->input_dev);
65 if (ret)
66 goto err_free_device;
67
68 return 0;
69
70err_free_device:
71 input_free_device(priv->input_dev);
72 return ret;
73}
74
75static void intel_vbtn_input_destroy(struct platform_device *device)
76{
77 struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev);
78
79 input_unregister_device(priv->input_dev);
80} 65}
81 66
82static void notify_handler(acpi_handle handle, u32 event, void *context) 67static void notify_handler(acpi_handle handle, u32 event, void *context)
@@ -97,7 +82,7 @@ static int intel_vbtn_probe(struct platform_device *device)
97 int err; 82 int err;
98 83
99 status = acpi_evaluate_object(handle, "VBDL", NULL, NULL); 84 status = acpi_evaluate_object(handle, "VBDL", NULL, NULL);
100 if (!ACPI_SUCCESS(status)) { 85 if (ACPI_FAILURE(status)) {
101 dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n"); 86 dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n");
102 return -ENODEV; 87 return -ENODEV;
103 } 88 }
@@ -117,24 +102,16 @@ static int intel_vbtn_probe(struct platform_device *device)
117 ACPI_DEVICE_NOTIFY, 102 ACPI_DEVICE_NOTIFY,
118 notify_handler, 103 notify_handler,
119 device); 104 device);
120 if (ACPI_FAILURE(status)) { 105 if (ACPI_FAILURE(status))
121 err = -EBUSY; 106 return -EBUSY;
122 goto err_remove_input;
123 }
124 107
125 return 0; 108 return 0;
126
127err_remove_input:
128 intel_vbtn_input_destroy(device);
129
130 return err;
131} 109}
132 110
133static int intel_vbtn_remove(struct platform_device *device) 111static int intel_vbtn_remove(struct platform_device *device)
134{ 112{
135 acpi_handle handle = ACPI_HANDLE(&device->dev); 113 acpi_handle handle = ACPI_HANDLE(&device->dev);
136 114
137 intel_vbtn_input_destroy(device);
138 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); 115 acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler);
139 116
140 /* 117 /*
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index 9f713b832ba3..0df3c9d37509 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -415,6 +415,7 @@ static struct thermal_device_info *initialize_sensor(int index)
415 return td_info; 415 return td_info;
416} 416}
417 417
418#ifdef CONFIG_PM_SLEEP
418/** 419/**
419 * mid_thermal_resume - resume routine 420 * mid_thermal_resume - resume routine
420 * @dev: device structure 421 * @dev: device structure
@@ -442,6 +443,7 @@ static int mid_thermal_suspend(struct device *dev)
442 */ 443 */
443 return configure_adc(0); 444 return configure_adc(0);
444} 445}
446#endif
445 447
446static SIMPLE_DEV_PM_OPS(mid_thermal_pm, 448static SIMPLE_DEV_PM_OPS(mid_thermal_pm,
447 mid_thermal_suspend, mid_thermal_resume); 449 mid_thermal_suspend, mid_thermal_resume);
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index e8b1b836ca2d..b130b8c9b9d7 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -19,10 +19,12 @@
19 */ 19 */
20 20
21#include <linux/debugfs.h> 21#include <linux/debugfs.h>
22#include <linux/delay.h>
22#include <linux/device.h> 23#include <linux/device.h>
23#include <linux/init.h> 24#include <linux/init.h>
24#include <linux/io.h> 25#include <linux/io.h>
25#include <linux/pci.h> 26#include <linux/pci.h>
27#include <linux/uaccess.h>
26 28
27#include <asm/cpu_device_id.h> 29#include <asm/cpu_device_id.h>
28#include <asm/intel-family.h> 30#include <asm/intel-family.h>
@@ -32,16 +34,106 @@
32 34
33static struct pmc_dev pmc; 35static struct pmc_dev pmc;
34 36
37static const struct pmc_bit_map spt_pll_map[] = {
38 {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0},
39 {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1},
40 {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2},
41 {"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3},
42 {},
43};
44
45static const struct pmc_bit_map spt_mphy_map[] = {
46 {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0},
47 {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1},
48 {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2},
49 {"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3},
50 {"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4},
51 {"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5},
52 {"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6},
53 {"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7},
54 {"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8},
55 {"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9},
56 {"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10},
57 {"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11},
58 {"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12},
59 {"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13},
60 {"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14},
61 {"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15},
62 {},
63};
64
65static const struct pmc_bit_map spt_pfear_map[] = {
66 {"PMC", SPT_PMC_BIT_PMC},
67 {"OPI-DMI", SPT_PMC_BIT_OPI},
68 {"SPI / eSPI", SPT_PMC_BIT_SPI},
69 {"XHCI", SPT_PMC_BIT_XHCI},
70 {"SPA", SPT_PMC_BIT_SPA},
71 {"SPB", SPT_PMC_BIT_SPB},
72 {"SPC", SPT_PMC_BIT_SPC},
73 {"GBE", SPT_PMC_BIT_GBE},
74 {"SATA", SPT_PMC_BIT_SATA},
75 {"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0},
76 {"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1},
77 {"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2},
78 {"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3},
79 {"RSVD", SPT_PMC_BIT_RSVD_0B},
80 {"LPSS", SPT_PMC_BIT_LPSS},
81 {"LPC", SPT_PMC_BIT_LPC},
82 {"SMB", SPT_PMC_BIT_SMB},
83 {"ISH", SPT_PMC_BIT_ISH},
84 {"P2SB", SPT_PMC_BIT_P2SB},
85 {"DFX", SPT_PMC_BIT_DFX},
86 {"SCC", SPT_PMC_BIT_SCC},
87 {"RSVD", SPT_PMC_BIT_RSVD_0C},
88 {"FUSE", SPT_PMC_BIT_FUSE},
89 {"CAMERA", SPT_PMC_BIT_CAMREA},
90 {"RSVD", SPT_PMC_BIT_RSVD_0D},
91 {"USB3-OTG", SPT_PMC_BIT_USB3_OTG},
92 {"EXI", SPT_PMC_BIT_EXI},
93 {"CSE", SPT_PMC_BIT_CSE},
94 {"CSME_KVM", SPT_PMC_BIT_CSME_KVM},
95 {"CSME_PMT", SPT_PMC_BIT_CSME_PMT},
96 {"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK},
97 {"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO},
98 {"CSME_USBR", SPT_PMC_BIT_CSME_USBR},
99 {"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM},
100 {"CSME_SMT", SPT_PMC_BIT_CSME_SMT},
101 {"RSVD", SPT_PMC_BIT_RSVD_1A},
102 {"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2},
103 {"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1},
104 {"CSME_RTC", SPT_PMC_BIT_CSME_RTC},
105 {"CSME_PSF", SPT_PMC_BIT_CSME_PSF},
106 {},
107};
108
109static const struct pmc_reg_map spt_reg_map = {
110 .pfear_sts = spt_pfear_map,
111 .mphy_sts = spt_mphy_map,
112 .pll_sts = spt_pll_map,
113};
114
35static const struct pci_device_id pmc_pci_ids[] = { 115static const struct pci_device_id pmc_pci_ids[] = {
36 { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), (kernel_ulong_t)NULL }, 116 { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID),
117 (kernel_ulong_t)&spt_reg_map },
37 { 0, }, 118 { 0, },
38}; 119};
39 120
121static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset)
122{
123 return readb(pmcdev->regbase + offset);
124}
125
40static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset) 126static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset)
41{ 127{
42 return readl(pmcdev->regbase + reg_offset); 128 return readl(pmcdev->regbase + reg_offset);
43} 129}
44 130
131static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int
132 reg_offset, u32 val)
133{
134 writel(val, pmcdev->regbase + reg_offset);
135}
136
45static inline u32 pmc_core_adjust_slp_s0_step(u32 value) 137static inline u32 pmc_core_adjust_slp_s0_step(u32 value)
46{ 138{
47 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP; 139 return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP;
@@ -90,6 +182,245 @@ static int pmc_core_dev_state_get(void *data, u64 *val)
90 182
91DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); 183DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n");
92 184
185static int pmc_core_check_read_lock_bit(void)
186{
187 struct pmc_dev *pmcdev = &pmc;
188 u32 value;
189
190 value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET);
191 return test_bit(SPT_PMC_READ_DISABLE_BIT,
192 (unsigned long *)&value);
193}
194
195#if IS_ENABLED(CONFIG_DEBUG_FS)
196static void pmc_core_display_map(struct seq_file *s, int index,
197 u8 pf_reg, const struct pmc_bit_map *pf_map)
198{
199 seq_printf(s, "PCH IP: %-2d - %-32s\tState: %s\n",
200 index, pf_map[index].name,
201 pf_map[index].bit_mask & pf_reg ? "Off" : "On");
202}
203
204static int pmc_core_ppfear_sts_show(struct seq_file *s, void *unused)
205{
206 struct pmc_dev *pmcdev = s->private;
207 const struct pmc_bit_map *map = pmcdev->map->pfear_sts;
208 u8 pf_regs[NUM_ENTRIES];
209 int index, iter;
210
211 iter = SPT_PMC_XRAM_PPFEAR0A;
212
213 for (index = 0; index < NUM_ENTRIES; index++, iter++)
214 pf_regs[index] = pmc_core_reg_read_byte(pmcdev, iter);
215
216 for (index = 0; map[index].name; index++)
217 pmc_core_display_map(s, index, pf_regs[index / 8], map);
218
219 return 0;
220}
221
222static int pmc_core_ppfear_sts_open(struct inode *inode, struct file *file)
223{
224 return single_open(file, pmc_core_ppfear_sts_show, inode->i_private);
225}
226
227static const struct file_operations pmc_core_ppfear_ops = {
228 .open = pmc_core_ppfear_sts_open,
229 .read = seq_read,
230 .llseek = seq_lseek,
231 .release = single_release,
232};
233
234/* This function should return link status, 0 means ready */
235static int pmc_core_mtpmc_link_status(void)
236{
237 struct pmc_dev *pmcdev = &pmc;
238 u32 value;
239
240 value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET);
241 return test_bit(SPT_PMC_MSG_FULL_STS_BIT,
242 (unsigned long *)&value);
243}
244
245static int pmc_core_send_msg(u32 *addr_xram)
246{
247 struct pmc_dev *pmcdev = &pmc;
248 u32 dest;
249 int timeout;
250
251 for (timeout = NUM_RETRIES; timeout > 0; timeout--) {
252 if (pmc_core_mtpmc_link_status() == 0)
253 break;
254 msleep(5);
255 }
256
257 if (timeout <= 0 && pmc_core_mtpmc_link_status())
258 return -EBUSY;
259
260 dest = (*addr_xram & MTPMC_MASK) | (1U << 1);
261 pmc_core_reg_write(pmcdev, SPT_PMC_MTPMC_OFFSET, dest);
262 return 0;
263}
264
265static int pmc_core_mphy_pg_sts_show(struct seq_file *s, void *unused)
266{
267 struct pmc_dev *pmcdev = s->private;
268 const struct pmc_bit_map *map = pmcdev->map->mphy_sts;
269 u32 mphy_core_reg_low, mphy_core_reg_high;
270 u32 val_low, val_high;
271 int index, err = 0;
272
273 if (pmcdev->pmc_xram_read_bit) {
274 seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS.");
275 return 0;
276 }
277
278 mphy_core_reg_low = (SPT_PMC_MPHY_CORE_STS_0 << 16);
279 mphy_core_reg_high = (SPT_PMC_MPHY_CORE_STS_1 << 16);
280
281 mutex_lock(&pmcdev->lock);
282
283 if (pmc_core_send_msg(&mphy_core_reg_low) != 0) {
284 err = -EBUSY;
285 goto out_unlock;
286 }
287
288 msleep(10);
289 val_low = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET);
290
291 if (pmc_core_send_msg(&mphy_core_reg_high) != 0) {
292 err = -EBUSY;
293 goto out_unlock;
294 }
295
296 msleep(10);
297 val_high = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET);
298
299 for (index = 0; map[index].name && index < 8; index++) {
300 seq_printf(s, "%-32s\tState: %s\n",
301 map[index].name,
302 map[index].bit_mask & val_low ? "Not power gated" :
303 "Power gated");
304 }
305
306 for (index = 8; map[index].name; index++) {
307 seq_printf(s, "%-32s\tState: %s\n",
308 map[index].name,
309 map[index].bit_mask & val_high ? "Not power gated" :
310 "Power gated");
311 }
312
313out_unlock:
314 mutex_unlock(&pmcdev->lock);
315 return err;
316}
317
318static int pmc_core_mphy_pg_sts_open(struct inode *inode, struct file *file)
319{
320 return single_open(file, pmc_core_mphy_pg_sts_show, inode->i_private);
321}
322
323static const struct file_operations pmc_core_mphy_pg_ops = {
324 .open = pmc_core_mphy_pg_sts_open,
325 .read = seq_read,
326 .llseek = seq_lseek,
327 .release = single_release,
328};
329
330static int pmc_core_pll_show(struct seq_file *s, void *unused)
331{
332 struct pmc_dev *pmcdev = s->private;
333 const struct pmc_bit_map *map = pmcdev->map->pll_sts;
334 u32 mphy_common_reg, val;
335 int index, err = 0;
336
337 if (pmcdev->pmc_xram_read_bit) {
338 seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS.");
339 return 0;
340 }
341
342 mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16);
343 mutex_lock(&pmcdev->lock);
344
345 if (pmc_core_send_msg(&mphy_common_reg) != 0) {
346 err = -EBUSY;
347 goto out_unlock;
348 }
349
350 /* Observed PMC HW response latency for MTPMC-MFPMC is ~10 ms */
351 msleep(10);
352 val = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET);
353
354 for (index = 0; map[index].name ; index++) {
355 seq_printf(s, "%-32s\tState: %s\n",
356 map[index].name,
357 map[index].bit_mask & val ? "Active" : "Idle");
358 }
359
360out_unlock:
361 mutex_unlock(&pmcdev->lock);
362 return err;
363}
364
365static int pmc_core_pll_open(struct inode *inode, struct file *file)
366{
367 return single_open(file, pmc_core_pll_show, inode->i_private);
368}
369
370static const struct file_operations pmc_core_pll_ops = {
371 .open = pmc_core_pll_open,
372 .read = seq_read,
373 .llseek = seq_lseek,
374 .release = single_release,
375};
376
377static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user
378*userbuf, size_t count, loff_t *ppos)
379{
380 struct pmc_dev *pmcdev = &pmc;
381 u32 val, buf_size, fd;
382 int err = 0;
383
384 buf_size = count < 64 ? count : 64;
385 mutex_lock(&pmcdev->lock);
386
387 if (kstrtou32_from_user(userbuf, buf_size, 10, &val)) {
388 err = -EFAULT;
389 goto out_unlock;
390 }
391
392 if (val > NUM_IP_IGN_ALLOWED) {
393 err = -EINVAL;
394 goto out_unlock;
395 }
396
397 fd = pmc_core_reg_read(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET);
398 fd |= (1U << val);
399 pmc_core_reg_write(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET, fd);
400
401out_unlock:
402 mutex_unlock(&pmcdev->lock);
403 return err == 0 ? count : err;
404}
405
406static int pmc_core_ltr_ignore_show(struct seq_file *s, void *unused)
407{
408 return 0;
409}
410
411static int pmc_core_ltr_ignore_open(struct inode *inode, struct file *file)
412{
413 return single_open(file, pmc_core_ltr_ignore_show, inode->i_private);
414}
415
416static const struct file_operations pmc_core_ltr_ignore_ops = {
417 .open = pmc_core_ltr_ignore_open,
418 .read = seq_read,
419 .write = pmc_core_ltr_ignore_write,
420 .llseek = seq_lseek,
421 .release = single_release,
422};
423
93static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) 424static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
94{ 425{
95 debugfs_remove_recursive(pmcdev->dbgfs_dir); 426 debugfs_remove_recursive(pmcdev->dbgfs_dir);
@@ -106,20 +437,59 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
106 pmcdev->dbgfs_dir = dir; 437 pmcdev->dbgfs_dir = dir;
107 file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, 438 file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO,
108 dir, pmcdev, &pmc_core_dev_state); 439 dir, pmcdev, &pmc_core_dev_state);
440 if (!file)
441 goto err;
109 442
110 if (!file) { 443 file = debugfs_create_file("pch_ip_power_gating_status",
111 pmc_core_dbgfs_unregister(pmcdev); 444 S_IFREG | S_IRUGO, dir, pmcdev,
112 return -ENODEV; 445 &pmc_core_ppfear_ops);
113 } 446 if (!file)
447 goto err;
448
449 file = debugfs_create_file("mphy_core_lanes_power_gating_status",
450 S_IFREG | S_IRUGO, dir, pmcdev,
451 &pmc_core_mphy_pg_ops);
452 if (!file)
453 goto err;
454
455 file = debugfs_create_file("pll_status",
456 S_IFREG | S_IRUGO, dir, pmcdev,
457 &pmc_core_pll_ops);
458 if (!file)
459 goto err;
460
461 file = debugfs_create_file("ltr_ignore",
462 S_IFREG | S_IRUGO, dir, pmcdev,
463 &pmc_core_ltr_ignore_ops);
464
465 if (!file)
466 goto err;
114 467
115 return 0; 468 return 0;
469err:
470 pmc_core_dbgfs_unregister(pmcdev);
471 return -ENODEV;
116} 472}
473#else
474static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
475{
476 return 0;
477}
478
479static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
480{
481}
482#endif /* CONFIG_DEBUG_FS */
117 483
118static const struct x86_cpu_id intel_pmc_core_ids[] = { 484static const struct x86_cpu_id intel_pmc_core_ids[] = {
119 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, 485 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT,
120 (kernel_ulong_t)NULL}, 486 (kernel_ulong_t)NULL},
121 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, 487 { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT,
122 (kernel_ulong_t)NULL}, 488 (kernel_ulong_t)NULL},
489 { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT,
490 (kernel_ulong_t)NULL},
491 { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT,
492 (kernel_ulong_t)NULL},
123 {} 493 {}
124}; 494};
125 495
@@ -128,6 +498,7 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
128 struct device *ptr_dev = &dev->dev; 498 struct device *ptr_dev = &dev->dev;
129 struct pmc_dev *pmcdev = &pmc; 499 struct pmc_dev *pmcdev = &pmc;
130 const struct x86_cpu_id *cpu_id; 500 const struct x86_cpu_id *cpu_id;
501 const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data;
131 int err; 502 int err;
132 503
133 cpu_id = x86_match_cpu(intel_pmc_core_ids); 504 cpu_id = x86_match_cpu(intel_pmc_core_ids);
@@ -149,6 +520,7 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
149 dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n"); 520 dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n");
150 return err; 521 return err;
151 } 522 }
523 pmcdev->base_addr &= PMC_BASE_ADDR_MASK;
152 dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr); 524 dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr);
153 525
154 pmcdev->regbase = devm_ioremap_nocache(ptr_dev, 526 pmcdev->regbase = devm_ioremap_nocache(ptr_dev,
@@ -159,6 +531,10 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id)
159 return -ENOMEM; 531 return -ENOMEM;
160 } 532 }
161 533
534 mutex_init(&pmcdev->lock);
535 pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit();
536 pmcdev->map = map;
537
162 err = pmc_core_dbgfs_register(pmcdev); 538 err = pmc_core_dbgfs_register(pmcdev);
163 if (err < 0) 539 if (err < 0)
164 dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); 540 dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n");
diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h
index e3f671f4d122..5a48e7728479 100644
--- a/drivers/platform/x86/intel_pmc_core.h
+++ b/drivers/platform/x86/intel_pmc_core.h
@@ -26,8 +26,111 @@
26 26
27#define SPT_PMC_BASE_ADDR_OFFSET 0x48 27#define SPT_PMC_BASE_ADDR_OFFSET 0x48
28#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c 28#define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c
29#define SPT_PMC_MMIO_REG_LEN 0x100 29#define SPT_PMC_PM_CFG_OFFSET 0x18
30#define SPT_PMC_PM_STS_OFFSET 0x1c
31#define SPT_PMC_MTPMC_OFFSET 0x20
32#define SPT_PMC_MFPMC_OFFSET 0x38
33#define SPT_PMC_LTR_IGNORE_OFFSET 0x30C
34#define SPT_PMC_MPHY_CORE_STS_0 0x1143
35#define SPT_PMC_MPHY_CORE_STS_1 0x1142
36#define SPT_PMC_MPHY_COM_STS_0 0x1155
37#define SPT_PMC_MMIO_REG_LEN 0x1000
30#define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 38#define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64
39#define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1)
40#define MTPMC_MASK 0xffff0000
41#define NUM_ENTRIES 5
42#define SPT_PMC_READ_DISABLE_BIT 0x16
43#define SPT_PMC_MSG_FULL_STS_BIT 0x18
44#define NUM_RETRIES 100
45#define NUM_IP_IGN_ALLOWED 17
46
47/* Sunrise Point: PGD PFET Enable Ack Status Registers */
48enum ppfear_regs {
49 SPT_PMC_XRAM_PPFEAR0A = 0x590,
50 SPT_PMC_XRAM_PPFEAR0B,
51 SPT_PMC_XRAM_PPFEAR0C,
52 SPT_PMC_XRAM_PPFEAR0D,
53 SPT_PMC_XRAM_PPFEAR1A,
54};
55
56#define SPT_PMC_BIT_PMC BIT(0)
57#define SPT_PMC_BIT_OPI BIT(1)
58#define SPT_PMC_BIT_SPI BIT(2)
59#define SPT_PMC_BIT_XHCI BIT(3)
60#define SPT_PMC_BIT_SPA BIT(4)
61#define SPT_PMC_BIT_SPB BIT(5)
62#define SPT_PMC_BIT_SPC BIT(6)
63#define SPT_PMC_BIT_GBE BIT(7)
64
65#define SPT_PMC_BIT_SATA BIT(0)
66#define SPT_PMC_BIT_HDA_PGD0 BIT(1)
67#define SPT_PMC_BIT_HDA_PGD1 BIT(2)
68#define SPT_PMC_BIT_HDA_PGD2 BIT(3)
69#define SPT_PMC_BIT_HDA_PGD3 BIT(4)
70#define SPT_PMC_BIT_RSVD_0B BIT(5)
71#define SPT_PMC_BIT_LPSS BIT(6)
72#define SPT_PMC_BIT_LPC BIT(7)
73
74#define SPT_PMC_BIT_SMB BIT(0)
75#define SPT_PMC_BIT_ISH BIT(1)
76#define SPT_PMC_BIT_P2SB BIT(2)
77#define SPT_PMC_BIT_DFX BIT(3)
78#define SPT_PMC_BIT_SCC BIT(4)
79#define SPT_PMC_BIT_RSVD_0C BIT(5)
80#define SPT_PMC_BIT_FUSE BIT(6)
81#define SPT_PMC_BIT_CAMREA BIT(7)
82
83#define SPT_PMC_BIT_RSVD_0D BIT(0)
84#define SPT_PMC_BIT_USB3_OTG BIT(1)
85#define SPT_PMC_BIT_EXI BIT(2)
86#define SPT_PMC_BIT_CSE BIT(3)
87#define SPT_PMC_BIT_CSME_KVM BIT(4)
88#define SPT_PMC_BIT_CSME_PMT BIT(5)
89#define SPT_PMC_BIT_CSME_CLINK BIT(6)
90#define SPT_PMC_BIT_CSME_PTIO BIT(7)
91
92#define SPT_PMC_BIT_CSME_USBR BIT(0)
93#define SPT_PMC_BIT_CSME_SUSRAM BIT(1)
94#define SPT_PMC_BIT_CSME_SMT BIT(2)
95#define SPT_PMC_BIT_RSVD_1A BIT(3)
96#define SPT_PMC_BIT_CSME_SMS2 BIT(4)
97#define SPT_PMC_BIT_CSME_SMS1 BIT(5)
98#define SPT_PMC_BIT_CSME_RTC BIT(6)
99#define SPT_PMC_BIT_CSME_PSF BIT(7)
100
101#define SPT_PMC_BIT_MPHY_LANE0 BIT(0)
102#define SPT_PMC_BIT_MPHY_LANE1 BIT(1)
103#define SPT_PMC_BIT_MPHY_LANE2 BIT(2)
104#define SPT_PMC_BIT_MPHY_LANE3 BIT(3)
105#define SPT_PMC_BIT_MPHY_LANE4 BIT(4)
106#define SPT_PMC_BIT_MPHY_LANE5 BIT(5)
107#define SPT_PMC_BIT_MPHY_LANE6 BIT(6)
108#define SPT_PMC_BIT_MPHY_LANE7 BIT(7)
109
110#define SPT_PMC_BIT_MPHY_LANE8 BIT(0)
111#define SPT_PMC_BIT_MPHY_LANE9 BIT(1)
112#define SPT_PMC_BIT_MPHY_LANE10 BIT(2)
113#define SPT_PMC_BIT_MPHY_LANE11 BIT(3)
114#define SPT_PMC_BIT_MPHY_LANE12 BIT(4)
115#define SPT_PMC_BIT_MPHY_LANE13 BIT(5)
116#define SPT_PMC_BIT_MPHY_LANE14 BIT(6)
117#define SPT_PMC_BIT_MPHY_LANE15 BIT(7)
118
119#define SPT_PMC_BIT_MPHY_CMN_LANE0 BIT(0)
120#define SPT_PMC_BIT_MPHY_CMN_LANE1 BIT(1)
121#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2)
122#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3)
123
124struct pmc_bit_map {
125 const char *name;
126 u32 bit_mask;
127};
128
129struct pmc_reg_map {
130 const struct pmc_bit_map *pfear_sts;
131 const struct pmc_bit_map *mphy_sts;
132 const struct pmc_bit_map *pll_sts;
133};
31 134
32/** 135/**
33 * struct pmc_dev - pmc device structure 136 * struct pmc_dev - pmc device structure
@@ -43,8 +146,13 @@
43struct pmc_dev { 146struct pmc_dev {
44 u32 base_addr; 147 u32 base_addr;
45 void __iomem *regbase; 148 void __iomem *regbase;
149 const struct pmc_reg_map *map;
150#if IS_ENABLED(CONFIG_DEBUG_FS)
46 struct dentry *dbgfs_dir; 151 struct dentry *dbgfs_dir;
152#endif /* CONFIG_DEBUG_FS */
47 bool has_slp_s0_res; 153 bool has_slp_s0_res;
154 int pmc_xram_read_bit;
155 struct mutex lock; /* generic mutex lock for PMC Core */
48}; 156};
49 157
50#endif /* PMC_CORE_H */ 158#endif /* PMC_CORE_H */
diff --git a/drivers/platform/x86/mlxcpld-hotplug.c b/drivers/platform/x86/mlxcpld-hotplug.c
new file mode 100644
index 000000000000..aff3686b3b37
--- /dev/null
+++ b/drivers/platform/x86/mlxcpld-hotplug.c
@@ -0,0 +1,515 @@
1/*
2 * drivers/platform/x86/mlxcpld-hotplug.c
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <linux/bitops.h>
36#include <linux/device.h>
37#include <linux/hwmon.h>
38#include <linux/hwmon-sysfs.h>
39#include <linux/i2c.h>
40#include <linux/interrupt.h>
41#include <linux/io.h>
42#include <linux/module.h>
43#include <linux/platform_data/mlxcpld-hotplug.h>
44#include <linux/platform_device.h>
45#include <linux/spinlock.h>
46#include <linux/wait.h>
47#include <linux/workqueue.h>
48
49/* Offset of event and mask registers from status register */
50#define MLXCPLD_HOTPLUG_EVENT_OFF 1
51#define MLXCPLD_HOTPLUG_MASK_OFF 2
52#define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1
53
54#define MLXCPLD_HOTPLUG_ATTRS_NUM 8
55
56/**
57 * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events:
58 * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute;
59 * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute;
60 * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute;
61 */
62enum mlxcpld_hotplug_attr_type {
63 MLXCPLD_HOTPLUG_ATTR_TYPE_PSU,
64 MLXCPLD_HOTPLUG_ATTR_TYPE_PWR,
65 MLXCPLD_HOTPLUG_ATTR_TYPE_FAN,
66};
67
68/**
69 * struct mlxcpld_hotplug_priv_data - platform private data:
70 * @irq: platform interrupt number;
71 * @pdev: platform device;
72 * @plat: platform data;
73 * @hwmon: hwmon device;
74 * @mlxcpld_hotplug_attr: sysfs attributes array;
75 * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array;
76 * @group: sysfs attribute group;
77 * @groups: list of sysfs attribute group for hwmon registration;
78 * @dwork: delayed work template;
79 * @lock: spin lock;
80 * @aggr_cache: last value of aggregation register status;
81 * @psu_cache: last value of PSU register status;
82 * @pwr_cache: last value of power register status;
83 * @fan_cache: last value of FAN register status;
84 */
85struct mlxcpld_hotplug_priv_data {
86 int irq;
87 struct platform_device *pdev;
88 struct mlxcpld_hotplug_platform_data *plat;
89 struct device *hwmon;
90 struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1];
91 struct sensor_device_attribute_2
92 mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM];
93 struct attribute_group group;
94 const struct attribute_group *groups[2];
95 struct delayed_work dwork;
96 spinlock_t lock;
97 u8 aggr_cache;
98 u8 psu_cache;
99 u8 pwr_cache;
100 u8 fan_cache;
101};
102
103static ssize_t mlxcpld_hotplug_attr_show(struct device *dev,
104 struct device_attribute *attr,
105 char *buf)
106{
107 struct platform_device *pdev = to_platform_device(dev);
108 struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
109 int index = to_sensor_dev_attr_2(attr)->index;
110 int nr = to_sensor_dev_attr_2(attr)->nr;
111 u8 reg_val = 0;
112
113 switch (nr) {
114 case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU:
115 /* Bit = 0 : PSU is present. */
116 reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index));
117 break;
118
119 case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR:
120 /* Bit = 1 : power cable is attached. */
121 reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index %
122 priv->plat->pwr_count));
123 break;
124
125 case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN:
126 /* Bit = 0 : FAN is present. */
127 reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index %
128 priv->plat->fan_count));
129 break;
130 }
131
132 return sprintf(buf, "%u\n", reg_val);
133}
134
135#define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i]
136#define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i]
137static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv)
138{
139 int num_attrs = priv->plat->psu_count + priv->plat->pwr_count +
140 priv->plat->fan_count;
141 int i;
142
143 priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *
144 sizeof(struct attribute *),
145 GFP_KERNEL);
146 if (!priv->group.attrs)
147 return -ENOMEM;
148
149 for (i = 0; i < num_attrs; i++) {
150 PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr;
151
152 if (i < priv->plat->psu_count) {
153 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
154 GFP_KERNEL, "psu%u", i + 1);
155 PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU;
156 } else if (i < priv->plat->psu_count + priv->plat->pwr_count) {
157 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
158 GFP_KERNEL, "pwr%u", i %
159 priv->plat->pwr_count + 1);
160 PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR;
161 } else {
162 PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev,
163 GFP_KERNEL, "fan%u", i %
164 priv->plat->fan_count + 1);
165 PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN;
166 }
167
168 if (!PRIV_ATTR(i)->name) {
169 dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n",
170 i + 1);
171 return -ENOMEM;
172 }
173
174 PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name;
175 PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO;
176 PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show;
177 PRIV_DEV_ATTR(i).index = i;
178 sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr);
179 }
180
181 priv->group.attrs = priv->mlxcpld_hotplug_attr;
182 priv->groups[0] = &priv->group;
183 priv->groups[1] = NULL;
184
185 return 0;
186}
187
188static int mlxcpld_hotplug_device_create(struct device *dev,
189 struct mlxcpld_hotplug_device *item)
190{
191 item->adapter = i2c_get_adapter(item->bus);
192 if (!item->adapter) {
193 dev_err(dev, "Failed to get adapter for bus %d\n",
194 item->bus);
195 return -EFAULT;
196 }
197
198 item->client = i2c_new_device(item->adapter, &item->brdinfo);
199 if (!item->client) {
200 dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n",
201 item->brdinfo.type, item->bus, item->brdinfo.addr);
202 i2c_put_adapter(item->adapter);
203 item->adapter = NULL;
204 return -EFAULT;
205 }
206
207 return 0;
208}
209
210static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item)
211{
212 if (item->client) {
213 i2c_unregister_device(item->client);
214 item->client = NULL;
215 }
216
217 if (item->adapter) {
218 i2c_put_adapter(item->adapter);
219 item->adapter = NULL;
220 }
221}
222
223static inline void
224mlxcpld_hotplug_work_helper(struct device *dev,
225 struct mlxcpld_hotplug_device *item, u8 is_inverse,
226 u16 offset, u8 mask, u8 *cache)
227{
228 u8 val, asserted;
229 int bit;
230
231 /* Mask event. */
232 outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF);
233 /* Read status. */
234 val = inb(offset) & mask;
235 asserted = *cache ^ val;
236 *cache = val;
237
238 /*
239 * Validate if item related to received signal type is valid.
240 * It should never happen, excepted the situation when some
241 * piece of hardware is broken. In such situation just produce
242 * error message and return. Caller must continue to handle the
243 * signals from other devices if any.
244 */
245 if (unlikely(!item)) {
246 dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n",
247 offset, mask);
248 return;
249 }
250
251 for_each_set_bit(bit, (unsigned long *)&asserted, 8) {
252 if (val & BIT(bit)) {
253 if (is_inverse)
254 mlxcpld_hotplug_device_destroy(item + bit);
255 else
256 mlxcpld_hotplug_device_create(dev, item + bit);
257 } else {
258 if (is_inverse)
259 mlxcpld_hotplug_device_create(dev, item + bit);
260 else
261 mlxcpld_hotplug_device_destroy(item + bit);
262 }
263 }
264
265 /* Acknowledge event. */
266 outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF);
267 /* Unmask event. */
268 outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF);
269}
270
271/*
272 * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt
273 * registers according to the below hierarchy schema:
274 *
275 * Aggregation registers (status/mask)
276 * PSU registers: *---*
277 * *-----------------* | |
278 * |status/event/mask|----->| * |
279 * *-----------------* | |
280 * Power registers: | |
281 * *-----------------* | |
282 * |status/event/mask|----->| * |---> CPU
283 * *-----------------* | |
284 * FAN registers:
285 * *-----------------* | |
286 * |status/event/mask|----->| * |
287 * *-----------------* | |
288 * *---*
289 * In case some system changed are detected: FAN in/out, PSU in/out, power
290 * cable attached/detached, relevant device is created or destroyed.
291 */
292static void mlxcpld_hotplug_work_handler(struct work_struct *work)
293{
294 struct mlxcpld_hotplug_priv_data *priv = container_of(work,
295 struct mlxcpld_hotplug_priv_data, dwork.work);
296 u8 val, aggr_asserted;
297 unsigned long flags;
298
299 /* Mask aggregation event. */
300 outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
301 /* Read aggregation status. */
302 val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask;
303 aggr_asserted = priv->aggr_cache ^ val;
304 priv->aggr_cache = val;
305
306 /* Handle PSU configuration changes. */
307 if (aggr_asserted & priv->plat->top_aggr_psu_mask)
308 mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu,
309 1, priv->plat->psu_reg_offset,
310 priv->plat->psu_mask,
311 &priv->psu_cache);
312
313 /* Handle power cable configuration changes. */
314 if (aggr_asserted & priv->plat->top_aggr_pwr_mask)
315 mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr,
316 0, priv->plat->pwr_reg_offset,
317 priv->plat->pwr_mask,
318 &priv->pwr_cache);
319
320 /* Handle FAN configuration changes. */
321 if (aggr_asserted & priv->plat->top_aggr_fan_mask)
322 mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan,
323 1, priv->plat->fan_reg_offset,
324 priv->plat->fan_mask,
325 &priv->fan_cache);
326
327 if (aggr_asserted) {
328 spin_lock_irqsave(&priv->lock, flags);
329
330 /*
331 * It is possible, that some signals have been inserted, while
332 * interrupt has been masked by mlxcpld_hotplug_work_handler.
333 * In this case such signals will be missed. In order to handle
334 * these signals delayed work is canceled and work task
335 * re-scheduled for immediate execution. It allows to handle
336 * missed signals, if any. In other case work handler just
337 * validates that no new signals have been received during
338 * masking.
339 */
340 cancel_delayed_work(&priv->dwork);
341 schedule_delayed_work(&priv->dwork, 0);
342
343 spin_unlock_irqrestore(&priv->lock, flags);
344
345 return;
346 }
347
348 /* Unmask aggregation event (no need acknowledge). */
349 outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
350 MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
351}
352
353static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv)
354{
355 /* Clear psu presense event. */
356 outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
357 /* Set psu initial status as mask and unmask psu event. */
358 priv->psu_cache = priv->plat->psu_mask;
359 outb(priv->plat->psu_mask, priv->plat->psu_reg_offset +
360 MLXCPLD_HOTPLUG_MASK_OFF);
361
362 /* Clear power cable event. */
363 outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
364 /* Keep power initial status as zero and unmask power event. */
365 outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset +
366 MLXCPLD_HOTPLUG_MASK_OFF);
367
368 /* Clear fan presense event. */
369 outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
370 /* Set fan initial status as mask and unmask fan event. */
371 priv->fan_cache = priv->plat->fan_mask;
372 outb(priv->plat->fan_mask, priv->plat->fan_reg_offset +
373 MLXCPLD_HOTPLUG_MASK_OFF);
374
375 /* Keep aggregation initial status as zero and unmask events. */
376 outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset +
377 MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
378
379 /* Invoke work handler for initializing hot plug devices setting. */
380 mlxcpld_hotplug_work_handler(&priv->dwork.work);
381
382 enable_irq(priv->irq);
383}
384
385static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv)
386{
387 int i;
388
389 disable_irq(priv->irq);
390 cancel_delayed_work_sync(&priv->dwork);
391
392 /* Mask aggregation event. */
393 outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF);
394
395 /* Mask psu presense event. */
396 outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
397 /* Clear psu presense event. */
398 outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
399
400 /* Mask power cable event. */
401 outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
402 /* Clear power cable event. */
403 outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
404
405 /* Mask fan presense event. */
406 outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF);
407 /* Clear fan presense event. */
408 outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF);
409
410 /* Remove all the attached devices. */
411 for (i = 0; i < priv->plat->psu_count; i++)
412 mlxcpld_hotplug_device_destroy(priv->plat->psu + i);
413
414 for (i = 0; i < priv->plat->pwr_count; i++)
415 mlxcpld_hotplug_device_destroy(priv->plat->pwr + i);
416
417 for (i = 0; i < priv->plat->fan_count; i++)
418 mlxcpld_hotplug_device_destroy(priv->plat->fan + i);
419}
420
421static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev)
422{
423 struct mlxcpld_hotplug_priv_data *priv =
424 (struct mlxcpld_hotplug_priv_data *)dev;
425
426 /* Schedule work task for immediate execution.*/
427 schedule_delayed_work(&priv->dwork, 0);
428
429 return IRQ_HANDLED;
430}
431
432static int mlxcpld_hotplug_probe(struct platform_device *pdev)
433{
434 struct mlxcpld_hotplug_platform_data *pdata;
435 struct mlxcpld_hotplug_priv_data *priv;
436 int err;
437
438 pdata = dev_get_platdata(&pdev->dev);
439 if (!pdata) {
440 dev_err(&pdev->dev, "Failed to get platform data.\n");
441 return -EINVAL;
442 }
443
444 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
445 if (!priv)
446 return -ENOMEM;
447
448 priv->pdev = pdev;
449 priv->plat = pdata;
450
451 priv->irq = platform_get_irq(pdev, 0);
452 if (priv->irq < 0) {
453 dev_err(&pdev->dev, "Failed to get platform irq: %d\n",
454 priv->irq);
455 return priv->irq;
456 }
457
458 err = devm_request_irq(&pdev->dev, priv->irq,
459 mlxcpld_hotplug_irq_handler, 0, pdev->name,
460 priv);
461 if (err) {
462 dev_err(&pdev->dev, "Failed to request irq: %d\n", err);
463 return err;
464 }
465 disable_irq(priv->irq);
466
467 INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler);
468 spin_lock_init(&priv->lock);
469
470 err = mlxcpld_hotplug_attr_init(priv);
471 if (err) {
472 dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err);
473 return err;
474 }
475
476 priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,
477 "mlxcpld_hotplug", priv, priv->groups);
478 if (IS_ERR(priv->hwmon)) {
479 dev_err(&pdev->dev, "Failed to register hwmon device %ld\n",
480 PTR_ERR(priv->hwmon));
481 return PTR_ERR(priv->hwmon);
482 }
483
484 platform_set_drvdata(pdev, priv);
485
486 /* Perform initial interrupts setup. */
487 mlxcpld_hotplug_set_irq(priv);
488
489 return 0;
490}
491
492static int mlxcpld_hotplug_remove(struct platform_device *pdev)
493{
494 struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev);
495
496 /* Clean interrupts setup. */
497 mlxcpld_hotplug_unset_irq(priv);
498
499 return 0;
500}
501
502static struct platform_driver mlxcpld_hotplug_driver = {
503 .driver = {
504 .name = "mlxcpld-hotplug",
505 },
506 .probe = mlxcpld_hotplug_probe,
507 .remove = mlxcpld_hotplug_remove,
508};
509
510module_platform_driver(mlxcpld_hotplug_driver);
511
512MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
513MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver");
514MODULE_LICENSE("Dual BSD/GPL");
515MODULE_ALIAS("platform:mlxcpld-hotplug");
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index 3f870972247c..59b8eb626dcc 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -458,7 +458,7 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
458 458
459 rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, 459 rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
460 NULL, &result); 460 NULL, &result);
461 if (!ACPI_SUCCESS(rc)) { 461 if (ACPI_FAILURE(rc)) {
462 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, 462 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
463 "error getting hotkey status\n")); 463 "error getting hotkey status\n"));
464 return; 464 return;
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index b65ce7519411..aa65a857a6b1 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -128,6 +128,7 @@ enum {
128/* ACPI HIDs */ 128/* ACPI HIDs */
129#define TPACPI_ACPI_IBM_HKEY_HID "IBM0068" 129#define TPACPI_ACPI_IBM_HKEY_HID "IBM0068"
130#define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068" 130#define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068"
131#define TPACPI_ACPI_LENOVO_HKEY_V2_HID "LEN0268"
131#define TPACPI_ACPI_EC_HID "PNP0C09" 132#define TPACPI_ACPI_EC_HID "PNP0C09"
132 133
133/* Input IDs */ 134/* Input IDs */
@@ -190,6 +191,9 @@ enum tpacpi_hkey_event_t {
190 TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ 191 TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */
191 TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ 192 TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */
192 TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ 193 TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */
194 TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016):
195 * enter/leave tablet mode
196 */
193 TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ 197 TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */
194 TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ 198 TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */
195 TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */ 199 TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */
@@ -302,7 +306,12 @@ static struct {
302 u32 hotkey:1; 306 u32 hotkey:1;
303 u32 hotkey_mask:1; 307 u32 hotkey_mask:1;
304 u32 hotkey_wlsw:1; 308 u32 hotkey_wlsw:1;
305 u32 hotkey_tablet:1; 309 enum {
310 TP_HOTKEY_TABLET_NONE = 0,
311 TP_HOTKEY_TABLET_USES_MHKG,
312 /* X1 Yoga 2016, seen on BIOS N1FET44W */
313 TP_HOTKEY_TABLET_USES_CMMD,
314 } hotkey_tablet;
306 u32 kbdlight:1; 315 u32 kbdlight:1;
307 u32 light:1; 316 u32 light:1;
308 u32 light_status:1; 317 u32 light_status:1;
@@ -2059,6 +2068,8 @@ static void hotkey_poll_setup(const bool may_warn);
2059 2068
2060/* HKEY.MHKG() return bits */ 2069/* HKEY.MHKG() return bits */
2061#define TP_HOTKEY_TABLET_MASK (1 << 3) 2070#define TP_HOTKEY_TABLET_MASK (1 << 3)
2071/* ThinkPad X1 Yoga (2016) */
2072#define TP_EC_CMMD_TABLET_MODE 0x6
2062 2073
2063static int hotkey_get_wlsw(void) 2074static int hotkey_get_wlsw(void)
2064{ 2075{
@@ -2083,10 +2094,23 @@ static int hotkey_get_tablet_mode(int *status)
2083{ 2094{
2084 int s; 2095 int s;
2085 2096
2086 if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) 2097 switch (tp_features.hotkey_tablet) {
2087 return -EIO; 2098 case TP_HOTKEY_TABLET_USES_MHKG:
2099 if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
2100 return -EIO;
2101
2102 *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
2103 break;
2104 case TP_HOTKEY_TABLET_USES_CMMD:
2105 if (!acpi_evalf(ec_handle, &s, "CMMD", "d"))
2106 return -EIO;
2107
2108 *status = (s == TP_EC_CMMD_TABLET_MODE);
2109 break;
2110 default:
2111 break;
2112 }
2088 2113
2089 *status = ((s & TP_HOTKEY_TABLET_MASK) != 0);
2090 return 0; 2114 return 0;
2091} 2115}
2092 2116
@@ -3117,6 +3141,37 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = {
3117typedef u16 tpacpi_keymap_entry_t; 3141typedef u16 tpacpi_keymap_entry_t;
3118typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; 3142typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN];
3119 3143
3144static int hotkey_init_tablet_mode(void)
3145{
3146 int in_tablet_mode = 0, res;
3147 char *type = NULL;
3148
3149 if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) {
3150 /* For X41t, X60t, X61t Tablets... */
3151 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG;
3152 in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK);
3153 type = "MHKG";
3154 } else if (acpi_evalf(ec_handle, &res, "CMMD", "qd")) {
3155 /* For X1 Yoga (2016) */
3156 tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_CMMD;
3157 in_tablet_mode = res == TP_EC_CMMD_TABLET_MODE;
3158 type = "CMMD";
3159 }
3160
3161 if (!tp_features.hotkey_tablet)
3162 return 0;
3163
3164 pr_info("Tablet mode switch found (type: %s), currently in %s mode\n",
3165 type, in_tablet_mode ? "tablet" : "laptop");
3166
3167 res = add_to_attr_set(hotkey_dev_attributes,
3168 &dev_attr_hotkey_tablet_mode.attr);
3169 if (res)
3170 return -1;
3171
3172 return in_tablet_mode;
3173}
3174
3120static int __init hotkey_init(struct ibm_init_struct *iibm) 3175static int __init hotkey_init(struct ibm_init_struct *iibm)
3121{ 3176{
3122 /* Requirements for changing the default keymaps: 3177 /* Requirements for changing the default keymaps:
@@ -3464,21 +3519,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3464 res = add_to_attr_set(hotkey_dev_attributes, 3519 res = add_to_attr_set(hotkey_dev_attributes,
3465 &dev_attr_hotkey_radio_sw.attr); 3520 &dev_attr_hotkey_radio_sw.attr);
3466 3521
3467 /* For X41t, X60t, X61t Tablets... */ 3522 res = hotkey_init_tablet_mode();
3468 if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { 3523 if (res < 0)
3469 tp_features.hotkey_tablet = 1; 3524 goto err_exit;
3470 tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK);
3471 pr_info("possible tablet mode switch found; "
3472 "ThinkPad in %s mode\n",
3473 (tabletsw_state) ? "tablet" : "laptop");
3474 res = add_to_attr_set(hotkey_dev_attributes,
3475 &dev_attr_hotkey_tablet_mode.attr);
3476 }
3477 3525
3478 if (!res) 3526 tabletsw_state = res;
3479 res = register_attr_set_with_sysfs( 3527
3480 hotkey_dev_attributes, 3528 res = register_attr_set_with_sysfs(hotkey_dev_attributes,
3481 &tpacpi_pdev->dev.kobj); 3529 &tpacpi_pdev->dev.kobj);
3482 if (res) 3530 if (res)
3483 goto err_exit; 3531 goto err_exit;
3484 3532
@@ -3899,6 +3947,12 @@ static bool hotkey_notify_6xxx(const u32 hkey,
3899 *ignore_acpi_ev = true; 3947 *ignore_acpi_ev = true;
3900 return true; 3948 return true;
3901 3949
3950 case TP_HKEY_EV_TABLET_CHANGED:
3951 tpacpi_input_send_tabletsw();
3952 hotkey_tablet_mode_notify_change();
3953 *send_acpi_ev = false;
3954 break;
3955
3902 default: 3956 default:
3903 pr_warn("unknown possible thermal alarm or keyboard event received\n"); 3957 pr_warn("unknown possible thermal alarm or keyboard event received\n");
3904 known = false; 3958 known = false;
@@ -4143,6 +4197,7 @@ errexit:
4143static const struct acpi_device_id ibm_htk_device_ids[] = { 4197static const struct acpi_device_id ibm_htk_device_ids[] = {
4144 {TPACPI_ACPI_IBM_HKEY_HID, 0}, 4198 {TPACPI_ACPI_IBM_HKEY_HID, 0},
4145 {TPACPI_ACPI_LENOVO_HKEY_HID, 0}, 4199 {TPACPI_ACPI_LENOVO_HKEY_HID, 0},
4200 {TPACPI_ACPI_LENOVO_HKEY_V2_HID, 0},
4146 {"", 0}, 4201 {"", 0},
4147}; 4202};
4148 4203
@@ -7716,7 +7771,7 @@ static struct ibm_struct volume_driver_data = {
7716 7771
7717#define alsa_card NULL 7772#define alsa_card NULL
7718 7773
7719static void inline volume_alsa_notify_change(void) 7774static inline void volume_alsa_notify_change(void)
7720{ 7775{
7721} 7776}
7722 7777
@@ -9018,7 +9073,7 @@ static int mute_led_on_off(struct tp_led_table *t, bool state)
9018 acpi_handle temp; 9073 acpi_handle temp;
9019 int output; 9074 int output;
9020 9075
9021 if (!ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) { 9076 if (ACPI_FAILURE(acpi_get_handle(hkey_handle, t->name, &temp))) {
9022 pr_warn("Thinkpad ACPI has no %s interface.\n", t->name); 9077 pr_warn("Thinkpad ACPI has no %s interface.\n", t->name);
9023 return -EIO; 9078 return -EIO;
9024 } 9079 }
diff --git a/include/linux/platform_data/mlxcpld-hotplug.h b/include/linux/platform_data/mlxcpld-hotplug.h
new file mode 100644
index 000000000000..e4cfcffaa6f4
--- /dev/null
+++ b/include/linux/platform_data/mlxcpld-hotplug.h
@@ -0,0 +1,99 @@
1/*
2 * include/linux/platform_data/mlxcpld-hotplug.h
3 * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4 * Copyright (c) 2016 Vadim Pasternak <vadimp@mellanox.com>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the names of the copyright holders nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * Alternatively, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") version 2 as published by the Free
20 * Software Foundation.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
36#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H
37
38/**
39 * struct mlxcpld_hotplug_device - I2C device data:
40 * @adapter: I2C device adapter;
41 * @client: I2C device client;
42 * @brdinfo: device board information;
43 * @bus: I2C bus, where device is attached;
44 *
45 * Structure represents I2C hotplug device static data (board topology) and
46 * dynamic data (related kernel objects handles).
47 */
48struct mlxcpld_hotplug_device {
49 struct i2c_adapter *adapter;
50 struct i2c_client *client;
51 struct i2c_board_info brdinfo;
52 u16 bus;
53};
54
55/**
56 * struct mlxcpld_hotplug_platform_data - device platform data:
57 * @top_aggr_offset: offset of top aggregation interrupt register;
58 * @top_aggr_mask: top aggregation interrupt common mask;
59 * @top_aggr_psu_mask: top aggregation interrupt PSU mask;
60 * @psu_reg_offset: offset of PSU interrupt register;
61 * @psu_mask: PSU interrupt mask;
62 * @psu_count: number of equipped replaceable PSUs;
63 * @psu: pointer to PSU devices data array;
64 * @top_aggr_pwr_mask: top aggregation interrupt power mask;
65 * @pwr_reg_offset: offset of power interrupt register
66 * @pwr_mask: power interrupt mask;
67 * @pwr_count: number of power sources;
68 * @pwr: pointer to power devices data array;
69 * @top_aggr_fan_mask: top aggregation interrupt FAN mask;
70 * @fan_reg_offset: offset of FAN interrupt register;
71 * @fan_mask: FAN interrupt mask;
72 * @fan_count: number of equipped replaceable FANs;
73 * @fan: pointer to FAN devices data array;
74 *
75 * Structure represents board platform data, related to system hotplug events,
76 * like FAN, PSU, power cable insertion and removing. This data provides the
77 * number of hot-pluggable devices and hardware description for event handling.
78 */
79struct mlxcpld_hotplug_platform_data {
80 u16 top_aggr_offset;
81 u8 top_aggr_mask;
82 u8 top_aggr_psu_mask;
83 u16 psu_reg_offset;
84 u8 psu_mask;
85 u8 psu_count;
86 struct mlxcpld_hotplug_device *psu;
87 u8 top_aggr_pwr_mask;
88 u16 pwr_reg_offset;
89 u8 pwr_mask;
90 u8 pwr_count;
91 struct mlxcpld_hotplug_device *pwr;
92 u8 top_aggr_fan_mask;
93 u16 fan_reg_offset;
94 u8 fan_mask;
95 u8 fan_count;
96 struct mlxcpld_hotplug_device *fan;
97};
98
99#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */