Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (88 commits)
ips driver: make it less chatty
intel_scu_ipc: fix size field for intel_scu_ipc_command
intel_scu_ipc: return -EIO for error condition in busy_loop
intel_scu_ipc: fix data packing of PMIC command on Moorestown
Clean up command packing on MRST.
zero the stack buffer before giving random garbage to the SCU
Fix stack buffer size for IPC writev messages
intel_scu_ipc: Use the new cpu identification function
intel_scu_ipc: tidy up unused bits
Remove indirect read write api support.
intel_scu_ipc: Support Medfield processors
intel_scu_ipc: detect CPU type automatically
x86 plat: limit x86 platform driver menu to X86
acpi ec_sys: Be more cautious about ec write access
acpi ec: Fix possible double io port registration
hp-wmi: acpi_drivers.h is already included through acpi.h two lines below
hp-wmi: Fix mixing up of and/or directive
dell-laptop: make dell_laptop_i8042_filter() static
asus-laptop: fix asus_input_init error path
msi-wmi: make needlessly global symbols static
...

+3838 -751
+20
Documentation/ABI/testing/debugfs-ec
···
··· 1 + What: /sys/kernel/debug/ec/*/{gpe,use_global_lock,io} 2 + Date: July 2010 3 + Contact: Thomas Renninger <trenn@suse.de> 4 + Description: 5 + 6 + General information like which GPE is assigned to the EC and whether 7 + the global lock should get used. 8 + Knowing the EC GPE one can watch the amount of HW events related to 9 + the EC here (XY -> GPE number from /sys/kernel/debug/ec/*/gpe): 10 + /sys/firmware/acpi/interrupts/gpeXY 11 + 12 + The io file is binary and a userspace tool located here: 13 + ftp://ftp.suse.com/pub/people/trenn/sources/ec/ 14 + should get used to read out the 256 Embedded Controller registers 15 + or writing to them. 16 + 17 + CAUTION: Do not write to the Embedded Controller if you don't know 18 + what you are doing! Rebooting afterwards also is a good idea. 19 + This can influence the way your machine is cooled and fans may 20 + not get switched on again after you did a wrong write.
+9 -58
Documentation/laptops/thinkpad-acpi.txt
··· 960 subsystem, and follow all of the hwmon guidelines at 961 Documentation/hwmon. 962 963 964 - EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump 965 - ------------------------------------------------------------------------ 966 967 - This feature is marked EXPERIMENTAL because the implementation 968 - directly accesses hardware registers and may not work as expected. USE 969 - WITH CAUTION! To use this feature, you need to supply the 970 - experimental=1 parameter when loading the module. 971 - 972 - This feature dumps the values of 256 embedded controller 973 - registers. Values which have changed since the last time the registers 974 - were dumped are marked with a star: 975 - 976 - [root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 977 - EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f 978 - EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00 979 - EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00 980 - EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80 981 - EC 0x30: 01 07 1a 00 30 04 00 00 *85 00 00 10 00 50 00 00 982 - EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00 983 - EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 *bc *02 *bc 984 - EC 0x60: *02 *bc *02 00 00 00 00 00 00 00 00 00 00 00 00 00 985 - EC 0x70: 00 00 00 00 00 12 30 40 *24 *26 *2c *27 *20 80 *1f 80 986 - EC 0x80: 00 00 00 06 *37 *0e 03 00 00 00 0e 07 00 00 00 00 987 - EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 988 - EC 0xa0: *ff 09 ff 09 ff ff *64 00 *00 *00 *a2 41 *ff *ff *e0 00 989 - EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 990 - EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 991 - EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 992 - EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03 993 - EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a 994 - 995 - This feature can be used to determine the register holding the fan 996 speed on some models. To do that, do the following: 997 - 998 - make sure the battery is fully charged 999 - make sure the fan is running 1000 - - run 'cat /proc/acpi/ibm/ecdump' several times, once per second or so 1001 1002 - The first step makes sure various charging-related values don't 1003 - vary. The second ensures that the fan-related values do vary, since 1004 - the fan speed fluctuates a bit. The third will (hopefully) mark the 1005 - fan register with a star: 1006 - 1007 - [root@x40 ibm-acpi]# cat /proc/acpi/ibm/ecdump 1008 - EC +00 +01 +02 +03 +04 +05 +06 +07 +08 +09 +0a +0b +0c +0d +0e +0f 1009 - EC 0x00: a7 47 87 01 fe 96 00 08 01 00 cb 00 00 00 40 00 1010 - EC 0x10: 00 00 ff ff f4 3c 87 09 01 ff 42 01 ff ff 0d 00 1011 - EC 0x20: 00 00 00 00 00 00 00 00 00 00 00 03 43 00 00 80 1012 - EC 0x30: 01 07 1a 00 30 04 00 00 85 00 00 10 00 50 00 00 1013 - EC 0x40: 00 00 00 00 00 00 14 01 00 04 00 00 00 00 00 00 1014 - EC 0x50: 00 c0 02 0d 00 01 01 02 02 03 03 03 03 bc 02 bc 1015 - EC 0x60: 02 bc 02 00 00 00 00 00 00 00 00 00 00 00 00 00 1016 - EC 0x70: 00 00 00 00 00 12 30 40 24 27 2c 27 21 80 1f 80 1017 - EC 0x80: 00 00 00 06 *be 0d 03 00 00 00 0e 07 00 00 00 00 1018 - EC 0x90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1019 - EC 0xa0: ff 09 ff 09 ff ff 64 00 00 00 a2 41 ff ff e0 00 1020 - EC 0xb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1021 - EC 0xc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1022 - EC 0xd0: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1023 - EC 0xe0: 00 00 00 00 00 00 00 00 11 20 49 04 24 06 55 03 1024 - EC 0xf0: 31 55 48 54 35 38 57 57 08 2f 45 73 07 65 6c 1a 1025 - 1026 - Another set of values that varies often is the temperature 1027 readings. Since temperatures don't change vary fast, you can take 1028 several quick dumps to eliminate them. 1029
··· 960 subsystem, and follow all of the hwmon guidelines at 961 Documentation/hwmon. 962 963 + EXPERIMENTAL: Embedded controller register dump 964 + ----------------------------------------------- 965 966 + This feature is not included in the thinkpad driver anymore. 967 + Instead the EC can be accessed through /sys/kernel/debug/ec with 968 + a userspace tool which can be found here: 969 + ftp://ftp.suse.com/pub/people/trenn/sources/ec 970 971 + Use it to determine the register holding the fan 972 speed on some models. To do that, do the following: 973 - make sure the battery is fully charged 974 - make sure the fan is running 975 + - use above mentioned tool to read out the EC 976 977 + Often fan and temperature values vary between 978 readings. Since temperatures don't change vary fast, you can take 979 several quick dumps to eliminate them. 980
+6 -14
arch/x86/include/asm/intel_scu_ipc.h
··· 1 #ifndef _ASM_X86_INTEL_SCU_IPC_H_ 2 #define _ASM_X86_INTEL_SCU_IPC_H_ 3 4 /* Read single register */ 5 int intel_scu_ipc_ioread8(u16 addr, u8 *data); 6 ··· 33 34 /* Update single register based on the mask */ 35 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask); 36 - 37 - /* 38 - * Indirect register read 39 - * Can be used when SCCB(System Controller Configuration Block) register 40 - * HRIM(Honor Restricted IPC Messages) is set (bit 23) 41 - */ 42 - int intel_scu_ipc_register_read(u32 addr, u32 *data); 43 - 44 - /* 45 - * Indirect register write 46 - * Can be used when SCCB(System Controller Configuration Block) register 47 - * HRIM(Honor Restricted IPC Messages) is set (bit 23) 48 - */ 49 - int intel_scu_ipc_register_write(u32 addr, u32 data); 50 51 /* Issue commands to the SCU with or without data */ 52 int intel_scu_ipc_simple_command(int cmd, int sub);
··· 1 #ifndef _ASM_X86_INTEL_SCU_IPC_H_ 2 #define _ASM_X86_INTEL_SCU_IPC_H_ 3 4 + #define IPCMSG_VRTC 0xFA /* Set vRTC device */ 5 + 6 + /* Command id associated with message IPCMSG_VRTC */ 7 + #define IPC_CMD_VRTC_SETTIME 1 /* Set time */ 8 + #define IPC_CMD_VRTC_SETALARM 2 /* Set alarm */ 9 + 10 /* Read single register */ 11 int intel_scu_ipc_ioread8(u16 addr, u8 *data); 12 ··· 27 28 /* Update single register based on the mask */ 29 int intel_scu_ipc_update_register(u16 addr, u8 data, u8 mask); 30 31 /* Issue commands to the SCU with or without data */ 32 int intel_scu_ipc_simple_command(int cmd, int sub);
+18
drivers/acpi/Kconfig
··· 104 help 105 Say N to disable power /sys interface 106 107 config ACPI_PROC_EVENT 108 bool "Deprecated /proc/acpi/event support" 109 depends on PROC_FS
··· 104 help 105 Say N to disable power /sys interface 106 107 + config ACPI_EC_DEBUGFS 108 + tristate "EC read/write access through /sys/kernel/debug/ec" 109 + default n 110 + help 111 + Say N to disable Embedded Controller /sys/kernel/debug interface 112 + 113 + Be aware that using this interface can confuse your Embedded 114 + Controller in a way that a normal reboot is not enough. You then 115 + have to power of your system, and remove the laptop battery for 116 + some seconds. 117 + An Embedded Controller typically is available on laptops and reads 118 + sensor values like battery state and temperature. 119 + The kernel accesses the EC through ACPI parsed code provided by BIOS 120 + tables. This option allows to access the EC directly without ACPI 121 + code being involved. 122 + Thus this option is a debug option that helps to write ACPI drivers 123 + and can be used to identify ACPI code or EC firmware bugs. 124 + 125 config ACPI_PROC_EVENT 126 bool "Deprecated /proc/acpi/event support" 127 depends on PROC_FS
+1
drivers/acpi/Makefile
··· 60 obj-$(CONFIG_ACPI_SBS) += sbs.o 61 obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o 62 obj-$(CONFIG_ACPI_HED) += hed.o 63 64 # processor has its own "processor." module_param namespace 65 processor-y := processor_driver.o processor_throttling.o
··· 60 obj-$(CONFIG_ACPI_SBS) += sbs.o 61 obj-$(CONFIG_ACPI_POWER_METER) += power_meter.o 62 obj-$(CONFIG_ACPI_HED) += hed.o 63 + obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o 64 65 # processor has its own "processor." module_param namespace 66 processor-y := processor_driver.o processor_throttling.o
+14 -93
drivers/acpi/ec.c
··· 34 #include <linux/init.h> 35 #include <linux/types.h> 36 #include <linux/delay.h> 37 - #include <linux/proc_fs.h> 38 - #include <linux/seq_file.h> 39 #include <linux/interrupt.h> 40 #include <linux/list.h> 41 #include <linux/spinlock.h> ··· 43 #include <acpi/acpi_drivers.h> 44 #include <linux/dmi.h> 45 46 #define ACPI_EC_CLASS "embedded_controller" 47 #define ACPI_EC_DEVICE_NAME "Embedded Controller" 48 #define ACPI_EC_FILE_INFO "info" 49 50 #define PREFIX "ACPI: EC: " 51 52 /* EC status register */ ··· 107 bool done; 108 }; 109 110 - static struct acpi_ec { 111 - acpi_handle handle; 112 - unsigned long gpe; 113 - unsigned long command_addr; 114 - unsigned long data_addr; 115 - unsigned long global_lock; 116 - unsigned long flags; 117 - struct mutex lock; 118 - wait_queue_head_t wait; 119 - struct list_head list; 120 - struct transaction *curr; 121 - spinlock_t curr_lock; 122 - } *boot_ec, *first_ec; 123 124 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ 125 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ ··· 669 } 670 671 /* -------------------------------------------------------------------------- 672 - FS Interface (/proc) 673 - -------------------------------------------------------------------------- */ 674 - 675 - static struct proc_dir_entry *acpi_ec_dir; 676 - 677 - static int acpi_ec_read_info(struct seq_file *seq, void *offset) 678 - { 679 - struct acpi_ec *ec = seq->private; 680 - 681 - if (!ec) 682 - goto end; 683 - 684 - seq_printf(seq, "gpe:\t\t\t0x%02x\n", (u32) ec->gpe); 685 - seq_printf(seq, "ports:\t\t\t0x%02x, 0x%02x\n", 686 - (unsigned)ec->command_addr, (unsigned)ec->data_addr); 687 - seq_printf(seq, "use global lock:\t%s\n", 688 - ec->global_lock ? "yes" : "no"); 689 - end: 690 - return 0; 691 - } 692 - 693 - static int acpi_ec_info_open_fs(struct inode *inode, struct file *file) 694 - { 695 - return single_open(file, acpi_ec_read_info, PDE(inode)->data); 696 - } 697 - 698 - static const struct file_operations acpi_ec_info_ops = { 699 - .open = acpi_ec_info_open_fs, 700 - .read = seq_read, 701 - .llseek = seq_lseek, 702 - .release = single_release, 703 - .owner = THIS_MODULE, 704 - }; 705 - 706 - static int acpi_ec_add_fs(struct acpi_device *device) 707 - { 708 - struct proc_dir_entry *entry = NULL; 709 - 710 - if (!acpi_device_dir(device)) { 711 - acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), 712 - acpi_ec_dir); 713 - if (!acpi_device_dir(device)) 714 - return -ENODEV; 715 - } 716 - 717 - entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO, 718 - acpi_device_dir(device), 719 - &acpi_ec_info_ops, acpi_driver_data(device)); 720 - if (!entry) 721 - return -ENODEV; 722 - return 0; 723 - } 724 - 725 - static int acpi_ec_remove_fs(struct acpi_device *device) 726 - { 727 - 728 - if (acpi_device_dir(device)) { 729 - remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device)); 730 - remove_proc_entry(acpi_device_bid(device), acpi_ec_dir); 731 - acpi_device_dir(device) = NULL; 732 - } 733 - 734 - return 0; 735 - } 736 - 737 - /* -------------------------------------------------------------------------- 738 Driver Interface 739 -------------------------------------------------------------------------- */ 740 static acpi_status ··· 818 if (!first_ec) 819 first_ec = ec; 820 device->driver_data = ec; 821 - acpi_ec_add_fs(device); 822 pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", 823 ec->gpe, ec->command_addr, ec->data_addr); 824 ··· 850 kfree(handler); 851 } 852 mutex_unlock(&ec->lock); 853 - acpi_ec_remove_fs(device); 854 device->driver_data = NULL; 855 if (ec == first_ec) 856 first_ec = NULL; ··· 1050 { 1051 int result = 0; 1052 1053 - acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir); 1054 - if (!acpi_ec_dir) 1055 - return -ENODEV; 1056 - 1057 /* Now register the driver for the EC */ 1058 result = acpi_bus_register_driver(&acpi_ec_driver); 1059 - if (result < 0) { 1060 - remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); 1061 return -ENODEV; 1062 - } 1063 1064 return result; 1065 } ··· 1064 { 1065 1066 acpi_bus_unregister_driver(&acpi_ec_driver); 1067 - 1068 - remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); 1069 - 1070 return; 1071 } 1072 #endif /* 0 */
··· 34 #include <linux/init.h> 35 #include <linux/types.h> 36 #include <linux/delay.h> 37 #include <linux/interrupt.h> 38 #include <linux/list.h> 39 #include <linux/spinlock.h> ··· 45 #include <acpi/acpi_drivers.h> 46 #include <linux/dmi.h> 47 48 + #include "internal.h" 49 + 50 #define ACPI_EC_CLASS "embedded_controller" 51 #define ACPI_EC_DEVICE_NAME "Embedded Controller" 52 #define ACPI_EC_FILE_INFO "info" 53 54 + #undef PREFIX 55 #define PREFIX "ACPI: EC: " 56 57 /* EC status register */ ··· 106 bool done; 107 }; 108 109 + struct acpi_ec *boot_ec, *first_ec; 110 + EXPORT_SYMBOL(first_ec); 111 112 static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */ 113 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */ ··· 679 } 680 681 /* -------------------------------------------------------------------------- 682 Driver Interface 683 -------------------------------------------------------------------------- */ 684 static acpi_status ··· 894 if (!first_ec) 895 first_ec = ec; 896 device->driver_data = ec; 897 + 898 + WARN(!request_region(ec->data_addr, 1, "EC data"), 899 + "Could not request EC data io port 0x%lx", ec->data_addr); 900 + WARN(!request_region(ec->command_addr, 1, "EC cmd"), 901 + "Could not request EC cmd io port 0x%lx", ec->command_addr); 902 + 903 pr_info(PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx\n", 904 ec->gpe, ec->command_addr, ec->data_addr); 905 ··· 921 kfree(handler); 922 } 923 mutex_unlock(&ec->lock); 924 + release_region(ec->data_addr, 1); 925 + release_region(ec->command_addr, 1); 926 device->driver_data = NULL; 927 if (ec == first_ec) 928 first_ec = NULL; ··· 1120 { 1121 int result = 0; 1122 1123 /* Now register the driver for the EC */ 1124 result = acpi_bus_register_driver(&acpi_ec_driver); 1125 + if (result < 0) 1126 return -ENODEV; 1127 1128 return result; 1129 } ··· 1140 { 1141 1142 acpi_bus_unregister_driver(&acpi_ec_driver); 1143 return; 1144 } 1145 #endif /* 0 */
+160
drivers/acpi/ec_sys.c
···
··· 1 + /* 2 + * ec_sys.c 3 + * 4 + * Copyright (C) 2010 SUSE Products GmbH/Novell 5 + * Author: 6 + * Thomas Renninger <trenn@suse.de> 7 + * 8 + * This work is licensed under the terms of the GNU GPL, version 2. 9 + */ 10 + 11 + #include <linux/kernel.h> 12 + #include <linux/acpi.h> 13 + #include <linux/debugfs.h> 14 + #include "internal.h" 15 + 16 + MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); 17 + MODULE_DESCRIPTION("ACPI EC sysfs access driver"); 18 + MODULE_LICENSE("GPL"); 19 + 20 + static bool write_support; 21 + module_param(write_support, bool, 0644); 22 + MODULE_PARM_DESC(write_support, "Dangerous, reboot and removal of battery may " 23 + "be needed."); 24 + 25 + #define EC_SPACE_SIZE 256 26 + 27 + struct sysdev_class acpi_ec_sysdev_class = { 28 + .name = "ec", 29 + }; 30 + 31 + static struct dentry *acpi_ec_debugfs_dir; 32 + 33 + static int acpi_ec_open_io(struct inode *i, struct file *f) 34 + { 35 + f->private_data = i->i_private; 36 + return 0; 37 + } 38 + 39 + static ssize_t acpi_ec_read_io(struct file *f, char __user *buf, 40 + size_t count, loff_t *off) 41 + { 42 + /* Use this if support reading/writing multiple ECs exists in ec.c: 43 + * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private; 44 + */ 45 + unsigned int size = EC_SPACE_SIZE; 46 + u8 *data = (u8 *) buf; 47 + loff_t init_off = *off; 48 + int err = 0; 49 + 50 + if (*off >= size) 51 + return 0; 52 + if (*off + count >= size) { 53 + size -= *off; 54 + count = size; 55 + } else 56 + size = count; 57 + 58 + while (size) { 59 + err = ec_read(*off, &data[*off - init_off]); 60 + if (err) 61 + return err; 62 + *off += 1; 63 + size--; 64 + } 65 + return count; 66 + } 67 + 68 + static ssize_t acpi_ec_write_io(struct file *f, const char __user *buf, 69 + size_t count, loff_t *off) 70 + { 71 + /* Use this if support reading/writing multiple ECs exists in ec.c: 72 + * struct acpi_ec *ec = ((struct seq_file *)f->private_data)->private; 73 + */ 74 + 75 + unsigned int size = count; 76 + loff_t init_off = *off; 77 + u8 *data = (u8 *) buf; 78 + int err = 0; 79 + 80 + if (*off >= EC_SPACE_SIZE) 81 + return 0; 82 + if (*off + count >= EC_SPACE_SIZE) { 83 + size = EC_SPACE_SIZE - *off; 84 + count = size; 85 + } 86 + 87 + while (size) { 88 + u8 byte_write = data[*off - init_off]; 89 + err = ec_write(*off, byte_write); 90 + if (err) 91 + return err; 92 + 93 + *off += 1; 94 + size--; 95 + } 96 + return count; 97 + } 98 + 99 + static struct file_operations acpi_ec_io_ops = { 100 + .owner = THIS_MODULE, 101 + .open = acpi_ec_open_io, 102 + .read = acpi_ec_read_io, 103 + .write = acpi_ec_write_io, 104 + }; 105 + 106 + int acpi_ec_add_debugfs(struct acpi_ec *ec, unsigned int ec_device_count) 107 + { 108 + struct dentry *dev_dir; 109 + char name[64]; 110 + mode_t mode = 0400; 111 + 112 + if (ec_device_count == 0) { 113 + acpi_ec_debugfs_dir = debugfs_create_dir("ec", NULL); 114 + if (!acpi_ec_debugfs_dir) 115 + return -ENOMEM; 116 + } 117 + 118 + sprintf(name, "ec%u", ec_device_count); 119 + dev_dir = debugfs_create_dir(name, acpi_ec_debugfs_dir); 120 + if (!dev_dir) { 121 + if (ec_device_count != 0) 122 + goto error; 123 + return -ENOMEM; 124 + } 125 + 126 + if (!debugfs_create_x32("gpe", 0444, dev_dir, (u32 *)&first_ec->gpe)) 127 + goto error; 128 + if (!debugfs_create_bool("use_global_lock", 0444, dev_dir, 129 + (u32 *)&first_ec->global_lock)) 130 + goto error; 131 + 132 + if (write_support) 133 + mode = 0600; 134 + if (!debugfs_create_file("io", mode, dev_dir, ec, &acpi_ec_io_ops)) 135 + goto error; 136 + 137 + return 0; 138 + 139 + error: 140 + debugfs_remove_recursive(acpi_ec_debugfs_dir); 141 + return -ENOMEM; 142 + } 143 + 144 + static int __init acpi_ec_sys_init(void) 145 + { 146 + int err = 0; 147 + if (first_ec) 148 + err = acpi_ec_add_debugfs(first_ec, 0); 149 + else 150 + err = -ENODEV; 151 + return err; 152 + } 153 + 154 + static void __exit acpi_ec_sys_exit(void) 155 + { 156 + debugfs_remove_recursive(acpi_ec_debugfs_dir); 157 + } 158 + 159 + module_init(acpi_ec_sys_init); 160 + module_exit(acpi_ec_sys_exit);
+24
drivers/acpi/internal.h
··· 18 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 #define PREFIX "ACPI: " 22 23 int init_acpi_device_notify(void); ··· 51 /* -------------------------------------------------------------------------- 52 Embedded Controller 53 -------------------------------------------------------------------------- */ 54 int acpi_ec_init(void); 55 int acpi_ec_ecdt_probe(void); 56 int acpi_boot_ec_enable(void); ··· 85 #else 86 static inline int acpi_sleep_proc_init(void) { return 0; } 87 #endif
··· 18 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 21 + #ifndef _ACPI_INTERNAL_H_ 22 + #define _ACPI_INTERNAL_H_ 23 + 24 + #include <linux/sysdev.h> 25 + 26 #define PREFIX "ACPI: " 27 28 int init_acpi_device_notify(void); ··· 46 /* -------------------------------------------------------------------------- 47 Embedded Controller 48 -------------------------------------------------------------------------- */ 49 + struct acpi_ec { 50 + acpi_handle handle; 51 + unsigned long gpe; 52 + unsigned long command_addr; 53 + unsigned long data_addr; 54 + unsigned long global_lock; 55 + unsigned long flags; 56 + struct mutex lock; 57 + wait_queue_head_t wait; 58 + struct list_head list; 59 + struct transaction *curr; 60 + spinlock_t curr_lock; 61 + struct sys_device sysdev; 62 + }; 63 + 64 + extern struct acpi_ec *first_ec; 65 + 66 int acpi_ec_init(void); 67 int acpi_ec_ecdt_probe(void); 68 int acpi_boot_ec_enable(void); ··· 63 #else 64 static inline int acpi_sleep_proc_init(void) { return 0; } 65 #endif 66 + 67 + #endif /* _ACPI_INTERNAL_H_ */
+44
drivers/platform/x86/Kconfig
··· 5 menuconfig X86_PLATFORM_DEVICES 6 bool "X86 Platform Specific Device Drivers" 7 default y 8 ---help--- 9 Say Y here to get to see options for device drivers for various 10 x86 platforms, including vendor-specific laptop extension drivers. ··· 152 depends on ACPI 153 depends on BACKLIGHT_CLASS_DEVICE 154 depends on RFKILL 155 ---help--- 156 This is a driver for laptops built by MSI (MICRO-STAR 157 INTERNATIONAL): ··· 183 depends on ACPI 184 depends on BACKLIGHT_CLASS_DEVICE 185 depends on RFKILL 186 ---help--- 187 This is a driver for laptops built by Compal: 188 ··· 524 config ACPI_CMPC 525 tristate "CMPC Laptop Extras" 526 depends on X86 && ACPI 527 select INPUT 528 select BACKLIGHT_CLASS_DEVICE 529 default n ··· 541 IPC is used to bridge the communications between kernel and SCU on 542 some embedded Intel x86 platforms. This is not needed for PC-type 543 machines. 544 545 endif # X86_PLATFORM_DEVICES
··· 5 menuconfig X86_PLATFORM_DEVICES 6 bool "X86 Platform Specific Device Drivers" 7 default y 8 + depends on X86 9 ---help--- 10 Say Y here to get to see options for device drivers for various 11 x86 platforms, including vendor-specific laptop extension drivers. ··· 151 depends on ACPI 152 depends on BACKLIGHT_CLASS_DEVICE 153 depends on RFKILL 154 + depends on SERIO_I8042 155 ---help--- 156 This is a driver for laptops built by MSI (MICRO-STAR 157 INTERNATIONAL): ··· 181 depends on ACPI 182 depends on BACKLIGHT_CLASS_DEVICE 183 depends on RFKILL 184 + depends on HWMON 185 + depends on POWER_SUPPLY 186 ---help--- 187 This is a driver for laptops built by Compal: 188 ··· 520 config ACPI_CMPC 521 tristate "CMPC Laptop Extras" 522 depends on X86 && ACPI 523 + depends on RFKILL || RFKILL=n 524 select INPUT 525 select BACKLIGHT_CLASS_DEVICE 526 default n ··· 536 IPC is used to bridge the communications between kernel and SCU on 537 some embedded Intel x86 platforms. This is not needed for PC-type 538 machines. 539 + 540 + config GPIO_INTEL_PMIC 541 + bool "Intel PMIC GPIO support" 542 + depends on INTEL_SCU_IPC && GPIOLIB 543 + ---help--- 544 + Say Y here to support GPIO via the SCU IPC interface 545 + on Intel MID platforms. 546 + 547 + config RAR_REGISTER 548 + bool "Restricted Access Region Register Driver" 549 + depends on PCI && X86_MRST 550 + default n 551 + ---help--- 552 + This driver allows other kernel drivers access to the 553 + contents of the restricted access region control registers. 554 + 555 + The restricted access region control registers 556 + (rar_registers) are used to pass address and 557 + locking information on restricted access regions 558 + to other drivers that use restricted access regions. 559 + 560 + The restricted access regions are regions of memory 561 + on the Intel MID Platform that are not accessible to 562 + the x86 processor, but are accessible to dedicated 563 + processors on board peripheral devices. 564 + 565 + The purpose of the restricted access regions is to 566 + protect sensitive data from compromise by unauthorized 567 + programs running on the x86 processor. 568 + 569 + config INTEL_IPS 570 + tristate "Intel Intelligent Power Sharing" 571 + depends on ACPI 572 + ---help--- 573 + Intel Calpella platforms support dynamic power sharing between the 574 + CPU and GPU, maximizing performance in a given TDP. This driver, 575 + along with the CPU frequency and i915 drivers, provides that 576 + functionality. If in doubt, say Y here; it will only load on 577 + supported platforms. 578 579 endif # X86_PLATFORM_DEVICES
+4
drivers/platform/x86/Makefile
··· 26 obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 27 obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 28 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
··· 26 obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 27 obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 28 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 29 + obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o 30 + obj-$(CONFIG_INTEL_IPS) += intel_ips.o 31 + obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 32 +
+48 -31
drivers/platform/x86/acer-wmi.c
··· 50 #define ACER_INFO KERN_INFO ACER_LOGPREFIX 51 52 /* 53 - * The following defines quirks to get some specific functions to work 54 - * which are known to not be supported over ACPI-WMI (such as the mail LED 55 - * on WMID based Acer's) 56 - */ 57 - struct acer_quirks { 58 - const char *vendor; 59 - const char *model; 60 - u16 quirks; 61 - }; 62 - 63 - /* 64 * Magic Number 65 * Meaning is unknown - this number is required for writing to ACPI for AMW0 66 * (it's also used in acerhk when directly accessing the BIOS) ··· 189 static int dmi_matched(const struct dmi_system_id *dmi) 190 { 191 quirks = dmi->driver_data; 192 - return 0; 193 } 194 195 static struct quirk_entry quirk_unknown = { ··· 544 obj->buffer.length == sizeof(struct wmab_ret)) { 545 ret = *((struct wmab_ret *) obj->buffer.pointer); 546 } else { 547 return AE_ERROR; 548 } 549 ··· 560 { 561 struct wmab_args args; 562 struct wmab_ret ret; 563 - acpi_status status = AE_OK; 564 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 565 union acpi_object *obj; 566 ··· 583 if (ACPI_FAILURE(status)) 584 return status; 585 586 - obj = (union acpi_object *) out.pointer; 587 if (obj && obj->type == ACPI_TYPE_BUFFER && 588 obj->buffer.length == sizeof(struct wmab_ret)) { 589 ret = *((struct wmab_ret *) obj->buffer.pointer); 590 } else { 591 - return AE_ERROR; 592 } 593 594 if (ret.eax & 0x1) ··· 598 args.ebx = 2 << 8; 599 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 600 601 status = wmab_execute(&args, &out); 602 if (ACPI_FAILURE(status)) 603 - return status; 604 605 obj = (union acpi_object *) out.pointer; 606 if (obj && obj->type == ACPI_TYPE_BUFFER 607 && obj->buffer.length == sizeof(struct wmab_ret)) { 608 ret = *((struct wmab_ret *) obj->buffer.pointer); 609 } else { 610 - return AE_ERROR; 611 } 612 613 if (ret.eax & 0x1) 614 interface->capability |= ACER_CAP_BLUETOOTH; 615 - 616 - kfree(out.pointer); 617 618 /* 619 * This appears to be safe to enable, since all Wistron based laptops ··· 626 if (quirks->brightness >= 0) 627 interface->capability |= ACER_CAP_BRIGHTNESS; 628 629 - return AE_OK; 630 } 631 632 static struct wmi_interface AMW0_interface = { ··· 769 obj->buffer.length == sizeof(u32)) { 770 devices = *((u32 *) obj->buffer.pointer); 771 } else { 772 return AE_ERROR; 773 } 774 ··· 786 if (!(devices & 0x20)) 787 max_brightness = 0x9; 788 789 return status; 790 } 791 ··· 1083 } 1084 } 1085 1086 - static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, 1087 - show_interface, NULL); 1088 1089 /* 1090 * debugfs functions ··· 1093 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1094 union acpi_object *obj; 1095 acpi_status status; 1096 1097 status = wmi_query_block(WMID_GUID2, 1, &out); 1098 if (ACPI_FAILURE(status)) ··· 1102 obj = (union acpi_object *) out.pointer; 1103 if (obj && obj->type == ACPI_TYPE_BUFFER && 1104 obj->buffer.length == sizeof(u32)) { 1105 - return *((u32 *) obj->buffer.pointer); 1106 - } else { 1107 - return 0; 1108 } 1109 } 1110 1111 /* ··· 1327 "generic video driver\n"); 1328 } 1329 1330 - if (platform_driver_register(&acer_platform_driver)) { 1331 printk(ACER_ERR "Unable to register platform driver.\n"); 1332 goto error_platform_register; 1333 } 1334 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1335 - platform_device_add(acer_platform_device); 1336 1337 err = create_sysfs(); 1338 if (err) 1339 - return err; 1340 1341 if (wmi_has_guid(WMID_GUID2)) { 1342 interface->debug.wmid_devices = get_wmid_devices(); 1343 err = create_debugfs(); 1344 if (err) 1345 - return err; 1346 } 1347 1348 /* Override any initial settings with values from the commandline */ ··· 1359 1360 return 0; 1361 1362 error_platform_register: 1363 - return -ENODEV; 1364 } 1365 1366 static void __exit acer_wmi_exit(void) 1367 { 1368 remove_sysfs(acer_platform_device); 1369 remove_debugfs(); 1370 - platform_device_del(acer_platform_device); 1371 platform_driver_unregister(&acer_platform_driver); 1372 1373 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
··· 50 #define ACER_INFO KERN_INFO ACER_LOGPREFIX 51 52 /* 53 * Magic Number 54 * Meaning is unknown - this number is required for writing to ACPI for AMW0 55 * (it's also used in acerhk when directly accessing the BIOS) ··· 200 static int dmi_matched(const struct dmi_system_id *dmi) 201 { 202 quirks = dmi->driver_data; 203 + return 1; 204 } 205 206 static struct quirk_entry quirk_unknown = { ··· 555 obj->buffer.length == sizeof(struct wmab_ret)) { 556 ret = *((struct wmab_ret *) obj->buffer.pointer); 557 } else { 558 + kfree(out.pointer); 559 return AE_ERROR; 560 } 561 ··· 570 { 571 struct wmab_args args; 572 struct wmab_ret ret; 573 + acpi_status status; 574 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 575 union acpi_object *obj; 576 ··· 593 if (ACPI_FAILURE(status)) 594 return status; 595 596 + obj = out.pointer; 597 if (obj && obj->type == ACPI_TYPE_BUFFER && 598 obj->buffer.length == sizeof(struct wmab_ret)) { 599 ret = *((struct wmab_ret *) obj->buffer.pointer); 600 } else { 601 + status = AE_ERROR; 602 + goto out; 603 } 604 605 if (ret.eax & 0x1) ··· 607 args.ebx = 2 << 8; 608 args.ebx |= ACER_AMW0_BLUETOOTH_MASK; 609 610 + /* 611 + * It's ok to use existing buffer for next wmab_execute call. 612 + * But we need to kfree(out.pointer) if next wmab_execute fail. 613 + */ 614 status = wmab_execute(&args, &out); 615 if (ACPI_FAILURE(status)) 616 + goto out; 617 618 obj = (union acpi_object *) out.pointer; 619 if (obj && obj->type == ACPI_TYPE_BUFFER 620 && obj->buffer.length == sizeof(struct wmab_ret)) { 621 ret = *((struct wmab_ret *) obj->buffer.pointer); 622 } else { 623 + status = AE_ERROR; 624 + goto out; 625 } 626 627 if (ret.eax & 0x1) 628 interface->capability |= ACER_CAP_BLUETOOTH; 629 630 /* 631 * This appears to be safe to enable, since all Wistron based laptops ··· 632 if (quirks->brightness >= 0) 633 interface->capability |= ACER_CAP_BRIGHTNESS; 634 635 + status = AE_OK; 636 + out: 637 + kfree(out.pointer); 638 + return status; 639 } 640 641 static struct wmi_interface AMW0_interface = { ··· 772 obj->buffer.length == sizeof(u32)) { 773 devices = *((u32 *) obj->buffer.pointer); 774 } else { 775 + kfree(out.pointer); 776 return AE_ERROR; 777 } 778 ··· 788 if (!(devices & 0x20)) 789 max_brightness = 0x9; 790 791 + kfree(out.pointer); 792 return status; 793 } 794 ··· 1084 } 1085 } 1086 1087 + static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL); 1088 1089 /* 1090 * debugfs functions ··· 1095 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 1096 union acpi_object *obj; 1097 acpi_status status; 1098 + u32 devices = 0; 1099 1100 status = wmi_query_block(WMID_GUID2, 1, &out); 1101 if (ACPI_FAILURE(status)) ··· 1103 obj = (union acpi_object *) out.pointer; 1104 if (obj && obj->type == ACPI_TYPE_BUFFER && 1105 obj->buffer.length == sizeof(u32)) { 1106 + devices = *((u32 *) obj->buffer.pointer); 1107 } 1108 + 1109 + kfree(out.pointer); 1110 + return devices; 1111 } 1112 1113 /* ··· 1327 "generic video driver\n"); 1328 } 1329 1330 + err = platform_driver_register(&acer_platform_driver); 1331 + if (err) { 1332 printk(ACER_ERR "Unable to register platform driver.\n"); 1333 goto error_platform_register; 1334 } 1335 + 1336 acer_platform_device = platform_device_alloc("acer-wmi", -1); 1337 + if (!acer_platform_device) { 1338 + err = -ENOMEM; 1339 + goto error_device_alloc; 1340 + } 1341 + 1342 + err = platform_device_add(acer_platform_device); 1343 + if (err) 1344 + goto error_device_add; 1345 1346 err = create_sysfs(); 1347 if (err) 1348 + goto error_create_sys; 1349 1350 if (wmi_has_guid(WMID_GUID2)) { 1351 interface->debug.wmid_devices = get_wmid_devices(); 1352 err = create_debugfs(); 1353 if (err) 1354 + goto error_create_debugfs; 1355 } 1356 1357 /* Override any initial settings with values from the commandline */ ··· 1350 1351 return 0; 1352 1353 + error_create_debugfs: 1354 + remove_sysfs(acer_platform_device); 1355 + error_create_sys: 1356 + platform_device_del(acer_platform_device); 1357 + error_device_add: 1358 + platform_device_put(acer_platform_device); 1359 + error_device_alloc: 1360 + platform_driver_unregister(&acer_platform_driver); 1361 error_platform_register: 1362 + return err; 1363 } 1364 1365 static void __exit acer_wmi_exit(void) 1366 { 1367 remove_sysfs(acer_platform_device); 1368 remove_debugfs(); 1369 + platform_device_unregister(acer_platform_device); 1370 platform_driver_unregister(&acer_platform_driver); 1371 1372 printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n");
+99 -52
drivers/platform/x86/acerhdf.c
··· 52 */ 53 #undef START_IN_KERNEL_MODE 54 55 - #define DRV_VER "0.5.22" 56 57 /* 58 * According to the Atom N270 datasheet, ··· 92 static char force_bios[16]; 93 static char force_product[16]; 94 static unsigned int prev_interval; 95 - struct thermal_zone_device *thz_dev; 96 - struct thermal_cooling_device *cl_dev; 97 - struct platform_device *acerhdf_dev; 98 99 module_param(kernelmode, uint, 0); 100 MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off"); ··· 112 MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); 113 114 /* 115 - * cmd_off: to switch the fan completely off 116 - * chk_off: to check if the fan is off 117 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then 118 * the fan speed depending on the temperature 119 */ 120 struct fancmd { 121 u8 cmd_off; 122 - u8 chk_off; 123 u8 cmd_auto; 124 }; 125 ··· 134 /* Register addresses and values for different BIOS versions */ 135 static const struct bios_settings_t bios_tbl[] = { 136 /* AOA110 */ 137 - {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, 138 - {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, 139 - {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 140 - {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 141 - {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 142 - {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, 143 - {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} }, 144 - {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} }, 145 - {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} }, 146 /* AOA150 */ 147 - {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} }, 148 - {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} }, 149 - {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} }, 150 - {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} }, 151 - {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} }, 152 - {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} }, 153 - {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} }, 154 - {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, 155 /* Acer 1410 */ 156 - {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 157 - {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 158 /* Acer 1810xx */ 159 - {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 160 - {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 161 - {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 162 - {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 163 /* Gateway */ 164 - {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, 165 - {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, 166 - {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 167 - {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 168 - {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x10, 0x0f, 0x00} }, 169 /* Packard Bell */ 170 - {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, 171 - {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 172 - {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, 173 - {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, 174 - {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 175 - {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, 176 /* pewpew-terminator */ 177 - {"", "", "", 0, 0, {0, 0, 0} } 178 }; 179 180 static const struct bios_settings_t *bios_cfg __read_mostly; ··· 232 if (ec_read(bios_cfg->fanreg, &fan)) 233 return -EINVAL; 234 235 - if (fan != bios_cfg->cmd.chk_off) 236 *state = ACERHDF_FAN_AUTO; 237 else 238 *state = ACERHDF_FAN_OFF; ··· 406 } 407 408 /* bind callback functions to thermalzone */ 409 - struct thermal_zone_device_ops acerhdf_dev_ops = { 410 .bind = acerhdf_bind, 411 .unbind = acerhdf_unbind, 412 .get_temp = acerhdf_get_ec_temp, ··· 481 } 482 483 /* bind fan callbacks to fan device */ 484 - struct thermal_cooling_device_ops acerhdf_cooling_ops = { 485 .get_max_state = acerhdf_get_max_state, 486 .get_cur_state = acerhdf_get_cur_state, 487 .set_cur_state = acerhdf_set_cur_state, ··· 550 version = dmi_get_system_info(DMI_BIOS_VERSION); 551 product = dmi_get_system_info(DMI_PRODUCT_NAME); 552 553 554 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); 555 ··· 615 return err; 616 617 acerhdf_dev = platform_device_alloc("acerhdf", -1); 618 - platform_device_add(acerhdf_dev); 619 620 return 0; 621 } 622 623 static void acerhdf_unregister_platform(void) 624 { 625 - if (!acerhdf_dev) 626 - return; 627 - 628 - platform_device_del(acerhdf_dev); 629 platform_driver_unregister(&acerhdf_driver); 630 } 631 ··· 678 679 err = acerhdf_register_platform(); 680 if (err) 681 - goto err_unreg; 682 683 err = acerhdf_register_thermal(); 684 if (err) ··· 691 acerhdf_unregister_platform(); 692 693 out_err: 694 - return -ENODEV; 695 } 696 697 static void __exit acerhdf_exit(void) ··· 707 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); 708 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); 709 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); 710 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 711 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); 712 MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); 713 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); 714 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); 715 716 module_init(acerhdf_init); 717 module_exit(acerhdf_exit);
··· 52 */ 53 #undef START_IN_KERNEL_MODE 54 55 + #define DRV_VER "0.5.24" 56 57 /* 58 * According to the Atom N270 datasheet, ··· 92 static char force_bios[16]; 93 static char force_product[16]; 94 static unsigned int prev_interval; 95 + static struct thermal_zone_device *thz_dev; 96 + static struct thermal_cooling_device *cl_dev; 97 + static struct platform_device *acerhdf_dev; 98 99 module_param(kernelmode, uint, 0); 100 MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off"); ··· 112 MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); 113 114 /* 115 + * cmd_off: to switch the fan completely off and check if the fan is off 116 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then 117 * the fan speed depending on the temperature 118 */ 119 struct fancmd { 120 u8 cmd_off; 121 u8 cmd_auto; 122 }; 123 ··· 136 /* Register addresses and values for different BIOS versions */ 137 static const struct bios_settings_t bios_tbl[] = { 138 /* AOA110 */ 139 + {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, 140 + {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 141 + {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, 142 + {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, 143 + {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, 144 + {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, 145 + {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, 146 + {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, 147 + {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, 148 /* AOA150 */ 149 + {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, 150 + {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, 151 + {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, 152 + {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, 153 + {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, 154 + {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, 155 + {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, 156 + {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, 157 /* Acer 1410 */ 158 + {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 159 + {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 160 + {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 161 + {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 162 + {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 163 + {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 164 + {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 165 + {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 166 + {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 167 + {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 168 /* Acer 1810xx */ 169 + {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 170 + {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 171 + {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 172 + {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 173 + {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 174 + {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 175 + {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 176 + {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 177 + {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 178 + {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 179 + {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 180 + {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 181 + {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 182 + {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 183 + {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 184 + {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 185 + {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 186 + {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00} }, 187 + {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 188 + {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00} }, 189 + /* Acer 531 */ 190 + {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00} }, 191 /* Gateway */ 192 + {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, 193 + {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, 194 + {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00} }, 195 + {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, 196 + {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, 197 /* Packard Bell */ 198 + {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, 199 + {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, 200 + {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, 201 + {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, 202 + {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00} }, 203 + {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00} }, 204 + {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00} }, 205 + {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00} }, 206 + {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00} }, 207 + {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00} }, 208 + {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00} }, 209 + {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00} }, 210 + {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00} }, 211 + {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00} }, 212 /* pewpew-terminator */ 213 + {"", "", "", 0, 0, {0, 0} } 214 }; 215 216 static const struct bios_settings_t *bios_cfg __read_mostly; ··· 200 if (ec_read(bios_cfg->fanreg, &fan)) 201 return -EINVAL; 202 203 + if (fan != bios_cfg->cmd.cmd_off) 204 *state = ACERHDF_FAN_AUTO; 205 else 206 *state = ACERHDF_FAN_OFF; ··· 374 } 375 376 /* bind callback functions to thermalzone */ 377 + static struct thermal_zone_device_ops acerhdf_dev_ops = { 378 .bind = acerhdf_bind, 379 .unbind = acerhdf_unbind, 380 .get_temp = acerhdf_get_ec_temp, ··· 449 } 450 451 /* bind fan callbacks to fan device */ 452 + static struct thermal_cooling_device_ops acerhdf_cooling_ops = { 453 .get_max_state = acerhdf_get_max_state, 454 .get_cur_state = acerhdf_get_cur_state, 455 .set_cur_state = acerhdf_set_cur_state, ··· 518 version = dmi_get_system_info(DMI_BIOS_VERSION); 519 product = dmi_get_system_info(DMI_PRODUCT_NAME); 520 521 + if (!vendor || !version || !product) { 522 + pr_err("error getting hardware information\n"); 523 + return -EINVAL; 524 + } 525 526 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); 527 ··· 579 return err; 580 581 acerhdf_dev = platform_device_alloc("acerhdf", -1); 582 + if (!acerhdf_dev) { 583 + err = -ENOMEM; 584 + goto err_device_alloc; 585 + } 586 + err = platform_device_add(acerhdf_dev); 587 + if (err) 588 + goto err_device_add; 589 590 return 0; 591 + 592 + err_device_add: 593 + platform_device_put(acerhdf_dev); 594 + err_device_alloc: 595 + platform_driver_unregister(&acerhdf_driver); 596 + return err; 597 } 598 599 static void acerhdf_unregister_platform(void) 600 { 601 + platform_device_unregister(acerhdf_dev); 602 platform_driver_unregister(&acerhdf_driver); 603 } 604 ··· 633 634 err = acerhdf_register_platform(); 635 if (err) 636 + goto out_err; 637 638 err = acerhdf_register_thermal(); 639 if (err) ··· 646 acerhdf_unregister_platform(); 647 648 out_err: 649 + return err; 650 } 651 652 static void __exit acerhdf_exit(void) ··· 662 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); 663 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1410*:"); 664 MODULE_ALIAS("dmi:*:*Acer*:pnAspire 1810*:"); 665 + MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); 666 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 667 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); 668 MODULE_ALIAS("dmi:*:*Packard Bell*:pnAOA*:"); 669 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOA*:"); 670 MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMU*:"); 671 + MODULE_ALIAS("dmi:*:*Packard Bell*:pnDOTMA*:"); 672 673 module_init(acerhdf_init); 674 module_exit(acerhdf_exit);
+16 -13
drivers/platform/x86/asus-laptop.c
··· 76 * So, if something doesn't work as you want, just try other values =) 77 */ 78 static uint wapf = 1; 79 - module_param(wapf, uint, 0644); 80 MODULE_PARM_DESC(wapf, "WAPF value"); 81 82 static int wlan_status = 1; 83 static int bluetooth_status = 1; 84 85 - module_param(wlan_status, int, 0644); 86 MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " 87 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 88 "default is 1"); 89 90 - module_param(bluetooth_status, int, 0644); 91 MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " 92 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 93 "default is 1"); ··· 297 acpi_status status; 298 299 if (!handle) 300 - return 0; 301 302 params.count = 1; 303 params.pointer = &in_obj; ··· 796 797 rv = parse_arg(buf, count, &value); 798 if (rv > 0) { 799 - if (write_acpi_int(asus->handle, METHOD_LEDD, value)) 800 pr_warning("LED display write failed\n"); 801 - else 802 - asus->ledd_status = (u32) value; 803 } 804 return rv; 805 } ··· 1124 input = input_allocate_device(); 1125 if (!input) { 1126 pr_info("Unable to allocate input device\n"); 1127 - return 0; 1128 } 1129 input->name = "Asus Laptop extra buttons"; 1130 input->phys = ASUS_LAPTOP_FILE "/input0"; ··· 1135 error = sparse_keymap_setup(input, asus_keymap, NULL); 1136 if (error) { 1137 pr_err("Unable to setup input device keymap\n"); 1138 - goto err_keymap; 1139 } 1140 error = input_register_device(input); 1141 if (error) { 1142 pr_info("Unable to register input device\n"); 1143 - goto err_device; 1144 } 1145 1146 asus->inputdev = input; 1147 return 0; 1148 1149 - err_keymap: 1150 sparse_keymap_free(input); 1151 - err_device: 1152 input_free_device(input); 1153 return error; 1154 } ··· 1398 } 1399 } 1400 asus->name = kstrdup(string, GFP_KERNEL); 1401 - if (!asus->name) 1402 return -ENOMEM; 1403 1404 if (*string) 1405 pr_notice(" %s model detected\n", string);
··· 76 * So, if something doesn't work as you want, just try other values =) 77 */ 78 static uint wapf = 1; 79 + module_param(wapf, uint, 0444); 80 MODULE_PARM_DESC(wapf, "WAPF value"); 81 82 static int wlan_status = 1; 83 static int bluetooth_status = 1; 84 85 + module_param(wlan_status, int, 0444); 86 MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " 87 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 88 "default is 1"); 89 90 + module_param(bluetooth_status, int, 0444); 91 MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot " 92 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 93 "default is 1"); ··· 297 acpi_status status; 298 299 if (!handle) 300 + return -1; 301 302 params.count = 1; 303 params.pointer = &in_obj; ··· 796 797 rv = parse_arg(buf, count, &value); 798 if (rv > 0) { 799 + if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { 800 pr_warning("LED display write failed\n"); 801 + return -ENODEV; 802 + } 803 + asus->ledd_status = (u32) value; 804 } 805 return rv; 806 } ··· 1123 input = input_allocate_device(); 1124 if (!input) { 1125 pr_info("Unable to allocate input device\n"); 1126 + return -ENOMEM; 1127 } 1128 input->name = "Asus Laptop extra buttons"; 1129 input->phys = ASUS_LAPTOP_FILE "/input0"; ··· 1134 error = sparse_keymap_setup(input, asus_keymap, NULL); 1135 if (error) { 1136 pr_err("Unable to setup input device keymap\n"); 1137 + goto err_free_dev; 1138 } 1139 error = input_register_device(input); 1140 if (error) { 1141 pr_info("Unable to register input device\n"); 1142 + goto err_free_keymap; 1143 } 1144 1145 asus->inputdev = input; 1146 return 0; 1147 1148 + err_free_keymap: 1149 sparse_keymap_free(input); 1150 + err_free_dev: 1151 input_free_device(input); 1152 return error; 1153 } ··· 1397 } 1398 } 1399 asus->name = kstrdup(string, GFP_KERNEL); 1400 + if (!asus->name) { 1401 + kfree(buffer.pointer); 1402 return -ENOMEM; 1403 + } 1404 1405 if (*string) 1406 pr_notice(" %s model detected\n", string);
+4 -3
drivers/platform/x86/asus_acpi.c
··· 1330 hotk->model = P30; 1331 printk(KERN_NOTICE 1332 " Samsung P30 detected, supported\n"); 1333 } else { 1334 hotk->model = M2E; 1335 printk(KERN_NOTICE " unsupported model %s, trying " ··· 1342 kfree(model); 1343 return -ENODEV; 1344 } 1345 - hotk->methods = &model_conf[hotk->model]; 1346 - return AE_OK; 1347 } 1348 hotk->methods = &model_conf[hotk->model]; 1349 printk(KERN_NOTICE " %s model detected, supported\n", string); ··· 1375 1376 kfree(model); 1377 1378 - return AE_OK; 1379 } 1380 1381 static int asus_hotk_check(void)
··· 1330 hotk->model = P30; 1331 printk(KERN_NOTICE 1332 " Samsung P30 detected, supported\n"); 1333 + hotk->methods = &model_conf[hotk->model]; 1334 + kfree(model); 1335 + return 0; 1336 } else { 1337 hotk->model = M2E; 1338 printk(KERN_NOTICE " unsupported model %s, trying " ··· 1339 kfree(model); 1340 return -ENODEV; 1341 } 1342 } 1343 hotk->methods = &model_conf[hotk->model]; 1344 printk(KERN_NOTICE " %s model detected, supported\n", string); ··· 1374 1375 kfree(model); 1376 1377 + return 0; 1378 } 1379 1380 static int asus_hotk_check(void)
+7 -6
drivers/platform/x86/classmate-laptop.c
··· 208 return strnlen(buf, count); 209 } 210 211 - struct device_attribute cmpc_accel_sensitivity_attr = { 212 .attr = { .name = "sensitivity", .mode = 0660 }, 213 .show = cmpc_accel_sensitivity_show, 214 .store = cmpc_accel_sensitivity_store ··· 573 574 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN, 575 &cmpc_rfkill_ops, acpi->handle); 576 - /* rfkill_alloc may fail if RFKILL is disabled. We should still work 577 - * anyway. */ 578 - if (!IS_ERR(ipml->rf)) { 579 retval = rfkill_register(ipml->rf); 580 if (retval) { 581 rfkill_destroy(ipml->rf); 582 ipml->rf = NULL; 583 } 584 - } else { 585 - ipml->rf = NULL; 586 } 587 588 dev_set_drvdata(&acpi->dev, ipml);
··· 208 return strnlen(buf, count); 209 } 210 211 + static struct device_attribute cmpc_accel_sensitivity_attr = { 212 .attr = { .name = "sensitivity", .mode = 0660 }, 213 .show = cmpc_accel_sensitivity_show, 214 .store = cmpc_accel_sensitivity_store ··· 573 574 ipml->rf = rfkill_alloc("cmpc_rfkill", &acpi->dev, RFKILL_TYPE_WLAN, 575 &cmpc_rfkill_ops, acpi->handle); 576 + /* 577 + * If RFKILL is disabled, rfkill_alloc will return ERR_PTR(-ENODEV). 578 + * This is OK, however, since all other uses of the device will not 579 + * derefence it. 580 + */ 581 + if (ipml->rf) { 582 retval = rfkill_register(ipml->rf); 583 if (retval) { 584 rfkill_destroy(ipml->rf); 585 ipml->rf = NULL; 586 } 587 } 588 589 dev_set_drvdata(&acpi->dev, ipml);
+833 -116
drivers/platform/x86/compal-laptop.c
··· 24 */ 25 26 /* 27 - * comapl-laptop.c - Compal laptop support. 28 * 29 - * The driver registers itself with the rfkill subsystem and 30 - * the Linux backlight control subsystem. 31 * 32 * This driver might work on other laptops produced by Compal. If you 33 * want to try it you can pass force=1 as argument to the module which 34 * will force it to load even when the DMI data doesn't identify the 35 - * laptop as FL9x. 36 */ 37 38 #include <linux/module.h> 39 #include <linux/kernel.h> ··· 76 #include <linux/backlight.h> 77 #include <linux/platform_device.h> 78 #include <linux/rfkill.h> 79 80 - #define COMPAL_DRIVER_VERSION "0.2.6" 81 82 - #define COMPAL_LCD_LEVEL_MAX 8 83 84 - #define COMPAL_EC_COMMAND_WIRELESS 0xBB 85 - #define COMPAL_EC_COMMAND_LCD_LEVEL 0xB9 86 87 - #define KILLSWITCH_MASK 0x10 88 - #define WLAN_MASK 0x01 89 - #define BT_MASK 0x02 90 91 - static struct rfkill *wifi_rfkill; 92 - static struct rfkill *bt_rfkill; 93 - static struct platform_device *compal_device; 94 95 static int force; 96 module_param(force, bool, 0); 97 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 98 99 - /* Hardware access */ 100 101 - static int set_lcd_level(int level) 102 { 103 - if (level < 0 || level >= COMPAL_LCD_LEVEL_MAX) 104 return -EINVAL; 105 106 - ec_write(COMPAL_EC_COMMAND_LCD_LEVEL, level); 107 108 return 0; 109 } 110 111 - static int get_lcd_level(void) 112 - { 113 - u8 result; 114 115 - ec_read(COMPAL_EC_COMMAND_LCD_LEVEL, &result); 116 117 - return (int) result; 118 - } 119 - 120 static int compal_rfkill_set(void *data, bool blocked) 121 { 122 unsigned long radio = (unsigned long) data; 123 - u8 result, value; 124 - 125 - ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 126 127 if (!blocked) 128 value = (u8) (result | radio); 129 else 130 value = (u8) (result & ~radio); 131 - ec_write(COMPAL_EC_COMMAND_WIRELESS, value); 132 133 return 0; 134 } 135 136 static void compal_rfkill_poll(struct rfkill *rfkill, void *data) 137 { 138 - u8 result; 139 - bool hw_blocked; 140 - 141 - ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 142 - 143 - hw_blocked = !(result & KILLSWITCH_MASK); 144 rfkill_set_hw_state(rfkill, hw_blocked); 145 } 146 ··· 374 .set_block = compal_rfkill_set, 375 }; 376 377 - static int setup_rfkill(void) 378 { 379 - int ret; 380 381 - wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev, 382 - RFKILL_TYPE_WLAN, &compal_rfkill_ops, 383 - (void *) WLAN_MASK); 384 - if (!wifi_rfkill) 385 - return -ENOMEM; 386 387 - ret = rfkill_register(wifi_rfkill); 388 - if (ret) 389 - goto err_wifi; 390 391 - bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev, 392 - RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops, 393 - (void *) BT_MASK); 394 - if (!bt_rfkill) { 395 - ret = -ENOMEM; 396 - goto err_allocate_bt; 397 } 398 - ret = rfkill_register(bt_rfkill); 399 - if (ret) 400 - goto err_register_bt; 401 402 return 0; 403 - 404 - err_register_bt: 405 - rfkill_destroy(bt_rfkill); 406 - 407 - err_allocate_bt: 408 - rfkill_unregister(wifi_rfkill); 409 - 410 - err_wifi: 411 - rfkill_destroy(wifi_rfkill); 412 - 413 - return ret; 414 - } 415 - 416 - /* Backlight device stuff */ 417 - 418 - static int bl_get_brightness(struct backlight_device *b) 419 - { 420 - return get_lcd_level(); 421 } 422 423 424 - static int bl_update_status(struct backlight_device *b) 425 - { 426 - return set_lcd_level(b->props.brightness); 427 - } 428 429 - static struct backlight_ops compalbl_ops = { 430 - .get_brightness = bl_get_brightness, 431 - .update_status = bl_update_status, 432 }; 433 434 static struct backlight_device *compalbl_device; 435 436 437 - static struct platform_driver compal_driver = { 438 - .driver = { 439 - .name = "compal-laptop", 440 - .owner = THIS_MODULE, 441 - } 442 - }; 443 444 - /* Initialization */ 445 446 static int dmi_check_cb(const struct dmi_system_id *id) 447 { 448 - printk(KERN_INFO "compal-laptop: Identified laptop model '%s'.\n", 449 id->ident); 450 451 return 0; 452 } 453 ··· 856 }, 857 .callback = dmi_check_cb 858 }, 859 - 860 { } 861 }; 862 863 static int __init compal_init(void) 864 { 865 int ret; 866 867 - if (acpi_disabled) 868 return -ENODEV; 869 870 - if (!force && !dmi_check_system(compal_dmi_table)) 871 return -ENODEV; 872 - 873 - /* Register backlight stuff */ 874 875 if (!acpi_video_backlight_support()) { 876 struct backlight_properties props; 877 memset(&props, 0, sizeof(struct backlight_properties)); 878 - props.max_brightness = COMPAL_LCD_LEVEL_MAX - 1; 879 - compalbl_device = backlight_device_register("compal-laptop", 880 NULL, NULL, 881 &compalbl_ops, 882 &props); ··· 965 966 ret = platform_driver_register(&compal_driver); 967 if (ret) 968 - goto fail_backlight; 969 970 - /* Register platform stuff */ 971 - 972 - compal_device = platform_device_alloc("compal-laptop", -1); 973 if (!compal_device) { 974 ret = -ENOMEM; 975 - goto fail_platform_driver; 976 } 977 978 - ret = platform_device_add(compal_device); 979 if (ret) 980 - goto fail_platform_device; 981 982 ret = setup_rfkill(); 983 if (ret) 984 - goto fail_rfkill; 985 986 - printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION 987 - " successfully loaded.\n"); 988 - 989 return 0; 990 991 - fail_rfkill: 992 platform_device_del(compal_device); 993 994 - fail_platform_device: 995 - 996 platform_device_put(compal_device); 997 998 - fail_platform_driver: 999 - 1000 platform_driver_unregister(&compal_driver); 1001 1002 - fail_backlight: 1003 - 1004 backlight_device_unregister(compalbl_device); 1005 1006 return ret; 1007 } 1008 1009 static void __exit compal_cleanup(void) 1010 { 1011 - 1012 platform_device_unregister(compal_device); 1013 platform_driver_unregister(&compal_driver); 1014 backlight_device_unregister(compalbl_device); 1015 rfkill_unregister(wifi_rfkill); 1016 - rfkill_destroy(wifi_rfkill); 1017 rfkill_unregister(bt_rfkill); 1018 rfkill_destroy(bt_rfkill); 1019 1020 - printk(KERN_INFO "compal-laptop: driver unloaded.\n"); 1021 } 1022 1023 module_init(compal_init); 1024 module_exit(compal_cleanup); 1025 1026 MODULE_AUTHOR("Cezary Jackiewicz"); 1027 MODULE_DESCRIPTION("Compal Laptop Support"); 1028 - MODULE_VERSION(COMPAL_DRIVER_VERSION); 1029 MODULE_LICENSE("GPL"); 1030 1031 MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*"); ··· 1088 MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); 1089 MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); 1090 MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); 1091 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*"); 1092 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*"); 1093 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
··· 24 */ 25 26 /* 27 + * compal-laptop.c - Compal laptop support. 28 * 29 + * This driver exports a few files in /sys/devices/platform/compal-laptop/: 30 + * wake_up_XXX Whether or not we listen to such wake up events (rw) 31 + * 32 + * In addition to these platform device attributes the driver 33 + * registers itself in the Linux backlight control, power_supply, rfkill 34 + * and hwmon subsystem and is available to userspace under: 35 + * 36 + * /sys/class/backlight/compal-laptop/ 37 + * /sys/class/power_supply/compal-laptop/ 38 + * /sys/class/rfkill/rfkillX/ 39 + * /sys/class/hwmon/hwmonX/ 40 + * 41 + * Notes on the power_supply battery interface: 42 + * - the "minimum" design voltage is *the* design voltage 43 + * - the ambient temperature is the average battery temperature 44 + * and the value is an educated guess (see commented code below) 45 + * 46 * 47 * This driver might work on other laptops produced by Compal. If you 48 * want to try it you can pass force=1 as argument to the module which 49 * will force it to load even when the DMI data doesn't identify the 50 + * laptop as compatible. 51 + * 52 + * Lots of data available at: 53 + * http://service1.marasst.com/Compal/JHL90_91/Service%20Manual/ 54 + * JHL90%20service%20manual-Final-0725.pdf 55 + * 56 + * 57 + * 58 + * Support for the Compal JHL90 added by Roald Frederickx 59 + * (roald.frederickx@gmail.com): 60 + * Driver got large revision. Added functionalities: backlight 61 + * power, wake_on_XXX, a hwmon and power_supply interface. 62 + * 63 + * In case this gets merged into the kernel source: I want to dedicate this 64 + * to Kasper Meerts, the awesome guy who showed me Linux and C! 65 */ 66 + 67 + /* NOTE: currently the wake_on_XXX, hwmon and power_supply interfaces are 68 + * only enabled on a JHL90 board until it is verified that they work on the 69 + * other boards too. See the extra_features variable. */ 70 71 #include <linux/module.h> 72 #include <linux/kernel.h> ··· 43 #include <linux/backlight.h> 44 #include <linux/platform_device.h> 45 #include <linux/rfkill.h> 46 + #include <linux/hwmon.h> 47 + #include <linux/hwmon-sysfs.h> 48 + #include <linux/power_supply.h> 49 + #include <linux/fb.h> 50 51 52 + /* ======= */ 53 + /* Defines */ 54 + /* ======= */ 55 + #define DRIVER_NAME "compal-laptop" 56 + #define DRIVER_VERSION "0.2.7" 57 58 + #define BACKLIGHT_LEVEL_ADDR 0xB9 59 + #define BACKLIGHT_LEVEL_MAX 7 60 + #define BACKLIGHT_STATE_ADDR 0x59 61 + #define BACKLIGHT_STATE_ON_DATA 0xE1 62 + #define BACKLIGHT_STATE_OFF_DATA 0xE2 63 64 + #define WAKE_UP_ADDR 0xA4 65 + #define WAKE_UP_PME (1 << 0) 66 + #define WAKE_UP_MODEM (1 << 1) 67 + #define WAKE_UP_LAN (1 << 2) 68 + #define WAKE_UP_WLAN (1 << 4) 69 + #define WAKE_UP_KEY (1 << 6) 70 + #define WAKE_UP_MOUSE (1 << 7) 71 72 + #define WIRELESS_ADDR 0xBB 73 + #define WIRELESS_WLAN (1 << 0) 74 + #define WIRELESS_BT (1 << 1) 75 + #define WIRELESS_WLAN_EXISTS (1 << 2) 76 + #define WIRELESS_BT_EXISTS (1 << 3) 77 + #define WIRELESS_KILLSWITCH (1 << 4) 78 79 + #define PWM_ADDRESS 0x46 80 + #define PWM_DISABLE_ADDR 0x59 81 + #define PWM_DISABLE_DATA 0xA5 82 + #define PWM_ENABLE_ADDR 0x59 83 + #define PWM_ENABLE_DATA 0xA8 84 + 85 + #define FAN_ADDRESS 0x46 86 + #define FAN_DATA 0x81 87 + #define FAN_FULL_ON_CMD 0x59 /* Doesn't seem to work. Just */ 88 + #define FAN_FULL_ON_ENABLE 0x76 /* force the pwm signal to its */ 89 + #define FAN_FULL_ON_DISABLE 0x77 /* maximum value instead */ 90 + 91 + #define TEMP_CPU 0xB0 92 + #define TEMP_CPU_LOCAL 0xB1 93 + #define TEMP_CPU_DTS 0xB5 94 + #define TEMP_NORTHBRIDGE 0xB6 95 + #define TEMP_VGA 0xB4 96 + #define TEMP_SKIN 0xB2 97 + 98 + #define BAT_MANUFACTURER_NAME_ADDR 0x10 99 + #define BAT_MANUFACTURER_NAME_LEN 9 100 + #define BAT_MODEL_NAME_ADDR 0x19 101 + #define BAT_MODEL_NAME_LEN 6 102 + #define BAT_SERIAL_NUMBER_ADDR 0xC4 103 + #define BAT_SERIAL_NUMBER_LEN 5 104 + #define BAT_CHARGE_NOW 0xC2 105 + #define BAT_CHARGE_DESIGN 0xCA 106 + #define BAT_VOLTAGE_NOW 0xC6 107 + #define BAT_VOLTAGE_DESIGN 0xC8 108 + #define BAT_CURRENT_NOW 0xD0 109 + #define BAT_CURRENT_AVG 0xD2 110 + #define BAT_POWER 0xD4 111 + #define BAT_CAPACITY 0xCE 112 + #define BAT_TEMP 0xD6 113 + #define BAT_TEMP_AVG 0xD7 114 + #define BAT_STATUS0 0xC1 115 + #define BAT_STATUS1 0xF0 116 + #define BAT_STATUS2 0xF1 117 + #define BAT_STOP_CHARGE1 0xF2 118 + #define BAT_STOP_CHARGE2 0xF3 119 + 120 + #define BAT_S0_DISCHARGE (1 << 0) 121 + #define BAT_S0_DISCHRG_CRITICAL (1 << 2) 122 + #define BAT_S0_LOW (1 << 3) 123 + #define BAT_S0_CHARGING (1 << 1) 124 + #define BAT_S0_AC (1 << 7) 125 + #define BAT_S1_EXISTS (1 << 0) 126 + #define BAT_S1_FULL (1 << 1) 127 + #define BAT_S1_EMPTY (1 << 2) 128 + #define BAT_S1_LiION_OR_NiMH (1 << 7) 129 + #define BAT_S2_LOW_LOW (1 << 0) 130 + #define BAT_STOP_CHRG1_BAD_CELL (1 << 1) 131 + #define BAT_STOP_CHRG1_COMM_FAIL (1 << 2) 132 + #define BAT_STOP_CHRG1_OVERVOLTAGE (1 << 6) 133 + #define BAT_STOP_CHRG1_OVERTEMPERATURE (1 << 7) 134 + 135 + 136 + /* ======= */ 137 + /* Structs */ 138 + /* ======= */ 139 + struct compal_data{ 140 + /* Fan control */ 141 + struct device *hwmon_dev; 142 + int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */ 143 + unsigned char curr_pwm; 144 + 145 + /* Power supply */ 146 + struct power_supply psy; 147 + struct power_supply_info psy_info; 148 + char bat_model_name[BAT_MODEL_NAME_LEN + 1]; 149 + char bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN + 1]; 150 + char bat_serial_number[BAT_SERIAL_NUMBER_LEN + 1]; 151 + }; 152 + 153 + 154 + /* =============== */ 155 + /* General globals */ 156 + /* =============== */ 157 static int force; 158 module_param(force, bool, 0); 159 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 160 161 + /* Support for the wake_on_XXX, hwmon and power_supply interface. Currently 162 + * only gets enabled on a JHL90 board. Might work with the others too */ 163 + static bool extra_features; 164 165 + /* Nasty stuff. For some reason the fan control is very un-linear. I've 166 + * come up with these values by looping through the possible inputs and 167 + * watching the output of address 0x4F (do an ec_transaction writing 0x33 168 + * into 0x4F and read a few bytes from the output, like so: 169 + * u8 writeData = 0x33; 170 + * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); 171 + * That address is labled "fan1 table information" in the service manual. 172 + * It should be clear which value in 'buffer' changes). This seems to be 173 + * related to fan speed. It isn't a proper 'realtime' fan speed value 174 + * though, because physically stopping or speeding up the fan doesn't 175 + * change it. It might be the average voltage or current of the pwm output. 176 + * Nevertheless, it is more fine-grained than the actual RPM reading */ 177 + static const unsigned char pwm_lookup_table[256] = { 178 + 0, 0, 0, 1, 1, 1, 2, 253, 254, 3, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 179 + 7, 7, 7, 8, 86, 86, 9, 9, 9, 10, 10, 10, 11, 92, 92, 12, 12, 95, 180 + 13, 66, 66, 14, 14, 98, 15, 15, 15, 16, 16, 67, 17, 17, 72, 18, 70, 181 + 75, 19, 90, 90, 73, 73, 73, 21, 21, 91, 91, 91, 96, 23, 94, 94, 94, 182 + 94, 94, 94, 94, 94, 94, 94, 141, 141, 238, 223, 192, 139, 139, 139, 183 + 139, 139, 142, 142, 142, 142, 142, 78, 78, 78, 78, 78, 76, 76, 76, 184 + 76, 76, 79, 79, 79, 79, 79, 79, 79, 20, 20, 20, 20, 20, 22, 22, 22, 185 + 22, 22, 24, 24, 24, 24, 24, 24, 219, 219, 219, 219, 219, 219, 219, 186 + 219, 27, 27, 188, 188, 28, 28, 28, 29, 186, 186, 186, 186, 186, 187 + 186, 186, 186, 186, 186, 31, 31, 31, 31, 31, 32, 32, 32, 41, 33, 188 + 33, 33, 33, 33, 252, 252, 34, 34, 34, 43, 35, 35, 35, 36, 36, 38, 189 + 206, 206, 206, 206, 206, 206, 206, 206, 206, 37, 37, 37, 46, 46, 190 + 47, 47, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 48, 48, 191 + 48, 48, 48, 40, 40, 40, 49, 42, 42, 42, 42, 42, 42, 42, 42, 44, 192 + 189, 189, 189, 189, 54, 54, 45, 45, 45, 45, 45, 45, 45, 45, 251, 193 + 191, 199, 199, 199, 199, 199, 215, 215, 215, 215, 187, 187, 187, 194 + 187, 187, 193, 50 195 + }; 196 + 197 + 198 + 199 + 200 + /* ========================= */ 201 + /* Hardware access functions */ 202 + /* ========================= */ 203 + /* General access */ 204 + static u8 ec_read_u8(u8 addr) 205 { 206 + u8 value; 207 + ec_read(addr, &value); 208 + return value; 209 + } 210 + 211 + static s8 ec_read_s8(u8 addr) 212 + { 213 + return (s8)ec_read_u8(addr); 214 + } 215 + 216 + static u16 ec_read_u16(u8 addr) 217 + { 218 + int hi, lo; 219 + lo = ec_read_u8(addr); 220 + hi = ec_read_u8(addr + 1); 221 + return (hi << 8) + lo; 222 + } 223 + 224 + static s16 ec_read_s16(u8 addr) 225 + { 226 + return (s16) ec_read_u16(addr); 227 + } 228 + 229 + static void ec_read_sequence(u8 addr, u8 *buf, int len) 230 + { 231 + int i; 232 + for (i = 0; i < len; i++) 233 + ec_read(addr + i, buf + i); 234 + } 235 + 236 + 237 + /* Backlight access */ 238 + static int set_backlight_level(int level) 239 + { 240 + if (level < 0 || level > BACKLIGHT_LEVEL_MAX) 241 return -EINVAL; 242 243 + ec_write(BACKLIGHT_LEVEL_ADDR, level); 244 245 + return 1; 246 + } 247 + 248 + static int get_backlight_level(void) 249 + { 250 + return (int) ec_read_u8(BACKLIGHT_LEVEL_ADDR); 251 + } 252 + 253 + static void set_backlight_state(bool on) 254 + { 255 + u8 data = on ? BACKLIGHT_STATE_ON_DATA : BACKLIGHT_STATE_OFF_DATA; 256 + ec_transaction(BACKLIGHT_STATE_ADDR, &data, 1, NULL, 0, 0); 257 + } 258 + 259 + 260 + /* Fan control access */ 261 + static void pwm_enable_control(void) 262 + { 263 + unsigned char writeData = PWM_ENABLE_DATA; 264 + ec_transaction(PWM_ENABLE_ADDR, &writeData, 1, NULL, 0, 0); 265 + } 266 + 267 + static void pwm_disable_control(void) 268 + { 269 + unsigned char writeData = PWM_DISABLE_DATA; 270 + ec_transaction(PWM_DISABLE_ADDR, &writeData, 1, NULL, 0, 0); 271 + } 272 + 273 + static void set_pwm(int pwm) 274 + { 275 + ec_transaction(PWM_ADDRESS, &pwm_lookup_table[pwm], 1, NULL, 0, 0); 276 + } 277 + 278 + static int get_fan_rpm(void) 279 + { 280 + u8 value, data = FAN_DATA; 281 + ec_transaction(FAN_ADDRESS, &data, 1, &value, 1, 0); 282 + return 100 * (int)value; 283 + } 284 + 285 + 286 + 287 + 288 + /* =================== */ 289 + /* Interface functions */ 290 + /* =================== */ 291 + 292 + /* Backlight interface */ 293 + static int bl_get_brightness(struct backlight_device *b) 294 + { 295 + return get_backlight_level(); 296 + } 297 + 298 + static int bl_update_status(struct backlight_device *b) 299 + { 300 + int ret = set_backlight_level(b->props.brightness); 301 + if (ret) 302 + return ret; 303 + 304 + set_backlight_state((b->props.power == FB_BLANK_UNBLANK) 305 + && !(b->props.state & BL_CORE_SUSPENDED) 306 + && !(b->props.state & BL_CORE_FBBLANK)); 307 return 0; 308 } 309 310 + static const struct backlight_ops compalbl_ops = { 311 + .get_brightness = bl_get_brightness, 312 + .update_status = bl_update_status, 313 + }; 314 315 316 + /* Wireless interface */ 317 static int compal_rfkill_set(void *data, bool blocked) 318 { 319 unsigned long radio = (unsigned long) data; 320 + u8 result = ec_read_u8(WIRELESS_ADDR); 321 + u8 value; 322 323 if (!blocked) 324 value = (u8) (result | radio); 325 else 326 value = (u8) (result & ~radio); 327 + ec_write(WIRELESS_ADDR, value); 328 329 return 0; 330 } 331 332 static void compal_rfkill_poll(struct rfkill *rfkill, void *data) 333 { 334 + u8 result = ec_read_u8(WIRELESS_ADDR); 335 + bool hw_blocked = !(result & WIRELESS_KILLSWITCH); 336 rfkill_set_hw_state(rfkill, hw_blocked); 337 } 338 ··· 116 .set_block = compal_rfkill_set, 117 }; 118 119 + 120 + /* Wake_up interface */ 121 + #define SIMPLE_MASKED_STORE_SHOW(NAME, ADDR, MASK) \ 122 + static ssize_t NAME##_show(struct device *dev, \ 123 + struct device_attribute *attr, char *buf) \ 124 + { \ 125 + return sprintf(buf, "%d\n", ((ec_read_u8(ADDR) & MASK) != 0)); \ 126 + } \ 127 + static ssize_t NAME##_store(struct device *dev, \ 128 + struct device_attribute *attr, const char *buf, size_t count) \ 129 + { \ 130 + int state; \ 131 + u8 old_val = ec_read_u8(ADDR); \ 132 + if (sscanf(buf, "%d", &state) != 1 || (state < 0 || state > 1)) \ 133 + return -EINVAL; \ 134 + ec_write(ADDR, state ? (old_val | MASK) : (old_val & ~MASK)); \ 135 + return count; \ 136 + } 137 + 138 + SIMPLE_MASKED_STORE_SHOW(wake_up_pme, WAKE_UP_ADDR, WAKE_UP_PME) 139 + SIMPLE_MASKED_STORE_SHOW(wake_up_modem, WAKE_UP_ADDR, WAKE_UP_MODEM) 140 + SIMPLE_MASKED_STORE_SHOW(wake_up_lan, WAKE_UP_ADDR, WAKE_UP_LAN) 141 + SIMPLE_MASKED_STORE_SHOW(wake_up_wlan, WAKE_UP_ADDR, WAKE_UP_WLAN) 142 + SIMPLE_MASKED_STORE_SHOW(wake_up_key, WAKE_UP_ADDR, WAKE_UP_KEY) 143 + SIMPLE_MASKED_STORE_SHOW(wake_up_mouse, WAKE_UP_ADDR, WAKE_UP_MOUSE) 144 + 145 + 146 + /* General hwmon interface */ 147 + static ssize_t hwmon_name_show(struct device *dev, 148 + struct device_attribute *attr, char *buf) 149 { 150 + return sprintf(buf, "%s\n", DRIVER_NAME); 151 + } 152 153 154 + /* Fan control interface */ 155 + static ssize_t pwm_enable_show(struct device *dev, 156 + struct device_attribute *attr, char *buf) 157 + { 158 + struct compal_data *data = dev_get_drvdata(dev); 159 + return sprintf(buf, "%d\n", data->pwm_enable); 160 + } 161 162 + static ssize_t pwm_enable_store(struct device *dev, 163 + struct device_attribute *attr, const char *buf, size_t count) 164 + { 165 + struct compal_data *data = dev_get_drvdata(dev); 166 + long val; 167 + int err; 168 + err = strict_strtol(buf, 10, &val); 169 + if (err) 170 + return err; 171 + if (val < 0) 172 + return -EINVAL; 173 + 174 + data->pwm_enable = val; 175 + 176 + switch (val) { 177 + case 0: /* Full speed */ 178 + pwm_enable_control(); 179 + set_pwm(255); 180 + break; 181 + case 1: /* As set by pwm1 */ 182 + pwm_enable_control(); 183 + set_pwm(data->curr_pwm); 184 + break; 185 + default: /* Control by motherboard */ 186 + pwm_disable_control(); 187 + break; 188 } 189 190 + return count; 191 + } 192 + 193 + static ssize_t pwm_show(struct device *dev, struct device_attribute *attr, 194 + char *buf) 195 + { 196 + struct compal_data *data = dev_get_drvdata(dev); 197 + return sprintf(buf, "%hhu\n", data->curr_pwm); 198 + } 199 + 200 + static ssize_t pwm_store(struct device *dev, struct device_attribute *attr, 201 + const char *buf, size_t count) 202 + { 203 + struct compal_data *data = dev_get_drvdata(dev); 204 + long val; 205 + int err; 206 + err = strict_strtol(buf, 10, &val); 207 + if (err) 208 + return err; 209 + if (val < 0 || val > 255) 210 + return -EINVAL; 211 + 212 + data->curr_pwm = val; 213 + 214 + if (data->pwm_enable != 1) 215 + return count; 216 + set_pwm(val); 217 + 218 + return count; 219 + } 220 + 221 + static ssize_t fan_show(struct device *dev, struct device_attribute *attr, 222 + char *buf) 223 + { 224 + return sprintf(buf, "%d\n", get_fan_rpm()); 225 + } 226 + 227 + 228 + /* Temperature interface */ 229 + #define TEMPERATURE_SHOW_TEMP_AND_LABEL(POSTFIX, ADDRESS, LABEL) \ 230 + static ssize_t temp_##POSTFIX(struct device *dev, \ 231 + struct device_attribute *attr, char *buf) \ 232 + { \ 233 + return sprintf(buf, "%d\n", 1000 * (int)ec_read_s8(ADDRESS)); \ 234 + } \ 235 + static ssize_t label_##POSTFIX(struct device *dev, \ 236 + struct device_attribute *attr, char *buf) \ 237 + { \ 238 + return sprintf(buf, "%s\n", LABEL); \ 239 + } 240 + 241 + /* Labels as in service guide */ 242 + TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu, TEMP_CPU, "CPU_TEMP"); 243 + TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_local, TEMP_CPU_LOCAL, "CPU_TEMP_LOCAL"); 244 + TEMPERATURE_SHOW_TEMP_AND_LABEL(cpu_DTS, TEMP_CPU_DTS, "CPU_DTS"); 245 + TEMPERATURE_SHOW_TEMP_AND_LABEL(northbridge,TEMP_NORTHBRIDGE,"NorthBridge"); 246 + TEMPERATURE_SHOW_TEMP_AND_LABEL(vga, TEMP_VGA, "VGA_TEMP"); 247 + TEMPERATURE_SHOW_TEMP_AND_LABEL(SKIN, TEMP_SKIN, "SKIN_TEMP90"); 248 + 249 + 250 + /* Power supply interface */ 251 + static int bat_status(void) 252 + { 253 + u8 status0 = ec_read_u8(BAT_STATUS0); 254 + u8 status1 = ec_read_u8(BAT_STATUS1); 255 + 256 + if (status0 & BAT_S0_CHARGING) 257 + return POWER_SUPPLY_STATUS_CHARGING; 258 + if (status0 & BAT_S0_DISCHARGE) 259 + return POWER_SUPPLY_STATUS_DISCHARGING; 260 + if (status1 & BAT_S1_FULL) 261 + return POWER_SUPPLY_STATUS_FULL; 262 + return POWER_SUPPLY_STATUS_NOT_CHARGING; 263 + } 264 + 265 + static int bat_health(void) 266 + { 267 + u8 status = ec_read_u8(BAT_STOP_CHARGE1); 268 + 269 + if (status & BAT_STOP_CHRG1_OVERTEMPERATURE) 270 + return POWER_SUPPLY_HEALTH_OVERHEAT; 271 + if (status & BAT_STOP_CHRG1_OVERVOLTAGE) 272 + return POWER_SUPPLY_HEALTH_OVERVOLTAGE; 273 + if (status & BAT_STOP_CHRG1_BAD_CELL) 274 + return POWER_SUPPLY_HEALTH_DEAD; 275 + if (status & BAT_STOP_CHRG1_COMM_FAIL) 276 + return POWER_SUPPLY_HEALTH_UNKNOWN; 277 + return POWER_SUPPLY_HEALTH_GOOD; 278 + } 279 + 280 + static int bat_is_present(void) 281 + { 282 + u8 status = ec_read_u8(BAT_STATUS2); 283 + return ((status & BAT_S1_EXISTS) != 0); 284 + } 285 + 286 + static int bat_technology(void) 287 + { 288 + u8 status = ec_read_u8(BAT_STATUS1); 289 + 290 + if (status & BAT_S1_LiION_OR_NiMH) 291 + return POWER_SUPPLY_TECHNOLOGY_LION; 292 + return POWER_SUPPLY_TECHNOLOGY_NiMH; 293 + } 294 + 295 + static int bat_capacity_level(void) 296 + { 297 + u8 status0 = ec_read_u8(BAT_STATUS0); 298 + u8 status1 = ec_read_u8(BAT_STATUS1); 299 + u8 status2 = ec_read_u8(BAT_STATUS2); 300 + 301 + if (status0 & BAT_S0_DISCHRG_CRITICAL 302 + || status1 & BAT_S1_EMPTY 303 + || status2 & BAT_S2_LOW_LOW) 304 + return POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 305 + if (status0 & BAT_S0_LOW) 306 + return POWER_SUPPLY_CAPACITY_LEVEL_LOW; 307 + if (status1 & BAT_S1_FULL) 308 + return POWER_SUPPLY_CAPACITY_LEVEL_FULL; 309 + return POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 310 + } 311 + 312 + static int bat_get_property(struct power_supply *psy, 313 + enum power_supply_property psp, 314 + union power_supply_propval *val) 315 + { 316 + struct compal_data *data; 317 + data = container_of(psy, struct compal_data, psy); 318 + 319 + switch (psp) { 320 + case POWER_SUPPLY_PROP_STATUS: 321 + val->intval = bat_status(); 322 + break; 323 + case POWER_SUPPLY_PROP_HEALTH: 324 + val->intval = bat_health(); 325 + break; 326 + case POWER_SUPPLY_PROP_PRESENT: 327 + val->intval = bat_is_present(); 328 + break; 329 + case POWER_SUPPLY_PROP_TECHNOLOGY: 330 + val->intval = bat_technology(); 331 + break; 332 + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: /* THE design voltage... */ 333 + val->intval = ec_read_u16(BAT_VOLTAGE_DESIGN) * 1000; 334 + break; 335 + case POWER_SUPPLY_PROP_VOLTAGE_NOW: 336 + val->intval = ec_read_u16(BAT_VOLTAGE_NOW) * 1000; 337 + break; 338 + case POWER_SUPPLY_PROP_CURRENT_NOW: 339 + val->intval = ec_read_s16(BAT_CURRENT_NOW) * 1000; 340 + break; 341 + case POWER_SUPPLY_PROP_CURRENT_AVG: 342 + val->intval = ec_read_s16(BAT_CURRENT_AVG) * 1000; 343 + break; 344 + case POWER_SUPPLY_PROP_POWER_NOW: 345 + val->intval = ec_read_u8(BAT_POWER) * 1000000; 346 + break; 347 + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 348 + val->intval = ec_read_u16(BAT_CHARGE_DESIGN) * 1000; 349 + break; 350 + case POWER_SUPPLY_PROP_CHARGE_NOW: 351 + val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000; 352 + break; 353 + case POWER_SUPPLY_PROP_CAPACITY: 354 + val->intval = ec_read_u8(BAT_CAPACITY); 355 + break; 356 + case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 357 + val->intval = bat_capacity_level(); 358 + break; 359 + /* It smees that BAT_TEMP_AVG is a (2's complement?) value showing 360 + * the number of degrees, whereas BAT_TEMP is somewhat more 361 + * complicated. It looks like this is a negative nember with a 362 + * 100/256 divider and an offset of 222. Both were determined 363 + * experimentally by comparing BAT_TEMP and BAT_TEMP_AVG. */ 364 + case POWER_SUPPLY_PROP_TEMP: 365 + val->intval = ((222 - (int)ec_read_u8(BAT_TEMP)) * 1000) >> 8; 366 + break; 367 + case POWER_SUPPLY_PROP_TEMP_AMBIENT: /* Ambient, Avg, ... same thing */ 368 + val->intval = ec_read_s8(BAT_TEMP_AVG) * 10; 369 + break; 370 + /* Neither the model name nor manufacturer name work for me. */ 371 + case POWER_SUPPLY_PROP_MODEL_NAME: 372 + val->strval = data->bat_model_name; 373 + break; 374 + case POWER_SUPPLY_PROP_MANUFACTURER: 375 + val->strval = data->bat_manufacturer_name; 376 + break; 377 + case POWER_SUPPLY_PROP_SERIAL_NUMBER: 378 + val->strval = data->bat_serial_number; 379 + break; 380 + default: 381 + break; 382 + } 383 return 0; 384 } 385 386 387 388 + 389 + 390 + /* ============== */ 391 + /* Driver Globals */ 392 + /* ============== */ 393 + static DEVICE_ATTR(wake_up_pme, 394 + 0644, wake_up_pme_show, wake_up_pme_store); 395 + static DEVICE_ATTR(wake_up_modem, 396 + 0644, wake_up_modem_show, wake_up_modem_store); 397 + static DEVICE_ATTR(wake_up_lan, 398 + 0644, wake_up_lan_show, wake_up_lan_store); 399 + static DEVICE_ATTR(wake_up_wlan, 400 + 0644, wake_up_wlan_show, wake_up_wlan_store); 401 + static DEVICE_ATTR(wake_up_key, 402 + 0644, wake_up_key_show, wake_up_key_store); 403 + static DEVICE_ATTR(wake_up_mouse, 404 + 0644, wake_up_mouse_show, wake_up_mouse_store); 405 + 406 + static SENSOR_DEVICE_ATTR(name, S_IRUGO, hwmon_name_show, NULL, 1); 407 + static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, fan_show, NULL, 1); 408 + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu, NULL, 1); 409 + static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local, NULL, 1); 410 + static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS, NULL, 1); 411 + static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge, NULL, 1); 412 + static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga, NULL, 1); 413 + static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN, NULL, 1); 414 + static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu, NULL, 1); 415 + static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local, NULL, 1); 416 + static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS, NULL, 1); 417 + static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1); 418 + static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga, NULL, 1); 419 + static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN, NULL, 1); 420 + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1); 421 + static SENSOR_DEVICE_ATTR(pwm1_enable, 422 + S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0); 423 + 424 + static struct attribute *compal_attributes[] = { 425 + &dev_attr_wake_up_pme.attr, 426 + &dev_attr_wake_up_modem.attr, 427 + &dev_attr_wake_up_lan.attr, 428 + &dev_attr_wake_up_wlan.attr, 429 + &dev_attr_wake_up_key.attr, 430 + &dev_attr_wake_up_mouse.attr, 431 + /* Maybe put the sensor-stuff in a separate hwmon-driver? That way, 432 + * the hwmon sysfs won't be cluttered with the above files. */ 433 + &sensor_dev_attr_name.dev_attr.attr, 434 + &sensor_dev_attr_pwm1_enable.dev_attr.attr, 435 + &sensor_dev_attr_pwm1.dev_attr.attr, 436 + &sensor_dev_attr_fan1_input.dev_attr.attr, 437 + &sensor_dev_attr_temp1_input.dev_attr.attr, 438 + &sensor_dev_attr_temp2_input.dev_attr.attr, 439 + &sensor_dev_attr_temp3_input.dev_attr.attr, 440 + &sensor_dev_attr_temp4_input.dev_attr.attr, 441 + &sensor_dev_attr_temp5_input.dev_attr.attr, 442 + &sensor_dev_attr_temp6_input.dev_attr.attr, 443 + &sensor_dev_attr_temp1_label.dev_attr.attr, 444 + &sensor_dev_attr_temp2_label.dev_attr.attr, 445 + &sensor_dev_attr_temp3_label.dev_attr.attr, 446 + &sensor_dev_attr_temp4_label.dev_attr.attr, 447 + &sensor_dev_attr_temp5_label.dev_attr.attr, 448 + &sensor_dev_attr_temp6_label.dev_attr.attr, 449 + NULL 450 + }; 451 + 452 + static struct attribute_group compal_attribute_group = { 453 + .attrs = compal_attributes 454 + }; 455 + 456 + static int __devinit compal_probe(struct platform_device *); 457 + static int __devexit compal_remove(struct platform_device *); 458 + static struct platform_driver compal_driver = { 459 + .driver = { 460 + .name = DRIVER_NAME, 461 + .owner = THIS_MODULE, 462 + }, 463 + .probe = compal_probe, 464 + .remove = __devexit_p(compal_remove) 465 + }; 466 + 467 + static enum power_supply_property compal_bat_properties[] = { 468 + POWER_SUPPLY_PROP_STATUS, 469 + POWER_SUPPLY_PROP_HEALTH, 470 + POWER_SUPPLY_PROP_PRESENT, 471 + POWER_SUPPLY_PROP_TECHNOLOGY, 472 + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, 473 + POWER_SUPPLY_PROP_VOLTAGE_NOW, 474 + POWER_SUPPLY_PROP_CURRENT_NOW, 475 + POWER_SUPPLY_PROP_CURRENT_AVG, 476 + POWER_SUPPLY_PROP_POWER_NOW, 477 + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 478 + POWER_SUPPLY_PROP_CHARGE_NOW, 479 + POWER_SUPPLY_PROP_CAPACITY, 480 + POWER_SUPPLY_PROP_CAPACITY_LEVEL, 481 + POWER_SUPPLY_PROP_TEMP, 482 + POWER_SUPPLY_PROP_TEMP_AMBIENT, 483 + POWER_SUPPLY_PROP_MODEL_NAME, 484 + POWER_SUPPLY_PROP_MANUFACTURER, 485 + POWER_SUPPLY_PROP_SERIAL_NUMBER, 486 }; 487 488 static struct backlight_device *compalbl_device; 489 490 + static struct platform_device *compal_device; 491 492 + static struct rfkill *wifi_rfkill; 493 + static struct rfkill *bt_rfkill; 494 495 + 496 + 497 + 498 + 499 + /* =================================== */ 500 + /* Initialization & clean-up functions */ 501 + /* =================================== */ 502 503 static int dmi_check_cb(const struct dmi_system_id *id) 504 { 505 + printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", 506 id->ident); 507 + extra_features = false; 508 + return 0; 509 + } 510 511 + static int dmi_check_cb_extra(const struct dmi_system_id *id) 512 + { 513 + printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s', " 514 + "enabling extra features\n", 515 + id->ident); 516 + extra_features = true; 517 return 0; 518 } 519 ··· 274 }, 275 .callback = dmi_check_cb 276 }, 277 + { 278 + .ident = "JHL90", 279 + .matches = { 280 + DMI_MATCH(DMI_BOARD_NAME, "JHL90"), 281 + DMI_MATCH(DMI_BOARD_VERSION, "REFERENCE"), 282 + }, 283 + .callback = dmi_check_cb_extra 284 + }, 285 { } 286 }; 287 + 288 + static void initialize_power_supply_data(struct compal_data *data) 289 + { 290 + data->psy.name = DRIVER_NAME; 291 + data->psy.type = POWER_SUPPLY_TYPE_BATTERY; 292 + data->psy.properties = compal_bat_properties; 293 + data->psy.num_properties = ARRAY_SIZE(compal_bat_properties); 294 + data->psy.get_property = bat_get_property; 295 + 296 + ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR, 297 + data->bat_manufacturer_name, 298 + BAT_MANUFACTURER_NAME_LEN); 299 + data->bat_manufacturer_name[BAT_MANUFACTURER_NAME_LEN] = 0; 300 + 301 + ec_read_sequence(BAT_MODEL_NAME_ADDR, 302 + data->bat_model_name, 303 + BAT_MODEL_NAME_LEN); 304 + data->bat_model_name[BAT_MODEL_NAME_LEN] = 0; 305 + 306 + scnprintf(data->bat_serial_number, BAT_SERIAL_NUMBER_LEN + 1, "%d", 307 + ec_read_u16(BAT_SERIAL_NUMBER_ADDR)); 308 + } 309 + 310 + static void initialize_fan_control_data(struct compal_data *data) 311 + { 312 + data->pwm_enable = 2; /* Keep motherboard in control for now */ 313 + data->curr_pwm = 255; /* Try not to cause a CPU_on_fire exception 314 + if we take over... */ 315 + } 316 + 317 + static int setup_rfkill(void) 318 + { 319 + int ret; 320 + 321 + wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev, 322 + RFKILL_TYPE_WLAN, &compal_rfkill_ops, 323 + (void *) WIRELESS_WLAN); 324 + if (!wifi_rfkill) 325 + return -ENOMEM; 326 + 327 + ret = rfkill_register(wifi_rfkill); 328 + if (ret) 329 + goto err_wifi; 330 + 331 + bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev, 332 + RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops, 333 + (void *) WIRELESS_BT); 334 + if (!bt_rfkill) { 335 + ret = -ENOMEM; 336 + goto err_allocate_bt; 337 + } 338 + ret = rfkill_register(bt_rfkill); 339 + if (ret) 340 + goto err_register_bt; 341 + 342 + return 0; 343 + 344 + err_register_bt: 345 + rfkill_destroy(bt_rfkill); 346 + 347 + err_allocate_bt: 348 + rfkill_unregister(wifi_rfkill); 349 + 350 + err_wifi: 351 + rfkill_destroy(wifi_rfkill); 352 + 353 + return ret; 354 + } 355 356 static int __init compal_init(void) 357 { 358 int ret; 359 360 + if (acpi_disabled) { 361 + printk(KERN_ERR DRIVER_NAME": ACPI needs to be enabled for " 362 + "this driver to work!\n"); 363 return -ENODEV; 364 + } 365 366 + if (!force && !dmi_check_system(compal_dmi_table)) { 367 + printk(KERN_ERR DRIVER_NAME": Motherboard not recognized (You " 368 + "could try the module's force-parameter)"); 369 return -ENODEV; 370 + } 371 372 if (!acpi_video_backlight_support()) { 373 struct backlight_properties props; 374 memset(&props, 0, sizeof(struct backlight_properties)); 375 + props.max_brightness = BACKLIGHT_LEVEL_MAX; 376 + compalbl_device = backlight_device_register(DRIVER_NAME, 377 NULL, NULL, 378 &compalbl_ops, 379 &props); ··· 304 305 ret = platform_driver_register(&compal_driver); 306 if (ret) 307 + goto err_backlight; 308 309 + compal_device = platform_device_alloc(DRIVER_NAME, -1); 310 if (!compal_device) { 311 ret = -ENOMEM; 312 + goto err_platform_driver; 313 } 314 315 + ret = platform_device_add(compal_device); /* This calls compal_probe */ 316 if (ret) 317 + goto err_platform_device; 318 319 ret = setup_rfkill(); 320 if (ret) 321 + goto err_rfkill; 322 323 + printk(KERN_INFO DRIVER_NAME": Driver "DRIVER_VERSION 324 + " successfully loaded\n"); 325 return 0; 326 327 + err_rfkill: 328 platform_device_del(compal_device); 329 330 + err_platform_device: 331 platform_device_put(compal_device); 332 333 + err_platform_driver: 334 platform_driver_unregister(&compal_driver); 335 336 + err_backlight: 337 backlight_device_unregister(compalbl_device); 338 339 return ret; 340 } 341 342 + static int __devinit compal_probe(struct platform_device *pdev) 343 + { 344 + int err; 345 + struct compal_data *data; 346 + 347 + if (!extra_features) 348 + return 0; 349 + 350 + /* Fan control */ 351 + data = kzalloc(sizeof(struct compal_data), GFP_KERNEL); 352 + if (!data) 353 + return -ENOMEM; 354 + 355 + initialize_fan_control_data(data); 356 + 357 + err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group); 358 + if (err) 359 + return err; 360 + 361 + data->hwmon_dev = hwmon_device_register(&pdev->dev); 362 + if (IS_ERR(data->hwmon_dev)) { 363 + err = PTR_ERR(data->hwmon_dev); 364 + sysfs_remove_group(&pdev->dev.kobj, 365 + &compal_attribute_group); 366 + kfree(data); 367 + return err; 368 + } 369 + 370 + /* Power supply */ 371 + initialize_power_supply_data(data); 372 + power_supply_register(&compal_device->dev, &data->psy); 373 + 374 + platform_set_drvdata(pdev, data); 375 + 376 + return 0; 377 + } 378 + 379 static void __exit compal_cleanup(void) 380 { 381 platform_device_unregister(compal_device); 382 platform_driver_unregister(&compal_driver); 383 backlight_device_unregister(compalbl_device); 384 rfkill_unregister(wifi_rfkill); 385 rfkill_unregister(bt_rfkill); 386 + rfkill_destroy(wifi_rfkill); 387 rfkill_destroy(bt_rfkill); 388 389 + printk(KERN_INFO DRIVER_NAME": Driver unloaded\n"); 390 } 391 + 392 + static int __devexit compal_remove(struct platform_device *pdev) 393 + { 394 + struct compal_data *data; 395 + 396 + if (!extra_features) 397 + return 0; 398 + 399 + printk(KERN_INFO DRIVER_NAME": Unloading: resetting fan control " 400 + "to motherboard\n"); 401 + pwm_disable_control(); 402 + 403 + data = platform_get_drvdata(pdev); 404 + hwmon_device_unregister(data->hwmon_dev); 405 + power_supply_unregister(&data->psy); 406 + 407 + platform_set_drvdata(pdev, NULL); 408 + kfree(data); 409 + 410 + sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group); 411 + 412 + return 0; 413 + } 414 + 415 416 module_init(compal_init); 417 module_exit(compal_cleanup); 418 419 MODULE_AUTHOR("Cezary Jackiewicz"); 420 + MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)"); 421 MODULE_DESCRIPTION("Compal Laptop Support"); 422 + MODULE_VERSION(DRIVER_VERSION); 423 MODULE_LICENSE("GPL"); 424 425 MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*"); ··· 372 MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); 373 MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); 374 MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); 375 + MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*"); 376 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*"); 377 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*"); 378 MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
+8 -1
drivers/platform/x86/dell-laptop.c
··· 83 }, 84 }, 85 { 86 .ident = "Dell Computer Corporation", 87 .matches = { 88 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), ··· 473 .update_status = dell_send_intensity, 474 }; 475 476 - bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, 477 struct serio *port) 478 { 479 static bool extended; ··· 627 MODULE_DESCRIPTION("Dell laptop driver"); 628 MODULE_LICENSE("GPL"); 629 MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); 630 MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
··· 83 }, 84 }, 85 { 86 + .matches = { 87 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 88 + DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /*Laptop*/ 89 + }, 90 + }, 91 + { 92 .ident = "Dell Computer Corporation", 93 .matches = { 94 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), ··· 467 .update_status = dell_send_intensity, 468 }; 469 470 + static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, 471 struct serio *port) 472 { 473 static bool extended; ··· 621 MODULE_DESCRIPTION("Dell laptop driver"); 622 MODULE_LICENSE("GPL"); 623 MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); 624 + MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*"); 625 MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
+9 -2
drivers/platform/x86/dell-wmi.c
··· 221 return; 222 } 223 224 - if (dell_new_hk_type) 225 reported_key = (int)buffer_entry[2]; 226 else 227 reported_key = (int)buffer_entry[1] & 0xffff; ··· 339 acpi_video = acpi_video_backlight_support(); 340 341 err = dell_wmi_input_setup(); 342 - if (err) 343 return err; 344 345 status = wmi_install_notify_handler(DELL_EVENT_GUID, 346 dell_wmi_notify, NULL); 347 if (ACPI_FAILURE(status)) { 348 input_unregister_device(dell_wmi_input_dev); 349 printk(KERN_ERR 350 "dell-wmi: Unable to register notify handler - %d\n", 351 status); ··· 364 { 365 wmi_remove_notify_handler(DELL_EVENT_GUID); 366 input_unregister_device(dell_wmi_input_dev); 367 } 368 369 module_init(dell_wmi_init);
··· 221 return; 222 } 223 224 + if (dell_new_hk_type || buffer_entry[1] == 0x0) 225 reported_key = (int)buffer_entry[2]; 226 else 227 reported_key = (int)buffer_entry[1] & 0xffff; ··· 339 acpi_video = acpi_video_backlight_support(); 340 341 err = dell_wmi_input_setup(); 342 + if (err) { 343 + if (dell_new_hk_type) 344 + kfree(dell_wmi_keymap); 345 return err; 346 + } 347 348 status = wmi_install_notify_handler(DELL_EVENT_GUID, 349 dell_wmi_notify, NULL); 350 if (ACPI_FAILURE(status)) { 351 input_unregister_device(dell_wmi_input_dev); 352 + if (dell_new_hk_type) 353 + kfree(dell_wmi_keymap); 354 printk(KERN_ERR 355 "dell-wmi: Unable to register notify handler - %d\n", 356 status); ··· 359 { 360 wmi_remove_notify_handler(DELL_EVENT_GUID); 361 input_unregister_device(dell_wmi_input_dev); 362 + if (dell_new_hk_type) 363 + kfree(dell_wmi_keymap); 364 } 365 366 module_init(dell_wmi_init);
+1 -1
drivers/platform/x86/eeepc-laptop.c
··· 53 54 static bool hotplug_disabled; 55 56 - module_param(hotplug_disabled, bool, 0644); 57 MODULE_PARM_DESC(hotplug_disabled, 58 "Disable hotplug for wireless device. " 59 "If your laptop need that, please report to "
··· 53 54 static bool hotplug_disabled; 55 56 + module_param(hotplug_disabled, bool, 0444); 57 MODULE_PARM_DESC(hotplug_disabled, 58 "Disable hotplug for wireless device. " 59 "If your laptop need that, please report to "
+7 -9
drivers/platform/x86/fujitsu-laptop.c
··· 182 static void logolamp_set(struct led_classdev *cdev, 183 enum led_brightness brightness); 184 185 - struct led_classdev logolamp_led = { 186 .name = "fujitsu::logolamp", 187 .brightness_get = logolamp_get, 188 .brightness_set = logolamp_set ··· 192 static void kblamps_set(struct led_classdev *cdev, 193 enum led_brightness brightness); 194 195 - struct led_classdev kblamps_led = { 196 .name = "fujitsu::kblamps", 197 .brightness_get = kblamps_get, 198 .brightness_set = kblamps_set ··· 603 dmi_check_cb_common(id); 604 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 605 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 606 - return 0; 607 } 608 609 static int dmi_check_cb_s6420(const struct dmi_system_id *id) ··· 611 dmi_check_cb_common(id); 612 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 613 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 614 - return 0; 615 } 616 617 static int dmi_check_cb_p8010(const struct dmi_system_id *id) ··· 620 fujitsu->keycode1 = KEY_HELP; /* "Support" */ 621 fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ 622 fujitsu->keycode4 = KEY_WWW; /* "Internet" */ 623 - return 0; 624 } 625 626 static struct dmi_system_id fujitsu_dmi_table[] = { ··· 725 726 err_unregister_input_dev: 727 input_unregister_device(input); 728 err_free_input_dev: 729 input_free_device(input); 730 err_stop: ··· 738 struct input_dev *input = fujitsu->input; 739 740 input_unregister_device(input); 741 - 742 - input_free_device(input); 743 744 fujitsu->acpi_handle = NULL; 745 ··· 929 930 err_unregister_input_dev: 931 input_unregister_device(input); 932 err_free_input_dev: 933 input_free_device(input); 934 err_free_fifo: ··· 952 #endif 953 954 input_unregister_device(input); 955 - 956 - input_free_device(input); 957 958 kfifo_free(&fujitsu_hotkey->fifo); 959
··· 182 static void logolamp_set(struct led_classdev *cdev, 183 enum led_brightness brightness); 184 185 + static struct led_classdev logolamp_led = { 186 .name = "fujitsu::logolamp", 187 .brightness_get = logolamp_get, 188 .brightness_set = logolamp_set ··· 192 static void kblamps_set(struct led_classdev *cdev, 193 enum led_brightness brightness); 194 195 + static struct led_classdev kblamps_led = { 196 .name = "fujitsu::kblamps", 197 .brightness_get = kblamps_get, 198 .brightness_set = kblamps_set ··· 603 dmi_check_cb_common(id); 604 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 605 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 606 + return 1; 607 } 608 609 static int dmi_check_cb_s6420(const struct dmi_system_id *id) ··· 611 dmi_check_cb_common(id); 612 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 613 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 614 + return 1; 615 } 616 617 static int dmi_check_cb_p8010(const struct dmi_system_id *id) ··· 620 fujitsu->keycode1 = KEY_HELP; /* "Support" */ 621 fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ 622 fujitsu->keycode4 = KEY_WWW; /* "Internet" */ 623 + return 1; 624 } 625 626 static struct dmi_system_id fujitsu_dmi_table[] = { ··· 725 726 err_unregister_input_dev: 727 input_unregister_device(input); 728 + input = NULL; 729 err_free_input_dev: 730 input_free_device(input); 731 err_stop: ··· 737 struct input_dev *input = fujitsu->input; 738 739 input_unregister_device(input); 740 741 fujitsu->acpi_handle = NULL; 742 ··· 930 931 err_unregister_input_dev: 932 input_unregister_device(input); 933 + input = NULL; 934 err_free_input_dev: 935 input_free_device(input); 936 err_free_fifo: ··· 952 #endif 953 954 input_unregister_device(input); 955 956 kfifo_free(&fujitsu_hotkey->fifo); 957
+219 -62
drivers/platform/x86/hp-wmi.c
··· 29 #include <linux/slab.h> 30 #include <linux/types.h> 31 #include <linux/input.h> 32 - #include <acpi/acpi_drivers.h> 33 #include <linux/platform_device.h> 34 #include <linux/acpi.h> 35 #include <linux/rfkill.h> ··· 51 #define HPWMI_WIRELESS_QUERY 0x5 52 #define HPWMI_HOTKEY_QUERY 0xc 53 54 enum hp_wmi_radio { 55 HPWMI_WIFI = 0, 56 HPWMI_BLUETOOTH = 1, 57 HPWMI_WWAN = 2, 58 }; 59 60 static int __devinit hp_wmi_bios_setup(struct platform_device *device); ··· 79 u32 command; 80 u32 commandtype; 81 u32 datasize; 82 - u32 data; 83 }; 84 85 struct bios_return { 86 u32 sigpass; 87 u32 return_code; 88 - u32 value; 89 }; 90 91 struct key_entry { ··· 99 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 100 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, 101 {KE_KEY, 0x20e6, KEY_PROG1}, 102 {KE_KEY, 0x2142, KEY_MEDIA}, 103 {KE_KEY, 0x213b, KEY_INFO}, 104 {KE_KEY, 0x2169, KEY_DIRECTION}, ··· 129 .remove = hp_wmi_bios_remove, 130 }; 131 132 - static int hp_wmi_perform_query(int query, int write, int value) 133 { 134 struct bios_return bios_return; 135 acpi_status status; ··· 158 .signature = 0x55434553, 159 .command = write ? 0x2 : 0x1, 160 .commandtype = query, 161 - .datasize = write ? 0x4 : 0, 162 - .data = value, 163 }; 164 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 165 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; ··· 176 } 177 178 bios_return = *((struct bios_return *)obj->buffer.pointer); 179 kfree(obj); 180 - if (bios_return.return_code > 0) 181 - return bios_return.return_code * -1; 182 - else 183 - return bios_return.value; 184 } 185 186 static int hp_wmi_display_state(void) 187 { 188 - return hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, 0); 189 } 190 191 static int hp_wmi_hddtemp_state(void) 192 { 193 - return hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, 0); 194 } 195 196 static int hp_wmi_als_state(void) 197 { 198 - return hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, 0); 199 } 200 201 static int hp_wmi_dock_state(void) 202 { 203 - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); 204 205 - if (ret < 0) 206 - return ret; 207 208 - return ret & 0x1; 209 } 210 211 static int hp_wmi_tablet_state(void) 212 { 213 - int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, 0); 214 - 215 - if (ret < 0) 216 return ret; 217 218 - return (ret & 0x4) ? 1 : 0; 219 } 220 221 static int hp_wmi_set_block(void *data, bool blocked) 222 { 223 enum hp_wmi_radio r = (enum hp_wmi_radio) data; 224 int query = BIT(r + 8) | ((!blocked) << r); 225 226 - return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); 227 } 228 229 static const struct rfkill_ops hp_wmi_rfkill_ops = { ··· 268 269 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 270 { 271 - int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 272 - int mask = 0x200 << (r * 8); 273 274 if (wireless & mask) 275 return false; ··· 284 285 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 286 { 287 - int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 288 - int mask = 0x800 << (r * 8); 289 290 if (wireless & mask) 291 return false; ··· 347 const char *buf, size_t count) 348 { 349 u32 tmp = simple_strtoul(buf, NULL, 10); 350 - hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, tmp); 351 return count; 352 } 353 ··· 420 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 421 static struct key_entry *key; 422 union acpi_object *obj; 423 - int eventcode; 424 acpi_status status; 425 426 status = wmi_get_event_data(value, &response); 427 if (status != AE_OK) { 428 - printk(KERN_INFO "hp-wmi: bad event status 0x%x\n", status); 429 return; 430 } 431 432 obj = (union acpi_object *)response.pointer; 433 434 - if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) { 435 - printk(KERN_INFO "HP WMI: Unknown response received\n"); 436 kfree(obj); 437 return; 438 } 439 440 - eventcode = *((u8 *) obj->buffer.pointer); 441 kfree(obj); 442 - if (eventcode == 0x4) 443 - eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 444 - 0); 445 - key = hp_wmi_get_entry_by_scancode(eventcode); 446 - if (key) { 447 - switch (key->type) { 448 - case KE_KEY: 449 - input_report_key(hp_wmi_input_dev, 450 - key->keycode, 1); 451 - input_sync(hp_wmi_input_dev); 452 - input_report_key(hp_wmi_input_dev, 453 - key->keycode, 0); 454 - input_sync(hp_wmi_input_dev); 455 - break; 456 - } 457 - } else if (eventcode == 0x1) { 458 input_report_switch(hp_wmi_input_dev, SW_DOCK, 459 hp_wmi_dock_state()); 460 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 461 hp_wmi_tablet_state()); 462 input_sync(hp_wmi_input_dev); 463 - } else if (eventcode == 0x5) { 464 if (wifi_rfkill) 465 rfkill_set_states(wifi_rfkill, 466 hp_wmi_get_sw_state(HPWMI_WIFI), ··· 508 rfkill_set_states(wwan_rfkill, 509 hp_wmi_get_sw_state(HPWMI_WWAN), 510 hp_wmi_get_hw_state(HPWMI_WWAN)); 511 - } else 512 - printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", 513 - eventcode); 514 } 515 516 static int __init hp_wmi_input_setup(void) ··· 528 int err; 529 530 hp_wmi_input_dev = input_allocate_device(); 531 532 hp_wmi_input_dev->name = "HP WMI hotkeys"; 533 hp_wmi_input_dev->phys = "wmi/input0"; ··· 578 static int __devinit hp_wmi_bios_setup(struct platform_device *device) 579 { 580 int err; 581 - int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); 582 583 err = device_create_file(&device->dev, &dev_attr_display); 584 if (err) ··· 714 static int __init hp_wmi_init(void) 715 { 716 int err; 717 718 - if (wmi_has_guid(HPWMI_EVENT_GUID)) { 719 err = wmi_install_notify_handler(HPWMI_EVENT_GUID, 720 hp_wmi_notify, NULL); 721 - if (ACPI_SUCCESS(err)) 722 - hp_wmi_input_setup(); 723 } 724 725 - if (wmi_has_guid(HPWMI_BIOS_GUID)) { 726 err = platform_driver_register(&hp_wmi_driver); 727 if (err) 728 - return 0; 729 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1); 730 if (!hp_wmi_platform_dev) { 731 - platform_driver_unregister(&hp_wmi_driver); 732 - return 0; 733 } 734 - platform_device_add(hp_wmi_platform_dev); 735 } 736 737 return 0; 738 } 739 740 static void __exit hp_wmi_exit(void) ··· 768 input_unregister_device(hp_wmi_input_dev); 769 } 770 if (hp_wmi_platform_dev) { 771 - platform_device_del(hp_wmi_platform_dev); 772 platform_driver_unregister(&hp_wmi_driver); 773 } 774 }
··· 29 #include <linux/slab.h> 30 #include <linux/types.h> 31 #include <linux/input.h> 32 #include <linux/platform_device.h> 33 #include <linux/acpi.h> 34 #include <linux/rfkill.h> ··· 52 #define HPWMI_WIRELESS_QUERY 0x5 53 #define HPWMI_HOTKEY_QUERY 0xc 54 55 + #define PREFIX "HP WMI: " 56 + #define UNIMP "Unimplemented " 57 + 58 enum hp_wmi_radio { 59 HPWMI_WIFI = 0, 60 HPWMI_BLUETOOTH = 1, 61 HPWMI_WWAN = 2, 62 + }; 63 + 64 + enum hp_wmi_event_ids { 65 + HPWMI_DOCK_EVENT = 1, 66 + HPWMI_PARK_HDD = 2, 67 + HPWMI_SMART_ADAPTER = 3, 68 + HPWMI_BEZEL_BUTTON = 4, 69 + HPWMI_WIRELESS = 5, 70 + HPWMI_CPU_BATTERY_THROTTLE = 6, 71 + HPWMI_LOCK_SWITCH = 7, 72 }; 73 74 static int __devinit hp_wmi_bios_setup(struct platform_device *device); ··· 67 u32 command; 68 u32 commandtype; 69 u32 datasize; 70 + char *data; 71 }; 72 73 struct bios_return { 74 u32 sigpass; 75 u32 return_code; 76 }; 77 78 struct key_entry { ··· 88 {KE_KEY, 0x02, KEY_BRIGHTNESSUP}, 89 {KE_KEY, 0x03, KEY_BRIGHTNESSDOWN}, 90 {KE_KEY, 0x20e6, KEY_PROG1}, 91 + {KE_KEY, 0x20e8, KEY_MEDIA}, 92 {KE_KEY, 0x2142, KEY_MEDIA}, 93 {KE_KEY, 0x213b, KEY_INFO}, 94 {KE_KEY, 0x2169, KEY_DIRECTION}, ··· 117 .remove = hp_wmi_bios_remove, 118 }; 119 120 + /* 121 + * hp_wmi_perform_query 122 + * 123 + * query: The commandtype -> What should be queried 124 + * write: The command -> 0 read, 1 write, 3 ODM specific 125 + * buffer: Buffer used as input and/or output 126 + * buffersize: Size of buffer 127 + * 128 + * returns zero on success 129 + * an HP WMI query specific error code (which is positive) 130 + * -EINVAL if the query was not successful at all 131 + * -EINVAL if the output buffer size exceeds buffersize 132 + * 133 + * Note: The buffersize must at least be the maximum of the input and output 134 + * size. E.g. Battery info query (0x7) is defined to have 1 byte input 135 + * and 128 byte output. The caller would do: 136 + * buffer = kzalloc(128, GFP_KERNEL); 137 + * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 138 + */ 139 + static int hp_wmi_perform_query(int query, int write, char *buffer, 140 + int buffersize) 141 { 142 struct bios_return bios_return; 143 acpi_status status; ··· 126 .signature = 0x55434553, 127 .command = write ? 0x2 : 0x1, 128 .commandtype = query, 129 + .datasize = buffersize, 130 + .data = buffer, 131 }; 132 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 133 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; ··· 144 } 145 146 bios_return = *((struct bios_return *)obj->buffer.pointer); 147 + 148 + if (bios_return.return_code) { 149 + printk(KERN_WARNING PREFIX "Query %d returned %d\n", query, 150 + bios_return.return_code); 151 + kfree(obj); 152 + return bios_return.return_code; 153 + } 154 + if (obj->buffer.length - sizeof(bios_return) > buffersize) { 155 + kfree(obj); 156 + return -EINVAL; 157 + } 158 + 159 + memset(buffer, 0, buffersize); 160 + memcpy(buffer, 161 + ((char *)obj->buffer.pointer) + sizeof(struct bios_return), 162 + obj->buffer.length - sizeof(bios_return)); 163 kfree(obj); 164 + return 0; 165 } 166 167 static int hp_wmi_display_state(void) 168 { 169 + int state; 170 + int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, (char *)&state, 171 + sizeof(state)); 172 + if (ret) 173 + return -EINVAL; 174 + return state; 175 } 176 177 static int hp_wmi_hddtemp_state(void) 178 { 179 + int state; 180 + int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, (char *)&state, 181 + sizeof(state)); 182 + if (ret) 183 + return -EINVAL; 184 + return state; 185 } 186 187 static int hp_wmi_als_state(void) 188 { 189 + int state; 190 + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, (char *)&state, 191 + sizeof(state)); 192 + if (ret) 193 + return -EINVAL; 194 + return state; 195 } 196 197 static int hp_wmi_dock_state(void) 198 { 199 + int state; 200 + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, 201 + sizeof(state)); 202 203 + if (ret) 204 + return -EINVAL; 205 206 + return state & 0x1; 207 } 208 209 static int hp_wmi_tablet_state(void) 210 { 211 + int state; 212 + int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, (char *)&state, 213 + sizeof(state)); 214 + if (ret) 215 return ret; 216 217 + return (state & 0x4) ? 1 : 0; 218 } 219 220 static int hp_wmi_set_block(void *data, bool blocked) 221 { 222 enum hp_wmi_radio r = (enum hp_wmi_radio) data; 223 int query = BIT(r + 8) | ((!blocked) << r); 224 + int ret; 225 226 + ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 227 + (char *)&query, sizeof(query)); 228 + if (ret) 229 + return -EINVAL; 230 + return 0; 231 } 232 233 static const struct rfkill_ops hp_wmi_rfkill_ops = { ··· 200 201 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) 202 { 203 + int wireless; 204 + int mask; 205 + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 206 + (char *)&wireless, sizeof(wireless)); 207 + /* TBD: Pass error */ 208 + 209 + mask = 0x200 << (r * 8); 210 211 if (wireless & mask) 212 return false; ··· 211 212 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) 213 { 214 + int wireless; 215 + int mask; 216 + hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 217 + (char *)&wireless, sizeof(wireless)); 218 + /* TBD: Pass error */ 219 + 220 + mask = 0x800 << (r * 8); 221 222 if (wireless & mask) 223 return false; ··· 269 const char *buf, size_t count) 270 { 271 u32 tmp = simple_strtoul(buf, NULL, 10); 272 + int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, (char *)&tmp, 273 + sizeof(tmp)); 274 + if (ret) 275 + return -EINVAL; 276 + 277 return count; 278 } 279 ··· 338 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 339 static struct key_entry *key; 340 union acpi_object *obj; 341 + u32 event_id, event_data; 342 + int key_code, ret; 343 + u32 *location; 344 acpi_status status; 345 346 status = wmi_get_event_data(value, &response); 347 if (status != AE_OK) { 348 + printk(KERN_INFO PREFIX "bad event status 0x%x\n", status); 349 return; 350 } 351 352 obj = (union acpi_object *)response.pointer; 353 354 + if (!obj) 355 + return; 356 + if (obj->type != ACPI_TYPE_BUFFER) { 357 + printk(KERN_INFO "hp-wmi: Unknown response received %d\n", 358 + obj->type); 359 kfree(obj); 360 return; 361 } 362 363 + /* 364 + * Depending on ACPI version the concatenation of id and event data 365 + * inside _WED function will result in a 8 or 16 byte buffer. 366 + */ 367 + location = (u32 *)obj->buffer.pointer; 368 + if (obj->buffer.length == 8) { 369 + event_id = *location; 370 + event_data = *(location + 1); 371 + } else if (obj->buffer.length == 16) { 372 + event_id = *location; 373 + event_data = *(location + 2); 374 + } else { 375 + printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n", 376 + obj->buffer.length); 377 + kfree(obj); 378 + return; 379 + } 380 kfree(obj); 381 + 382 + switch (event_id) { 383 + case HPWMI_DOCK_EVENT: 384 input_report_switch(hp_wmi_input_dev, SW_DOCK, 385 hp_wmi_dock_state()); 386 input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, 387 hp_wmi_tablet_state()); 388 input_sync(hp_wmi_input_dev); 389 + break; 390 + case HPWMI_PARK_HDD: 391 + break; 392 + case HPWMI_SMART_ADAPTER: 393 + break; 394 + case HPWMI_BEZEL_BUTTON: 395 + ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 396 + (char *)&key_code, 397 + sizeof(key_code)); 398 + if (ret) 399 + break; 400 + key = hp_wmi_get_entry_by_scancode(key_code); 401 + if (key) { 402 + switch (key->type) { 403 + case KE_KEY: 404 + input_report_key(hp_wmi_input_dev, 405 + key->keycode, 1); 406 + input_sync(hp_wmi_input_dev); 407 + input_report_key(hp_wmi_input_dev, 408 + key->keycode, 0); 409 + input_sync(hp_wmi_input_dev); 410 + break; 411 + } 412 + } else 413 + printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n", 414 + key_code); 415 + break; 416 + case HPWMI_WIRELESS: 417 if (wifi_rfkill) 418 rfkill_set_states(wifi_rfkill, 419 hp_wmi_get_sw_state(HPWMI_WIFI), ··· 391 rfkill_set_states(wwan_rfkill, 392 hp_wmi_get_sw_state(HPWMI_WWAN), 393 hp_wmi_get_hw_state(HPWMI_WWAN)); 394 + break; 395 + case HPWMI_CPU_BATTERY_THROTTLE: 396 + printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell" 397 + " battery event detected\n"); 398 + break; 399 + case HPWMI_LOCK_SWITCH: 400 + break; 401 + default: 402 + printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n", 403 + event_id, event_data); 404 + break; 405 + } 406 } 407 408 static int __init hp_wmi_input_setup(void) ··· 402 int err; 403 404 hp_wmi_input_dev = input_allocate_device(); 405 + if (!hp_wmi_input_dev) 406 + return -ENOMEM; 407 408 hp_wmi_input_dev->name = "HP WMI hotkeys"; 409 hp_wmi_input_dev->phys = "wmi/input0"; ··· 450 static int __devinit hp_wmi_bios_setup(struct platform_device *device) 451 { 452 int err; 453 + int wireless; 454 + 455 + err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, (char *)&wireless, 456 + sizeof(wireless)); 457 + if (err) 458 + return err; 459 460 err = device_create_file(&device->dev, &dev_attr_display); 461 if (err) ··· 581 static int __init hp_wmi_init(void) 582 { 583 int err; 584 + int event_capable = wmi_has_guid(HPWMI_EVENT_GUID); 585 + int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID); 586 587 + if (event_capable) { 588 err = wmi_install_notify_handler(HPWMI_EVENT_GUID, 589 hp_wmi_notify, NULL); 590 + if (ACPI_FAILURE(err)) 591 + return -EINVAL; 592 + err = hp_wmi_input_setup(); 593 + if (err) { 594 + wmi_remove_notify_handler(HPWMI_EVENT_GUID); 595 + return err; 596 + } 597 } 598 599 + if (bios_capable) { 600 err = platform_driver_register(&hp_wmi_driver); 601 if (err) 602 + goto err_driver_reg; 603 hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1); 604 if (!hp_wmi_platform_dev) { 605 + err = -ENOMEM; 606 + goto err_device_alloc; 607 } 608 + err = platform_device_add(hp_wmi_platform_dev); 609 + if (err) 610 + goto err_device_add; 611 } 612 613 + if (!bios_capable && !event_capable) 614 + return -ENODEV; 615 + 616 return 0; 617 + 618 + err_device_add: 619 + platform_device_put(hp_wmi_platform_dev); 620 + err_device_alloc: 621 + platform_driver_unregister(&hp_wmi_driver); 622 + err_driver_reg: 623 + if (wmi_has_guid(HPWMI_EVENT_GUID)) { 624 + input_unregister_device(hp_wmi_input_dev); 625 + wmi_remove_notify_handler(HPWMI_EVENT_GUID); 626 + } 627 + 628 + return err; 629 } 630 631 static void __exit hp_wmi_exit(void) ··· 611 input_unregister_device(hp_wmi_input_dev); 612 } 613 if (hp_wmi_platform_dev) { 614 + platform_device_unregister(hp_wmi_platform_dev); 615 platform_driver_unregister(&hp_wmi_driver); 616 } 617 }
+1660
drivers/platform/x86/intel_ips.c
···
··· 1 + /* 2 + * Copyright (c) 2009-2010 Intel Corporation 3 + * 4 + * This program is free software; you can redistribute it and/or modify it 5 + * under the terms and conditions of the GNU General Public License, 6 + * version 2, as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope it will be useful, but WITHOUT 9 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 + * more details. 12 + * 13 + * You should have received a copy of the GNU General Public License along with 14 + * this program; if not, write to the Free Software Foundation, Inc., 15 + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. 16 + * 17 + * The full GNU General Public License is included in this distribution in 18 + * the file called "COPYING". 19 + * 20 + * Authors: 21 + * Jesse Barnes <jbarnes@virtuousgeek.org> 22 + */ 23 + 24 + /* 25 + * Some Intel Ibex Peak based platforms support so-called "intelligent 26 + * power sharing", which allows the CPU and GPU to cooperate to maximize 27 + * performance within a given TDP (thermal design point). This driver 28 + * performs the coordination between the CPU and GPU, monitors thermal and 29 + * power statistics in the platform, and initializes power monitoring 30 + * hardware. It also provides a few tunables to control behavior. Its 31 + * primary purpose is to safely allow CPU and GPU turbo modes to be enabled 32 + * by tracking power and thermal budget; secondarily it can boost turbo 33 + * performance by allocating more power or thermal budget to the CPU or GPU 34 + * based on available headroom and activity. 35 + * 36 + * The basic algorithm is driven by a 5s moving average of tempurature. If 37 + * thermal headroom is available, the CPU and/or GPU power clamps may be 38 + * adjusted upwards. If we hit the thermal ceiling or a thermal trigger, 39 + * we scale back the clamp. Aside from trigger events (when we're critically 40 + * close or over our TDP) we don't adjust the clamps more than once every 41 + * five seconds. 42 + * 43 + * The thermal device (device 31, function 6) has a set of registers that 44 + * are updated by the ME firmware. The ME should also take the clamp values 45 + * written to those registers and write them to the CPU, but we currently 46 + * bypass that functionality and write the CPU MSR directly. 47 + * 48 + * UNSUPPORTED: 49 + * - dual MCP configs 50 + * 51 + * TODO: 52 + * - handle CPU hotplug 53 + * - provide turbo enable/disable api 54 + * - make sure we can write turbo enable/disable reg based on MISC_EN 55 + * 56 + * Related documents: 57 + * - CDI 403777, 403778 - Auburndale EDS vol 1 & 2 58 + * - CDI 401376 - Ibex Peak EDS 59 + * - ref 26037, 26641 - IPS BIOS spec 60 + * - ref 26489 - Nehalem BIOS writer's guide 61 + * - ref 26921 - Ibex Peak BIOS Specification 62 + */ 63 + 64 + #include <linux/debugfs.h> 65 + #include <linux/delay.h> 66 + #include <linux/interrupt.h> 67 + #include <linux/kernel.h> 68 + #include <linux/kthread.h> 69 + #include <linux/module.h> 70 + #include <linux/pci.h> 71 + #include <linux/sched.h> 72 + #include <linux/seq_file.h> 73 + #include <linux/string.h> 74 + #include <linux/tick.h> 75 + #include <linux/timer.h> 76 + #include <drm/i915_drm.h> 77 + #include <asm/msr.h> 78 + #include <asm/processor.h> 79 + 80 + #define PCI_DEVICE_ID_INTEL_THERMAL_SENSOR 0x3b32 81 + 82 + /* 83 + * Package level MSRs for monitor/control 84 + */ 85 + #define PLATFORM_INFO 0xce 86 + #define PLATFORM_TDP (1<<29) 87 + #define PLATFORM_RATIO (1<<28) 88 + 89 + #define IA32_MISC_ENABLE 0x1a0 90 + #define IA32_MISC_TURBO_EN (1ULL<<38) 91 + 92 + #define TURBO_POWER_CURRENT_LIMIT 0x1ac 93 + #define TURBO_TDC_OVR_EN (1UL<<31) 94 + #define TURBO_TDC_MASK (0x000000007fff0000UL) 95 + #define TURBO_TDC_SHIFT (16) 96 + #define TURBO_TDP_OVR_EN (1UL<<15) 97 + #define TURBO_TDP_MASK (0x0000000000003fffUL) 98 + 99 + /* 100 + * Core/thread MSRs for monitoring 101 + */ 102 + #define IA32_PERF_CTL 0x199 103 + #define IA32_PERF_TURBO_DIS (1ULL<<32) 104 + 105 + /* 106 + * Thermal PCI device regs 107 + */ 108 + #define THM_CFG_TBAR 0x10 109 + #define THM_CFG_TBAR_HI 0x14 110 + 111 + #define THM_TSIU 0x00 112 + #define THM_TSE 0x01 113 + #define TSE_EN 0xb8 114 + #define THM_TSS 0x02 115 + #define THM_TSTR 0x03 116 + #define THM_TSTTP 0x04 117 + #define THM_TSCO 0x08 118 + #define THM_TSES 0x0c 119 + #define THM_TSGPEN 0x0d 120 + #define TSGPEN_HOT_LOHI (1<<1) 121 + #define TSGPEN_CRIT_LOHI (1<<2) 122 + #define THM_TSPC 0x0e 123 + #define THM_PPEC 0x10 124 + #define THM_CTA 0x12 125 + #define THM_PTA 0x14 126 + #define PTA_SLOPE_MASK (0xff00) 127 + #define PTA_SLOPE_SHIFT 8 128 + #define PTA_OFFSET_MASK (0x00ff) 129 + #define THM_MGTA 0x16 130 + #define MGTA_SLOPE_MASK (0xff00) 131 + #define MGTA_SLOPE_SHIFT 8 132 + #define MGTA_OFFSET_MASK (0x00ff) 133 + #define THM_TRC 0x1a 134 + #define TRC_CORE2_EN (1<<15) 135 + #define TRC_THM_EN (1<<12) 136 + #define TRC_C6_WAR (1<<8) 137 + #define TRC_CORE1_EN (1<<7) 138 + #define TRC_CORE_PWR (1<<6) 139 + #define TRC_PCH_EN (1<<5) 140 + #define TRC_MCH_EN (1<<4) 141 + #define TRC_DIMM4 (1<<3) 142 + #define TRC_DIMM3 (1<<2) 143 + #define TRC_DIMM2 (1<<1) 144 + #define TRC_DIMM1 (1<<0) 145 + #define THM_TES 0x20 146 + #define THM_TEN 0x21 147 + #define TEN_UPDATE_EN 1 148 + #define THM_PSC 0x24 149 + #define PSC_NTG (1<<0) /* No GFX turbo support */ 150 + #define PSC_NTPC (1<<1) /* No CPU turbo support */ 151 + #define PSC_PP_DEF (0<<2) /* Perf policy up to driver */ 152 + #define PSP_PP_PC (1<<2) /* BIOS prefers CPU perf */ 153 + #define PSP_PP_BAL (2<<2) /* BIOS wants balanced perf */ 154 + #define PSP_PP_GFX (3<<2) /* BIOS prefers GFX perf */ 155 + #define PSP_PBRT (1<<4) /* BIOS run time support */ 156 + #define THM_CTV1 0x30 157 + #define CTV_TEMP_ERROR (1<<15) 158 + #define CTV_TEMP_MASK 0x3f 159 + #define CTV_ 160 + #define THM_CTV2 0x32 161 + #define THM_CEC 0x34 /* undocumented power accumulator in joules */ 162 + #define THM_AE 0x3f 163 + #define THM_HTS 0x50 /* 32 bits */ 164 + #define HTS_PCPL_MASK (0x7fe00000) 165 + #define HTS_PCPL_SHIFT 21 166 + #define HTS_GPL_MASK (0x001ff000) 167 + #define HTS_GPL_SHIFT 12 168 + #define HTS_PP_MASK (0x00000c00) 169 + #define HTS_PP_SHIFT 10 170 + #define HTS_PP_DEF 0 171 + #define HTS_PP_PROC 1 172 + #define HTS_PP_BAL 2 173 + #define HTS_PP_GFX 3 174 + #define HTS_PCTD_DIS (1<<9) 175 + #define HTS_GTD_DIS (1<<8) 176 + #define HTS_PTL_MASK (0x000000fe) 177 + #define HTS_PTL_SHIFT 1 178 + #define HTS_NVV (1<<0) 179 + #define THM_HTSHI 0x54 /* 16 bits */ 180 + #define HTS2_PPL_MASK (0x03ff) 181 + #define HTS2_PRST_MASK (0x3c00) 182 + #define HTS2_PRST_SHIFT 10 183 + #define HTS2_PRST_UNLOADED 0 184 + #define HTS2_PRST_RUNNING 1 185 + #define HTS2_PRST_TDISOP 2 /* turbo disabled due to power */ 186 + #define HTS2_PRST_TDISHT 3 /* turbo disabled due to high temp */ 187 + #define HTS2_PRST_TDISUSR 4 /* user disabled turbo */ 188 + #define HTS2_PRST_TDISPLAT 5 /* platform disabled turbo */ 189 + #define HTS2_PRST_TDISPM 6 /* power management disabled turbo */ 190 + #define HTS2_PRST_TDISERR 7 /* some kind of error disabled turbo */ 191 + #define THM_PTL 0x56 192 + #define THM_MGTV 0x58 193 + #define TV_MASK 0x000000000000ff00 194 + #define TV_SHIFT 8 195 + #define THM_PTV 0x60 196 + #define PTV_MASK 0x00ff 197 + #define THM_MMGPC 0x64 198 + #define THM_MPPC 0x66 199 + #define THM_MPCPC 0x68 200 + #define THM_TSPIEN 0x82 201 + #define TSPIEN_AUX_LOHI (1<<0) 202 + #define TSPIEN_HOT_LOHI (1<<1) 203 + #define TSPIEN_CRIT_LOHI (1<<2) 204 + #define TSPIEN_AUX2_LOHI (1<<3) 205 + #define THM_TSLOCK 0x83 206 + #define THM_ATR 0x84 207 + #define THM_TOF 0x87 208 + #define THM_STS 0x98 209 + #define STS_PCPL_MASK (0x7fe00000) 210 + #define STS_PCPL_SHIFT 21 211 + #define STS_GPL_MASK (0x001ff000) 212 + #define STS_GPL_SHIFT 12 213 + #define STS_PP_MASK (0x00000c00) 214 + #define STS_PP_SHIFT 10 215 + #define STS_PP_DEF 0 216 + #define STS_PP_PROC 1 217 + #define STS_PP_BAL 2 218 + #define STS_PP_GFX 3 219 + #define STS_PCTD_DIS (1<<9) 220 + #define STS_GTD_DIS (1<<8) 221 + #define STS_PTL_MASK (0x000000fe) 222 + #define STS_PTL_SHIFT 1 223 + #define STS_NVV (1<<0) 224 + #define THM_SEC 0x9c 225 + #define SEC_ACK (1<<0) 226 + #define THM_TC3 0xa4 227 + #define THM_TC1 0xa8 228 + #define STS_PPL_MASK (0x0003ff00) 229 + #define STS_PPL_SHIFT 16 230 + #define THM_TC2 0xac 231 + #define THM_DTV 0xb0 232 + #define THM_ITV 0xd8 233 + #define ITV_ME_SEQNO_MASK 0x000f0000 /* ME should update every ~200ms */ 234 + #define ITV_ME_SEQNO_SHIFT (16) 235 + #define ITV_MCH_TEMP_MASK 0x0000ff00 236 + #define ITV_MCH_TEMP_SHIFT (8) 237 + #define ITV_PCH_TEMP_MASK 0x000000ff 238 + 239 + #define thm_readb(off) readb(ips->regmap + (off)) 240 + #define thm_readw(off) readw(ips->regmap + (off)) 241 + #define thm_readl(off) readl(ips->regmap + (off)) 242 + #define thm_readq(off) readq(ips->regmap + (off)) 243 + 244 + #define thm_writeb(off, val) writeb((val), ips->regmap + (off)) 245 + #define thm_writew(off, val) writew((val), ips->regmap + (off)) 246 + #define thm_writel(off, val) writel((val), ips->regmap + (off)) 247 + 248 + static const int IPS_ADJUST_PERIOD = 5000; /* ms */ 249 + 250 + /* For initial average collection */ 251 + static const int IPS_SAMPLE_PERIOD = 200; /* ms */ 252 + static const int IPS_SAMPLE_WINDOW = 5000; /* 5s moving window of samples */ 253 + #define IPS_SAMPLE_COUNT (IPS_SAMPLE_WINDOW / IPS_SAMPLE_PERIOD) 254 + 255 + /* Per-SKU limits */ 256 + struct ips_mcp_limits { 257 + int cpu_family; 258 + int cpu_model; /* includes extended model... */ 259 + int mcp_power_limit; /* mW units */ 260 + int core_power_limit; 261 + int mch_power_limit; 262 + int core_temp_limit; /* degrees C */ 263 + int mch_temp_limit; 264 + }; 265 + 266 + /* Max temps are -10 degrees C to avoid PROCHOT# */ 267 + 268 + struct ips_mcp_limits ips_sv_limits = { 269 + .mcp_power_limit = 35000, 270 + .core_power_limit = 29000, 271 + .mch_power_limit = 20000, 272 + .core_temp_limit = 95, 273 + .mch_temp_limit = 90 274 + }; 275 + 276 + struct ips_mcp_limits ips_lv_limits = { 277 + .mcp_power_limit = 25000, 278 + .core_power_limit = 21000, 279 + .mch_power_limit = 13000, 280 + .core_temp_limit = 95, 281 + .mch_temp_limit = 90 282 + }; 283 + 284 + struct ips_mcp_limits ips_ulv_limits = { 285 + .mcp_power_limit = 18000, 286 + .core_power_limit = 14000, 287 + .mch_power_limit = 11000, 288 + .core_temp_limit = 95, 289 + .mch_temp_limit = 90 290 + }; 291 + 292 + struct ips_driver { 293 + struct pci_dev *dev; 294 + void *regmap; 295 + struct task_struct *monitor; 296 + struct task_struct *adjust; 297 + struct dentry *debug_root; 298 + 299 + /* Average CPU core temps (all averages in .01 degrees C for precision) */ 300 + u16 ctv1_avg_temp; 301 + u16 ctv2_avg_temp; 302 + /* GMCH average */ 303 + u16 mch_avg_temp; 304 + /* Average for the CPU (both cores?) */ 305 + u16 mcp_avg_temp; 306 + /* Average power consumption (in mW) */ 307 + u32 cpu_avg_power; 308 + u32 mch_avg_power; 309 + 310 + /* Offset values */ 311 + u16 cta_val; 312 + u16 pta_val; 313 + u16 mgta_val; 314 + 315 + /* Maximums & prefs, protected by turbo status lock */ 316 + spinlock_t turbo_status_lock; 317 + u16 mcp_temp_limit; 318 + u16 mcp_power_limit; 319 + u16 core_power_limit; 320 + u16 mch_power_limit; 321 + bool cpu_turbo_enabled; 322 + bool __cpu_turbo_on; 323 + bool gpu_turbo_enabled; 324 + bool __gpu_turbo_on; 325 + bool gpu_preferred; 326 + bool poll_turbo_status; 327 + bool second_cpu; 328 + struct ips_mcp_limits *limits; 329 + 330 + /* Optional MCH interfaces for if i915 is in use */ 331 + unsigned long (*read_mch_val)(void); 332 + bool (*gpu_raise)(void); 333 + bool (*gpu_lower)(void); 334 + bool (*gpu_busy)(void); 335 + bool (*gpu_turbo_disable)(void); 336 + 337 + /* For restoration at unload */ 338 + u64 orig_turbo_limit; 339 + u64 orig_turbo_ratios; 340 + }; 341 + 342 + /** 343 + * ips_cpu_busy - is CPU busy? 344 + * @ips: IPS driver struct 345 + * 346 + * Check CPU for load to see whether we should increase its thermal budget. 347 + * 348 + * RETURNS: 349 + * True if the CPU could use more power, false otherwise. 350 + */ 351 + static bool ips_cpu_busy(struct ips_driver *ips) 352 + { 353 + if ((avenrun[0] >> FSHIFT) > 1) 354 + return true; 355 + 356 + return false; 357 + } 358 + 359 + /** 360 + * ips_cpu_raise - raise CPU power clamp 361 + * @ips: IPS driver struct 362 + * 363 + * Raise the CPU power clamp by %IPS_CPU_STEP, in accordance with TDP for 364 + * this platform. 365 + * 366 + * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR upwards (as 367 + * long as we haven't hit the TDP limit for the SKU). 368 + */ 369 + static void ips_cpu_raise(struct ips_driver *ips) 370 + { 371 + u64 turbo_override; 372 + u16 cur_tdp_limit, new_tdp_limit; 373 + 374 + if (!ips->cpu_turbo_enabled) 375 + return; 376 + 377 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 378 + 379 + cur_tdp_limit = turbo_override & TURBO_TDP_MASK; 380 + new_tdp_limit = cur_tdp_limit + 8; /* 1W increase */ 381 + 382 + /* Clamp to SKU TDP limit */ 383 + if (((new_tdp_limit * 10) / 8) > ips->core_power_limit) 384 + new_tdp_limit = cur_tdp_limit; 385 + 386 + thm_writew(THM_MPCPC, (new_tdp_limit * 10) / 8); 387 + 388 + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; 389 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 390 + 391 + turbo_override &= ~TURBO_TDP_MASK; 392 + turbo_override |= new_tdp_limit; 393 + 394 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 395 + } 396 + 397 + /** 398 + * ips_cpu_lower - lower CPU power clamp 399 + * @ips: IPS driver struct 400 + * 401 + * Lower CPU power clamp b %IPS_CPU_STEP if possible. 402 + * 403 + * We do this by adjusting the TURBO_POWER_CURRENT_LIMIT MSR down, going 404 + * as low as the platform limits will allow (though we could go lower there 405 + * wouldn't be much point). 406 + */ 407 + static void ips_cpu_lower(struct ips_driver *ips) 408 + { 409 + u64 turbo_override; 410 + u16 cur_limit, new_limit; 411 + 412 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 413 + 414 + cur_limit = turbo_override & TURBO_TDP_MASK; 415 + new_limit = cur_limit - 8; /* 1W decrease */ 416 + 417 + /* Clamp to SKU TDP limit */ 418 + if (((new_limit * 10) / 8) < (ips->orig_turbo_limit & TURBO_TDP_MASK)) 419 + new_limit = ips->orig_turbo_limit & TURBO_TDP_MASK; 420 + 421 + thm_writew(THM_MPCPC, (new_limit * 10) / 8); 422 + 423 + turbo_override |= TURBO_TDC_OVR_EN | TURBO_TDC_OVR_EN; 424 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 425 + 426 + turbo_override &= ~TURBO_TDP_MASK; 427 + turbo_override |= new_limit; 428 + 429 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 430 + } 431 + 432 + /** 433 + * do_enable_cpu_turbo - internal turbo enable function 434 + * @data: unused 435 + * 436 + * Internal function for actually updating MSRs. When we enable/disable 437 + * turbo, we need to do it on each CPU; this function is the one called 438 + * by on_each_cpu() when needed. 439 + */ 440 + static void do_enable_cpu_turbo(void *data) 441 + { 442 + u64 perf_ctl; 443 + 444 + rdmsrl(IA32_PERF_CTL, perf_ctl); 445 + if (perf_ctl & IA32_PERF_TURBO_DIS) { 446 + perf_ctl &= ~IA32_PERF_TURBO_DIS; 447 + wrmsrl(IA32_PERF_CTL, perf_ctl); 448 + } 449 + } 450 + 451 + /** 452 + * ips_enable_cpu_turbo - enable turbo mode on all CPUs 453 + * @ips: IPS driver struct 454 + * 455 + * Enable turbo mode by clearing the disable bit in IA32_PERF_CTL on 456 + * all logical threads. 457 + */ 458 + static void ips_enable_cpu_turbo(struct ips_driver *ips) 459 + { 460 + /* Already on, no need to mess with MSRs */ 461 + if (ips->__cpu_turbo_on) 462 + return; 463 + 464 + on_each_cpu(do_enable_cpu_turbo, ips, 1); 465 + 466 + ips->__cpu_turbo_on = true; 467 + } 468 + 469 + /** 470 + * do_disable_cpu_turbo - internal turbo disable function 471 + * @data: unused 472 + * 473 + * Internal function for actually updating MSRs. When we enable/disable 474 + * turbo, we need to do it on each CPU; this function is the one called 475 + * by on_each_cpu() when needed. 476 + */ 477 + static void do_disable_cpu_turbo(void *data) 478 + { 479 + u64 perf_ctl; 480 + 481 + rdmsrl(IA32_PERF_CTL, perf_ctl); 482 + if (!(perf_ctl & IA32_PERF_TURBO_DIS)) { 483 + perf_ctl |= IA32_PERF_TURBO_DIS; 484 + wrmsrl(IA32_PERF_CTL, perf_ctl); 485 + } 486 + } 487 + 488 + /** 489 + * ips_disable_cpu_turbo - disable turbo mode on all CPUs 490 + * @ips: IPS driver struct 491 + * 492 + * Disable turbo mode by setting the disable bit in IA32_PERF_CTL on 493 + * all logical threads. 494 + */ 495 + static void ips_disable_cpu_turbo(struct ips_driver *ips) 496 + { 497 + /* Already off, leave it */ 498 + if (!ips->__cpu_turbo_on) 499 + return; 500 + 501 + on_each_cpu(do_disable_cpu_turbo, ips, 1); 502 + 503 + ips->__cpu_turbo_on = false; 504 + } 505 + 506 + /** 507 + * ips_gpu_busy - is GPU busy? 508 + * @ips: IPS driver struct 509 + * 510 + * Check GPU for load to see whether we should increase its thermal budget. 511 + * We need to call into the i915 driver in this case. 512 + * 513 + * RETURNS: 514 + * True if the GPU could use more power, false otherwise. 515 + */ 516 + static bool ips_gpu_busy(struct ips_driver *ips) 517 + { 518 + if (!ips->gpu_turbo_enabled) 519 + return false; 520 + 521 + return ips->gpu_busy(); 522 + } 523 + 524 + /** 525 + * ips_gpu_raise - raise GPU power clamp 526 + * @ips: IPS driver struct 527 + * 528 + * Raise the GPU frequency/power if possible. We need to call into the 529 + * i915 driver in this case. 530 + */ 531 + static void ips_gpu_raise(struct ips_driver *ips) 532 + { 533 + if (!ips->gpu_turbo_enabled) 534 + return; 535 + 536 + if (!ips->gpu_raise()) 537 + ips->gpu_turbo_enabled = false; 538 + 539 + return; 540 + } 541 + 542 + /** 543 + * ips_gpu_lower - lower GPU power clamp 544 + * @ips: IPS driver struct 545 + * 546 + * Lower GPU frequency/power if possible. Need to call i915. 547 + */ 548 + static void ips_gpu_lower(struct ips_driver *ips) 549 + { 550 + if (!ips->gpu_turbo_enabled) 551 + return; 552 + 553 + if (!ips->gpu_lower()) 554 + ips->gpu_turbo_enabled = false; 555 + 556 + return; 557 + } 558 + 559 + /** 560 + * ips_enable_gpu_turbo - notify the gfx driver turbo is available 561 + * @ips: IPS driver struct 562 + * 563 + * Call into the graphics driver indicating that it can safely use 564 + * turbo mode. 565 + */ 566 + static void ips_enable_gpu_turbo(struct ips_driver *ips) 567 + { 568 + if (ips->__gpu_turbo_on) 569 + return; 570 + ips->__gpu_turbo_on = true; 571 + } 572 + 573 + /** 574 + * ips_disable_gpu_turbo - notify the gfx driver to disable turbo mode 575 + * @ips: IPS driver struct 576 + * 577 + * Request that the graphics driver disable turbo mode. 578 + */ 579 + static void ips_disable_gpu_turbo(struct ips_driver *ips) 580 + { 581 + /* Avoid calling i915 if turbo is already disabled */ 582 + if (!ips->__gpu_turbo_on) 583 + return; 584 + 585 + if (!ips->gpu_turbo_disable()) 586 + dev_err(&ips->dev->dev, "failed to disable graphis turbo\n"); 587 + else 588 + ips->__gpu_turbo_on = false; 589 + } 590 + 591 + /** 592 + * mcp_exceeded - check whether we're outside our thermal & power limits 593 + * @ips: IPS driver struct 594 + * 595 + * Check whether the MCP is over its thermal or power budget. 596 + */ 597 + static bool mcp_exceeded(struct ips_driver *ips) 598 + { 599 + unsigned long flags; 600 + bool ret = false; 601 + 602 + spin_lock_irqsave(&ips->turbo_status_lock, flags); 603 + if (ips->mcp_avg_temp > (ips->mcp_temp_limit * 100)) 604 + ret = true; 605 + if (ips->cpu_avg_power + ips->mch_avg_power > ips->mcp_power_limit) 606 + ret = true; 607 + spin_unlock_irqrestore(&ips->turbo_status_lock, flags); 608 + 609 + if (ret) 610 + dev_info(&ips->dev->dev, 611 + "MCP power or thermal limit exceeded\n"); 612 + 613 + return ret; 614 + } 615 + 616 + /** 617 + * cpu_exceeded - check whether a CPU core is outside its limits 618 + * @ips: IPS driver struct 619 + * @cpu: CPU number to check 620 + * 621 + * Check a given CPU's average temp or power is over its limit. 622 + */ 623 + static bool cpu_exceeded(struct ips_driver *ips, int cpu) 624 + { 625 + unsigned long flags; 626 + int avg; 627 + bool ret = false; 628 + 629 + spin_lock_irqsave(&ips->turbo_status_lock, flags); 630 + avg = cpu ? ips->ctv2_avg_temp : ips->ctv1_avg_temp; 631 + if (avg > (ips->limits->core_temp_limit * 100)) 632 + ret = true; 633 + if (ips->cpu_avg_power > ips->core_power_limit * 100) 634 + ret = true; 635 + spin_unlock_irqrestore(&ips->turbo_status_lock, flags); 636 + 637 + if (ret) 638 + dev_info(&ips->dev->dev, 639 + "CPU power or thermal limit exceeded\n"); 640 + 641 + return ret; 642 + } 643 + 644 + /** 645 + * mch_exceeded - check whether the GPU is over budget 646 + * @ips: IPS driver struct 647 + * 648 + * Check the MCH temp & power against their maximums. 649 + */ 650 + static bool mch_exceeded(struct ips_driver *ips) 651 + { 652 + unsigned long flags; 653 + bool ret = false; 654 + 655 + spin_lock_irqsave(&ips->turbo_status_lock, flags); 656 + if (ips->mch_avg_temp > (ips->limits->mch_temp_limit * 100)) 657 + ret = true; 658 + if (ips->mch_avg_power > ips->mch_power_limit) 659 + ret = true; 660 + spin_unlock_irqrestore(&ips->turbo_status_lock, flags); 661 + 662 + return ret; 663 + } 664 + 665 + /** 666 + * update_turbo_limits - get various limits & settings from regs 667 + * @ips: IPS driver struct 668 + * 669 + * Update the IPS power & temp limits, along with turbo enable flags, 670 + * based on latest register contents. 671 + * 672 + * Used at init time and for runtime BIOS support, which requires polling 673 + * the regs for updates (as a result of AC->DC transition for example). 674 + * 675 + * LOCKING: 676 + * Caller must hold turbo_status_lock (outside of init) 677 + */ 678 + static void update_turbo_limits(struct ips_driver *ips) 679 + { 680 + u32 hts = thm_readl(THM_HTS); 681 + 682 + ips->cpu_turbo_enabled = !(hts & HTS_PCTD_DIS); 683 + ips->gpu_turbo_enabled = !(hts & HTS_GTD_DIS); 684 + ips->core_power_limit = thm_readw(THM_MPCPC); 685 + ips->mch_power_limit = thm_readw(THM_MMGPC); 686 + ips->mcp_temp_limit = thm_readw(THM_PTL); 687 + ips->mcp_power_limit = thm_readw(THM_MPPC); 688 + 689 + /* Ignore BIOS CPU vs GPU pref */ 690 + } 691 + 692 + /** 693 + * ips_adjust - adjust power clamp based on thermal state 694 + * @data: ips driver structure 695 + * 696 + * Wake up every 5s or so and check whether we should adjust the power clamp. 697 + * Check CPU and GPU load to determine which needs adjustment. There are 698 + * several things to consider here: 699 + * - do we need to adjust up or down? 700 + * - is CPU busy? 701 + * - is GPU busy? 702 + * - is CPU in turbo? 703 + * - is GPU in turbo? 704 + * - is CPU or GPU preferred? (CPU is default) 705 + * 706 + * So, given the above, we do the following: 707 + * - up (TDP available) 708 + * - CPU not busy, GPU not busy - nothing 709 + * - CPU busy, GPU not busy - adjust CPU up 710 + * - CPU not busy, GPU busy - adjust GPU up 711 + * - CPU busy, GPU busy - adjust preferred unit up, taking headroom from 712 + * non-preferred unit if necessary 713 + * - down (at TDP limit) 714 + * - adjust both CPU and GPU down if possible 715 + * 716 + cpu+ gpu+ cpu+gpu- cpu-gpu+ cpu-gpu- 717 + cpu < gpu < cpu+gpu+ cpu+ gpu+ nothing 718 + cpu < gpu >= cpu+gpu-(mcp<) cpu+gpu-(mcp<) gpu- gpu- 719 + cpu >= gpu < cpu-gpu+(mcp<) cpu- cpu-gpu+(mcp<) cpu- 720 + cpu >= gpu >= cpu-gpu- cpu-gpu- cpu-gpu- cpu-gpu- 721 + * 722 + */ 723 + static int ips_adjust(void *data) 724 + { 725 + struct ips_driver *ips = data; 726 + unsigned long flags; 727 + 728 + dev_dbg(&ips->dev->dev, "starting ips-adjust thread\n"); 729 + 730 + /* 731 + * Adjust CPU and GPU clamps every 5s if needed. Doing it more 732 + * often isn't recommended due to ME interaction. 733 + */ 734 + do { 735 + bool cpu_busy = ips_cpu_busy(ips); 736 + bool gpu_busy = ips_gpu_busy(ips); 737 + 738 + spin_lock_irqsave(&ips->turbo_status_lock, flags); 739 + if (ips->poll_turbo_status) 740 + update_turbo_limits(ips); 741 + spin_unlock_irqrestore(&ips->turbo_status_lock, flags); 742 + 743 + /* Update turbo status if necessary */ 744 + if (ips->cpu_turbo_enabled) 745 + ips_enable_cpu_turbo(ips); 746 + else 747 + ips_disable_cpu_turbo(ips); 748 + 749 + if (ips->gpu_turbo_enabled) 750 + ips_enable_gpu_turbo(ips); 751 + else 752 + ips_disable_gpu_turbo(ips); 753 + 754 + /* We're outside our comfort zone, crank them down */ 755 + if (mcp_exceeded(ips)) { 756 + ips_cpu_lower(ips); 757 + ips_gpu_lower(ips); 758 + goto sleep; 759 + } 760 + 761 + if (!cpu_exceeded(ips, 0) && cpu_busy) 762 + ips_cpu_raise(ips); 763 + else 764 + ips_cpu_lower(ips); 765 + 766 + if (!mch_exceeded(ips) && gpu_busy) 767 + ips_gpu_raise(ips); 768 + else 769 + ips_gpu_lower(ips); 770 + 771 + sleep: 772 + schedule_timeout_interruptible(msecs_to_jiffies(IPS_ADJUST_PERIOD)); 773 + } while (!kthread_should_stop()); 774 + 775 + dev_dbg(&ips->dev->dev, "ips-adjust thread stopped\n"); 776 + 777 + return 0; 778 + } 779 + 780 + /* 781 + * Helpers for reading out temp/power values and calculating their 782 + * averages for the decision making and monitoring functions. 783 + */ 784 + 785 + static u16 calc_avg_temp(struct ips_driver *ips, u16 *array) 786 + { 787 + u64 total = 0; 788 + int i; 789 + u16 avg; 790 + 791 + for (i = 0; i < IPS_SAMPLE_COUNT; i++) 792 + total += (u64)(array[i] * 100); 793 + 794 + do_div(total, IPS_SAMPLE_COUNT); 795 + 796 + avg = (u16)total; 797 + 798 + return avg; 799 + } 800 + 801 + static u16 read_mgtv(struct ips_driver *ips) 802 + { 803 + u16 ret; 804 + u64 slope, offset; 805 + u64 val; 806 + 807 + val = thm_readq(THM_MGTV); 808 + val = (val & TV_MASK) >> TV_SHIFT; 809 + 810 + slope = offset = thm_readw(THM_MGTA); 811 + slope = (slope & MGTA_SLOPE_MASK) >> MGTA_SLOPE_SHIFT; 812 + offset = offset & MGTA_OFFSET_MASK; 813 + 814 + ret = ((val * slope + 0x40) >> 7) + offset; 815 + 816 + return 0; /* MCH temp reporting buggy */ 817 + } 818 + 819 + static u16 read_ptv(struct ips_driver *ips) 820 + { 821 + u16 val, slope, offset; 822 + 823 + slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT; 824 + offset = ips->pta_val & PTA_OFFSET_MASK; 825 + 826 + val = thm_readw(THM_PTV) & PTV_MASK; 827 + 828 + return val; 829 + } 830 + 831 + static u16 read_ctv(struct ips_driver *ips, int cpu) 832 + { 833 + int reg = cpu ? THM_CTV2 : THM_CTV1; 834 + u16 val; 835 + 836 + val = thm_readw(reg); 837 + if (!(val & CTV_TEMP_ERROR)) 838 + val = (val) >> 6; /* discard fractional component */ 839 + else 840 + val = 0; 841 + 842 + return val; 843 + } 844 + 845 + static u32 get_cpu_power(struct ips_driver *ips, u32 *last, int period) 846 + { 847 + u32 val; 848 + u32 ret; 849 + 850 + /* 851 + * CEC is in joules/65535. Take difference over time to 852 + * get watts. 853 + */ 854 + val = thm_readl(THM_CEC); 855 + 856 + /* period is in ms and we want mW */ 857 + ret = (((val - *last) * 1000) / period); 858 + ret = (ret * 1000) / 65535; 859 + *last = val; 860 + 861 + return ret; 862 + } 863 + 864 + static const u16 temp_decay_factor = 2; 865 + static u16 update_average_temp(u16 avg, u16 val) 866 + { 867 + u16 ret; 868 + 869 + /* Multiply by 100 for extra precision */ 870 + ret = (val * 100 / temp_decay_factor) + 871 + (((temp_decay_factor - 1) * avg) / temp_decay_factor); 872 + return ret; 873 + } 874 + 875 + static const u16 power_decay_factor = 2; 876 + static u16 update_average_power(u32 avg, u32 val) 877 + { 878 + u32 ret; 879 + 880 + ret = (val / power_decay_factor) + 881 + (((power_decay_factor - 1) * avg) / power_decay_factor); 882 + 883 + return ret; 884 + } 885 + 886 + static u32 calc_avg_power(struct ips_driver *ips, u32 *array) 887 + { 888 + u64 total = 0; 889 + u32 avg; 890 + int i; 891 + 892 + for (i = 0; i < IPS_SAMPLE_COUNT; i++) 893 + total += array[i]; 894 + 895 + do_div(total, IPS_SAMPLE_COUNT); 896 + avg = (u32)total; 897 + 898 + return avg; 899 + } 900 + 901 + static void monitor_timeout(unsigned long arg) 902 + { 903 + wake_up_process((struct task_struct *)arg); 904 + } 905 + 906 + /** 907 + * ips_monitor - temp/power monitoring thread 908 + * @data: ips driver structure 909 + * 910 + * This is the main function for the IPS driver. It monitors power and 911 + * tempurature in the MCP and adjusts CPU and GPU power clams accordingly. 912 + * 913 + * We keep a 5s moving average of power consumption and tempurature. Using 914 + * that data, along with CPU vs GPU preference, we adjust the power clamps 915 + * up or down. 916 + */ 917 + static int ips_monitor(void *data) 918 + { 919 + struct ips_driver *ips = data; 920 + struct timer_list timer; 921 + unsigned long seqno_timestamp, expire, last_msecs, last_sample_period; 922 + int i; 923 + u32 *cpu_samples, *mchp_samples, old_cpu_power; 924 + u16 *mcp_samples, *ctv1_samples, *ctv2_samples, *mch_samples; 925 + u8 cur_seqno, last_seqno; 926 + 927 + mcp_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); 928 + ctv1_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); 929 + ctv2_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); 930 + mch_samples = kzalloc(sizeof(u16) * IPS_SAMPLE_COUNT, GFP_KERNEL); 931 + cpu_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL); 932 + mchp_samples = kzalloc(sizeof(u32) * IPS_SAMPLE_COUNT, GFP_KERNEL); 933 + if (!mcp_samples || !ctv1_samples || !ctv2_samples || !mch_samples || 934 + !cpu_samples || !mchp_samples) { 935 + dev_err(&ips->dev->dev, 936 + "failed to allocate sample array, ips disabled\n"); 937 + kfree(mcp_samples); 938 + kfree(ctv1_samples); 939 + kfree(ctv2_samples); 940 + kfree(mch_samples); 941 + kfree(cpu_samples); 942 + kfree(mchp_samples); 943 + kthread_stop(ips->adjust); 944 + return -ENOMEM; 945 + } 946 + 947 + last_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >> 948 + ITV_ME_SEQNO_SHIFT; 949 + seqno_timestamp = get_jiffies_64(); 950 + 951 + old_cpu_power = thm_readl(THM_CEC) / 65535; 952 + schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD)); 953 + 954 + /* Collect an initial average */ 955 + for (i = 0; i < IPS_SAMPLE_COUNT; i++) { 956 + u32 mchp, cpu_power; 957 + u16 val; 958 + 959 + mcp_samples[i] = read_ptv(ips); 960 + 961 + val = read_ctv(ips, 0); 962 + ctv1_samples[i] = val; 963 + 964 + val = read_ctv(ips, 1); 965 + ctv2_samples[i] = val; 966 + 967 + val = read_mgtv(ips); 968 + mch_samples[i] = val; 969 + 970 + cpu_power = get_cpu_power(ips, &old_cpu_power, 971 + IPS_SAMPLE_PERIOD); 972 + cpu_samples[i] = cpu_power; 973 + 974 + if (ips->read_mch_val) { 975 + mchp = ips->read_mch_val(); 976 + mchp_samples[i] = mchp; 977 + } 978 + 979 + schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD)); 980 + if (kthread_should_stop()) 981 + break; 982 + } 983 + 984 + ips->mcp_avg_temp = calc_avg_temp(ips, mcp_samples); 985 + ips->ctv1_avg_temp = calc_avg_temp(ips, ctv1_samples); 986 + ips->ctv2_avg_temp = calc_avg_temp(ips, ctv2_samples); 987 + ips->mch_avg_temp = calc_avg_temp(ips, mch_samples); 988 + ips->cpu_avg_power = calc_avg_power(ips, cpu_samples); 989 + ips->mch_avg_power = calc_avg_power(ips, mchp_samples); 990 + kfree(mcp_samples); 991 + kfree(ctv1_samples); 992 + kfree(ctv2_samples); 993 + kfree(mch_samples); 994 + kfree(cpu_samples); 995 + kfree(mchp_samples); 996 + 997 + /* Start the adjustment thread now that we have data */ 998 + wake_up_process(ips->adjust); 999 + 1000 + /* 1001 + * Ok, now we have an initial avg. From here on out, we track the 1002 + * running avg using a decaying average calculation. This allows 1003 + * us to reduce the sample frequency if the CPU and GPU are idle. 1004 + */ 1005 + old_cpu_power = thm_readl(THM_CEC); 1006 + schedule_timeout_interruptible(msecs_to_jiffies(IPS_SAMPLE_PERIOD)); 1007 + last_sample_period = IPS_SAMPLE_PERIOD; 1008 + 1009 + setup_deferrable_timer_on_stack(&timer, monitor_timeout, 1010 + (unsigned long)current); 1011 + do { 1012 + u32 cpu_val, mch_val; 1013 + u16 val; 1014 + 1015 + /* MCP itself */ 1016 + val = read_ptv(ips); 1017 + ips->mcp_avg_temp = update_average_temp(ips->mcp_avg_temp, val); 1018 + 1019 + /* Processor 0 */ 1020 + val = read_ctv(ips, 0); 1021 + ips->ctv1_avg_temp = 1022 + update_average_temp(ips->ctv1_avg_temp, val); 1023 + /* Power */ 1024 + cpu_val = get_cpu_power(ips, &old_cpu_power, 1025 + last_sample_period); 1026 + ips->cpu_avg_power = 1027 + update_average_power(ips->cpu_avg_power, cpu_val); 1028 + 1029 + if (ips->second_cpu) { 1030 + /* Processor 1 */ 1031 + val = read_ctv(ips, 1); 1032 + ips->ctv2_avg_temp = 1033 + update_average_temp(ips->ctv2_avg_temp, val); 1034 + } 1035 + 1036 + /* MCH */ 1037 + val = read_mgtv(ips); 1038 + ips->mch_avg_temp = update_average_temp(ips->mch_avg_temp, val); 1039 + /* Power */ 1040 + if (ips->read_mch_val) { 1041 + mch_val = ips->read_mch_val(); 1042 + ips->mch_avg_power = 1043 + update_average_power(ips->mch_avg_power, 1044 + mch_val); 1045 + } 1046 + 1047 + /* 1048 + * Make sure ME is updating thermal regs. 1049 + * Note: 1050 + * If it's been more than a second since the last update, 1051 + * the ME is probably hung. 1052 + */ 1053 + cur_seqno = (thm_readl(THM_ITV) & ITV_ME_SEQNO_MASK) >> 1054 + ITV_ME_SEQNO_SHIFT; 1055 + if (cur_seqno == last_seqno && 1056 + time_after(jiffies, seqno_timestamp + HZ)) { 1057 + dev_warn(&ips->dev->dev, "ME failed to update for more than 1s, likely hung\n"); 1058 + } else { 1059 + seqno_timestamp = get_jiffies_64(); 1060 + last_seqno = cur_seqno; 1061 + } 1062 + 1063 + last_msecs = jiffies_to_msecs(jiffies); 1064 + expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); 1065 + 1066 + __set_current_state(TASK_UNINTERRUPTIBLE); 1067 + mod_timer(&timer, expire); 1068 + schedule(); 1069 + 1070 + /* Calculate actual sample period for power averaging */ 1071 + last_sample_period = jiffies_to_msecs(jiffies) - last_msecs; 1072 + if (!last_sample_period) 1073 + last_sample_period = 1; 1074 + } while (!kthread_should_stop()); 1075 + 1076 + del_timer_sync(&timer); 1077 + destroy_timer_on_stack(&timer); 1078 + 1079 + dev_dbg(&ips->dev->dev, "ips-monitor thread stopped\n"); 1080 + 1081 + return 0; 1082 + } 1083 + 1084 + #if 0 1085 + #define THM_DUMPW(reg) \ 1086 + { \ 1087 + u16 val = thm_readw(reg); \ 1088 + dev_dbg(&ips->dev->dev, #reg ": 0x%04x\n", val); \ 1089 + } 1090 + #define THM_DUMPL(reg) \ 1091 + { \ 1092 + u32 val = thm_readl(reg); \ 1093 + dev_dbg(&ips->dev->dev, #reg ": 0x%08x\n", val); \ 1094 + } 1095 + #define THM_DUMPQ(reg) \ 1096 + { \ 1097 + u64 val = thm_readq(reg); \ 1098 + dev_dbg(&ips->dev->dev, #reg ": 0x%016x\n", val); \ 1099 + } 1100 + 1101 + static void dump_thermal_info(struct ips_driver *ips) 1102 + { 1103 + u16 ptl; 1104 + 1105 + ptl = thm_readw(THM_PTL); 1106 + dev_dbg(&ips->dev->dev, "Processor temp limit: %d\n", ptl); 1107 + 1108 + THM_DUMPW(THM_CTA); 1109 + THM_DUMPW(THM_TRC); 1110 + THM_DUMPW(THM_CTV1); 1111 + THM_DUMPL(THM_STS); 1112 + THM_DUMPW(THM_PTV); 1113 + THM_DUMPQ(THM_MGTV); 1114 + } 1115 + #endif 1116 + 1117 + /** 1118 + * ips_irq_handler - handle temperature triggers and other IPS events 1119 + * @irq: irq number 1120 + * @arg: unused 1121 + * 1122 + * Handle temperature limit trigger events, generally by lowering the clamps. 1123 + * If we're at a critical limit, we clamp back to the lowest possible value 1124 + * to prevent emergency shutdown. 1125 + */ 1126 + static irqreturn_t ips_irq_handler(int irq, void *arg) 1127 + { 1128 + struct ips_driver *ips = arg; 1129 + u8 tses = thm_readb(THM_TSES); 1130 + u8 tes = thm_readb(THM_TES); 1131 + 1132 + if (!tses && !tes) 1133 + return IRQ_NONE; 1134 + 1135 + dev_info(&ips->dev->dev, "TSES: 0x%02x\n", tses); 1136 + dev_info(&ips->dev->dev, "TES: 0x%02x\n", tes); 1137 + 1138 + /* STS update from EC? */ 1139 + if (tes & 1) { 1140 + u32 sts, tc1; 1141 + 1142 + sts = thm_readl(THM_STS); 1143 + tc1 = thm_readl(THM_TC1); 1144 + 1145 + if (sts & STS_NVV) { 1146 + spin_lock(&ips->turbo_status_lock); 1147 + ips->core_power_limit = (sts & STS_PCPL_MASK) >> 1148 + STS_PCPL_SHIFT; 1149 + ips->mch_power_limit = (sts & STS_GPL_MASK) >> 1150 + STS_GPL_SHIFT; 1151 + /* ignore EC CPU vs GPU pref */ 1152 + ips->cpu_turbo_enabled = !(sts & STS_PCTD_DIS); 1153 + ips->gpu_turbo_enabled = !(sts & STS_GTD_DIS); 1154 + ips->mcp_temp_limit = (sts & STS_PTL_MASK) >> 1155 + STS_PTL_SHIFT; 1156 + ips->mcp_power_limit = (tc1 & STS_PPL_MASK) >> 1157 + STS_PPL_SHIFT; 1158 + spin_unlock(&ips->turbo_status_lock); 1159 + 1160 + thm_writeb(THM_SEC, SEC_ACK); 1161 + } 1162 + thm_writeb(THM_TES, tes); 1163 + } 1164 + 1165 + /* Thermal trip */ 1166 + if (tses) { 1167 + dev_warn(&ips->dev->dev, 1168 + "thermal trip occurred, tses: 0x%04x\n", tses); 1169 + thm_writeb(THM_TSES, tses); 1170 + } 1171 + 1172 + return IRQ_HANDLED; 1173 + } 1174 + 1175 + #ifndef CONFIG_DEBUG_FS 1176 + static void ips_debugfs_init(struct ips_driver *ips) { return; } 1177 + static void ips_debugfs_cleanup(struct ips_driver *ips) { return; } 1178 + #else 1179 + 1180 + /* Expose current state and limits in debugfs if possible */ 1181 + 1182 + struct ips_debugfs_node { 1183 + struct ips_driver *ips; 1184 + char *name; 1185 + int (*show)(struct seq_file *m, void *data); 1186 + }; 1187 + 1188 + static int show_cpu_temp(struct seq_file *m, void *data) 1189 + { 1190 + struct ips_driver *ips = m->private; 1191 + 1192 + seq_printf(m, "%d.%02d\n", ips->ctv1_avg_temp / 100, 1193 + ips->ctv1_avg_temp % 100); 1194 + 1195 + return 0; 1196 + } 1197 + 1198 + static int show_cpu_power(struct seq_file *m, void *data) 1199 + { 1200 + struct ips_driver *ips = m->private; 1201 + 1202 + seq_printf(m, "%dmW\n", ips->cpu_avg_power); 1203 + 1204 + return 0; 1205 + } 1206 + 1207 + static int show_cpu_clamp(struct seq_file *m, void *data) 1208 + { 1209 + u64 turbo_override; 1210 + int tdp, tdc; 1211 + 1212 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 1213 + 1214 + tdp = (int)(turbo_override & TURBO_TDP_MASK); 1215 + tdc = (int)((turbo_override & TURBO_TDC_MASK) >> TURBO_TDC_SHIFT); 1216 + 1217 + /* Convert to .1W/A units */ 1218 + tdp = tdp * 10 / 8; 1219 + tdc = tdc * 10 / 8; 1220 + 1221 + /* Watts Amperes */ 1222 + seq_printf(m, "%d.%dW %d.%dA\n", tdp / 10, tdp % 10, 1223 + tdc / 10, tdc % 10); 1224 + 1225 + return 0; 1226 + } 1227 + 1228 + static int show_mch_temp(struct seq_file *m, void *data) 1229 + { 1230 + struct ips_driver *ips = m->private; 1231 + 1232 + seq_printf(m, "%d.%02d\n", ips->mch_avg_temp / 100, 1233 + ips->mch_avg_temp % 100); 1234 + 1235 + return 0; 1236 + } 1237 + 1238 + static int show_mch_power(struct seq_file *m, void *data) 1239 + { 1240 + struct ips_driver *ips = m->private; 1241 + 1242 + seq_printf(m, "%dmW\n", ips->mch_avg_power); 1243 + 1244 + return 0; 1245 + } 1246 + 1247 + static struct ips_debugfs_node ips_debug_files[] = { 1248 + { NULL, "cpu_temp", show_cpu_temp }, 1249 + { NULL, "cpu_power", show_cpu_power }, 1250 + { NULL, "cpu_clamp", show_cpu_clamp }, 1251 + { NULL, "mch_temp", show_mch_temp }, 1252 + { NULL, "mch_power", show_mch_power }, 1253 + }; 1254 + 1255 + static int ips_debugfs_open(struct inode *inode, struct file *file) 1256 + { 1257 + struct ips_debugfs_node *node = inode->i_private; 1258 + 1259 + return single_open(file, node->show, node->ips); 1260 + } 1261 + 1262 + static const struct file_operations ips_debugfs_ops = { 1263 + .owner = THIS_MODULE, 1264 + .open = ips_debugfs_open, 1265 + .read = seq_read, 1266 + .llseek = seq_lseek, 1267 + .release = single_release, 1268 + }; 1269 + 1270 + static void ips_debugfs_cleanup(struct ips_driver *ips) 1271 + { 1272 + if (ips->debug_root) 1273 + debugfs_remove_recursive(ips->debug_root); 1274 + return; 1275 + } 1276 + 1277 + static void ips_debugfs_init(struct ips_driver *ips) 1278 + { 1279 + int i; 1280 + 1281 + ips->debug_root = debugfs_create_dir("ips", NULL); 1282 + if (!ips->debug_root) { 1283 + dev_err(&ips->dev->dev, 1284 + "failed to create debugfs entries: %ld\n", 1285 + PTR_ERR(ips->debug_root)); 1286 + return; 1287 + } 1288 + 1289 + for (i = 0; i < ARRAY_SIZE(ips_debug_files); i++) { 1290 + struct dentry *ent; 1291 + struct ips_debugfs_node *node = &ips_debug_files[i]; 1292 + 1293 + node->ips = ips; 1294 + ent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, 1295 + ips->debug_root, node, 1296 + &ips_debugfs_ops); 1297 + if (!ent) { 1298 + dev_err(&ips->dev->dev, 1299 + "failed to create debug file: %ld\n", 1300 + PTR_ERR(ent)); 1301 + goto err_cleanup; 1302 + } 1303 + } 1304 + 1305 + return; 1306 + 1307 + err_cleanup: 1308 + ips_debugfs_cleanup(ips); 1309 + return; 1310 + } 1311 + #endif /* CONFIG_DEBUG_FS */ 1312 + 1313 + /** 1314 + * ips_detect_cpu - detect whether CPU supports IPS 1315 + * 1316 + * Walk our list and see if we're on a supported CPU. If we find one, 1317 + * return the limits for it. 1318 + */ 1319 + static struct ips_mcp_limits *ips_detect_cpu(struct ips_driver *ips) 1320 + { 1321 + u64 turbo_power, misc_en; 1322 + struct ips_mcp_limits *limits = NULL; 1323 + u16 tdp; 1324 + 1325 + if (!(boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 37)) { 1326 + dev_info(&ips->dev->dev, "Non-IPS CPU detected.\n"); 1327 + goto out; 1328 + } 1329 + 1330 + rdmsrl(IA32_MISC_ENABLE, misc_en); 1331 + /* 1332 + * If the turbo enable bit isn't set, we shouldn't try to enable/disable 1333 + * turbo manually or we'll get an illegal MSR access, even though 1334 + * turbo will still be available. 1335 + */ 1336 + if (!(misc_en & IA32_MISC_TURBO_EN)) 1337 + ; /* add turbo MSR write allowed flag if necessary */ 1338 + 1339 + if (strstr(boot_cpu_data.x86_model_id, "CPU M")) 1340 + limits = &ips_sv_limits; 1341 + else if (strstr(boot_cpu_data.x86_model_id, "CPU L")) 1342 + limits = &ips_lv_limits; 1343 + else if (strstr(boot_cpu_data.x86_model_id, "CPU U")) 1344 + limits = &ips_ulv_limits; 1345 + else 1346 + dev_info(&ips->dev->dev, "No CPUID match found.\n"); 1347 + 1348 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_power); 1349 + tdp = turbo_power & TURBO_TDP_MASK; 1350 + 1351 + /* Sanity check TDP against CPU */ 1352 + if (limits->mcp_power_limit != (tdp / 8) * 1000) { 1353 + dev_warn(&ips->dev->dev, "Warning: CPU TDP doesn't match expected value (found %d, expected %d)\n", 1354 + tdp / 8, limits->mcp_power_limit / 1000); 1355 + } 1356 + 1357 + out: 1358 + return limits; 1359 + } 1360 + 1361 + /** 1362 + * ips_get_i915_syms - try to get GPU control methods from i915 driver 1363 + * @ips: IPS driver 1364 + * 1365 + * The i915 driver exports several interfaces to allow the IPS driver to 1366 + * monitor and control graphics turbo mode. If we can find them, we can 1367 + * enable graphics turbo, otherwise we must disable it to avoid exceeding 1368 + * thermal and power limits in the MCP. 1369 + */ 1370 + static bool ips_get_i915_syms(struct ips_driver *ips) 1371 + { 1372 + ips->read_mch_val = symbol_get(i915_read_mch_val); 1373 + if (!ips->read_mch_val) 1374 + goto out_err; 1375 + ips->gpu_raise = symbol_get(i915_gpu_raise); 1376 + if (!ips->gpu_raise) 1377 + goto out_put_mch; 1378 + ips->gpu_lower = symbol_get(i915_gpu_lower); 1379 + if (!ips->gpu_lower) 1380 + goto out_put_raise; 1381 + ips->gpu_busy = symbol_get(i915_gpu_busy); 1382 + if (!ips->gpu_busy) 1383 + goto out_put_lower; 1384 + ips->gpu_turbo_disable = symbol_get(i915_gpu_turbo_disable); 1385 + if (!ips->gpu_turbo_disable) 1386 + goto out_put_busy; 1387 + 1388 + return true; 1389 + 1390 + out_put_busy: 1391 + symbol_put(i915_gpu_turbo_disable); 1392 + out_put_lower: 1393 + symbol_put(i915_gpu_lower); 1394 + out_put_raise: 1395 + symbol_put(i915_gpu_raise); 1396 + out_put_mch: 1397 + symbol_put(i915_read_mch_val); 1398 + out_err: 1399 + return false; 1400 + } 1401 + 1402 + static DEFINE_PCI_DEVICE_TABLE(ips_id_table) = { 1403 + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 1404 + PCI_DEVICE_ID_INTEL_THERMAL_SENSOR), }, 1405 + { 0, } 1406 + }; 1407 + 1408 + MODULE_DEVICE_TABLE(pci, ips_id_table); 1409 + 1410 + static int ips_probe(struct pci_dev *dev, const struct pci_device_id *id) 1411 + { 1412 + u64 platform_info; 1413 + struct ips_driver *ips; 1414 + u32 hts; 1415 + int ret = 0; 1416 + u16 htshi, trc, trc_required_mask; 1417 + u8 tse; 1418 + 1419 + ips = kzalloc(sizeof(struct ips_driver), GFP_KERNEL); 1420 + if (!ips) 1421 + return -ENOMEM; 1422 + 1423 + pci_set_drvdata(dev, ips); 1424 + ips->dev = dev; 1425 + 1426 + ips->limits = ips_detect_cpu(ips); 1427 + if (!ips->limits) { 1428 + dev_info(&dev->dev, "IPS not supported on this CPU\n"); 1429 + ret = -ENXIO; 1430 + goto error_free; 1431 + } 1432 + 1433 + spin_lock_init(&ips->turbo_status_lock); 1434 + 1435 + if (!pci_resource_start(dev, 0)) { 1436 + dev_err(&dev->dev, "TBAR not assigned, aborting\n"); 1437 + ret = -ENXIO; 1438 + goto error_free; 1439 + } 1440 + 1441 + ret = pci_request_regions(dev, "ips thermal sensor"); 1442 + if (ret) { 1443 + dev_err(&dev->dev, "thermal resource busy, aborting\n"); 1444 + goto error_free; 1445 + } 1446 + 1447 + ret = pci_enable_device(dev); 1448 + if (ret) { 1449 + dev_err(&dev->dev, "can't enable PCI device, aborting\n"); 1450 + goto error_free; 1451 + } 1452 + 1453 + ips->regmap = ioremap(pci_resource_start(dev, 0), 1454 + pci_resource_len(dev, 0)); 1455 + if (!ips->regmap) { 1456 + dev_err(&dev->dev, "failed to map thermal regs, aborting\n"); 1457 + ret = -EBUSY; 1458 + goto error_release; 1459 + } 1460 + 1461 + tse = thm_readb(THM_TSE); 1462 + if (tse != TSE_EN) { 1463 + dev_err(&dev->dev, "thermal device not enabled (0x%02x), aborting\n", tse); 1464 + ret = -ENXIO; 1465 + goto error_unmap; 1466 + } 1467 + 1468 + trc = thm_readw(THM_TRC); 1469 + trc_required_mask = TRC_CORE1_EN | TRC_CORE_PWR | TRC_MCH_EN; 1470 + if ((trc & trc_required_mask) != trc_required_mask) { 1471 + dev_err(&dev->dev, "thermal reporting for required devices not enabled, aborting\n"); 1472 + ret = -ENXIO; 1473 + goto error_unmap; 1474 + } 1475 + 1476 + if (trc & TRC_CORE2_EN) 1477 + ips->second_cpu = true; 1478 + 1479 + update_turbo_limits(ips); 1480 + dev_dbg(&dev->dev, "max cpu power clamp: %dW\n", 1481 + ips->mcp_power_limit / 10); 1482 + dev_dbg(&dev->dev, "max core power clamp: %dW\n", 1483 + ips->core_power_limit / 10); 1484 + /* BIOS may update limits at runtime */ 1485 + if (thm_readl(THM_PSC) & PSP_PBRT) 1486 + ips->poll_turbo_status = true; 1487 + 1488 + if (!ips_get_i915_syms(ips)) { 1489 + dev_err(&dev->dev, "failed to get i915 symbols, graphics turbo disabled\n"); 1490 + ips->gpu_turbo_enabled = false; 1491 + } else { 1492 + dev_dbg(&dev->dev, "graphics turbo enabled\n"); 1493 + ips->gpu_turbo_enabled = true; 1494 + } 1495 + 1496 + /* 1497 + * Check PLATFORM_INFO MSR to make sure this chip is 1498 + * turbo capable. 1499 + */ 1500 + rdmsrl(PLATFORM_INFO, platform_info); 1501 + if (!(platform_info & PLATFORM_TDP)) { 1502 + dev_err(&dev->dev, "platform indicates TDP override unavailable, aborting\n"); 1503 + ret = -ENODEV; 1504 + goto error_unmap; 1505 + } 1506 + 1507 + /* 1508 + * IRQ handler for ME interaction 1509 + * Note: don't use MSI here as the PCH has bugs. 1510 + */ 1511 + pci_disable_msi(dev); 1512 + ret = request_irq(dev->irq, ips_irq_handler, IRQF_SHARED, "ips", 1513 + ips); 1514 + if (ret) { 1515 + dev_err(&dev->dev, "request irq failed, aborting\n"); 1516 + goto error_unmap; 1517 + } 1518 + 1519 + /* Enable aux, hot & critical interrupts */ 1520 + thm_writeb(THM_TSPIEN, TSPIEN_AUX2_LOHI | TSPIEN_CRIT_LOHI | 1521 + TSPIEN_HOT_LOHI | TSPIEN_AUX_LOHI); 1522 + thm_writeb(THM_TEN, TEN_UPDATE_EN); 1523 + 1524 + /* Collect adjustment values */ 1525 + ips->cta_val = thm_readw(THM_CTA); 1526 + ips->pta_val = thm_readw(THM_PTA); 1527 + ips->mgta_val = thm_readw(THM_MGTA); 1528 + 1529 + /* Save turbo limits & ratios */ 1530 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit); 1531 + 1532 + ips_enable_cpu_turbo(ips); 1533 + ips->cpu_turbo_enabled = true; 1534 + 1535 + /* Set up the work queue and monitor/adjust threads */ 1536 + ips->monitor = kthread_run(ips_monitor, ips, "ips-monitor"); 1537 + if (IS_ERR(ips->monitor)) { 1538 + dev_err(&dev->dev, 1539 + "failed to create thermal monitor thread, aborting\n"); 1540 + ret = -ENOMEM; 1541 + goto error_free_irq; 1542 + } 1543 + 1544 + ips->adjust = kthread_create(ips_adjust, ips, "ips-adjust"); 1545 + if (IS_ERR(ips->adjust)) { 1546 + dev_err(&dev->dev, 1547 + "failed to create thermal adjust thread, aborting\n"); 1548 + ret = -ENOMEM; 1549 + goto error_thread_cleanup; 1550 + } 1551 + 1552 + hts = (ips->core_power_limit << HTS_PCPL_SHIFT) | 1553 + (ips->mcp_temp_limit << HTS_PTL_SHIFT) | HTS_NVV; 1554 + htshi = HTS2_PRST_RUNNING << HTS2_PRST_SHIFT; 1555 + 1556 + thm_writew(THM_HTSHI, htshi); 1557 + thm_writel(THM_HTS, hts); 1558 + 1559 + ips_debugfs_init(ips); 1560 + 1561 + dev_info(&dev->dev, "IPS driver initialized, MCP temp limit %d\n", 1562 + ips->mcp_temp_limit); 1563 + return ret; 1564 + 1565 + error_thread_cleanup: 1566 + kthread_stop(ips->monitor); 1567 + error_free_irq: 1568 + free_irq(ips->dev->irq, ips); 1569 + error_unmap: 1570 + iounmap(ips->regmap); 1571 + error_release: 1572 + pci_release_regions(dev); 1573 + error_free: 1574 + kfree(ips); 1575 + return ret; 1576 + } 1577 + 1578 + static void ips_remove(struct pci_dev *dev) 1579 + { 1580 + struct ips_driver *ips = pci_get_drvdata(dev); 1581 + u64 turbo_override; 1582 + 1583 + if (!ips) 1584 + return; 1585 + 1586 + ips_debugfs_cleanup(ips); 1587 + 1588 + /* Release i915 driver */ 1589 + if (ips->read_mch_val) 1590 + symbol_put(i915_read_mch_val); 1591 + if (ips->gpu_raise) 1592 + symbol_put(i915_gpu_raise); 1593 + if (ips->gpu_lower) 1594 + symbol_put(i915_gpu_lower); 1595 + if (ips->gpu_busy) 1596 + symbol_put(i915_gpu_busy); 1597 + if (ips->gpu_turbo_disable) 1598 + symbol_put(i915_gpu_turbo_disable); 1599 + 1600 + rdmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 1601 + turbo_override &= ~(TURBO_TDC_OVR_EN | TURBO_TDP_OVR_EN); 1602 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, turbo_override); 1603 + wrmsrl(TURBO_POWER_CURRENT_LIMIT, ips->orig_turbo_limit); 1604 + 1605 + free_irq(ips->dev->irq, ips); 1606 + if (ips->adjust) 1607 + kthread_stop(ips->adjust); 1608 + if (ips->monitor) 1609 + kthread_stop(ips->monitor); 1610 + iounmap(ips->regmap); 1611 + pci_release_regions(dev); 1612 + kfree(ips); 1613 + dev_dbg(&dev->dev, "IPS driver removed\n"); 1614 + } 1615 + 1616 + #ifdef CONFIG_PM 1617 + static int ips_suspend(struct pci_dev *dev, pm_message_t state) 1618 + { 1619 + return 0; 1620 + } 1621 + 1622 + static int ips_resume(struct pci_dev *dev) 1623 + { 1624 + return 0; 1625 + } 1626 + #else 1627 + #define ips_suspend NULL 1628 + #define ips_resume NULL 1629 + #endif /* CONFIG_PM */ 1630 + 1631 + static void ips_shutdown(struct pci_dev *dev) 1632 + { 1633 + } 1634 + 1635 + static struct pci_driver ips_pci_driver = { 1636 + .name = "intel ips", 1637 + .id_table = ips_id_table, 1638 + .probe = ips_probe, 1639 + .remove = ips_remove, 1640 + .suspend = ips_suspend, 1641 + .resume = ips_resume, 1642 + .shutdown = ips_shutdown, 1643 + }; 1644 + 1645 + static int __init ips_init(void) 1646 + { 1647 + return pci_register_driver(&ips_pci_driver); 1648 + } 1649 + module_init(ips_init); 1650 + 1651 + static void ips_exit(void) 1652 + { 1653 + pci_unregister_driver(&ips_pci_driver); 1654 + return; 1655 + } 1656 + module_exit(ips_exit); 1657 + 1658 + MODULE_LICENSE("GPL"); 1659 + MODULE_AUTHOR("Jesse Barnes <jbarnes@virtuousgeek.org>"); 1660 + MODULE_DESCRIPTION("Intelligent Power Sharing Driver");
+22 -11
drivers/platform/x86/intel_menlow.c
··· 53 #define MEMORY_ARG_CUR_BANDWIDTH 1 54 #define MEMORY_ARG_MAX_BANDWIDTH 0 55 56 /* 57 * GTHS returning 'n' would mean that [0,n-1] states are supported 58 * In that case max_cstate would be n-1 ··· 408 attr->handle = handle; 409 410 result = device_create_file(dev, &attr->attr); 411 - if (result) 412 return result; 413 414 mutex_lock(&intel_menlow_attr_lock); 415 list_add_tail(&attr->node, &intel_menlow_attr_list); ··· 435 /* _TZ must have the AUX0/1 methods */ 436 status = acpi_get_handle(handle, GET_AUX0, &dummy); 437 if (ACPI_FAILURE(status)) 438 - goto not_found; 439 440 status = acpi_get_handle(handle, SET_AUX0, &dummy); 441 if (ACPI_FAILURE(status)) 442 - goto not_found; 443 444 result = intel_menlow_add_one_attribute("aux0", 0644, 445 aux0_show, aux0_store, ··· 449 450 status = acpi_get_handle(handle, GET_AUX1, &dummy); 451 if (ACPI_FAILURE(status)) 452 - goto not_found; 453 454 status = acpi_get_handle(handle, SET_AUX1, &dummy); 455 if (ACPI_FAILURE(status)) 456 - goto not_found; 457 458 result = intel_menlow_add_one_attribute("aux1", 0644, 459 aux1_show, aux1_store, 460 &thermal->device, handle); 461 - if (result) 462 return AE_ERROR; 463 464 /* 465 * create the "dabney_enabled" attribute which means the user app ··· 471 result = intel_menlow_add_one_attribute("bios_enabled", 0444, 472 bios_enabled_show, NULL, 473 &thermal->device, handle); 474 - if (result) 475 return AE_ERROR; 476 477 - not_found: 478 if (status == AE_NOT_FOUND) 479 return AE_OK; 480 - else 481 - return status; 482 } 483 484 static void intel_menlow_unregister_sensor(void) ··· 522 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, 523 ACPI_UINT32_MAX, 524 intel_menlow_register_sensor, NULL, NULL, NULL); 525 - if (ACPI_FAILURE(status)) 526 return -ENODEV; 527 528 return 0; 529 }
··· 53 #define MEMORY_ARG_CUR_BANDWIDTH 1 54 #define MEMORY_ARG_MAX_BANDWIDTH 0 55 56 + static void intel_menlow_unregister_sensor(void); 57 + 58 /* 59 * GTHS returning 'n' would mean that [0,n-1] states are supported 60 * In that case max_cstate would be n-1 ··· 406 attr->handle = handle; 407 408 result = device_create_file(dev, &attr->attr); 409 + if (result) { 410 + kfree(attr); 411 return result; 412 + } 413 414 mutex_lock(&intel_menlow_attr_lock); 415 list_add_tail(&attr->node, &intel_menlow_attr_list); ··· 431 /* _TZ must have the AUX0/1 methods */ 432 status = acpi_get_handle(handle, GET_AUX0, &dummy); 433 if (ACPI_FAILURE(status)) 434 + return (status == AE_NOT_FOUND) ? AE_OK : status; 435 436 status = acpi_get_handle(handle, SET_AUX0, &dummy); 437 if (ACPI_FAILURE(status)) 438 + return (status == AE_NOT_FOUND) ? AE_OK : status; 439 440 result = intel_menlow_add_one_attribute("aux0", 0644, 441 aux0_show, aux0_store, ··· 445 446 status = acpi_get_handle(handle, GET_AUX1, &dummy); 447 if (ACPI_FAILURE(status)) 448 + goto aux1_not_found; 449 450 status = acpi_get_handle(handle, SET_AUX1, &dummy); 451 if (ACPI_FAILURE(status)) 452 + goto aux1_not_found; 453 454 result = intel_menlow_add_one_attribute("aux1", 0644, 455 aux1_show, aux1_store, 456 &thermal->device, handle); 457 + if (result) { 458 + intel_menlow_unregister_sensor(); 459 return AE_ERROR; 460 + } 461 462 /* 463 * create the "dabney_enabled" attribute which means the user app ··· 465 result = intel_menlow_add_one_attribute("bios_enabled", 0444, 466 bios_enabled_show, NULL, 467 &thermal->device, handle); 468 + if (result) { 469 + intel_menlow_unregister_sensor(); 470 return AE_ERROR; 471 + } 472 473 + aux1_not_found: 474 if (status == AE_NOT_FOUND) 475 return AE_OK; 476 + 477 + intel_menlow_unregister_sensor(); 478 + return status; 479 } 480 481 static void intel_menlow_unregister_sensor(void) ··· 513 status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT, 514 ACPI_UINT32_MAX, 515 intel_menlow_register_sensor, NULL, NULL, NULL); 516 + if (ACPI_FAILURE(status)) { 517 + acpi_bus_unregister_driver(&intel_menlow_memory_driver); 518 return -ENODEV; 519 + } 520 521 return 0; 522 }
+340
drivers/platform/x86/intel_pmic_gpio.c
···
··· 1 + /* Moorestown PMIC GPIO (access through IPC) driver 2 + * Copyright (c) 2008 - 2009, Intel Corporation. 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 + * GNU General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public License 14 + * along with this program; if not, write to the Free Software 15 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 16 + */ 17 + 18 + /* Supports: 19 + * Moorestown platform PMIC chip 20 + */ 21 + 22 + #include <linux/module.h> 23 + #include <linux/kernel.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/delay.h> 26 + #include <linux/stddef.h> 27 + #include <linux/slab.h> 28 + #include <linux/ioport.h> 29 + #include <linux/init.h> 30 + #include <linux/io.h> 31 + #include <linux/gpio.h> 32 + #include <linux/interrupt.h> 33 + #include <asm/intel_scu_ipc.h> 34 + #include <linux/device.h> 35 + #include <linux/intel_pmic_gpio.h> 36 + #include <linux/platform_device.h> 37 + 38 + #define DRIVER_NAME "pmic_gpio" 39 + 40 + /* register offset that IPC driver should use 41 + * 8 GPIO + 8 GPOSW (6 controllable) + 8GPO 42 + */ 43 + enum pmic_gpio_register { 44 + GPIO0 = 0xE0, 45 + GPIO7 = 0xE7, 46 + GPIOINT = 0xE8, 47 + GPOSWCTL0 = 0xEC, 48 + GPOSWCTL5 = 0xF1, 49 + GPO = 0xF4, 50 + }; 51 + 52 + /* bits definition for GPIO & GPOSW */ 53 + #define GPIO_DRV 0x01 54 + #define GPIO_DIR 0x02 55 + #define GPIO_DIN 0x04 56 + #define GPIO_DOU 0x08 57 + #define GPIO_INTCTL 0x30 58 + #define GPIO_DBC 0xc0 59 + 60 + #define GPOSW_DRV 0x01 61 + #define GPOSW_DOU 0x08 62 + #define GPOSW_RDRV 0x30 63 + 64 + 65 + #define NUM_GPIO 24 66 + 67 + struct pmic_gpio_irq { 68 + spinlock_t lock; 69 + u32 trigger[NUM_GPIO]; 70 + u32 dirty; 71 + struct work_struct work; 72 + }; 73 + 74 + 75 + struct pmic_gpio { 76 + struct gpio_chip chip; 77 + struct pmic_gpio_irq irqtypes; 78 + void *gpiointr; 79 + int irq; 80 + unsigned irq_base; 81 + }; 82 + 83 + static void pmic_program_irqtype(int gpio, int type) 84 + { 85 + if (type & IRQ_TYPE_EDGE_RISING) 86 + intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); 87 + else 88 + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); 89 + 90 + if (type & IRQ_TYPE_EDGE_FALLING) 91 + intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); 92 + else 93 + intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); 94 + }; 95 + 96 + static void pmic_irqtype_work(struct work_struct *work) 97 + { 98 + struct pmic_gpio_irq *t = 99 + container_of(work, struct pmic_gpio_irq, work); 100 + unsigned long flags; 101 + int i; 102 + u16 type; 103 + 104 + spin_lock_irqsave(&t->lock, flags); 105 + /* As we drop the lock, we may need multiple scans if we race the 106 + pmic_irq_type function */ 107 + while (t->dirty) { 108 + /* 109 + * For each pin that has the dirty bit set send an IPC 110 + * message to configure the hardware via the PMIC 111 + */ 112 + for (i = 0; i < NUM_GPIO; i++) { 113 + if (!(t->dirty & (1 << i))) 114 + continue; 115 + t->dirty &= ~(1 << i); 116 + /* We can't trust the array entry or dirty 117 + once the lock is dropped */ 118 + type = t->trigger[i]; 119 + spin_unlock_irqrestore(&t->lock, flags); 120 + pmic_program_irqtype(i, type); 121 + spin_lock_irqsave(&t->lock, flags); 122 + } 123 + } 124 + spin_unlock_irqrestore(&t->lock, flags); 125 + } 126 + 127 + static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 128 + { 129 + if (offset > 8) { 130 + printk(KERN_ERR 131 + "%s: only pin 0-7 support input\n", __func__); 132 + return -1;/* we only have 8 GPIO can use as input */ 133 + } 134 + return intel_scu_ipc_update_register(GPIO0 + offset, 135 + GPIO_DIR, GPIO_DIR); 136 + } 137 + 138 + static int pmic_gpio_direction_output(struct gpio_chip *chip, 139 + unsigned offset, int value) 140 + { 141 + int rc = 0; 142 + 143 + if (offset < 8)/* it is GPIO */ 144 + rc = intel_scu_ipc_update_register(GPIO0 + offset, 145 + GPIO_DRV | GPIO_DOU | GPIO_DIR, 146 + GPIO_DRV | (value ? GPIO_DOU : 0)); 147 + else if (offset < 16)/* it is GPOSW */ 148 + rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, 149 + GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV, 150 + GPOSW_DRV | (value ? GPOSW_DOU : 0)); 151 + else if (offset > 15 && offset < 24)/* it is GPO */ 152 + rc = intel_scu_ipc_update_register(GPO, 153 + 1 << (offset - 16), 154 + value ? 1 << (offset - 16) : 0); 155 + else { 156 + printk(KERN_ERR 157 + "%s: invalid PMIC GPIO pin %d!\n", __func__, offset); 158 + WARN_ON(1); 159 + } 160 + 161 + return rc; 162 + } 163 + 164 + static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) 165 + { 166 + u8 r; 167 + int ret; 168 + 169 + /* we only have 8 GPIO pins we can use as input */ 170 + if (offset > 8) 171 + return -EOPNOTSUPP; 172 + ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); 173 + if (ret < 0) 174 + return ret; 175 + return r & GPIO_DIN; 176 + } 177 + 178 + static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 179 + { 180 + if (offset < 8)/* it is GPIO */ 181 + intel_scu_ipc_update_register(GPIO0 + offset, 182 + GPIO_DRV | GPIO_DOU, 183 + GPIO_DRV | (value ? GPIO_DOU : 0)); 184 + else if (offset < 16)/* it is GPOSW */ 185 + intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, 186 + GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV, 187 + GPOSW_DRV | (value ? GPOSW_DOU : 0)); 188 + else if (offset > 15 && offset < 24) /* it is GPO */ 189 + intel_scu_ipc_update_register(GPO, 190 + 1 << (offset - 16), 191 + value ? 1 << (offset - 16) : 0); 192 + } 193 + 194 + static int pmic_irq_type(unsigned irq, unsigned type) 195 + { 196 + struct pmic_gpio *pg = get_irq_chip_data(irq); 197 + u32 gpio = irq - pg->irq_base; 198 + unsigned long flags; 199 + 200 + if (gpio > pg->chip.ngpio) 201 + return -EINVAL; 202 + 203 + spin_lock_irqsave(&pg->irqtypes.lock, flags); 204 + pg->irqtypes.trigger[gpio] = type; 205 + pg->irqtypes.dirty |= (1 << gpio); 206 + spin_unlock_irqrestore(&pg->irqtypes.lock, flags); 207 + schedule_work(&pg->irqtypes.work); 208 + return 0; 209 + } 210 + 211 + 212 + 213 + static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) 214 + { 215 + struct pmic_gpio *pg = container_of(chip, struct pmic_gpio, chip); 216 + 217 + return pg->irq_base + offset; 218 + } 219 + 220 + /* the gpiointr register is read-clear, so just do nothing. */ 221 + static void pmic_irq_unmask(unsigned irq) 222 + { 223 + }; 224 + 225 + static void pmic_irq_mask(unsigned irq) 226 + { 227 + }; 228 + 229 + static struct irq_chip pmic_irqchip = { 230 + .name = "PMIC-GPIO", 231 + .mask = pmic_irq_mask, 232 + .unmask = pmic_irq_unmask, 233 + .set_type = pmic_irq_type, 234 + }; 235 + 236 + static void pmic_irq_handler(unsigned irq, struct irq_desc *desc) 237 + { 238 + struct pmic_gpio *pg = (struct pmic_gpio *)get_irq_data(irq); 239 + u8 intsts = *((u8 *)pg->gpiointr + 4); 240 + int gpio; 241 + 242 + for (gpio = 0; gpio < 8; gpio++) { 243 + if (intsts & (1 << gpio)) { 244 + pr_debug("pmic pin %d triggered\n", gpio); 245 + generic_handle_irq(pg->irq_base + gpio); 246 + } 247 + } 248 + desc->chip->eoi(irq); 249 + } 250 + 251 + static int __devinit platform_pmic_gpio_probe(struct platform_device *pdev) 252 + { 253 + struct device *dev = &pdev->dev; 254 + int irq = platform_get_irq(pdev, 0); 255 + struct intel_pmic_gpio_platform_data *pdata = dev->platform_data; 256 + 257 + struct pmic_gpio *pg; 258 + int retval; 259 + int i; 260 + 261 + if (irq < 0) { 262 + dev_dbg(dev, "no IRQ line\n"); 263 + return -EINVAL; 264 + } 265 + 266 + if (!pdata || !pdata->gpio_base || !pdata->irq_base) { 267 + dev_dbg(dev, "incorrect or missing platform data\n"); 268 + return -EINVAL; 269 + } 270 + 271 + pg = kzalloc(sizeof(*pg), GFP_KERNEL); 272 + if (!pg) 273 + return -ENOMEM; 274 + 275 + dev_set_drvdata(dev, pg); 276 + 277 + pg->irq = irq; 278 + /* setting up SRAM mapping for GPIOINT register */ 279 + pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8); 280 + if (!pg->gpiointr) { 281 + printk(KERN_ERR "%s: Can not map GPIOINT.\n", __func__); 282 + retval = -EINVAL; 283 + goto err2; 284 + } 285 + pg->irq_base = pdata->irq_base; 286 + pg->chip.label = "intel_pmic"; 287 + pg->chip.direction_input = pmic_gpio_direction_input; 288 + pg->chip.direction_output = pmic_gpio_direction_output; 289 + pg->chip.get = pmic_gpio_get; 290 + pg->chip.set = pmic_gpio_set; 291 + pg->chip.to_irq = pmic_gpio_to_irq; 292 + pg->chip.base = pdata->gpio_base; 293 + pg->chip.ngpio = NUM_GPIO; 294 + pg->chip.can_sleep = 1; 295 + pg->chip.dev = dev; 296 + 297 + INIT_WORK(&pg->irqtypes.work, pmic_irqtype_work); 298 + spin_lock_init(&pg->irqtypes.lock); 299 + 300 + pg->chip.dev = dev; 301 + retval = gpiochip_add(&pg->chip); 302 + if (retval) { 303 + printk(KERN_ERR "%s: Can not add pmic gpio chip.\n", __func__); 304 + goto err; 305 + } 306 + set_irq_data(pg->irq, pg); 307 + set_irq_chained_handler(pg->irq, pmic_irq_handler); 308 + for (i = 0; i < 8; i++) { 309 + set_irq_chip_and_handler_name(i + pg->irq_base, &pmic_irqchip, 310 + handle_simple_irq, "demux"); 311 + set_irq_chip_data(i + pg->irq_base, pg); 312 + } 313 + return 0; 314 + err: 315 + iounmap(pg->gpiointr); 316 + err2: 317 + kfree(pg); 318 + return retval; 319 + } 320 + 321 + /* at the same time, register a platform driver 322 + * this supports the sfi 0.81 fw */ 323 + static struct platform_driver platform_pmic_gpio_driver = { 324 + .driver = { 325 + .name = DRIVER_NAME, 326 + .owner = THIS_MODULE, 327 + }, 328 + .probe = platform_pmic_gpio_probe, 329 + }; 330 + 331 + static int __init platform_pmic_gpio_init(void) 332 + { 333 + return platform_driver_register(&platform_pmic_gpio_driver); 334 + } 335 + 336 + subsys_initcall(platform_pmic_gpio_init); 337 + 338 + MODULE_AUTHOR("Alek Du <alek.du@intel.com>"); 339 + MODULE_DESCRIPTION("Intel Moorestown PMIC GPIO driver"); 340 + MODULE_LICENSE("GPL v2");
+52 -128
drivers/platform/x86/intel_scu_ipc.c
··· 23 #include <linux/pm.h> 24 #include <linux/pci.h> 25 #include <linux/interrupt.h> 26 - #include <asm/setup.h> 27 #include <asm/intel_scu_ipc.h> 28 29 /* IPC defines the following message types */ ··· 37 #define IPC_CMD_PCNTRL_W 0 /* Register write */ 38 #define IPC_CMD_PCNTRL_R 1 /* Register read */ 39 #define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */ 40 - 41 - /* Miscelaneous Command ids */ 42 - #define IPC_CMD_INDIRECT_RD 2 /* 32bit indirect read */ 43 - #define IPC_CMD_INDIRECT_WR 5 /* 32bit indirect write */ 44 45 /* 46 * IPC register summary ··· 58 59 #define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ 60 #define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ 61 - #define IPC_WWBUF_SIZE 16 /* IPC Write buffer Size */ 62 - #define IPC_RWBUF_SIZE 16 /* IPC Read buffer Size */ 63 #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ 64 #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ 65 ··· 74 75 static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ 76 77 - static int platform = 1; 78 - module_param(platform, int, 0); 79 - MODULE_PARM_DESC(platform, "1 for moorestown platform"); 80 - 81 - 82 - 83 84 /* 85 * IPC Read Buffer (Read Only): ··· 110 } 111 112 /* 113 - * IPC destination Pointer (Write Only): 114 - * Use content as pointer for destination write 115 - */ 116 - static inline void ipc_write_dptr(u32 data) /* Write dptr data */ 117 - { 118 - writel(data, ipcdev.ipc_base + 0x0C); 119 - } 120 - 121 - /* 122 - * IPC Source Pointer (Write Only): 123 - * Use content as pointer for read location 124 - */ 125 - static inline void ipc_write_sptr(u32 data) /* Write dptr data */ 126 - { 127 - writel(data, ipcdev.ipc_base + 0x08); 128 - } 129 - 130 - /* 131 * Status Register (Read Only): 132 * Driver will read this register to get the ready/busy status of the IPC 133 * block and error status of the IPC command that was just processed by SCU ··· 127 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 128 } 129 130 - static inline u8 ipc_data_readl(u32 offset) /* Read ipc u32 data */ 131 { 132 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 133 } ··· 148 return -ETIMEDOUT; 149 } 150 } 151 - return (status >> 1) & 1; 152 } 153 154 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ 155 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) 156 { 157 - int nc; 158 u32 offset = 0; 159 u32 err = 0; 160 - u8 cbuf[IPC_WWBUF_SIZE] = { '\0' }; 161 u32 *wbuf = (u32 *)&cbuf; 162 163 mutex_lock(&ipclock); 164 if (ipcdev.pdev == NULL) { 165 mutex_unlock(&ipclock); 166 return -ENODEV; 167 } 168 169 - if (platform == 1) { 170 - /* Entry is 4 bytes for read/write, 5 bytes for read modify */ 171 - for (nc = 0; nc < count; nc++) { 172 cbuf[offset] = addr[nc]; 173 cbuf[offset + 1] = addr[nc] >> 8; 174 - if (id != IPC_CMD_PCNTRL_R) 175 - cbuf[offset + 2] = data[nc]; 176 - if (id == IPC_CMD_PCNTRL_M) { 177 - cbuf[offset + 3] = data[nc + 1]; 178 - offset += 1; 179 - } 180 - offset += 3; 181 } 182 - for (nc = 0, offset = 0; nc < count; nc++, offset += 4) 183 - ipc_data_writel(wbuf[nc], offset); /* Write wbuff */ 184 185 - } else { 186 - for (nc = 0, offset = 0; nc < count; nc++, offset += 2) 187 - ipc_data_writel(addr[nc], offset); /* Write addresses */ 188 - if (id != IPC_CMD_PCNTRL_R) { 189 - for (nc = 0; nc < count; nc++, offset++) 190 - ipc_data_writel(data[nc], offset); /* Write data */ 191 - if (id == IPC_CMD_PCNTRL_M) 192 - ipc_data_writel(data[nc + 1], offset); /* Mask value*/ 193 } 194 } 195 196 - if (id != IPC_CMD_PCNTRL_M) 197 - ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op); 198 - else 199 - ipc_command((count * 4) << 16 | id << 12 | 0 << 8 | op); 200 - 201 err = busy_loop(); 202 - 203 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ 204 /* Workaround: values are read as 0 without memcpy_fromio */ 205 - memcpy_fromio(cbuf, ipcdev.ipc_base + IPC_READ_BUFFER, 16); 206 - if (platform == 1) { 207 for (nc = 0, offset = 2; nc < count; nc++, offset += 3) 208 data[nc] = ipc_data_readb(offset); 209 } else { ··· 389 EXPORT_SYMBOL(intel_scu_ipc_update_register); 390 391 /** 392 - * intel_scu_ipc_register_read - 32bit indirect read 393 - * @addr: register address 394 - * @value: 32bit value return 395 - * 396 - * Performs IA 32 bit indirect read, returns 0 on success, or an 397 - * error code. 398 - * 399 - * Can be used when SCCB(System Controller Configuration Block) register 400 - * HRIM(Honor Restricted IPC Messages) is set (bit 23) 401 - * 402 - * This function may sleep. Locking for SCU accesses is handled for 403 - * the caller. 404 - */ 405 - int intel_scu_ipc_register_read(u32 addr, u32 *value) 406 - { 407 - u32 err = 0; 408 - 409 - mutex_lock(&ipclock); 410 - if (ipcdev.pdev == NULL) { 411 - mutex_unlock(&ipclock); 412 - return -ENODEV; 413 - } 414 - ipc_write_sptr(addr); 415 - ipc_command(4 << 16 | IPC_CMD_INDIRECT_RD); 416 - err = busy_loop(); 417 - *value = ipc_data_readl(0); 418 - mutex_unlock(&ipclock); 419 - return err; 420 - } 421 - EXPORT_SYMBOL(intel_scu_ipc_register_read); 422 - 423 - /** 424 - * intel_scu_ipc_register_write - 32bit indirect write 425 - * @addr: register address 426 - * @value: 32bit value to write 427 - * 428 - * Performs IA 32 bit indirect write, returns 0 on success, or an 429 - * error code. 430 - * 431 - * Can be used when SCCB(System Controller Configuration Block) register 432 - * HRIM(Honor Restricted IPC Messages) is set (bit 23) 433 - * 434 - * This function may sleep. Locking for SCU accesses is handled for 435 - * the caller. 436 - */ 437 - int intel_scu_ipc_register_write(u32 addr, u32 value) 438 - { 439 - u32 err = 0; 440 - 441 - mutex_lock(&ipclock); 442 - if (ipcdev.pdev == NULL) { 443 - mutex_unlock(&ipclock); 444 - return -ENODEV; 445 - } 446 - ipc_write_dptr(addr); 447 - ipc_data_writel(value, 0); 448 - ipc_command(4 << 16 | IPC_CMD_INDIRECT_WR); 449 - err = busy_loop(); 450 - mutex_unlock(&ipclock); 451 - return err; 452 - } 453 - EXPORT_SYMBOL(intel_scu_ipc_register_write); 454 - 455 - /** 456 * intel_scu_ipc_simple_command - send a simple command 457 * @cmd: command 458 * @sub: sub type ··· 444 for (i = 0; i < inlen; i++) 445 ipc_data_writel(*in++, 4 * i); 446 447 - ipc_command((sub << 12) | cmd | (inlen << 18)); 448 err = busy_loop(); 449 450 for (i = 0; i < outlen; i++) ··· 723 724 static const struct pci_device_id pci_ids[] = { 725 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, 726 { 0,} 727 }; 728 MODULE_DEVICE_TABLE(pci, pci_ids); ··· 738 739 static int __init intel_scu_ipc_init(void) 740 { 741 return pci_register_driver(&ipc_driver); 742 } 743
··· 23 #include <linux/pm.h> 24 #include <linux/pci.h> 25 #include <linux/interrupt.h> 26 + #include <asm/mrst.h> 27 #include <asm/intel_scu_ipc.h> 28 29 /* IPC defines the following message types */ ··· 37 #define IPC_CMD_PCNTRL_W 0 /* Register write */ 38 #define IPC_CMD_PCNTRL_R 1 /* Register read */ 39 #define IPC_CMD_PCNTRL_M 2 /* Register read-modify-write */ 40 41 /* 42 * IPC register summary ··· 62 63 #define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ 64 #define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ 65 + #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ 66 + #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ 67 #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ 68 #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ 69 ··· 78 79 static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ 80 81 + static int platform; /* Platform type */ 82 83 /* 84 * IPC Read Buffer (Read Only): ··· 119 } 120 121 /* 122 * Status Register (Read Only): 123 * Driver will read this register to get the ready/busy status of the IPC 124 * block and error status of the IPC command that was just processed by SCU ··· 154 return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 155 } 156 157 + static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */ 158 { 159 return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset); 160 } ··· 175 return -ETIMEDOUT; 176 } 177 } 178 + if ((status >> 1) & 1) 179 + return -EIO; 180 + 181 + return 0; 182 } 183 184 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ 185 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) 186 { 187 + int i, nc, bytes, d; 188 u32 offset = 0; 189 u32 err = 0; 190 + u8 cbuf[IPC_WWBUF_SIZE] = { }; 191 u32 *wbuf = (u32 *)&cbuf; 192 193 mutex_lock(&ipclock); 194 + 195 + memset(cbuf, 0, sizeof(cbuf)); 196 + 197 if (ipcdev.pdev == NULL) { 198 mutex_unlock(&ipclock); 199 return -ENODEV; 200 } 201 202 + if (platform != MRST_CPU_CHIP_PENWELL) { 203 + bytes = 0; 204 + d = 0; 205 + for (i = 0; i < count; i++) { 206 + cbuf[bytes++] = addr[i]; 207 + cbuf[bytes++] = addr[i] >> 8; 208 + if (id != IPC_CMD_PCNTRL_R) 209 + cbuf[bytes++] = data[d++]; 210 + if (id == IPC_CMD_PCNTRL_M) 211 + cbuf[bytes++] = data[d++]; 212 + } 213 + for (i = 0; i < bytes; i += 4) 214 + ipc_data_writel(wbuf[i/4], i); 215 + ipc_command(bytes << 16 | id << 12 | 0 << 8 | op); 216 + } else { 217 + for (nc = 0; nc < count; nc++, offset += 2) { 218 cbuf[offset] = addr[nc]; 219 cbuf[offset + 1] = addr[nc] >> 8; 220 } 221 222 + if (id == IPC_CMD_PCNTRL_R) { 223 + for (nc = 0, offset = 0; nc < count; nc++, offset += 4) 224 + ipc_data_writel(wbuf[nc], offset); 225 + ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); 226 + } else if (id == IPC_CMD_PCNTRL_W) { 227 + for (nc = 0; nc < count; nc++, offset += 1) 228 + cbuf[offset] = data[nc]; 229 + for (nc = 0, offset = 0; nc < count; nc++, offset += 4) 230 + ipc_data_writel(wbuf[nc], offset); 231 + ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); 232 + } else if (id == IPC_CMD_PCNTRL_M) { 233 + cbuf[offset] = data[0]; 234 + cbuf[offset + 1] = data[1]; 235 + ipc_data_writel(wbuf[0], 0); /* Write wbuff */ 236 + ipc_command(4 << 16 | id << 12 | 0 << 8 | op); 237 } 238 } 239 240 err = busy_loop(); 241 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ 242 /* Workaround: values are read as 0 without memcpy_fromio */ 243 + memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); 244 + if (platform != MRST_CPU_CHIP_PENWELL) { 245 for (nc = 0, offset = 2; nc < count; nc++, offset += 3) 246 data[nc] = ipc_data_readb(offset); 247 } else { ··· 405 EXPORT_SYMBOL(intel_scu_ipc_update_register); 406 407 /** 408 * intel_scu_ipc_simple_command - send a simple command 409 * @cmd: command 410 * @sub: sub type ··· 524 for (i = 0; i < inlen; i++) 525 ipc_data_writel(*in++, 4 * i); 526 527 + ipc_command((inlen << 16) | (sub << 12) | cmd); 528 err = busy_loop(); 529 530 for (i = 0; i < outlen; i++) ··· 803 804 static const struct pci_device_id pci_ids[] = { 805 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)}, 806 + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, 807 { 0,} 808 }; 809 MODULE_DEVICE_TABLE(pci, pci_ids); ··· 817 818 static int __init intel_scu_ipc_init(void) 819 { 820 + platform = mrst_identify_cpu(); 821 + if (platform == 0) 822 + return -ENODEV; 823 return pci_register_driver(&ipc_driver); 824 } 825
+4 -4
drivers/platform/x86/msi-laptop.c
··· 434 { 435 printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 436 id->ident); 437 - return 0; 438 } 439 440 static struct dmi_system_id __initdata msi_dmi_table[] = { ··· 562 return 0; 563 } 564 565 - static struct rfkill_ops rfkill_bluetooth_ops = { 566 .set_block = rfkill_bluetooth_set 567 }; 568 569 - static struct rfkill_ops rfkill_wlan_ops = { 570 .set_block = rfkill_wlan_set 571 }; 572 573 - static struct rfkill_ops rfkill_threeg_ops = { 574 .set_block = rfkill_threeg_set 575 }; 576
··· 434 { 435 printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 436 id->ident); 437 + return 1; 438 } 439 440 static struct dmi_system_id __initdata msi_dmi_table[] = { ··· 562 return 0; 563 } 564 565 + static const struct rfkill_ops rfkill_bluetooth_ops = { 566 .set_block = rfkill_bluetooth_set 567 }; 568 569 + static const struct rfkill_ops rfkill_wlan_ops = { 570 .set_block = rfkill_wlan_set 571 }; 572 573 + static const struct rfkill_ops rfkill_threeg_ops = { 574 .set_block = rfkill_threeg_set 575 }; 576
+1 -1
drivers/platform/x86/msi-wmi.c
··· 57 }; 58 static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; 59 60 - struct backlight_device *backlight; 61 62 static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF }; 63
··· 57 }; 58 static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; 59 60 + static struct backlight_device *backlight; 61 62 static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF }; 63
+2 -5
drivers/platform/x86/panasonic-laptop.c
··· 248 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, 249 &params, NULL); 250 251 - return status == AE_OK; 252 } 253 254 static inline int acpi_pcc_get_sqty(struct acpi_device *device) ··· 586 static int acpi_pcc_hotkey_resume(struct acpi_device *device) 587 { 588 struct pcc_acpi *pcc = acpi_driver_data(device); 589 - acpi_status status = AE_OK; 590 591 if (device == NULL || pcc == NULL) 592 return -EINVAL; ··· 593 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n", 594 pcc->sticky_mode)); 595 596 - status = acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode); 597 - 598 - return status == AE_OK ? 0 : -EINVAL; 599 } 600 601 static int acpi_pcc_hotkey_add(struct acpi_device *device)
··· 248 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, 249 &params, NULL); 250 251 + return (status == AE_OK) ? 0 : -EIO; 252 } 253 254 static inline int acpi_pcc_get_sqty(struct acpi_device *device) ··· 586 static int acpi_pcc_hotkey_resume(struct acpi_device *device) 587 { 588 struct pcc_acpi *pcc = acpi_driver_data(device); 589 590 if (device == NULL || pcc == NULL) 591 return -EINVAL; ··· 594 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Sticky mode restore: %d\n", 595 pcc->sticky_mode)); 596 597 + return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode); 598 } 599 600 static int acpi_pcc_hotkey_add(struct acpi_device *device)
+8 -5
drivers/platform/x86/sony-laptop.c
··· 561 if (!atomic_dec_and_test(&sony_pf_users)) 562 return; 563 564 - platform_device_del(sony_pf_device); 565 - platform_device_put(sony_pf_device); 566 platform_driver_unregister(&sony_pf_driver); 567 } 568 ··· 1195 } 1196 1197 device_enum = (union acpi_object *) buffer.pointer; 1198 - if (!device_enum || device_enum->type != ACPI_TYPE_BUFFER) { 1199 - printk(KERN_ERR "Invalid SN06 return object 0x%.2x\n", 1200 - device_enum->type); 1201 goto out_no_enum; 1202 } 1203
··· 561 if (!atomic_dec_and_test(&sony_pf_users)) 562 return; 563 564 + platform_device_unregister(sony_pf_device); 565 platform_driver_unregister(&sony_pf_driver); 566 } 567 ··· 1196 } 1197 1198 device_enum = (union acpi_object *) buffer.pointer; 1199 + if (!device_enum) { 1200 + pr_err("Invalid SN06 return object\n"); 1201 + goto out_no_enum; 1202 + } 1203 + if (device_enum->type != ACPI_TYPE_BUFFER) { 1204 + pr_err("Invalid SN06 return object type 0x%.2x\n", 1205 + device_enum->type); 1206 goto out_no_enum; 1207 } 1208
-73
drivers/platform/x86/thinkpad_acpi.c
··· 5838 }; 5839 5840 /************************************************************************* 5841 - * EC Dump subdriver 5842 - */ 5843 - 5844 - static u8 ecdump_regs[256]; 5845 - 5846 - static int ecdump_read(struct seq_file *m) 5847 - { 5848 - int i, j; 5849 - u8 v; 5850 - 5851 - seq_printf(m, "EC " 5852 - " +00 +01 +02 +03 +04 +05 +06 +07" 5853 - " +08 +09 +0a +0b +0c +0d +0e +0f\n"); 5854 - for (i = 0; i < 256; i += 16) { 5855 - seq_printf(m, "EC 0x%02x:", i); 5856 - for (j = 0; j < 16; j++) { 5857 - if (!acpi_ec_read(i + j, &v)) 5858 - break; 5859 - if (v != ecdump_regs[i + j]) 5860 - seq_printf(m, " *%02x", v); 5861 - else 5862 - seq_printf(m, " %02x", v); 5863 - ecdump_regs[i + j] = v; 5864 - } 5865 - seq_putc(m, '\n'); 5866 - if (j != 16) 5867 - break; 5868 - } 5869 - 5870 - /* These are way too dangerous to advertise openly... */ 5871 - #if 0 5872 - seq_printf(m, "commands:\t0x<offset> 0x<value>" 5873 - " (<offset> is 00-ff, <value> is 00-ff)\n"); 5874 - seq_printf(m, "commands:\t0x<offset> <value> " 5875 - " (<offset> is 00-ff, <value> is 0-255)\n"); 5876 - #endif 5877 - return 0; 5878 - } 5879 - 5880 - static int ecdump_write(char *buf) 5881 - { 5882 - char *cmd; 5883 - int i, v; 5884 - 5885 - while ((cmd = next_cmd(&buf))) { 5886 - if (sscanf(cmd, "0x%x 0x%x", &i, &v) == 2) { 5887 - /* i and v set */ 5888 - } else if (sscanf(cmd, "0x%x %u", &i, &v) == 2) { 5889 - /* i and v set */ 5890 - } else 5891 - return -EINVAL; 5892 - if (i >= 0 && i < 256 && v >= 0 && v < 256) { 5893 - if (!acpi_ec_write(i, v)) 5894 - return -EIO; 5895 - } else 5896 - return -EINVAL; 5897 - } 5898 - 5899 - return 0; 5900 - } 5901 - 5902 - static struct ibm_struct ecdump_driver_data = { 5903 - .name = "ecdump", 5904 - .read = ecdump_read, 5905 - .write = ecdump_write, 5906 - .flags.experimental = 1, 5907 - }; 5908 - 5909 - /************************************************************************* 5910 * Backlight/brightness subdriver 5911 */ 5912 ··· 8814 .data = &thermal_driver_data, 8815 }, 8816 { 8817 - .data = &ecdump_driver_data, 8818 - }, 8819 - { 8820 .init = brightness_init, 8821 .data = &brightness_driver_data, 8822 }, ··· 8921 TPACPI_PARAM(cmos); 8922 TPACPI_PARAM(led); 8923 TPACPI_PARAM(beep); 8924 - TPACPI_PARAM(ecdump); 8925 TPACPI_PARAM(brightness); 8926 TPACPI_PARAM(volume); 8927 TPACPI_PARAM(fan);
··· 5838 }; 5839 5840 /************************************************************************* 5841 * Backlight/brightness subdriver 5842 */ 5843 ··· 8883 .data = &thermal_driver_data, 8884 }, 8885 { 8886 .init = brightness_init, 8887 .data = &brightness_driver_data, 8888 }, ··· 8993 TPACPI_PARAM(cmos); 8994 TPACPI_PARAM(led); 8995 TPACPI_PARAM(beep); 8996 TPACPI_PARAM(brightness); 8997 TPACPI_PARAM(volume); 8998 TPACPI_PARAM(fan);
+123 -12
drivers/platform/x86/toshiba_acpi.c
··· 4 * 5 * Copyright (C) 2002-2004 John Belmonte 6 * Copyright (C) 2008 Philip Langdale 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by ··· 48 #include <linux/platform_device.h> 49 #include <linux/rfkill.h> 50 #include <linux/input.h> 51 #include <linux/slab.h> 52 53 #include <asm/uaccess.h> ··· 131 132 static struct key_entry toshiba_acpi_keymap[] = { 133 {KE_KEY, 0x101, KEY_MUTE}, 134 {KE_KEY, 0x13b, KEY_COFFEE}, 135 {KE_KEY, 0x13c, KEY_BATTERY}, 136 {KE_KEY, 0x13d, KEY_SLEEP}, ··· 289 struct platform_device *p_dev; 290 struct rfkill *bt_rfk; 291 struct input_dev *hotkey_dev; 292 acpi_handle handle; 293 294 const char *bt_name; 295 296 struct mutex mutex; 297 }; 298 299 static struct toshiba_acpi_dev toshiba_acpi = { ··· 829 830 #define PROC_TOSHIBA "toshiba" 831 832 - static acpi_status __init add_device(void) 833 { 834 proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops); 835 proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops); 836 proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops); 837 proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops); 838 proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops); 839 - 840 - return AE_OK; 841 } 842 843 - static acpi_status remove_device(void) 844 { 845 remove_proc_entry("lcd", toshiba_proc_dir); 846 remove_proc_entry("video", toshiba_proc_dir); 847 remove_proc_entry("fan", toshiba_proc_dir); 848 remove_proc_entry("keys", toshiba_proc_dir); 849 remove_proc_entry("version", toshiba_proc_dir); 850 - return AE_OK; 851 } 852 853 static struct backlight_ops toshiba_backlight_data = { ··· 1012 if (toshiba_backlight_device) 1013 backlight_device_unregister(toshiba_backlight_device); 1014 1015 - remove_device(); 1016 1017 if (toshiba_proc_dir) 1018 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 1019 1020 acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, 1021 toshiba_acpi_notify); 1022 1023 platform_device_unregister(toshiba_acpi.p_dev); 1024 ··· 1030 1031 static int __init toshiba_acpi_init(void) 1032 { 1033 - acpi_status status = AE_OK; 1034 u32 hci_result; 1035 bool bt_present; 1036 int ret = 0; ··· 1077 toshiba_acpi_exit(); 1078 return -ENODEV; 1079 } else { 1080 - status = add_device(); 1081 - if (ACPI_FAILURE(status)) { 1082 - toshiba_acpi_exit(); 1083 - return -ENODEV; 1084 - } 1085 } 1086 1087 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; ··· 1115 toshiba_acpi_exit(); 1116 return ret; 1117 } 1118 } 1119 1120 return 0;
··· 4 * 5 * Copyright (C) 2002-2004 John Belmonte 6 * Copyright (C) 2008 Philip Langdale 7 + * Copyright (C) 2010 Pierre Ducroquet 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by ··· 47 #include <linux/platform_device.h> 48 #include <linux/rfkill.h> 49 #include <linux/input.h> 50 + #include <linux/leds.h> 51 #include <linux/slab.h> 52 53 #include <asm/uaccess.h> ··· 129 130 static struct key_entry toshiba_acpi_keymap[] = { 131 {KE_KEY, 0x101, KEY_MUTE}, 132 + {KE_KEY, 0x102, KEY_ZOOMOUT}, 133 + {KE_KEY, 0x103, KEY_ZOOMIN}, 134 {KE_KEY, 0x13b, KEY_COFFEE}, 135 {KE_KEY, 0x13c, KEY_BATTERY}, 136 {KE_KEY, 0x13d, KEY_SLEEP}, ··· 285 struct platform_device *p_dev; 286 struct rfkill *bt_rfk; 287 struct input_dev *hotkey_dev; 288 + int illumination_installed; 289 acpi_handle handle; 290 291 const char *bt_name; 292 293 struct mutex mutex; 294 + }; 295 + 296 + /* Illumination support */ 297 + static int toshiba_illumination_available(void) 298 + { 299 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 300 + u32 out[HCI_WORDS]; 301 + acpi_status status; 302 + 303 + in[0] = 0xf100; 304 + status = hci_raw(in, out); 305 + if (ACPI_FAILURE(status)) { 306 + printk(MY_INFO "Illumination device not available\n"); 307 + return 0; 308 + } 309 + in[0] = 0xf400; 310 + status = hci_raw(in, out); 311 + return 1; 312 + } 313 + 314 + static void toshiba_illumination_set(struct led_classdev *cdev, 315 + enum led_brightness brightness) 316 + { 317 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 318 + u32 out[HCI_WORDS]; 319 + acpi_status status; 320 + 321 + /* First request : initialize communication. */ 322 + in[0] = 0xf100; 323 + status = hci_raw(in, out); 324 + if (ACPI_FAILURE(status)) { 325 + printk(MY_INFO "Illumination device not available\n"); 326 + return; 327 + } 328 + 329 + if (brightness) { 330 + /* Switch the illumination on */ 331 + in[0] = 0xf400; 332 + in[1] = 0x14e; 333 + in[2] = 1; 334 + status = hci_raw(in, out); 335 + if (ACPI_FAILURE(status)) { 336 + printk(MY_INFO "ACPI call for illumination failed.\n"); 337 + return; 338 + } 339 + } else { 340 + /* Switch the illumination off */ 341 + in[0] = 0xf400; 342 + in[1] = 0x14e; 343 + in[2] = 0; 344 + status = hci_raw(in, out); 345 + if (ACPI_FAILURE(status)) { 346 + printk(MY_INFO "ACPI call for illumination failed.\n"); 347 + return; 348 + } 349 + } 350 + 351 + /* Last request : close communication. */ 352 + in[0] = 0xf200; 353 + in[1] = 0; 354 + in[2] = 0; 355 + hci_raw(in, out); 356 + } 357 + 358 + static enum led_brightness toshiba_illumination_get(struct led_classdev *cdev) 359 + { 360 + u32 in[HCI_WORDS] = { 0, 0, 0, 0, 0, 0 }; 361 + u32 out[HCI_WORDS]; 362 + acpi_status status; 363 + enum led_brightness result; 364 + 365 + /* First request : initialize communication. */ 366 + in[0] = 0xf100; 367 + status = hci_raw(in, out); 368 + if (ACPI_FAILURE(status)) { 369 + printk(MY_INFO "Illumination device not available\n"); 370 + return LED_OFF; 371 + } 372 + 373 + /* Check the illumination */ 374 + in[0] = 0xf300; 375 + in[1] = 0x14e; 376 + status = hci_raw(in, out); 377 + if (ACPI_FAILURE(status)) { 378 + printk(MY_INFO "ACPI call for illumination failed.\n"); 379 + return LED_OFF; 380 + } 381 + 382 + result = out[2] ? LED_FULL : LED_OFF; 383 + 384 + /* Last request : close communication. */ 385 + in[0] = 0xf200; 386 + in[1] = 0; 387 + in[2] = 0; 388 + hci_raw(in, out); 389 + 390 + return result; 391 + } 392 + 393 + static struct led_classdev toshiba_led = { 394 + .name = "toshiba::illumination", 395 + .max_brightness = 1, 396 + .brightness_set = toshiba_illumination_set, 397 + .brightness_get = toshiba_illumination_get, 398 }; 399 400 static struct toshiba_acpi_dev toshiba_acpi = { ··· 720 721 #define PROC_TOSHIBA "toshiba" 722 723 + static void __init create_toshiba_proc_entries(void) 724 { 725 proc_create("lcd", S_IRUGO | S_IWUSR, toshiba_proc_dir, &lcd_proc_fops); 726 proc_create("video", S_IRUGO | S_IWUSR, toshiba_proc_dir, &video_proc_fops); 727 proc_create("fan", S_IRUGO | S_IWUSR, toshiba_proc_dir, &fan_proc_fops); 728 proc_create("keys", S_IRUGO | S_IWUSR, toshiba_proc_dir, &keys_proc_fops); 729 proc_create("version", S_IRUGO, toshiba_proc_dir, &version_proc_fops); 730 } 731 732 + static void remove_toshiba_proc_entries(void) 733 { 734 remove_proc_entry("lcd", toshiba_proc_dir); 735 remove_proc_entry("video", toshiba_proc_dir); 736 remove_proc_entry("fan", toshiba_proc_dir); 737 remove_proc_entry("keys", toshiba_proc_dir); 738 remove_proc_entry("version", toshiba_proc_dir); 739 } 740 741 static struct backlight_ops toshiba_backlight_data = { ··· 906 if (toshiba_backlight_device) 907 backlight_device_unregister(toshiba_backlight_device); 908 909 + remove_toshiba_proc_entries(); 910 911 if (toshiba_proc_dir) 912 remove_proc_entry(PROC_TOSHIBA, acpi_root_dir); 913 914 acpi_remove_notify_handler(toshiba_acpi.handle, ACPI_DEVICE_NOTIFY, 915 toshiba_acpi_notify); 916 + 917 + if (toshiba_acpi.illumination_installed) 918 + led_classdev_unregister(&toshiba_led); 919 920 platform_device_unregister(toshiba_acpi.p_dev); 921 ··· 921 922 static int __init toshiba_acpi_init(void) 923 { 924 u32 hci_result; 925 bool bt_present; 926 int ret = 0; ··· 969 toshiba_acpi_exit(); 970 return -ENODEV; 971 } else { 972 + create_toshiba_proc_entries(); 973 } 974 975 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; ··· 1011 toshiba_acpi_exit(); 1012 return ret; 1013 } 1014 + } 1015 + 1016 + toshiba_acpi.illumination_installed = 0; 1017 + if (toshiba_illumination_available()) { 1018 + if (!led_classdev_register(&(toshiba_acpi.p_dev->dev), 1019 + &toshiba_led)) 1020 + toshiba_acpi.illumination_installed = 1; 1021 } 1022 1023 return 0;
+20 -8
drivers/platform/x86/wmi.c
··· 518 { 519 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 520 union acpi_object *obj; 521 522 - wmi_get_event_data(value, &response); 523 524 obj = (union acpi_object *)response.pointer; 525 ··· 548 default: 549 printk("object type 0x%X\n", obj->type); 550 } 551 } 552 553 /** ··· 810 /* 811 * Parse the _WDG method for the GUID data blocks 812 */ 813 - static __init acpi_status parse_wdg(acpi_handle handle) 814 { 815 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 816 union acpi_object *obj; ··· 833 total = obj->buffer.length / sizeof(struct guid_block); 834 835 gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); 836 - if (!gblock) 837 - return AE_NO_MEMORY; 838 839 for (i = 0; i < total; i++) { 840 /* ··· 856 wmi_dump_wdg(&gblock[i]); 857 858 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 859 - if (!wblock) 860 - return AE_NO_MEMORY; 861 862 wblock->gblock = gblock[i]; 863 wblock->handle = handle; ··· 870 list_add_tail(&wblock->list, &wmi_blocks.list); 871 } 872 873 - kfree(out.pointer); 874 kfree(gblock); 875 876 return status; 877 } ··· 959 return 0; 960 } 961 962 - static int __init acpi_wmi_add(struct acpi_device *device) 963 { 964 acpi_status status; 965 int result = 0;
··· 518 { 519 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 520 union acpi_object *obj; 521 + acpi_status status; 522 523 + status = wmi_get_event_data(value, &response); 524 + if (status != AE_OK) { 525 + printk(KERN_INFO "wmi: bad event status 0x%x\n", status); 526 + return; 527 + } 528 529 obj = (union acpi_object *)response.pointer; 530 ··· 543 default: 544 printk("object type 0x%X\n", obj->type); 545 } 546 + kfree(obj); 547 } 548 549 /** ··· 804 /* 805 * Parse the _WDG method for the GUID data blocks 806 */ 807 + static acpi_status parse_wdg(acpi_handle handle) 808 { 809 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; 810 union acpi_object *obj; ··· 827 total = obj->buffer.length / sizeof(struct guid_block); 828 829 gblock = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); 830 + if (!gblock) { 831 + status = AE_NO_MEMORY; 832 + goto out_free_pointer; 833 + } 834 835 for (i = 0; i < total; i++) { 836 /* ··· 848 wmi_dump_wdg(&gblock[i]); 849 850 wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL); 851 + if (!wblock) { 852 + status = AE_NO_MEMORY; 853 + goto out_free_gblock; 854 + } 855 856 wblock->gblock = gblock[i]; 857 wblock->handle = handle; ··· 860 list_add_tail(&wblock->list, &wmi_blocks.list); 861 } 862 863 + out_free_gblock: 864 kfree(gblock); 865 + out_free_pointer: 866 + kfree(out.pointer); 867 868 return status; 869 } ··· 947 return 0; 948 } 949 950 + static int acpi_wmi_add(struct acpi_device *device) 951 { 952 acpi_status status; 953 int result = 0;
-2
drivers/staging/Kconfig
··· 109 110 source "drivers/staging/vme/Kconfig" 111 112 - source "drivers/staging/rar_register/Kconfig" 113 - 114 source "drivers/staging/memrar/Kconfig" 115 116 source "drivers/staging/sep/Kconfig"
··· 109 110 source "drivers/staging/vme/Kconfig" 111 112 source "drivers/staging/memrar/Kconfig" 113 114 source "drivers/staging/sep/Kconfig"
-1
drivers/staging/Makefile
··· 36 obj-$(CONFIG_FB_UDL) += udlfb/ 37 obj-$(CONFIG_HYPERV) += hv/ 38 obj-$(CONFIG_VME_BUS) += vme/ 39 - obj-$(CONFIG_RAR_REGISTER) += rar_register/ 40 obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ 41 obj-$(CONFIG_DX_SEP) += sep/ 42 obj-$(CONFIG_IIO) += iio/
··· 36 obj-$(CONFIG_FB_UDL) += udlfb/ 37 obj-$(CONFIG_HYPERV) += hv/ 38 obj-$(CONFIG_VME_BUS) += vme/ 39 obj-$(CONFIG_MRST_RAR_HANDLER) += memrar/ 40 obj-$(CONFIG_DX_SEP) += sep/ 41 obj-$(CONFIG_IIO) += iio/
+1 -2
drivers/staging/memrar/memrar_handler.c
··· 47 #include <linux/mm.h> 48 #include <linux/ioport.h> 49 #include <linux/io.h> 50 - 51 - #include "../rar_register/rar_register.h" 52 53 #include "memrar.h" 54 #include "memrar_allocator.h"
··· 47 #include <linux/mm.h> 48 #include <linux/ioport.h> 49 #include <linux/io.h> 50 + #include <linux/rar_register.h> 51 52 #include "memrar.h" 53 #include "memrar_allocator.h"
-30
drivers/staging/rar_register/Kconfig
··· 1 - # 2 - # RAR device configuration 3 - # 4 - 5 - menu "RAR Register Driver" 6 - # 7 - # Restricted Access Register Manager 8 - # 9 - config RAR_REGISTER 10 - tristate "Restricted Access Region Register Driver" 11 - depends on PCI 12 - default n 13 - ---help--- 14 - This driver allows other kernel drivers access to the 15 - contents of the restricted access region control registers. 16 - 17 - The restricted access region control registers 18 - (rar_registers) are used to pass address and 19 - locking information on restricted access regions 20 - to other drivers that use restricted access regions. 21 - 22 - The restricted access regions are regions of memory 23 - on the Intel MID Platform that are not accessible to 24 - the x86 processor, but are accessible to dedicated 25 - processors on board peripheral devices. 26 - 27 - The purpose of the restricted access regions is to 28 - protect sensitive data from compromise by unauthorized 29 - programs running on the x86 processor. 30 - endmenu
···
-2
drivers/staging/rar_register/Makefile
··· 1 - EXTRA_CFLAGS += -DLITTLE__ENDIAN 2 - obj-$(CONFIG_RAR_REGISTER) += rar_register.o
···
+2 -6
drivers/staging/rar_register/rar_register.c drivers/platform/x86/intel_rar_register.c
··· 40 * Initial publish 41 */ 42 43 - #define DEBUG 1 44 - 45 - #include "rar_register.h" 46 - 47 #include <linux/module.h> 48 #include <linux/pci.h> 49 #include <linux/spinlock.h> 50 #include <linux/device.h> 51 #include <linux/kernel.h> 52 53 /* === Lincroft Message Bus Interface === */ 54 #define LNC_MCR_OFFSET 0xD0 /* Message Control Register */ ··· 151 } 152 return NULL; 153 } 154 - 155 156 /** 157 * rar_to_device - return the device handling this RAR ··· 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 an error code on failure. 496 */ 497 int register_rar(int num, int (*callback)(unsigned long data), 498 unsigned long data)
··· 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 */ ··· 154 } 155 return NULL; 156 } 157 158 /** 159 * rar_to_device - return the device handling this RAR ··· 496 * a driver that do require a valid RAR address. One of those 497 * steps would be to call rar_get_address() 498 * 499 + * This function return 0 on success or an error code on failure. 500 */ 501 int register_rar(int num, int (*callback)(unsigned long data), 502 unsigned long data)
drivers/staging/rar_register/rar_register.h include/linux/rar_register.h
+9
include/drm/i915_drm.h
··· 33 * subject to backwards-compatibility constraints. 34 */ 35 36 /* Each region is a minimum of 16k, and there are at most 255 of them. 37 */ 38 #define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
··· 33 * subject to backwards-compatibility constraints. 34 */ 35 36 + #ifdef __KERNEL__ 37 + /* For use by IPS driver */ 38 + extern unsigned long i915_read_mch_val(void); 39 + extern bool i915_gpu_raise(void); 40 + extern bool i915_gpu_lower(void); 41 + extern bool i915_gpu_busy(void); 42 + extern bool i915_gpu_turbo_disable(void); 43 + #endif 44 + 45 /* Each region is a minimum of 16k, and there are at most 255 of them. 46 */ 47 #define I915_NR_TEX_REGIONS 255 /* table size 2k - maximum due to use
+15
include/linux/intel_pmic_gpio.h
···
··· 1 + #ifndef LINUX_INTEL_PMIC_H 2 + #define LINUX_INTEL_PMIC_H 3 + 4 + struct intel_pmic_gpio_platform_data { 5 + /* the first IRQ of the chip */ 6 + unsigned irq_base; 7 + /* number assigned to the first GPIO */ 8 + unsigned gpio_base; 9 + /* sram address for gpiointr register, the langwell chip will map 10 + * the PMIC spi GPIO expander's GPIOINTR register in sram. 11 + */ 12 + unsigned gpiointr; 13 + }; 14 + 15 + #endif
+15
include/linux/timer.h
··· 100 setup_timer_on_stack_key((timer), #timer, &__key, \ 101 (fn), (data)); \ 102 } while (0) 103 #else 104 #define init_timer(timer)\ 105 init_timer_key((timer), NULL, NULL) ··· 118 setup_timer_key((timer), NULL, NULL, (fn), (data)) 119 #define setup_timer_on_stack(timer, fn, data)\ 120 setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data)) 121 #endif 122 123 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS ··· 158 timer->data = data; 159 init_timer_on_stack_key(timer, name, key); 160 } 161 162 /** 163 * timer_pending - is a timer pending?
··· 100 setup_timer_on_stack_key((timer), #timer, &__key, \ 101 (fn), (data)); \ 102 } while (0) 103 + #define setup_deferrable_timer_on_stack(timer, fn, data) \ 104 + do { \ 105 + static struct lock_class_key __key; \ 106 + setup_deferrable_timer_on_stack_key((timer), #timer, \ 107 + &__key, (fn), \ 108 + (data)); \ 109 + } while (0) 110 #else 111 #define init_timer(timer)\ 112 init_timer_key((timer), NULL, NULL) ··· 111 setup_timer_key((timer), NULL, NULL, (fn), (data)) 112 #define setup_timer_on_stack(timer, fn, data)\ 113 setup_timer_on_stack_key((timer), NULL, NULL, (fn), (data)) 114 + #define setup_deferrable_timer_on_stack(timer, fn, data)\ 115 + setup_deferrable_timer_on_stack_key((timer), NULL, NULL, (fn), (data)) 116 #endif 117 118 #ifdef CONFIG_DEBUG_OBJECTS_TIMERS ··· 149 timer->data = data; 150 init_timer_on_stack_key(timer, name, key); 151 } 152 + 153 + extern void setup_deferrable_timer_on_stack_key(struct timer_list *timer, 154 + const char *name, 155 + struct lock_class_key *key, 156 + void (*function)(unsigned long), 157 + unsigned long data); 158 159 /** 160 * timer_pending - is a timer pending?
+13
kernel/timer.c
··· 577 lockdep_init_map(&timer->lockdep_map, name, key, 0); 578 } 579 580 /** 581 * init_timer_key - initialize a timer 582 * @timer: the timer to be initialized
··· 577 lockdep_init_map(&timer->lockdep_map, name, key, 0); 578 } 579 580 + void setup_deferrable_timer_on_stack_key(struct timer_list *timer, 581 + const char *name, 582 + struct lock_class_key *key, 583 + void (*function)(unsigned long), 584 + unsigned long data) 585 + { 586 + timer->function = function; 587 + timer->data = data; 588 + init_timer_on_stack_key(timer, name, key); 589 + timer_set_deferrable(timer); 590 + } 591 + EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key); 592 + 593 /** 594 * init_timer_key - initialize a timer 595 * @timer: the timer to be initialized