diff options
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/Kconfig | 48 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 3 | ||||
-rw-r--r-- | drivers/platform/x86/acer-wmi.c | 30 | ||||
-rw-r--r-- | drivers/platform/x86/amilo-rfkill.c | 173 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-tablet.c | 478 | ||||
-rw-r--r-- | drivers/platform/x86/hdaps.c | 4 | ||||
-rw-r--r-- | drivers/platform/x86/ibm_rtl.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/intel_ips.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/intel_mid_powerbtn.c | 32 | ||||
-rw-r--r-- | drivers/platform/x86/intel_mid_thermal.c | 47 | ||||
-rw-r--r-- | drivers/platform/x86/intel_rar_register.c | 669 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 208 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipcutil.c | 32 | ||||
-rw-r--r-- | drivers/platform/x86/panasonic-laptop.c | 4 |
14 files changed, 796 insertions, 962 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f995e6e2f78c..2dc02c972ce9 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -143,6 +143,30 @@ config FUJITSU_LAPTOP_DEBUG | |||
143 | 143 | ||
144 | If you are not sure, say N here. | 144 | If you are not sure, say N here. |
145 | 145 | ||
146 | config FUJITSU_TABLET | ||
147 | tristate "Fujitsu Tablet Extras" | ||
148 | depends on ACPI | ||
149 | depends on INPUT | ||
150 | ---help--- | ||
151 | This is a driver for tablets built by Fujitsu: | ||
152 | |||
153 | * Lifebook P1510/P1610/P1620/Txxxx | ||
154 | * Stylistic ST5xxx | ||
155 | * Possibly other Fujitsu tablet models | ||
156 | |||
157 | It adds support for the panel buttons, docking station detection, | ||
158 | tablet/notebook mode detection for convertible and | ||
159 | orientation detection for docked slates. | ||
160 | |||
161 | If you have a Fujitsu convertible or slate, say Y or M here. | ||
162 | |||
163 | config AMILO_RFKILL | ||
164 | tristate "Fujitsu-Siemens Amilo rfkill support" | ||
165 | depends on RFKILL | ||
166 | ---help--- | ||
167 | This is a driver for enabling wifi on some Fujitsu-Siemens Amilo | ||
168 | laptops. | ||
169 | |||
146 | config TC1100_WMI | 170 | config TC1100_WMI |
147 | tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" | 171 | tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" |
148 | depends on !X86_64 | 172 | depends on !X86_64 |
@@ -672,33 +696,11 @@ config INTEL_MID_POWER_BUTTON | |||
672 | 696 | ||
673 | config INTEL_MFLD_THERMAL | 697 | config INTEL_MFLD_THERMAL |
674 | tristate "Thermal driver for Intel Medfield platform" | 698 | tristate "Thermal driver for Intel Medfield platform" |
675 | depends on INTEL_SCU_IPC && THERMAL | 699 | depends on MFD_INTEL_MSIC && THERMAL |
676 | help | 700 | help |
677 | Say Y here to enable thermal driver support for the Intel Medfield | 701 | Say Y here to enable thermal driver support for the Intel Medfield |
678 | platform. | 702 | platform. |
679 | 703 | ||
680 | config RAR_REGISTER | ||
681 | bool "Restricted Access Region Register Driver" | ||
682 | depends on PCI && X86_MRST | ||
683 | default n | ||
684 | ---help--- | ||
685 | This driver allows other kernel drivers access to the | ||
686 | contents of the restricted access region control registers. | ||
687 | |||
688 | The restricted access region control registers | ||
689 | (rar_registers) are used to pass address and | ||
690 | locking information on restricted access regions | ||
691 | to other drivers that use restricted access regions. | ||
692 | |||
693 | The restricted access regions are regions of memory | ||
694 | on the Intel MID Platform that are not accessible to | ||
695 | the x86 processor, but are accessible to dedicated | ||
696 | processors on board peripheral devices. | ||
697 | |||
698 | The purpose of the restricted access regions is to | ||
699 | protect sensitive data from compromise by unauthorized | ||
700 | programs running on the x86 processor. | ||
701 | |||
702 | config INTEL_IPS | 704 | config INTEL_IPS |
703 | tristate "Intel Intelligent Power Sharing" | 705 | tristate "Intel Intelligent Power Sharing" |
704 | depends on ACPI | 706 | depends on ACPI |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 293a320d9faa..bb947657d490 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -17,12 +17,14 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o | |||
17 | obj-$(CONFIG_ACERHDF) += acerhdf.o | 17 | obj-$(CONFIG_ACERHDF) += acerhdf.o |
18 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o | 18 | obj-$(CONFIG_HP_ACCEL) += hp_accel.o |
19 | obj-$(CONFIG_HP_WMI) += hp-wmi.o | 19 | obj-$(CONFIG_HP_WMI) += hp-wmi.o |
20 | obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o | ||
20 | obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o | 21 | obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o |
21 | obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o | 22 | obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o |
22 | obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o | 23 | obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o |
23 | obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o | 24 | obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o |
24 | obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o | 25 | obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o |
25 | obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o | 26 | obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o |
27 | obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o | ||
26 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o | 28 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o |
27 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o | 29 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o |
28 | obj-$(CONFIG_ACPI_WMI) += wmi.o | 30 | obj-$(CONFIG_ACPI_WMI) += wmi.o |
@@ -34,7 +36,6 @@ obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | |||
34 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o | 36 | obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o |
35 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o | 37 | obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o |
36 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o | 38 | obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o |
37 | obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o | ||
38 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o | 39 | obj-$(CONFIG_INTEL_IPS) += intel_ips.o |
39 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o | 40 | obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o |
40 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o | 41 | obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o |
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index b848277171a4..1e5290b5396d 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c | |||
@@ -679,6 +679,32 @@ static acpi_status AMW0_find_mailled(void) | |||
679 | return AE_OK; | 679 | return AE_OK; |
680 | } | 680 | } |
681 | 681 | ||
682 | static int AMW0_set_cap_acpi_check_device_found; | ||
683 | |||
684 | static acpi_status AMW0_set_cap_acpi_check_device_cb(acpi_handle handle, | ||
685 | u32 level, void *context, void **retval) | ||
686 | { | ||
687 | AMW0_set_cap_acpi_check_device_found = 1; | ||
688 | return AE_OK; | ||
689 | } | ||
690 | |||
691 | static const struct acpi_device_id norfkill_ids[] = { | ||
692 | { "VPC2004", 0}, | ||
693 | { "IBM0068", 0}, | ||
694 | { "LEN0068", 0}, | ||
695 | { "", 0}, | ||
696 | }; | ||
697 | |||
698 | static int AMW0_set_cap_acpi_check_device(void) | ||
699 | { | ||
700 | const struct acpi_device_id *id; | ||
701 | |||
702 | for (id = norfkill_ids; id->id[0]; id++) | ||
703 | acpi_get_devices(id->id, AMW0_set_cap_acpi_check_device_cb, | ||
704 | NULL, NULL); | ||
705 | return AMW0_set_cap_acpi_check_device_found; | ||
706 | } | ||
707 | |||
682 | static acpi_status AMW0_set_capabilities(void) | 708 | static acpi_status AMW0_set_capabilities(void) |
683 | { | 709 | { |
684 | struct wmab_args args; | 710 | struct wmab_args args; |
@@ -692,7 +718,9 @@ static acpi_status AMW0_set_capabilities(void) | |||
692 | * work. | 718 | * work. |
693 | */ | 719 | */ |
694 | if (wmi_has_guid(AMW0_GUID2)) { | 720 | if (wmi_has_guid(AMW0_GUID2)) { |
695 | interface->capability |= ACER_CAP_WIRELESS; | 721 | if ((quirks != &quirk_unknown) || |
722 | !AMW0_set_cap_acpi_check_device()) | ||
723 | interface->capability |= ACER_CAP_WIRELESS; | ||
696 | return AE_OK; | 724 | return AE_OK; |
697 | } | 725 | } |
698 | 726 | ||
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c new file mode 100644 index 000000000000..19170bb7700b --- /dev/null +++ b/drivers/platform/x86/amilo-rfkill.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Support for rfkill on some Fujitsu-Siemens Amilo laptops. | ||
3 | * Copyright 2011 Ben Hutchings. | ||
4 | * | ||
5 | * Based in part on the fsam7440 driver, which is: | ||
6 | * Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata. | ||
7 | * and on the fsaa1655g driver, which is: | ||
8 | * Copyright 2006 Martin Večeřa. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/dmi.h> | ||
18 | #include <linux/i8042.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/rfkill.h> | ||
23 | |||
24 | /* | ||
25 | * These values were obtained from disassembling and debugging the | ||
26 | * PM.exe program installed in the Fujitsu-Siemens AMILO A1655G | ||
27 | */ | ||
28 | #define A1655_WIFI_COMMAND 0x10C5 | ||
29 | #define A1655_WIFI_ON 0x25 | ||
30 | #define A1655_WIFI_OFF 0x45 | ||
31 | |||
32 | static int amilo_a1655_rfkill_set_block(void *data, bool blocked) | ||
33 | { | ||
34 | u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON; | ||
35 | int rc; | ||
36 | |||
37 | i8042_lock_chip(); | ||
38 | rc = i8042_command(¶m, A1655_WIFI_COMMAND); | ||
39 | i8042_unlock_chip(); | ||
40 | return rc; | ||
41 | } | ||
42 | |||
43 | static const struct rfkill_ops amilo_a1655_rfkill_ops = { | ||
44 | .set_block = amilo_a1655_rfkill_set_block | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * These values were obtained from disassembling the PM.exe program | ||
49 | * installed in the Fujitsu-Siemens AMILO M 7440 | ||
50 | */ | ||
51 | #define M7440_PORT1 0x118f | ||
52 | #define M7440_PORT2 0x118e | ||
53 | #define M7440_RADIO_ON1 0x12 | ||
54 | #define M7440_RADIO_ON2 0x80 | ||
55 | #define M7440_RADIO_OFF1 0x10 | ||
56 | #define M7440_RADIO_OFF2 0x00 | ||
57 | |||
58 | static int amilo_m7440_rfkill_set_block(void *data, bool blocked) | ||
59 | { | ||
60 | u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1; | ||
61 | u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2; | ||
62 | |||
63 | outb(val1, M7440_PORT1); | ||
64 | outb(val2, M7440_PORT2); | ||
65 | |||
66 | /* Check whether the state has changed correctly */ | ||
67 | if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2) | ||
68 | return -EIO; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static const struct rfkill_ops amilo_m7440_rfkill_ops = { | ||
74 | .set_block = amilo_m7440_rfkill_set_block | ||
75 | }; | ||
76 | |||
77 | static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = { | ||
78 | { | ||
79 | .matches = { | ||
80 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | ||
81 | DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"), | ||
82 | }, | ||
83 | .driver_data = (void *)&amilo_a1655_rfkill_ops | ||
84 | }, | ||
85 | { | ||
86 | .matches = { | ||
87 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | ||
88 | DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"), | ||
89 | }, | ||
90 | .driver_data = (void *)&amilo_m7440_rfkill_ops | ||
91 | }, | ||
92 | {} | ||
93 | }; | ||
94 | |||
95 | static struct platform_device *amilo_rfkill_pdev; | ||
96 | static struct rfkill *amilo_rfkill_dev; | ||
97 | |||
98 | static int __devinit amilo_rfkill_probe(struct platform_device *device) | ||
99 | { | ||
100 | const struct dmi_system_id *system_id = | ||
101 | dmi_first_match(amilo_rfkill_id_table); | ||
102 | int rc; | ||
103 | |||
104 | amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev, | ||
105 | RFKILL_TYPE_WLAN, | ||
106 | system_id->driver_data, NULL); | ||
107 | if (!amilo_rfkill_dev) | ||
108 | return -ENOMEM; | ||
109 | |||
110 | rc = rfkill_register(amilo_rfkill_dev); | ||
111 | if (rc) | ||
112 | goto fail; | ||
113 | |||
114 | return 0; | ||
115 | |||
116 | fail: | ||
117 | rfkill_destroy(amilo_rfkill_dev); | ||
118 | return rc; | ||
119 | } | ||
120 | |||
121 | static int amilo_rfkill_remove(struct platform_device *device) | ||
122 | { | ||
123 | rfkill_unregister(amilo_rfkill_dev); | ||
124 | rfkill_destroy(amilo_rfkill_dev); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static struct platform_driver amilo_rfkill_driver = { | ||
129 | .driver = { | ||
130 | .name = KBUILD_MODNAME, | ||
131 | .owner = THIS_MODULE, | ||
132 | }, | ||
133 | .probe = amilo_rfkill_probe, | ||
134 | .remove = amilo_rfkill_remove, | ||
135 | }; | ||
136 | |||
137 | static int __init amilo_rfkill_init(void) | ||
138 | { | ||
139 | int rc; | ||
140 | |||
141 | if (dmi_first_match(amilo_rfkill_id_table) == NULL) | ||
142 | return -ENODEV; | ||
143 | |||
144 | rc = platform_driver_register(&amilo_rfkill_driver); | ||
145 | if (rc) | ||
146 | return rc; | ||
147 | |||
148 | amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1, | ||
149 | NULL, 0); | ||
150 | if (IS_ERR(amilo_rfkill_pdev)) { | ||
151 | rc = PTR_ERR(amilo_rfkill_pdev); | ||
152 | goto fail; | ||
153 | } | ||
154 | |||
155 | return 0; | ||
156 | |||
157 | fail: | ||
158 | platform_driver_unregister(&amilo_rfkill_driver); | ||
159 | return rc; | ||
160 | } | ||
161 | |||
162 | static void __exit amilo_rfkill_exit(void) | ||
163 | { | ||
164 | platform_device_unregister(amilo_rfkill_pdev); | ||
165 | platform_driver_unregister(&amilo_rfkill_driver); | ||
166 | } | ||
167 | |||
168 | MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>"); | ||
169 | MODULE_LICENSE("GPL"); | ||
170 | MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table); | ||
171 | |||
172 | module_init(amilo_rfkill_init); | ||
173 | module_exit(amilo_rfkill_exit); | ||
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c new file mode 100644 index 000000000000..580d80a73c3a --- /dev/null +++ b/drivers/platform/x86/fujitsu-tablet.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2012 Robert Gerlach <khnz@gmx.de> | ||
3 | * Copyright (C) 2005-2006 Jan Rychter <jan@rychter.com> | ||
4 | * | ||
5 | * You can redistribute and/or modify this program under the terms of the | ||
6 | * GNU General Public License version 2 as published by the Free Software | ||
7 | * Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General | ||
12 | * Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along | ||
15 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
16 | * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/bitops.h> | ||
23 | #include <linux/io.h> | ||
24 | #include <linux/ioport.h> | ||
25 | #include <linux/acpi.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/input.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/dmi.h> | ||
31 | |||
32 | #define MODULENAME "fujitsu-tablet" | ||
33 | |||
34 | #define ACPI_FUJITSU_CLASS "fujitsu" | ||
35 | |||
36 | #define INVERT_TABLET_MODE_BIT 0x01 | ||
37 | #define FORCE_TABLET_MODE_IF_UNDOCK 0x02 | ||
38 | |||
39 | #define KEYMAP_LEN 16 | ||
40 | |||
41 | static const struct acpi_device_id fujitsu_ids[] = { | ||
42 | { .id = "FUJ02BD" }, | ||
43 | { .id = "FUJ02BF" }, | ||
44 | { .id = "" } | ||
45 | }; | ||
46 | |||
47 | struct fujitsu_config { | ||
48 | unsigned short keymap[KEYMAP_LEN]; | ||
49 | unsigned int quirks; | ||
50 | }; | ||
51 | |||
52 | static unsigned short keymap_Lifebook_Tseries[KEYMAP_LEN] __initconst = { | ||
53 | KEY_RESERVED, | ||
54 | KEY_RESERVED, | ||
55 | KEY_RESERVED, | ||
56 | KEY_RESERVED, | ||
57 | KEY_SCROLLDOWN, | ||
58 | KEY_SCROLLUP, | ||
59 | KEY_DIRECTION, | ||
60 | KEY_LEFTCTRL, | ||
61 | KEY_BRIGHTNESSUP, | ||
62 | KEY_BRIGHTNESSDOWN, | ||
63 | KEY_BRIGHTNESS_ZERO, | ||
64 | KEY_RESERVED, | ||
65 | KEY_RESERVED, | ||
66 | KEY_RESERVED, | ||
67 | KEY_RESERVED, | ||
68 | KEY_LEFTALT | ||
69 | }; | ||
70 | |||
71 | static unsigned short keymap_Lifebook_U810[KEYMAP_LEN] __initconst = { | ||
72 | KEY_RESERVED, | ||
73 | KEY_RESERVED, | ||
74 | KEY_RESERVED, | ||
75 | KEY_RESERVED, | ||
76 | KEY_PROG1, | ||
77 | KEY_PROG2, | ||
78 | KEY_DIRECTION, | ||
79 | KEY_RESERVED, | ||
80 | KEY_RESERVED, | ||
81 | KEY_RESERVED, | ||
82 | KEY_UP, | ||
83 | KEY_DOWN, | ||
84 | KEY_RESERVED, | ||
85 | KEY_RESERVED, | ||
86 | KEY_LEFTCTRL, | ||
87 | KEY_LEFTALT | ||
88 | }; | ||
89 | |||
90 | static unsigned short keymap_Stylistic_Tseries[KEYMAP_LEN] __initconst = { | ||
91 | KEY_RESERVED, | ||
92 | KEY_RESERVED, | ||
93 | KEY_RESERVED, | ||
94 | KEY_RESERVED, | ||
95 | KEY_PRINT, | ||
96 | KEY_BACKSPACE, | ||
97 | KEY_SPACE, | ||
98 | KEY_ENTER, | ||
99 | KEY_BRIGHTNESSUP, | ||
100 | KEY_BRIGHTNESSDOWN, | ||
101 | KEY_DOWN, | ||
102 | KEY_UP, | ||
103 | KEY_SCROLLUP, | ||
104 | KEY_SCROLLDOWN, | ||
105 | KEY_LEFTCTRL, | ||
106 | KEY_LEFTALT | ||
107 | }; | ||
108 | |||
109 | static unsigned short keymap_Stylistic_ST5xxx[KEYMAP_LEN] __initconst = { | ||
110 | KEY_RESERVED, | ||
111 | KEY_RESERVED, | ||
112 | KEY_RESERVED, | ||
113 | KEY_RESERVED, | ||
114 | KEY_MAIL, | ||
115 | KEY_DIRECTION, | ||
116 | KEY_ESC, | ||
117 | KEY_ENTER, | ||
118 | KEY_BRIGHTNESSUP, | ||
119 | KEY_BRIGHTNESSDOWN, | ||
120 | KEY_DOWN, | ||
121 | KEY_UP, | ||
122 | KEY_SCROLLUP, | ||
123 | KEY_SCROLLDOWN, | ||
124 | KEY_LEFTCTRL, | ||
125 | KEY_LEFTALT | ||
126 | }; | ||
127 | |||
128 | static struct { | ||
129 | struct input_dev *idev; | ||
130 | struct fujitsu_config config; | ||
131 | unsigned long prev_keymask; | ||
132 | |||
133 | char phys[21]; | ||
134 | |||
135 | int irq; | ||
136 | int io_base; | ||
137 | int io_length; | ||
138 | } fujitsu; | ||
139 | |||
140 | static u8 fujitsu_ack(void) | ||
141 | { | ||
142 | return inb(fujitsu.io_base + 2); | ||
143 | } | ||
144 | |||
145 | static u8 fujitsu_status(void) | ||
146 | { | ||
147 | return inb(fujitsu.io_base + 6); | ||
148 | } | ||
149 | |||
150 | static u8 fujitsu_read_register(const u8 addr) | ||
151 | { | ||
152 | outb(addr, fujitsu.io_base); | ||
153 | return inb(fujitsu.io_base + 4); | ||
154 | } | ||
155 | |||
156 | static void fujitsu_send_state(void) | ||
157 | { | ||
158 | int state; | ||
159 | int dock, tablet_mode; | ||
160 | |||
161 | state = fujitsu_read_register(0xdd); | ||
162 | |||
163 | dock = state & 0x02; | ||
164 | |||
165 | if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { | ||
166 | tablet_mode = 1; | ||
167 | } else{ | ||
168 | tablet_mode = state & 0x01; | ||
169 | if (fujitsu.config.quirks & INVERT_TABLET_MODE_BIT) | ||
170 | tablet_mode = !tablet_mode; | ||
171 | } | ||
172 | |||
173 | input_report_switch(fujitsu.idev, SW_DOCK, dock); | ||
174 | input_report_switch(fujitsu.idev, SW_TABLET_MODE, tablet_mode); | ||
175 | input_sync(fujitsu.idev); | ||
176 | } | ||
177 | |||
178 | static void fujitsu_reset(void) | ||
179 | { | ||
180 | int timeout = 50; | ||
181 | |||
182 | fujitsu_ack(); | ||
183 | |||
184 | while ((fujitsu_status() & 0x02) && (--timeout)) | ||
185 | msleep(20); | ||
186 | |||
187 | fujitsu_send_state(); | ||
188 | } | ||
189 | |||
190 | static int __devinit input_fujitsu_setup(struct device *parent, | ||
191 | const char *name, const char *phys) | ||
192 | { | ||
193 | struct input_dev *idev; | ||
194 | int error; | ||
195 | int i; | ||
196 | |||
197 | idev = input_allocate_device(); | ||
198 | if (!idev) | ||
199 | return -ENOMEM; | ||
200 | |||
201 | idev->dev.parent = parent; | ||
202 | idev->phys = phys; | ||
203 | idev->name = name; | ||
204 | idev->id.bustype = BUS_HOST; | ||
205 | idev->id.vendor = 0x1734; /* Fujitsu Siemens Computer GmbH */ | ||
206 | idev->id.product = 0x0001; | ||
207 | idev->id.version = 0x0101; | ||
208 | |||
209 | idev->keycode = fujitsu.config.keymap; | ||
210 | idev->keycodesize = sizeof(fujitsu.config.keymap[0]); | ||
211 | idev->keycodemax = ARRAY_SIZE(fujitsu.config.keymap); | ||
212 | |||
213 | __set_bit(EV_REP, idev->evbit); | ||
214 | |||
215 | for (i = 0; i < ARRAY_SIZE(fujitsu.config.keymap); i++) | ||
216 | if (fujitsu.config.keymap[i]) | ||
217 | input_set_capability(idev, EV_KEY, fujitsu.config.keymap[i]); | ||
218 | |||
219 | input_set_capability(idev, EV_MSC, MSC_SCAN); | ||
220 | |||
221 | input_set_capability(idev, EV_SW, SW_DOCK); | ||
222 | input_set_capability(idev, EV_SW, SW_TABLET_MODE); | ||
223 | |||
224 | input_set_capability(idev, EV_SW, SW_DOCK); | ||
225 | input_set_capability(idev, EV_SW, SW_TABLET_MODE); | ||
226 | |||
227 | error = input_register_device(idev); | ||
228 | if (error) { | ||
229 | input_free_device(idev); | ||
230 | return error; | ||
231 | } | ||
232 | |||
233 | fujitsu.idev = idev; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static void input_fujitsu_remove(void) | ||
238 | { | ||
239 | input_unregister_device(fujitsu.idev); | ||
240 | } | ||
241 | |||
242 | static irqreturn_t fujitsu_interrupt(int irq, void *dev_id) | ||
243 | { | ||
244 | unsigned long keymask, changed; | ||
245 | unsigned int keycode; | ||
246 | int pressed; | ||
247 | int i; | ||
248 | |||
249 | if (unlikely(!(fujitsu_status() & 0x01))) | ||
250 | return IRQ_NONE; | ||
251 | |||
252 | fujitsu_send_state(); | ||
253 | |||
254 | keymask = fujitsu_read_register(0xde); | ||
255 | keymask |= fujitsu_read_register(0xdf) << 8; | ||
256 | keymask ^= 0xffff; | ||
257 | |||
258 | changed = keymask ^ fujitsu.prev_keymask; | ||
259 | if (changed) { | ||
260 | fujitsu.prev_keymask = keymask; | ||
261 | |||
262 | for_each_set_bit(i, &changed, KEYMAP_LEN) { | ||
263 | keycode = fujitsu.config.keymap[i]; | ||
264 | pressed = keymask & changed & BIT(i); | ||
265 | |||
266 | if (pressed) | ||
267 | input_event(fujitsu.idev, EV_MSC, MSC_SCAN, i); | ||
268 | |||
269 | input_report_key(fujitsu.idev, keycode, pressed); | ||
270 | input_sync(fujitsu.idev); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | fujitsu_ack(); | ||
275 | return IRQ_HANDLED; | ||
276 | } | ||
277 | |||
278 | static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) | ||
279 | { | ||
280 | printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); | ||
281 | memcpy(fujitsu.config.keymap, dmi->driver_data, | ||
282 | sizeof(fujitsu.config.keymap)); | ||
283 | return 1; | ||
284 | } | ||
285 | |||
286 | static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) | ||
287 | { | ||
288 | fujitsu_dmi_default(dmi); | ||
289 | fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; | ||
290 | fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | static struct dmi_system_id dmi_ids[] __initconst = { | ||
295 | { | ||
296 | .callback = fujitsu_dmi_default, | ||
297 | .ident = "Fujitsu Siemens P/T Series", | ||
298 | .matches = { | ||
299 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
300 | DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK") | ||
301 | }, | ||
302 | .driver_data = keymap_Lifebook_Tseries | ||
303 | }, | ||
304 | { | ||
305 | .callback = fujitsu_dmi_default, | ||
306 | .ident = "Fujitsu Lifebook T Series", | ||
307 | .matches = { | ||
308 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
309 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook T") | ||
310 | }, | ||
311 | .driver_data = keymap_Lifebook_Tseries | ||
312 | }, | ||
313 | { | ||
314 | .callback = fujitsu_dmi_stylistic, | ||
315 | .ident = "Fujitsu Siemens Stylistic T Series", | ||
316 | .matches = { | ||
317 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
318 | DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic T") | ||
319 | }, | ||
320 | .driver_data = keymap_Stylistic_Tseries | ||
321 | }, | ||
322 | { | ||
323 | .callback = fujitsu_dmi_default, | ||
324 | .ident = "Fujitsu LifeBook U810", | ||
325 | .matches = { | ||
326 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
327 | DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook U810") | ||
328 | }, | ||
329 | .driver_data = keymap_Lifebook_U810 | ||
330 | }, | ||
331 | { | ||
332 | .callback = fujitsu_dmi_stylistic, | ||
333 | .ident = "Fujitsu Siemens Stylistic ST5xxx Series", | ||
334 | .matches = { | ||
335 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
336 | DMI_MATCH(DMI_PRODUCT_NAME, "STYLISTIC ST5") | ||
337 | }, | ||
338 | .driver_data = keymap_Stylistic_ST5xxx | ||
339 | }, | ||
340 | { | ||
341 | .callback = fujitsu_dmi_stylistic, | ||
342 | .ident = "Fujitsu Siemens Stylistic ST5xxx Series", | ||
343 | .matches = { | ||
344 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), | ||
345 | DMI_MATCH(DMI_PRODUCT_NAME, "Stylistic ST5") | ||
346 | }, | ||
347 | .driver_data = keymap_Stylistic_ST5xxx | ||
348 | }, | ||
349 | { | ||
350 | .callback = fujitsu_dmi_default, | ||
351 | .ident = "Unknown (using defaults)", | ||
352 | .matches = { | ||
353 | DMI_MATCH(DMI_SYS_VENDOR, ""), | ||
354 | DMI_MATCH(DMI_PRODUCT_NAME, "") | ||
355 | }, | ||
356 | .driver_data = keymap_Lifebook_Tseries | ||
357 | }, | ||
358 | { NULL } | ||
359 | }; | ||
360 | |||
361 | static acpi_status __devinit | ||
362 | fujitsu_walk_resources(struct acpi_resource *res, void *data) | ||
363 | { | ||
364 | switch (res->type) { | ||
365 | case ACPI_RESOURCE_TYPE_IRQ: | ||
366 | fujitsu.irq = res->data.irq.interrupts[0]; | ||
367 | return AE_OK; | ||
368 | |||
369 | case ACPI_RESOURCE_TYPE_IO: | ||
370 | fujitsu.io_base = res->data.io.minimum; | ||
371 | fujitsu.io_length = res->data.io.address_length; | ||
372 | return AE_OK; | ||
373 | |||
374 | case ACPI_RESOURCE_TYPE_END_TAG: | ||
375 | if (fujitsu.irq && fujitsu.io_base) | ||
376 | return AE_OK; | ||
377 | else | ||
378 | return AE_NOT_FOUND; | ||
379 | |||
380 | default: | ||
381 | return AE_ERROR; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | static int __devinit acpi_fujitsu_add(struct acpi_device *adev) | ||
386 | { | ||
387 | acpi_status status; | ||
388 | int error; | ||
389 | |||
390 | if (!adev) | ||
391 | return -EINVAL; | ||
392 | |||
393 | status = acpi_walk_resources(adev->handle, METHOD_NAME__CRS, | ||
394 | fujitsu_walk_resources, NULL); | ||
395 | if (ACPI_FAILURE(status) || !fujitsu.irq || !fujitsu.io_base) | ||
396 | return -ENODEV; | ||
397 | |||
398 | sprintf(acpi_device_name(adev), "Fujitsu %s", acpi_device_hid(adev)); | ||
399 | sprintf(acpi_device_class(adev), "%s", ACPI_FUJITSU_CLASS); | ||
400 | |||
401 | snprintf(fujitsu.phys, sizeof(fujitsu.phys), | ||
402 | "%s/input0", acpi_device_hid(adev)); | ||
403 | |||
404 | error = input_fujitsu_setup(&adev->dev, | ||
405 | acpi_device_name(adev), fujitsu.phys); | ||
406 | if (error) | ||
407 | return error; | ||
408 | |||
409 | if (!request_region(fujitsu.io_base, fujitsu.io_length, MODULENAME)) { | ||
410 | input_fujitsu_remove(); | ||
411 | return -EBUSY; | ||
412 | } | ||
413 | |||
414 | fujitsu_reset(); | ||
415 | |||
416 | error = request_irq(fujitsu.irq, fujitsu_interrupt, | ||
417 | IRQF_SHARED, MODULENAME, fujitsu_interrupt); | ||
418 | if (error) { | ||
419 | release_region(fujitsu.io_base, fujitsu.io_length); | ||
420 | input_fujitsu_remove(); | ||
421 | return error; | ||
422 | } | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type) | ||
428 | { | ||
429 | free_irq(fujitsu.irq, fujitsu_interrupt); | ||
430 | release_region(fujitsu.io_base, fujitsu.io_length); | ||
431 | input_fujitsu_remove(); | ||
432 | return 0; | ||
433 | } | ||
434 | |||
435 | static int acpi_fujitsu_resume(struct acpi_device *adev) | ||
436 | { | ||
437 | fujitsu_reset(); | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static struct acpi_driver acpi_fujitsu_driver = { | ||
442 | .name = MODULENAME, | ||
443 | .class = "hotkey", | ||
444 | .ids = fujitsu_ids, | ||
445 | .ops = { | ||
446 | .add = acpi_fujitsu_add, | ||
447 | .remove = acpi_fujitsu_remove, | ||
448 | .resume = acpi_fujitsu_resume, | ||
449 | } | ||
450 | }; | ||
451 | |||
452 | static int __init fujitsu_module_init(void) | ||
453 | { | ||
454 | int error; | ||
455 | |||
456 | dmi_check_system(dmi_ids); | ||
457 | |||
458 | error = acpi_bus_register_driver(&acpi_fujitsu_driver); | ||
459 | if (error) | ||
460 | return error; | ||
461 | |||
462 | return 0; | ||
463 | } | ||
464 | |||
465 | static void __exit fujitsu_module_exit(void) | ||
466 | { | ||
467 | acpi_bus_unregister_driver(&acpi_fujitsu_driver); | ||
468 | } | ||
469 | |||
470 | module_init(fujitsu_module_init); | ||
471 | module_exit(fujitsu_module_exit); | ||
472 | |||
473 | MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); | ||
474 | MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); | ||
475 | MODULE_LICENSE("GPL"); | ||
476 | MODULE_VERSION("2.4"); | ||
477 | |||
478 | MODULE_DEVICE_TABLE(acpi, fujitsu_ids); | ||
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c index 5a34973dc164..ba68d4e7a779 100644 --- a/drivers/platform/x86/hdaps.c +++ b/drivers/platform/x86/hdaps.c | |||
@@ -379,7 +379,7 @@ static ssize_t hdaps_temp1_show(struct device *dev, | |||
379 | int ret; | 379 | int ret; |
380 | 380 | ||
381 | ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp); | 381 | ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp); |
382 | if (ret < 0) | 382 | if (ret) |
383 | return ret; | 383 | return ret; |
384 | 384 | ||
385 | return sprintf(buf, "%u\n", temp); | 385 | return sprintf(buf, "%u\n", temp); |
@@ -392,7 +392,7 @@ static ssize_t hdaps_temp2_show(struct device *dev, | |||
392 | int ret; | 392 | int ret; |
393 | 393 | ||
394 | ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp); | 394 | ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp); |
395 | if (ret < 0) | 395 | if (ret) |
396 | return ret; | 396 | return ret; |
397 | 397 | ||
398 | return sprintf(buf, "%u\n", temp); | 398 | return sprintf(buf, "%u\n", temp); |
diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 42a7d603c870..7481146a5b47 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c | |||
@@ -33,6 +33,8 @@ | |||
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <asm/bios_ebda.h> | 34 | #include <asm/bios_ebda.h> |
35 | 35 | ||
36 | #include <asm-generic/io-64-nonatomic-lo-hi.h> | ||
37 | |||
36 | static bool force; | 38 | static bool force; |
37 | module_param(force, bool, 0); | 39 | module_param(force, bool, 0); |
38 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); | 40 | MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); |
@@ -83,19 +85,6 @@ static void __iomem *rtl_cmd_addr; | |||
83 | static u8 rtl_cmd_type; | 85 | static u8 rtl_cmd_type; |
84 | static u8 rtl_cmd_width; | 86 | static u8 rtl_cmd_width; |
85 | 87 | ||
86 | #ifndef readq | ||
87 | static inline __u64 readq(const volatile void __iomem *addr) | ||
88 | { | ||
89 | const volatile u32 __iomem *p = addr; | ||
90 | u32 low, high; | ||
91 | |||
92 | low = readl(p); | ||
93 | high = readl(p + 1); | ||
94 | |||
95 | return low + ((u64)high << 32); | ||
96 | } | ||
97 | #endif | ||
98 | |||
99 | static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len) | 88 | static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len) |
100 | { | 89 | { |
101 | if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO) | 90 | if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO) |
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 809a3ae943c6..88a98cff5a44 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c | |||
@@ -77,6 +77,8 @@ | |||
77 | #include <asm/processor.h> | 77 | #include <asm/processor.h> |
78 | #include "intel_ips.h" | 78 | #include "intel_ips.h" |
79 | 79 | ||
80 | #include <asm-generic/io-64-nonatomic-lo-hi.h> | ||
81 | |||
80 | #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 | 82 | #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 |
81 | 83 | ||
82 | /* | 84 | /* |
@@ -344,19 +346,6 @@ struct ips_driver { | |||
344 | static bool | 346 | static bool |
345 | ips_gpu_turbo_enabled(struct ips_driver *ips); | 347 | ips_gpu_turbo_enabled(struct ips_driver *ips); |
346 | 348 | ||
347 | #ifndef readq | ||
348 | static inline __u64 readq(const volatile void __iomem *addr) | ||
349 | { | ||
350 | const volatile u32 __iomem *p = addr; | ||
351 | u32 low, high; | ||
352 | |||
353 | low = readl(p); | ||
354 | high = readl(p + 1); | ||
355 | |||
356 | return low + ((u64)high << 32); | ||
357 | } | ||
358 | #endif | ||
359 | |||
360 | /** | 349 | /** |
361 | * ips_cpu_busy - is CPU busy? | 350 | * ips_cpu_busy - is CPU busy? |
362 | * @ips: IPS driver struct | 351 | * @ips: IPS driver struct |
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index f1ae5078b7ec..0903a883e9f4 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c | |||
@@ -23,21 +23,27 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/input.h> | 25 | #include <linux/input.h> |
26 | 26 | #include <linux/mfd/intel_msic.h> | |
27 | #include <asm/intel_scu_ipc.h> | ||
28 | 27 | ||
29 | #define DRIVER_NAME "msic_power_btn" | 28 | #define DRIVER_NAME "msic_power_btn" |
30 | 29 | ||
31 | #define MSIC_PB_STATUS 0x3f | ||
32 | #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ | 30 | #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ |
33 | 31 | ||
32 | /* | ||
33 | * MSIC document ti_datasheet defines the 1st bit reg 0x21 is used to mask | ||
34 | * power button interrupt | ||
35 | */ | ||
36 | #define MSIC_PWRBTNM (1 << 0) | ||
37 | |||
34 | static irqreturn_t mfld_pb_isr(int irq, void *dev_id) | 38 | static irqreturn_t mfld_pb_isr(int irq, void *dev_id) |
35 | { | 39 | { |
36 | struct input_dev *input = dev_id; | 40 | struct input_dev *input = dev_id; |
37 | int ret; | 41 | int ret; |
38 | u8 pbstat; | 42 | u8 pbstat; |
39 | 43 | ||
40 | ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); | 44 | ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat); |
45 | dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat); | ||
46 | |||
41 | if (ret < 0) { | 47 | if (ret < 0) { |
42 | dev_err(input->dev.parent, "Read error %d while reading" | 48 | dev_err(input->dev.parent, "Read error %d while reading" |
43 | " MSIC_PB_STATUS\n", ret); | 49 | " MSIC_PB_STATUS\n", ret); |
@@ -88,6 +94,24 @@ static int __devinit mfld_pb_probe(struct platform_device *pdev) | |||
88 | } | 94 | } |
89 | 95 | ||
90 | platform_set_drvdata(pdev, input); | 96 | platform_set_drvdata(pdev, input); |
97 | |||
98 | /* | ||
99 | * SCU firmware might send power button interrupts to IA core before | ||
100 | * kernel boots and doesn't get EOI from IA core. The first bit of | ||
101 | * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new | ||
102 | * power interrupt to Android kernel. Unmask the bit when probing | ||
103 | * power button in kernel. | ||
104 | * There is a very narrow race between irq handler and power button | ||
105 | * initialization. The race happens rarely. So we needn't worry | ||
106 | * about it. | ||
107 | */ | ||
108 | error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM); | ||
109 | if (error) { | ||
110 | dev_err(&pdev->dev, "Unable to clear power button interrupt, " | ||
111 | "error: %d\n", error); | ||
112 | goto err_free_irq; | ||
113 | } | ||
114 | |||
91 | return 0; | 115 | return 0; |
92 | 116 | ||
93 | err_free_irq: | 117 | err_free_irq: |
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index ccd7b1f83519..2ee9766737ea 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c | |||
@@ -33,18 +33,15 @@ | |||
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/pm.h> | 34 | #include <linux/pm.h> |
35 | #include <linux/thermal.h> | 35 | #include <linux/thermal.h> |
36 | 36 | #include <linux/mfd/intel_msic.h> | |
37 | #include <asm/intel_scu_ipc.h> | ||
38 | 37 | ||
39 | /* Number of thermal sensors */ | 38 | /* Number of thermal sensors */ |
40 | #define MSIC_THERMAL_SENSORS 4 | 39 | #define MSIC_THERMAL_SENSORS 4 |
41 | 40 | ||
42 | /* ADC1 - thermal registers */ | 41 | /* ADC1 - thermal registers */ |
43 | #define MSIC_THERM_ADC1CNTL1 0x1C0 | ||
44 | #define MSIC_ADC_ENBL 0x10 | 42 | #define MSIC_ADC_ENBL 0x10 |
45 | #define MSIC_ADC_START 0x08 | 43 | #define MSIC_ADC_START 0x08 |
46 | 44 | ||
47 | #define MSIC_THERM_ADC1CNTL3 0x1C2 | ||
48 | #define MSIC_ADCTHERM_ENBL 0x04 | 45 | #define MSIC_ADCTHERM_ENBL 0x04 |
49 | #define MSIC_ADCRRDATA_ENBL 0x05 | 46 | #define MSIC_ADCRRDATA_ENBL 0x05 |
50 | #define MSIC_CHANL_MASK_VAL 0x0F | 47 | #define MSIC_CHANL_MASK_VAL 0x0F |
@@ -75,8 +72,8 @@ | |||
75 | #define ADC_VAL60C 315 | 72 | #define ADC_VAL60C 315 |
76 | 73 | ||
77 | /* ADC base addresses */ | 74 | /* ADC base addresses */ |
78 | #define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ | 75 | #define ADC_CHNL_START_ADDR INTEL_MSIC_ADC1ADDR0 /* increments by 1 */ |
79 | #define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ | 76 | #define ADC_DATA_START_ADDR INTEL_MSIC_ADC1SNS0H /* increments by 2 */ |
80 | 77 | ||
81 | /* MSIC die attributes */ | 78 | /* MSIC die attributes */ |
82 | #define MSIC_DIE_ADC_MIN 488 | 79 | #define MSIC_DIE_ADC_MIN 488 |
@@ -189,17 +186,17 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) | |||
189 | addr = td_info->chnl_addr; | 186 | addr = td_info->chnl_addr; |
190 | 187 | ||
191 | /* Enable the msic for conversion before reading */ | 188 | /* Enable the msic for conversion before reading */ |
192 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); | 189 | ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); |
193 | if (ret) | 190 | if (ret) |
194 | return ret; | 191 | return ret; |
195 | 192 | ||
196 | /* Re-toggle the RRDATARD bit (temporary workaround) */ | 193 | /* Re-toggle the RRDATARD bit (temporary workaround) */ |
197 | ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); | 194 | ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCTHERM_ENBL); |
198 | if (ret) | 195 | if (ret) |
199 | return ret; | 196 | return ret; |
200 | 197 | ||
201 | /* Read the higher bits of data */ | 198 | /* Read the higher bits of data */ |
202 | ret = intel_scu_ipc_ioread8(addr, &data); | 199 | ret = intel_msic_reg_read(addr, &data); |
203 | if (ret) | 200 | if (ret) |
204 | return ret; | 201 | return ret; |
205 | 202 | ||
@@ -207,7 +204,7 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) | |||
207 | adc_val = (data << 2); | 204 | adc_val = (data << 2); |
208 | addr++; | 205 | addr++; |
209 | 206 | ||
210 | ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ | 207 | ret = intel_msic_reg_read(addr, &data);/* Read lower bits */ |
211 | if (ret) | 208 | if (ret) |
212 | return ret; | 209 | return ret; |
213 | 210 | ||
@@ -235,7 +232,7 @@ static int configure_adc(int val) | |||
235 | int ret; | 232 | int ret; |
236 | uint8_t data; | 233 | uint8_t data; |
237 | 234 | ||
238 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | 235 | ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data); |
239 | if (ret) | 236 | if (ret) |
240 | return ret; | 237 | return ret; |
241 | 238 | ||
@@ -246,7 +243,7 @@ static int configure_adc(int val) | |||
246 | /* Just stop the ADC */ | 243 | /* Just stop the ADC */ |
247 | data &= (~MSIC_ADC_START); | 244 | data &= (~MSIC_ADC_START); |
248 | } | 245 | } |
249 | return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); | 246 | return intel_msic_reg_write(INTEL_MSIC_ADC1CNTL1, data); |
250 | } | 247 | } |
251 | 248 | ||
252 | /** | 249 | /** |
@@ -262,21 +259,21 @@ static int set_up_therm_channel(u16 base_addr) | |||
262 | int ret; | 259 | int ret; |
263 | 260 | ||
264 | /* Enable all the sensor channels */ | 261 | /* Enable all the sensor channels */ |
265 | ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); | 262 | ret = intel_msic_reg_write(base_addr, SKIN_SENSOR0_CODE); |
266 | if (ret) | 263 | if (ret) |
267 | return ret; | 264 | return ret; |
268 | 265 | ||
269 | ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); | 266 | ret = intel_msic_reg_write(base_addr + 1, SKIN_SENSOR1_CODE); |
270 | if (ret) | 267 | if (ret) |
271 | return ret; | 268 | return ret; |
272 | 269 | ||
273 | ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); | 270 | ret = intel_msic_reg_write(base_addr + 2, SYS_SENSOR_CODE); |
274 | if (ret) | 271 | if (ret) |
275 | return ret; | 272 | return ret; |
276 | 273 | ||
277 | /* Since this is the last channel, set the stop bit | 274 | /* Since this is the last channel, set the stop bit |
278 | * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ | 275 | * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ |
279 | ret = intel_scu_ipc_iowrite8(base_addr + 3, | 276 | ret = intel_msic_reg_write(base_addr + 3, |
280 | (MSIC_DIE_SENSOR_CODE | 0x10)); | 277 | (MSIC_DIE_SENSOR_CODE | 0x10)); |
281 | if (ret) | 278 | if (ret) |
282 | return ret; | 279 | return ret; |
@@ -295,11 +292,11 @@ static int reset_stopbit(uint16_t addr) | |||
295 | { | 292 | { |
296 | int ret; | 293 | int ret; |
297 | uint8_t data; | 294 | uint8_t data; |
298 | ret = intel_scu_ipc_ioread8(addr, &data); | 295 | ret = intel_msic_reg_read(addr, &data); |
299 | if (ret) | 296 | if (ret) |
300 | return ret; | 297 | return ret; |
301 | /* Set the stop bit to zero */ | 298 | /* Set the stop bit to zero */ |
302 | return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); | 299 | return intel_msic_reg_write(addr, (data & 0xEF)); |
303 | } | 300 | } |
304 | 301 | ||
305 | /** | 302 | /** |
@@ -322,7 +319,7 @@ static int find_free_channel(void) | |||
322 | uint8_t data; | 319 | uint8_t data; |
323 | 320 | ||
324 | /* check whether ADC is enabled */ | 321 | /* check whether ADC is enabled */ |
325 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); | 322 | ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data); |
326 | if (ret) | 323 | if (ret) |
327 | return ret; | 324 | return ret; |
328 | 325 | ||
@@ -331,7 +328,7 @@ static int find_free_channel(void) | |||
331 | 328 | ||
332 | /* ADC is already enabled; Looking for an empty channel */ | 329 | /* ADC is already enabled; Looking for an empty channel */ |
333 | for (i = 0; i < ADC_CHANLS_MAX; i++) { | 330 | for (i = 0; i < ADC_CHANLS_MAX; i++) { |
334 | ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); | 331 | ret = intel_msic_reg_read(ADC_CHNL_START_ADDR + i, &data); |
335 | if (ret) | 332 | if (ret) |
336 | return ret; | 333 | return ret; |
337 | 334 | ||
@@ -359,12 +356,14 @@ static int mid_initialize_adc(struct device *dev) | |||
359 | * Ensure that adctherm is disabled before we | 356 | * Ensure that adctherm is disabled before we |
360 | * initialize the ADC | 357 | * initialize the ADC |
361 | */ | 358 | */ |
362 | ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); | 359 | ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL3, &data); |
363 | if (ret) | 360 | if (ret) |
364 | return ret; | 361 | return ret; |
365 | 362 | ||
366 | if (data & MSIC_ADCTHERM_MASK) | 363 | data &= ~MSIC_ADCTHERM_MASK; |
367 | dev_warn(dev, "ADCTHERM already set"); | 364 | ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, data); |
365 | if (ret) | ||
366 | return ret; | ||
368 | 367 | ||
369 | /* Index of the first channel in which the stop bit is set */ | 368 | /* Index of the first channel in which the stop bit is set */ |
370 | channel_index = find_free_channel(); | 369 | channel_index = find_free_channel(); |
@@ -546,7 +545,7 @@ static int mid_thermal_remove(struct platform_device *pdev) | |||
546 | return configure_adc(0); | 545 | return configure_adc(0); |
547 | } | 546 | } |
548 | 547 | ||
549 | #define DRIVER_NAME "msic_sensor" | 548 | #define DRIVER_NAME "msic_thermal" |
550 | 549 | ||
551 | static const struct platform_device_id therm_id_table[] = { | 550 | static const struct platform_device_id therm_id_table[] = { |
552 | { DRIVER_NAME, 1 }, | 551 | { DRIVER_NAME, 1 }, |
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c deleted file mode 100644 index c8a6aed45277..000000000000 --- a/drivers/platform/x86/intel_rar_register.c +++ /dev/null | |||
@@ -1,669 +0,0 @@ | |||
1 | /* | ||
2 | * rar_register.c - An Intel Restricted Access Region register driver | ||
3 | * | ||
4 | * Copyright(c) 2009 Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of the | ||
9 | * License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | ||
19 | * 02111-1307, USA. | ||
20 | * | ||
21 | * ------------------------------------------------------------------- | ||
22 | * 20091204 Mark Allyn <mark.a.allyn@intel.com> | ||
23 | * Ossama Othman <ossama.othman@intel.com> | ||
24 | * Cleanup per feedback from Alan Cox and Arjan Van De Ven | ||
25 | * | ||
26 | * 20090806 Ossama Othman <ossama.othman@intel.com> | ||
27 | * Return zero high address if upper 22 bits is zero. | ||
28 | * Cleaned up checkpatch errors. | ||
29 | * Clarified that driver is dealing with bus addresses. | ||
30 | * | ||
31 | * 20090702 Ossama Othman <ossama.othman@intel.com> | ||
32 | * Removed unnecessary include directives | ||
33 | * Cleaned up spinlocks. | ||
34 | * Cleaned up logging. | ||
35 | * Improved invalid parameter checks. | ||
36 | * Fixed and simplified RAR address retrieval and RAR locking | ||
37 | * code. | ||
38 | * | ||
39 | * 20090626 Mark Allyn <mark.a.allyn@intel.com> | ||
40 | * Initial publish | ||
41 | */ | ||
42 | |||
43 | #include <linux/module.h> | ||
44 | #include <linux/pci.h> | ||
45 | #include <linux/spinlock.h> | ||
46 | #include <linux/device.h> | ||
47 | #include <linux/kernel.h> | ||
48 | #include <linux/rar_register.h> | ||
49 | |||
50 | /* === Lincroft Message Bus Interface === */ | ||
51 | #define LNC_MCR_OFFSET 0xD0 /* Message Control Register */ | ||
52 | #define LNC_MDR_OFFSET 0xD4 /* Message Data Register */ | ||
53 | |||
54 | /* Message Opcodes */ | ||
55 | #define LNC_MESSAGE_READ_OPCODE 0xD0 | ||
56 | #define LNC_MESSAGE_WRITE_OPCODE 0xE0 | ||
57 | |||
58 | /* Message Write Byte Enables */ | ||
59 | #define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF | ||
60 | |||
61 | /* B-unit Port */ | ||
62 | #define LNC_BUNIT_PORT 0x3 | ||
63 | |||
64 | /* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */ | ||
65 | #define LNC_BRAR0L 0x10 | ||
66 | #define LNC_BRAR0H 0x11 | ||
67 | #define LNC_BRAR1L 0x12 | ||
68 | #define LNC_BRAR1H 0x13 | ||
69 | /* Reserved for SeP */ | ||
70 | #define LNC_BRAR2L 0x14 | ||
71 | #define LNC_BRAR2H 0x15 | ||
72 | |||
73 | /* Moorestown supports three restricted access regions. */ | ||
74 | #define MRST_NUM_RAR 3 | ||
75 | |||
76 | /* RAR Bus Address Range */ | ||
77 | struct rar_addr { | ||
78 | dma_addr_t low; | ||
79 | dma_addr_t high; | ||
80 | }; | ||
81 | |||
82 | /* | ||
83 | * We create one of these for each RAR | ||
84 | */ | ||
85 | struct client { | ||
86 | int (*callback)(unsigned long data); | ||
87 | unsigned long driver_priv; | ||
88 | bool busy; | ||
89 | }; | ||
90 | |||
91 | static DEFINE_MUTEX(rar_mutex); | ||
92 | static DEFINE_MUTEX(lnc_reg_mutex); | ||
93 | |||
94 | /* | ||
95 | * One per RAR device (currently only one device) | ||
96 | */ | ||
97 | struct rar_device { | ||
98 | struct rar_addr rar_addr[MRST_NUM_RAR]; | ||
99 | struct pci_dev *rar_dev; | ||
100 | bool registered; | ||
101 | bool allocated; | ||
102 | struct client client[MRST_NUM_RAR]; | ||
103 | }; | ||
104 | |||
105 | /* Current platforms have only one rar_device for 3 rar regions */ | ||
106 | static struct rar_device my_rar_device; | ||
107 | |||
108 | /* | ||
109 | * Abstract out multiple device support. Current platforms only | ||
110 | * have a single RAR device. | ||
111 | */ | ||
112 | |||
113 | /** | ||
114 | * alloc_rar_device - return a new RAR structure | ||
115 | * | ||
116 | * Return a new (but not yet ready) RAR device object | ||
117 | */ | ||
118 | static struct rar_device *alloc_rar_device(void) | ||
119 | { | ||
120 | if (my_rar_device.allocated) | ||
121 | return NULL; | ||
122 | my_rar_device.allocated = 1; | ||
123 | return &my_rar_device; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * free_rar_device - free a RAR object | ||
128 | * @rar: the RAR device being freed | ||
129 | * | ||
130 | * Release a RAR object and any attached resources | ||
131 | */ | ||
132 | static void free_rar_device(struct rar_device *rar) | ||
133 | { | ||
134 | pci_dev_put(rar->rar_dev); | ||
135 | rar->allocated = 0; | ||
136 | } | ||
137 | |||
138 | /** | ||
139 | * _rar_to_device - return the device handling this RAR | ||
140 | * @rar: RAR number | ||
141 | * @off: returned offset | ||
142 | * | ||
143 | * Internal helper for looking up RAR devices. This and alloc are the | ||
144 | * two functions that need touching to go to multiple RAR devices. | ||
145 | */ | ||
146 | static struct rar_device *_rar_to_device(int rar, int *off) | ||
147 | { | ||
148 | if (rar >= 0 && rar < MRST_NUM_RAR) { | ||
149 | *off = rar; | ||
150 | return &my_rar_device; | ||
151 | } | ||
152 | return NULL; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * rar_to_device - return the device handling this RAR | ||
157 | * @rar: RAR number | ||
158 | * @off: returned offset | ||
159 | * | ||
160 | * Return the device this RAR maps to if one is present, otherwise | ||
161 | * returns NULL. Reports the offset relative to the base of this | ||
162 | * RAR device in off. | ||
163 | */ | ||
164 | static struct rar_device *rar_to_device(int rar, int *off) | ||
165 | { | ||
166 | struct rar_device *rar_dev = _rar_to_device(rar, off); | ||
167 | if (rar_dev == NULL || !rar_dev->registered) | ||
168 | return NULL; | ||
169 | return rar_dev; | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * rar_to_client - return the client handling this RAR | ||
174 | * @rar: RAR number | ||
175 | * | ||
176 | * Return the client this RAR maps to if a mapping is known, otherwise | ||
177 | * returns NULL. | ||
178 | */ | ||
179 | static struct client *rar_to_client(int rar) | ||
180 | { | ||
181 | int idx; | ||
182 | struct rar_device *r = _rar_to_device(rar, &idx); | ||
183 | if (r != NULL) | ||
184 | return &r->client[idx]; | ||
185 | return NULL; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * rar_read_addr - retrieve a RAR mapping | ||
190 | * @pdev: PCI device for the RAR | ||
191 | * @offset: offset for message | ||
192 | * @addr: returned address | ||
193 | * | ||
194 | * Reads the address of a given RAR register. Returns 0 on success | ||
195 | * or an error code on failure. | ||
196 | */ | ||
197 | static int rar_read_addr(struct pci_dev *pdev, int offset, dma_addr_t *addr) | ||
198 | { | ||
199 | /* | ||
200 | * ======== The Lincroft Message Bus Interface ======== | ||
201 | * Lincroft registers may be obtained via PCI from | ||
202 | * the host bridge using the Lincroft Message Bus | ||
203 | * Interface. That message bus interface is generally | ||
204 | * comprised of two registers: a control register (MCR, 0xDO) | ||
205 | * and a data register (MDR, 0xD4). | ||
206 | * | ||
207 | * The MCR (message control register) format is the following: | ||
208 | * 1. [31:24]: Opcode | ||
209 | * 2. [23:16]: Port | ||
210 | * 3. [15:8]: Register Offset | ||
211 | * 4. [7:4]: Byte Enables (use 0xF to set all of these bits | ||
212 | * to 1) | ||
213 | * 5. [3:0]: reserved | ||
214 | * | ||
215 | * Read (0xD0) and write (0xE0) opcodes are written to the | ||
216 | * control register when reading and writing to Lincroft | ||
217 | * registers, respectively. | ||
218 | * | ||
219 | * We're interested in registers found in the Lincroft | ||
220 | * B-unit. The B-unit port is 0x3. | ||
221 | * | ||
222 | * The six B-unit RAR register offsets we use are listed | ||
223 | * earlier in this file. | ||
224 | * | ||
225 | * Lastly writing to the MCR register requires the "Byte | ||
226 | * enables" bits to be set to 1. This may be achieved by | ||
227 | * writing 0xF at bit 4. | ||
228 | * | ||
229 | * The MDR (message data register) format is the following: | ||
230 | * 1. [31:0]: Read/Write Data | ||
231 | * | ||
232 | * Data being read from this register is only available after | ||
233 | * writing the appropriate control message to the MCR | ||
234 | * register. | ||
235 | * | ||
236 | * Data being written to this register must be written before | ||
237 | * writing the appropriate control message to the MCR | ||
238 | * register. | ||
239 | */ | ||
240 | |||
241 | int result; | ||
242 | u32 addr32; | ||
243 | |||
244 | /* Construct control message */ | ||
245 | u32 const message = | ||
246 | (LNC_MESSAGE_READ_OPCODE << 24) | ||
247 | | (LNC_BUNIT_PORT << 16) | ||
248 | | (offset << 8) | ||
249 | | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4); | ||
250 | |||
251 | dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset); | ||
252 | |||
253 | /* | ||
254 | * We synchronize access to the Lincroft MCR and MDR registers | ||
255 | * until BOTH the command is issued through the MCR register | ||
256 | * and the corresponding data is read from the MDR register. | ||
257 | * Otherwise a race condition would exist between accesses to | ||
258 | * both registers. | ||
259 | */ | ||
260 | |||
261 | mutex_lock(&lnc_reg_mutex); | ||
262 | |||
263 | /* Send the control message */ | ||
264 | result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message); | ||
265 | if (!result) { | ||
266 | /* Read back the address as a 32bit value */ | ||
267 | result = pci_read_config_dword(pdev, LNC_MDR_OFFSET, &addr32); | ||
268 | *addr = (dma_addr_t)addr32; | ||
269 | } | ||
270 | mutex_unlock(&lnc_reg_mutex); | ||
271 | return result; | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * rar_set_addr - Set a RAR mapping | ||
276 | * @pdev: PCI device for the RAR | ||
277 | * @offset: offset for message | ||
278 | * @addr: address to set | ||
279 | * | ||
280 | * Sets the address of a given RAR register. Returns 0 on success | ||
281 | * or an error code on failure. | ||
282 | */ | ||
283 | static int rar_set_addr(struct pci_dev *pdev, | ||
284 | int offset, | ||
285 | dma_addr_t addr) | ||
286 | { | ||
287 | /* | ||
288 | * Data being written to this register must be written before | ||
289 | * writing the appropriate control message to the MCR | ||
290 | * register. | ||
291 | * See rar_get_addrs() for a description of the | ||
292 | * message bus interface being used here. | ||
293 | */ | ||
294 | |||
295 | int result; | ||
296 | |||
297 | /* Construct control message */ | ||
298 | u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24) | ||
299 | | (LNC_BUNIT_PORT << 16) | ||
300 | | (offset << 8) | ||
301 | | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4); | ||
302 | |||
303 | /* | ||
304 | * We synchronize access to the Lincroft MCR and MDR registers | ||
305 | * until BOTH the command is issued through the MCR register | ||
306 | * and the corresponding data is read from the MDR register. | ||
307 | * Otherwise a race condition would exist between accesses to | ||
308 | * both registers. | ||
309 | */ | ||
310 | |||
311 | mutex_lock(&lnc_reg_mutex); | ||
312 | |||
313 | /* Send the control message */ | ||
314 | result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr); | ||
315 | if (!result) | ||
316 | /* And address */ | ||
317 | result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message); | ||
318 | |||
319 | mutex_unlock(&lnc_reg_mutex); | ||
320 | return result; | ||
321 | } | ||
322 | |||
323 | /* | ||
324 | * rar_init_params - Initialize RAR parameters | ||
325 | * @rar: RAR device to initialise | ||
326 | * | ||
327 | * Initialize RAR parameters, such as bus addresses, etc. Returns 0 | ||
328 | * on success, or an error code on failure. | ||
329 | */ | ||
330 | static int init_rar_params(struct rar_device *rar) | ||
331 | { | ||
332 | struct pci_dev *pdev = rar->rar_dev; | ||
333 | unsigned int i; | ||
334 | int result = 0; | ||
335 | int offset = 0x10; /* RAR 0 to 2 in order low/high/low/high/... */ | ||
336 | |||
337 | /* Retrieve RAR start and end bus addresses. | ||
338 | * Access the RAR registers through the Lincroft Message Bus | ||
339 | * Interface on PCI device: 00:00.0 Host bridge. | ||
340 | */ | ||
341 | |||
342 | for (i = 0; i < MRST_NUM_RAR; ++i) { | ||
343 | struct rar_addr *addr = &rar->rar_addr[i]; | ||
344 | |||
345 | result = rar_read_addr(pdev, offset++, &addr->low); | ||
346 | if (result != 0) | ||
347 | return result; | ||
348 | |||
349 | result = rar_read_addr(pdev, offset++, &addr->high); | ||
350 | if (result != 0) | ||
351 | return result; | ||
352 | |||
353 | |||
354 | /* | ||
355 | * Only the upper 22 bits of the RAR addresses are | ||
356 | * stored in their corresponding RAR registers so we | ||
357 | * must set the lower 10 bits accordingly. | ||
358 | |||
359 | * The low address has its lower 10 bits cleared, and | ||
360 | * the high address has all its lower 10 bits set, | ||
361 | * e.g.: | ||
362 | * low = 0x2ffffc00 | ||
363 | */ | ||
364 | |||
365 | addr->low &= (dma_addr_t)0xfffffc00u; | ||
366 | |||
367 | /* | ||
368 | * Set bits 9:0 on uppser address if bits 31:10 are non | ||
369 | * zero; otherwize clear all bits | ||
370 | */ | ||
371 | |||
372 | if ((addr->high & 0xfffffc00u) == 0) | ||
373 | addr->high = 0; | ||
374 | else | ||
375 | addr->high |= 0x3ffu; | ||
376 | } | ||
377 | /* Done accessing the device. */ | ||
378 | |||
379 | if (result == 0) { | ||
380 | for (i = 0; i != MRST_NUM_RAR; ++i) { | ||
381 | /* | ||
382 | * "BRAR" refers to the RAR registers in the | ||
383 | * Lincroft B-unit. | ||
384 | */ | ||
385 | dev_info(&pdev->dev, "BRAR[%u] bus address range = " | ||
386 | "[%lx, %lx]\n", i, | ||
387 | (unsigned long)rar->rar_addr[i].low, | ||
388 | (unsigned long)rar->rar_addr[i].high); | ||
389 | } | ||
390 | } | ||
391 | return result; | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * rar_get_address - get the bus address in a RAR | ||
396 | * @start: return value of start address of block | ||
397 | * @end: return value of end address of block | ||
398 | * | ||
399 | * The rar_get_address function is used by other device drivers | ||
400 | * to obtain RAR address information on a RAR. It takes three | ||
401 | * parameters: | ||
402 | * | ||
403 | * The function returns a 0 upon success or an error if there is no RAR | ||
404 | * facility on this system. | ||
405 | */ | ||
406 | int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end) | ||
407 | { | ||
408 | int idx; | ||
409 | struct rar_device *rar = rar_to_device(rar_index, &idx); | ||
410 | |||
411 | if (rar == NULL) { | ||
412 | WARN_ON(1); | ||
413 | return -ENODEV; | ||
414 | } | ||
415 | |||
416 | *start = rar->rar_addr[idx].low; | ||
417 | *end = rar->rar_addr[idx].high; | ||
418 | return 0; | ||
419 | } | ||
420 | EXPORT_SYMBOL(rar_get_address); | ||
421 | |||
422 | /** | ||
423 | * rar_lock - lock a RAR register | ||
424 | * @rar_index: RAR to lock (0-2) | ||
425 | * | ||
426 | * The rar_lock function is ued by other device drivers to lock an RAR. | ||
427 | * once a RAR is locked, it stays locked until the next system reboot. | ||
428 | * | ||
429 | * The function returns a 0 upon success or an error if there is no RAR | ||
430 | * facility on this system, or the locking fails | ||
431 | */ | ||
432 | int rar_lock(int rar_index) | ||
433 | { | ||
434 | struct rar_device *rar; | ||
435 | int result; | ||
436 | int idx; | ||
437 | dma_addr_t low, high; | ||
438 | |||
439 | rar = rar_to_device(rar_index, &idx); | ||
440 | |||
441 | if (rar == NULL) { | ||
442 | WARN_ON(1); | ||
443 | return -EINVAL; | ||
444 | } | ||
445 | |||
446 | low = rar->rar_addr[idx].low & 0xfffffc00u; | ||
447 | high = rar->rar_addr[idx].high & 0xfffffc00u; | ||
448 | |||
449 | /* | ||
450 | * Only allow I/O from the graphics and Langwell; | ||
451 | * not from the x86 processor | ||
452 | */ | ||
453 | |||
454 | if (rar_index == RAR_TYPE_VIDEO) { | ||
455 | low |= 0x00000009; | ||
456 | high |= 0x00000015; | ||
457 | } else if (rar_index == RAR_TYPE_AUDIO) { | ||
458 | /* Only allow I/O from Langwell; nothing from x86 */ | ||
459 | low |= 0x00000008; | ||
460 | high |= 0x00000018; | ||
461 | } else | ||
462 | /* Read-only from all agents */ | ||
463 | high |= 0x00000018; | ||
464 | |||
465 | /* | ||
466 | * Now program the register using the Lincroft message | ||
467 | * bus interface. | ||
468 | */ | ||
469 | result = rar_set_addr(rar->rar_dev, | ||
470 | 2 * idx, low); | ||
471 | |||
472 | if (result == 0) | ||
473 | result = rar_set_addr(rar->rar_dev, | ||
474 | 2 * idx + 1, high); | ||
475 | |||
476 | return result; | ||
477 | } | ||
478 | EXPORT_SYMBOL(rar_lock); | ||
479 | |||
480 | /** | ||
481 | * register_rar - register a RAR handler | ||
482 | * @num: RAR we wish to register for | ||
483 | * @callback: function to call when RAR support is available | ||
484 | * @data: data to pass to this function | ||
485 | * | ||
486 | * The register_rar function is to used by other device drivers | ||
487 | * to ensure that this driver is ready. As we cannot be sure of | ||
488 | * the compile/execute order of drivers in the kernel, it is | ||
489 | * best to give this driver a callback function to call when | ||
490 | * it is ready to give out addresses. The callback function | ||
491 | * would have those steps that continue the initialization of | ||
492 | * a driver that do require a valid RAR address. One of those | ||
493 | * steps would be to call rar_get_address() | ||
494 | * | ||
495 | * This function return 0 on success or an error code on failure. | ||
496 | */ | ||
497 | int register_rar(int num, int (*callback)(unsigned long data), | ||
498 | unsigned long data) | ||
499 | { | ||
500 | /* For now we hardcode a single RAR device */ | ||
501 | struct rar_device *rar; | ||
502 | struct client *c; | ||
503 | int idx; | ||
504 | int retval = 0; | ||
505 | |||
506 | mutex_lock(&rar_mutex); | ||
507 | |||
508 | /* Do we have a client mapping for this RAR number ? */ | ||
509 | c = rar_to_client(num); | ||
510 | if (c == NULL) { | ||
511 | retval = -ERANGE; | ||
512 | goto done; | ||
513 | } | ||
514 | /* Is it claimed ? */ | ||
515 | if (c->busy) { | ||
516 | retval = -EBUSY; | ||
517 | goto done; | ||
518 | } | ||
519 | c->busy = 1; | ||
520 | |||
521 | /* See if we have a handler for this RAR yet, if we do then fire it */ | ||
522 | rar = rar_to_device(num, &idx); | ||
523 | |||
524 | if (rar) { | ||
525 | /* | ||
526 | * if the driver already registered, then we can simply | ||
527 | * call the callback right now | ||
528 | */ | ||
529 | (*callback)(data); | ||
530 | goto done; | ||
531 | } | ||
532 | |||
533 | /* Arrange to be called back when the hardware is found */ | ||
534 | c->callback = callback; | ||
535 | c->driver_priv = data; | ||
536 | done: | ||
537 | mutex_unlock(&rar_mutex); | ||
538 | return retval; | ||
539 | } | ||
540 | EXPORT_SYMBOL(register_rar); | ||
541 | |||
542 | /** | ||
543 | * unregister_rar - release a RAR allocation | ||
544 | * @num: RAR number | ||
545 | * | ||
546 | * Releases a RAR allocation, or pending allocation. If a callback is | ||
547 | * pending then this function will either complete before the unregister | ||
548 | * returns or not at all. | ||
549 | */ | ||
550 | |||
551 | void unregister_rar(int num) | ||
552 | { | ||
553 | struct client *c; | ||
554 | |||
555 | mutex_lock(&rar_mutex); | ||
556 | c = rar_to_client(num); | ||
557 | if (c == NULL || !c->busy) | ||
558 | WARN_ON(1); | ||
559 | else | ||
560 | c->busy = 0; | ||
561 | mutex_unlock(&rar_mutex); | ||
562 | } | ||
563 | EXPORT_SYMBOL(unregister_rar); | ||
564 | |||
565 | /** | ||
566 | * rar_callback - Process callbacks | ||
567 | * @rar: new RAR device | ||
568 | * | ||
569 | * Process the callbacks for a newly found RAR device. | ||
570 | */ | ||
571 | |||
572 | static void rar_callback(struct rar_device *rar) | ||
573 | { | ||
574 | struct client *c = &rar->client[0]; | ||
575 | int i; | ||
576 | |||
577 | mutex_lock(&rar_mutex); | ||
578 | |||
579 | rar->registered = 1; /* Ensure no more callbacks queue */ | ||
580 | |||
581 | for (i = 0; i < MRST_NUM_RAR; i++) { | ||
582 | if (c->callback && c->busy) { | ||
583 | c->callback(c->driver_priv); | ||
584 | c->callback = NULL; | ||
585 | } | ||
586 | c++; | ||
587 | } | ||
588 | mutex_unlock(&rar_mutex); | ||
589 | } | ||
590 | |||
591 | /** | ||
592 | * rar_probe - PCI probe callback | ||
593 | * @dev: PCI device | ||
594 | * @id: matching entry in the match table | ||
595 | * | ||
596 | * A RAR device has been discovered. Initialise it and if successful | ||
597 | * process any pending callbacks that can now be completed. | ||
598 | */ | ||
599 | static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id) | ||
600 | { | ||
601 | int error; | ||
602 | struct rar_device *rar; | ||
603 | |||
604 | dev_dbg(&dev->dev, "PCI probe starting\n"); | ||
605 | |||
606 | rar = alloc_rar_device(); | ||
607 | if (rar == NULL) | ||
608 | return -EBUSY; | ||
609 | |||
610 | /* Enable the device */ | ||
611 | error = pci_enable_device(dev); | ||
612 | if (error) { | ||
613 | dev_err(&dev->dev, | ||
614 | "Error enabling RAR register PCI device\n"); | ||
615 | goto end_function; | ||
616 | } | ||
617 | |||
618 | /* Fill in the rar_device structure */ | ||
619 | rar->rar_dev = pci_dev_get(dev); | ||
620 | pci_set_drvdata(dev, rar); | ||
621 | |||
622 | /* | ||
623 | * Initialize the RAR parameters, which have to be retrieved | ||
624 | * via the message bus interface. | ||
625 | */ | ||
626 | error = init_rar_params(rar); | ||
627 | if (error) { | ||
628 | pci_disable_device(dev); | ||
629 | dev_err(&dev->dev, "Error retrieving RAR addresses\n"); | ||
630 | goto end_function; | ||
631 | } | ||
632 | /* now call anyone who has registered (using callbacks) */ | ||
633 | rar_callback(rar); | ||
634 | return 0; | ||
635 | end_function: | ||
636 | free_rar_device(rar); | ||
637 | return error; | ||
638 | } | ||
639 | |||
640 | static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = { | ||
641 | { PCI_VDEVICE(INTEL, 0x4110) }, | ||
642 | { 0 } | ||
643 | }; | ||
644 | |||
645 | MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl); | ||
646 | |||
647 | /* field for registering driver to PCI device */ | ||
648 | static struct pci_driver rar_pci_driver = { | ||
649 | .name = "rar_register_driver", | ||
650 | .id_table = rar_pci_id_tbl, | ||
651 | .probe = rar_probe, | ||
652 | /* Cannot be unplugged - no remove */ | ||
653 | }; | ||
654 | |||
655 | static int __init rar_init_handler(void) | ||
656 | { | ||
657 | return pci_register_driver(&rar_pci_driver); | ||
658 | } | ||
659 | |||
660 | static void __exit rar_exit_handler(void) | ||
661 | { | ||
662 | pci_unregister_driver(&rar_pci_driver); | ||
663 | } | ||
664 | |||
665 | module_init(rar_init_handler); | ||
666 | module_exit(rar_exit_handler); | ||
667 | |||
668 | MODULE_LICENSE("GPL"); | ||
669 | MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver"); | ||
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f00d0d1e0653..9215ed72bece 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -159,7 +159,7 @@ static inline int busy_loop(void) /* Wait till scu status is busy */ | |||
159 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ | 159 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
160 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 160 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) |
161 | { | 161 | { |
162 | int i, nc, bytes, d; | 162 | int nc; |
163 | u32 offset = 0; | 163 | u32 offset = 0; |
164 | int err; | 164 | int err; |
165 | u8 cbuf[IPC_WWBUF_SIZE] = { }; | 165 | u8 cbuf[IPC_WWBUF_SIZE] = { }; |
@@ -174,55 +174,34 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | |||
174 | return -ENODEV; | 174 | return -ENODEV; |
175 | } | 175 | } |
176 | 176 | ||
177 | if (platform != MRST_CPU_CHIP_PENWELL) { | 177 | for (nc = 0; nc < count; nc++, offset += 2) { |
178 | bytes = 0; | 178 | cbuf[offset] = addr[nc]; |
179 | d = 0; | 179 | cbuf[offset + 1] = addr[nc] >> 8; |
180 | for (i = 0; i < count; i++) { | 180 | } |
181 | cbuf[bytes++] = addr[i]; | ||
182 | cbuf[bytes++] = addr[i] >> 8; | ||
183 | if (id != IPC_CMD_PCNTRL_R) | ||
184 | cbuf[bytes++] = data[d++]; | ||
185 | if (id == IPC_CMD_PCNTRL_M) | ||
186 | cbuf[bytes++] = data[d++]; | ||
187 | } | ||
188 | for (i = 0; i < bytes; i += 4) | ||
189 | ipc_data_writel(wbuf[i/4], i); | ||
190 | ipc_command(bytes << 16 | id << 12 | 0 << 8 | op); | ||
191 | } else { | ||
192 | for (nc = 0; nc < count; nc++, offset += 2) { | ||
193 | cbuf[offset] = addr[nc]; | ||
194 | cbuf[offset + 1] = addr[nc] >> 8; | ||
195 | } | ||
196 | 181 | ||
197 | if (id == IPC_CMD_PCNTRL_R) { | 182 | if (id == IPC_CMD_PCNTRL_R) { |
198 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 183 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
199 | ipc_data_writel(wbuf[nc], offset); | 184 | ipc_data_writel(wbuf[nc], offset); |
200 | ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); | 185 | ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); |
201 | } else if (id == IPC_CMD_PCNTRL_W) { | 186 | } else if (id == IPC_CMD_PCNTRL_W) { |
202 | for (nc = 0; nc < count; nc++, offset += 1) | 187 | for (nc = 0; nc < count; nc++, offset += 1) |
203 | cbuf[offset] = data[nc]; | 188 | cbuf[offset] = data[nc]; |
204 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) | 189 | for (nc = 0, offset = 0; nc < count; nc++, offset += 4) |
205 | ipc_data_writel(wbuf[nc], offset); | 190 | ipc_data_writel(wbuf[nc], offset); |
206 | ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); | 191 | ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); |
207 | } else if (id == IPC_CMD_PCNTRL_M) { | 192 | } else if (id == IPC_CMD_PCNTRL_M) { |
208 | cbuf[offset] = data[0]; | 193 | cbuf[offset] = data[0]; |
209 | cbuf[offset + 1] = data[1]; | 194 | cbuf[offset + 1] = data[1]; |
210 | ipc_data_writel(wbuf[0], 0); /* Write wbuff */ | 195 | ipc_data_writel(wbuf[0], 0); /* Write wbuff */ |
211 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); | 196 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); |
212 | } | ||
213 | } | 197 | } |
214 | 198 | ||
215 | err = busy_loop(); | 199 | err = busy_loop(); |
216 | if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ | 200 | if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ |
217 | /* Workaround: values are read as 0 without memcpy_fromio */ | 201 | /* Workaround: values are read as 0 without memcpy_fromio */ |
218 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); | 202 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); |
219 | if (platform != MRST_CPU_CHIP_PENWELL) { | 203 | for (nc = 0; nc < count; nc++) |
220 | for (nc = 0, offset = 2; nc < count; nc++, offset += 3) | 204 | data[nc] = ipc_data_readb(nc); |
221 | data[nc] = ipc_data_readb(offset); | ||
222 | } else { | ||
223 | for (nc = 0; nc < count; nc++) | ||
224 | data[nc] = ipc_data_readb(nc); | ||
225 | } | ||
226 | } | 205 | } |
227 | mutex_unlock(&ipclock); | 206 | mutex_unlock(&ipclock); |
228 | return err; | 207 | return err; |
@@ -503,148 +482,6 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data) | |||
503 | } | 482 | } |
504 | EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); | 483 | EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); |
505 | 484 | ||
506 | #define IPC_FW_LOAD_ADDR 0xFFFC0000 /* Storage location for FW image */ | ||
507 | #define IPC_FW_UPDATE_MBOX_ADDR 0xFFFFDFF4 /* Mailbox between ipc and scu */ | ||
508 | #define IPC_MAX_FW_SIZE 262144 /* 256K storage size for loading the FW image */ | ||
509 | #define IPC_FW_MIP_HEADER_SIZE 2048 /* Firmware MIP header size */ | ||
510 | /* IPC inform SCU to get ready for update process */ | ||
511 | #define IPC_CMD_FW_UPDATE_READY 0x10FE | ||
512 | /* IPC inform SCU to go for update process */ | ||
513 | #define IPC_CMD_FW_UPDATE_GO 0x20FE | ||
514 | /* Status code for fw update */ | ||
515 | #define IPC_FW_UPDATE_SUCCESS 0x444f4e45 /* Status code 'DONE' */ | ||
516 | #define IPC_FW_UPDATE_BADN 0x4241444E /* Status code 'BADN' */ | ||
517 | #define IPC_FW_TXHIGH 0x54784849 /* Status code 'IPC_FW_TXHIGH' */ | ||
518 | #define IPC_FW_TXLOW 0x54784c4f /* Status code 'IPC_FW_TXLOW' */ | ||
519 | |||
520 | struct fw_update_mailbox { | ||
521 | u32 status; | ||
522 | u32 scu_flag; | ||
523 | u32 driver_flag; | ||
524 | }; | ||
525 | |||
526 | |||
527 | /** | ||
528 | * intel_scu_ipc_fw_update - Firmware update utility | ||
529 | * @buffer: firmware buffer | ||
530 | * @length: size of firmware buffer | ||
531 | * | ||
532 | * This function provides an interface to load the firmware into | ||
533 | * the SCU. Returns 0 on success or -1 on failure | ||
534 | */ | ||
535 | int intel_scu_ipc_fw_update(u8 *buffer, u32 length) | ||
536 | { | ||
537 | void __iomem *fw_update_base; | ||
538 | struct fw_update_mailbox __iomem *mailbox = NULL; | ||
539 | int retry_cnt = 0; | ||
540 | u32 status; | ||
541 | |||
542 | mutex_lock(&ipclock); | ||
543 | fw_update_base = ioremap_nocache(IPC_FW_LOAD_ADDR, (128*1024)); | ||
544 | if (fw_update_base == NULL) { | ||
545 | mutex_unlock(&ipclock); | ||
546 | return -ENOMEM; | ||
547 | } | ||
548 | mailbox = ioremap_nocache(IPC_FW_UPDATE_MBOX_ADDR, | ||
549 | sizeof(struct fw_update_mailbox)); | ||
550 | if (mailbox == NULL) { | ||
551 | iounmap(fw_update_base); | ||
552 | mutex_unlock(&ipclock); | ||
553 | return -ENOMEM; | ||
554 | } | ||
555 | |||
556 | ipc_command(IPC_CMD_FW_UPDATE_READY); | ||
557 | |||
558 | /* Intitialize mailbox */ | ||
559 | writel(0, &mailbox->status); | ||
560 | writel(0, &mailbox->scu_flag); | ||
561 | writel(0, &mailbox->driver_flag); | ||
562 | |||
563 | /* Driver copies the 2KB MIP header to SRAM at 0xFFFC0000*/ | ||
564 | memcpy_toio(fw_update_base, buffer, 0x800); | ||
565 | |||
566 | /* Driver sends "FW Update" IPC command (CMD_ID 0xFE; MSG_ID 0x02). | ||
567 | * Upon receiving this command, SCU will write the 2K MIP header | ||
568 | * from 0xFFFC0000 into NAND. | ||
569 | * SCU will write a status code into the Mailbox, and then set scu_flag. | ||
570 | */ | ||
571 | |||
572 | ipc_command(IPC_CMD_FW_UPDATE_GO); | ||
573 | |||
574 | /*Driver stalls until scu_flag is set */ | ||
575 | while (readl(&mailbox->scu_flag) != 1) { | ||
576 | rmb(); | ||
577 | mdelay(1); | ||
578 | } | ||
579 | |||
580 | /* Driver checks Mailbox status. | ||
581 | * If the status is 'BADN', then abort (bad NAND). | ||
582 | * If the status is 'IPC_FW_TXLOW', then continue. | ||
583 | */ | ||
584 | while (readl(&mailbox->status) != IPC_FW_TXLOW) { | ||
585 | rmb(); | ||
586 | mdelay(10); | ||
587 | } | ||
588 | mdelay(10); | ||
589 | |||
590 | update_retry: | ||
591 | if (retry_cnt > 5) | ||
592 | goto update_end; | ||
593 | |||
594 | if (readl(&mailbox->status) != IPC_FW_TXLOW) | ||
595 | goto update_end; | ||
596 | buffer = buffer + 0x800; | ||
597 | memcpy_toio(fw_update_base, buffer, 0x20000); | ||
598 | writel(1, &mailbox->driver_flag); | ||
599 | while (readl(&mailbox->scu_flag) == 1) { | ||
600 | rmb(); | ||
601 | mdelay(1); | ||
602 | } | ||
603 | |||
604 | /* check for 'BADN' */ | ||
605 | if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN) | ||
606 | goto update_end; | ||
607 | |||
608 | while (readl(&mailbox->status) != IPC_FW_TXHIGH) { | ||
609 | rmb(); | ||
610 | mdelay(10); | ||
611 | } | ||
612 | mdelay(10); | ||
613 | |||
614 | if (readl(&mailbox->status) != IPC_FW_TXHIGH) | ||
615 | goto update_end; | ||
616 | |||
617 | buffer = buffer + 0x20000; | ||
618 | memcpy_toio(fw_update_base, buffer, 0x20000); | ||
619 | writel(0, &mailbox->driver_flag); | ||
620 | |||
621 | while (mailbox->scu_flag == 0) { | ||
622 | rmb(); | ||
623 | mdelay(1); | ||
624 | } | ||
625 | |||
626 | /* check for 'BADN' */ | ||
627 | if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN) | ||
628 | goto update_end; | ||
629 | |||
630 | if (readl(&mailbox->status) == IPC_FW_TXLOW) { | ||
631 | ++retry_cnt; | ||
632 | goto update_retry; | ||
633 | } | ||
634 | |||
635 | update_end: | ||
636 | status = readl(&mailbox->status); | ||
637 | |||
638 | iounmap(fw_update_base); | ||
639 | iounmap(mailbox); | ||
640 | mutex_unlock(&ipclock); | ||
641 | |||
642 | if (status == IPC_FW_UPDATE_SUCCESS) | ||
643 | return 0; | ||
644 | return -EIO; | ||
645 | } | ||
646 | EXPORT_SYMBOL(intel_scu_ipc_fw_update); | ||
647 | |||
648 | /* | 485 | /* |
649 | * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 | 486 | * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 |
650 | * When ioc bit is set to 1, caller api must wait for interrupt handler called | 487 | * When ioc bit is set to 1, caller api must wait for interrupt handler called |
@@ -727,7 +564,6 @@ static void ipc_remove(struct pci_dev *pdev) | |||
727 | } | 564 | } |
728 | 565 | ||
729 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { | 566 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { |
730 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, | ||
731 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, | 567 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, |
732 | { 0,} | 568 | { 0,} |
733 | }; | 569 | }; |
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c index 2d0f9136ea9a..02bc5a6343c3 100644 --- a/drivers/platform/x86/intel_scu_ipcutil.c +++ b/drivers/platform/x86/intel_scu_ipcutil.c | |||
@@ -26,13 +26,10 @@ | |||
26 | 26 | ||
27 | static int major; | 27 | static int major; |
28 | 28 | ||
29 | #define MAX_FW_SIZE 264192 | ||
30 | |||
31 | /* ioctl commnds */ | 29 | /* ioctl commnds */ |
32 | #define INTE_SCU_IPC_REGISTER_READ 0 | 30 | #define INTE_SCU_IPC_REGISTER_READ 0 |
33 | #define INTE_SCU_IPC_REGISTER_WRITE 1 | 31 | #define INTE_SCU_IPC_REGISTER_WRITE 1 |
34 | #define INTE_SCU_IPC_REGISTER_UPDATE 2 | 32 | #define INTE_SCU_IPC_REGISTER_UPDATE 2 |
35 | #define INTE_SCU_IPC_FW_UPDATE 0xA2 | ||
36 | 33 | ||
37 | struct scu_ipc_data { | 34 | struct scu_ipc_data { |
38 | u32 count; /* No. of registers */ | 35 | u32 count; /* No. of registers */ |
@@ -88,27 +85,14 @@ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd, | |||
88 | if (!capable(CAP_SYS_RAWIO)) | 85 | if (!capable(CAP_SYS_RAWIO)) |
89 | return -EPERM; | 86 | return -EPERM; |
90 | 87 | ||
91 | if (cmd == INTE_SCU_IPC_FW_UPDATE) { | 88 | if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) |
92 | u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); | 89 | return -EFAULT; |
93 | if (fwbuf == NULL) | 90 | ret = scu_reg_access(cmd, &data); |
94 | return -ENOMEM; | 91 | if (ret < 0) |
95 | if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { | 92 | return ret; |
96 | kfree(fwbuf); | 93 | if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) |
97 | return -EFAULT; | 94 | return -EFAULT; |
98 | } | 95 | return 0; |
99 | ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE); | ||
100 | kfree(fwbuf); | ||
101 | return ret; | ||
102 | } else { | ||
103 | if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data))) | ||
104 | return -EFAULT; | ||
105 | ret = scu_reg_access(cmd, &data); | ||
106 | if (ret < 0) | ||
107 | return ret; | ||
108 | if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data))) | ||
109 | return -EFAULT; | ||
110 | return 0; | ||
111 | } | ||
112 | } | 96 | } |
113 | 97 | ||
114 | static const struct file_operations scu_ipc_fops = { | 98 | static const struct file_operations scu_ipc_fops = { |
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 05be30ee158b..ffff8b4b4949 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c | |||
@@ -562,8 +562,8 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) | |||
562 | 562 | ||
563 | num_sifr = acpi_pcc_get_sqty(device); | 563 | num_sifr = acpi_pcc_get_sqty(device); |
564 | 564 | ||
565 | if (num_sifr > 255) { | 565 | if (num_sifr < 0 || num_sifr > 255) { |
566 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr too large")); | 566 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "num_sifr out of range")); |
567 | return -ENODEV; | 567 | return -ENODEV; |
568 | } | 568 | } |
569 | 569 | ||