]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'drivers-x86/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 03:21:15 +0000 (14:21 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Thu, 5 Nov 2015 03:21:15 +0000 (14:21 +1100)
12 files changed:
MAINTAINERS
drivers/platform/olpc/olpc-ec.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/toshiba-wmi.c [new file with mode: 0644]
drivers/platform/x86/toshiba_acpi.c

index 68663e8dc10ee0c65fc308ff511b438fa54f53e0..d99d47c8c2f8695ce31161bcc5b1939ee27867f5 100644 (file)
@@ -10687,6 +10687,12 @@ L:     platform-driver-x86@vger.kernel.org
 S:     Maintained
 F:     drivers/platform/x86/toshiba_haps.c
 
+TOSHIBA WMI HOTKEYS DRIVER
+M:     Azael Avalos <coproscefalo@gmail.com>
+L:     platform-driver-x86@vger.kernel.org
+S:     Maintained
+F:     drivers/platform/x86/toshiba-wmi.c
+
 TOSHIBA SMM DRIVER
 M:     Jonathan Buzzard <jonathan@buzzard.org.uk>
 W:     http://www.buzzard.org.uk/toshiba/
@@ -11624,6 +11630,7 @@ L:      platform-driver-x86@vger.kernel.org
 T:     git git://git.infradead.org/users/dvhart/linux-platform-drivers-x86.git
 S:     Maintained
 F:     drivers/platform/x86/
+F:     drivers/platform/olpc/
 
 X86 MCE INFRASTRUCTURE
 M:     Tony Luck <tony.luck@intel.com>
index f9119525f5570c2d041d563c0eefbc9a01e32c20..f99b183d5296f7981c9cfbf3bb25d5f5c236e46f 100644 (file)
@@ -192,18 +192,15 @@ static ssize_t ec_dbgfs_cmd_write(struct file *file, const char __user *buf,
        for (i = 0; i <= ec_cmd_bytes; i++)
                ec_cmd[i] = ec_cmd_int[i];
 
-       pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %02x %02x %02x %02x %02x, want %d returns\n",
-                       ec_cmd[0], ec_cmd_bytes, ec_cmd[1], ec_cmd[2],
-                       ec_cmd[3], ec_cmd[4], ec_cmd[5], ec_dbgfs_resp_bytes);
+       pr_debug("olpc-ec: debugfs cmd 0x%02x with %d args %5ph, want %d returns\n",
+                       ec_cmd[0], ec_cmd_bytes, ec_cmd + 1,
+                       ec_dbgfs_resp_bytes);
 
        olpc_ec_cmd(ec_cmd[0], (ec_cmd_bytes == 0) ? NULL : &ec_cmd[1],
                        ec_cmd_bytes, ec_dbgfs_resp, ec_dbgfs_resp_bytes);
 
-       pr_debug("olpc-ec: response %02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n",
-                       ec_dbgfs_resp[0], ec_dbgfs_resp[1], ec_dbgfs_resp[2],
-                       ec_dbgfs_resp[3], ec_dbgfs_resp[4], ec_dbgfs_resp[5],
-                       ec_dbgfs_resp[6], ec_dbgfs_resp[7],
-                       ec_dbgfs_resp_bytes);
+       pr_debug("olpc-ec: response %8ph (%d bytes expected)\n",
+                       ec_dbgfs_resp, ec_dbgfs_resp_bytes);
 
 out:
        mutex_unlock(&ec_dbgfs_lock);
index 744cb80fccbc7eb67f13d6ae5be560eb0fc7f334..02bbc70c332dd8fb2d241974e5e41f140aa8a8c3 100644 (file)
@@ -309,8 +309,8 @@ config COMPAL_LAPTOP
          This is a driver for laptops built by Compal, and some models by
          other brands (e.g. Dell, Toshiba).
 
-         It adds support for rfkill, Bluetooth, WLAN and LCD brightness
-         control.
+         It adds support for rfkill, Bluetooth, WLAN, LCD brightness, hwmon
+         and battery charging level control.
 
          For a (possibly incomplete) list of supported laptops, please refer
          to: Documentation/platform/x86-laptop-drivers.txt
@@ -700,6 +700,24 @@ config TOSHIBA_HAPS
          If you have a recent Toshiba laptop with a built-in accelerometer
          device, say Y.
 
+config TOSHIBA_WMI
+       tristate "Toshiba WMI Hotkeys Driver (EXPERIMENTAL)"
+       default n
+       depends on ACPI_WMI
+       depends on INPUT
+       select INPUT_SPARSEKMAP
+       ---help---
+         This driver adds hotkey monitoring support to some Toshiba models
+         that manage the hotkeys via WMI events.
+
+         WARNING: This driver is incomplete as it lacks a proper keymap and the
+         *notify function only prints the ACPI event type value. Be warned that
+         you will need to provide some information if you have a Toshiba model
+         with WMI event hotkeys and want to help with the develpment of this
+         driver.
+
+         If you have a WMI-based hotkeys Toshiba laptop, say Y or M here.
+
 config ACPI_CMPC
        tristate "CMPC Laptop Extras"
        depends on X86 && ACPI
index ada5128190285c5bad8b5be023811ce9db795339..3ca78a3eb6f84b5030377c5daf31084fb8f7ff75 100644 (file)
@@ -40,6 +40,7 @@ obj-$(CONFIG_ACPI_TOSHIBA)    += toshiba_acpi.o
 
 obj-$(CONFIG_TOSHIBA_BT_RFKILL)        += toshiba_bluetooth.o
 obj-$(CONFIG_TOSHIBA_HAPS)     += toshiba_haps.o
+obj-$(CONFIG_TOSHIBA_WMI)      += toshiba-wmi.o
 obj-$(CONFIG_INTEL_SCU_IPC)    += intel_scu_ipc.o
 obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
index d773b9dc48a0ad889ec9f9142ba0547afbd2bee4..1062fa42ff26c622cd261fc52f797947bf621542 100644 (file)
@@ -1662,58 +1662,6 @@ static void acer_rfkill_exit(void)
        return;
 }
 
-/*
- * sysfs interface
- */
-static ssize_t show_bool_threeg(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       u32 result; \
-       acpi_status status;
-
-       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
-               current->comm);
-       status = get_u32(&result, ACER_CAP_THREEG);
-       if (ACPI_SUCCESS(status))
-               return sprintf(buf, "%u\n", result);
-       return sprintf(buf, "Read error\n");
-}
-
-static ssize_t set_bool_threeg(struct device *dev,
-       struct device_attribute *attr, const char *buf, size_t count)
-{
-       u32 tmp = simple_strtoul(buf, NULL, 10);
-       acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
-       pr_info("This threeg sysfs will be removed in 2014 - used by: %s\n",
-               current->comm);
-       if (ACPI_FAILURE(status))
-               return -EINVAL;
-       return count;
-}
-static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
-       set_bool_threeg);
-
-static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
-       char *buf)
-{
-       pr_info("This interface sysfs will be removed in 2014 - used by: %s\n",
-               current->comm);
-       switch (interface->type) {
-       case ACER_AMW0:
-               return sprintf(buf, "AMW0\n");
-       case ACER_AMW0_V2:
-               return sprintf(buf, "AMW0 v2\n");
-       case ACER_WMID:
-               return sprintf(buf, "WMID\n");
-       case ACER_WMID_v2:
-               return sprintf(buf, "WMID v2\n");
-       default:
-               return sprintf(buf, "Error!\n");
-       }
-}
-
-static DEVICE_ATTR(interface, S_IRUGO, show_interface, NULL);
-
 static void acer_wmi_notify(u32 value, void *context)
 {
        struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -2127,39 +2075,6 @@ static struct platform_driver acer_platform_driver = {
 
 static struct platform_device *acer_platform_device;
 
-static int remove_sysfs(struct platform_device *device)
-{
-       if (has_cap(ACER_CAP_THREEG))
-               device_remove_file(&device->dev, &dev_attr_threeg);
-
-       device_remove_file(&device->dev, &dev_attr_interface);
-
-       return 0;
-}
-
-static int __init create_sysfs(void)
-{
-       int retval = -ENOMEM;
-
-       if (has_cap(ACER_CAP_THREEG)) {
-               retval = device_create_file(&acer_platform_device->dev,
-                       &dev_attr_threeg);
-               if (retval)
-                       goto error_sysfs;
-       }
-
-       retval = device_create_file(&acer_platform_device->dev,
-               &dev_attr_interface);
-       if (retval)
-               goto error_sysfs;
-
-       return 0;
-
-error_sysfs:
-               remove_sysfs(acer_platform_device);
-       return retval;
-}
-
 static void remove_debugfs(void)
 {
        debugfs_remove(interface->debug.devices);
@@ -2290,10 +2205,6 @@ static int __init acer_wmi_init(void)
        if (err)
                goto error_device_add;
 
-       err = create_sysfs();
-       if (err)
-               goto error_create_sys;
-
        if (wmi_has_guid(WMID_GUID2)) {
                interface->debug.wmid_devices = get_wmid_devices();
                err = create_debugfs();
@@ -2307,8 +2218,6 @@ static int __init acer_wmi_init(void)
        return 0;
 
 error_create_debugfs:
-       remove_sysfs(acer_platform_device);
-error_create_sys:
        platform_device_del(acer_platform_device);
 error_device_add:
        platform_device_put(acer_platform_device);
@@ -2331,7 +2240,6 @@ static void __exit acer_wmi_exit(void)
        if (has_cap(ACER_CAP_ACCEL))
                acer_wmi_accel_destroy();
 
-       remove_sysfs(acer_platform_device);
        remove_debugfs();
        platform_device_unregister(acer_platform_device);
        platform_driver_unregister(&acer_platform_driver);
index bb80f7a29496652dbb163e68f58a4668258b4011..e3a750224ae224b2265ef73003f2b28088518d99 100644 (file)
@@ -582,7 +582,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
 
 static int asus_wmi_led_init(struct asus_wmi *asus)
 {
-       int rv = 0;
+       int rv = 0, led_val;
 
        asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
        if (!asus->led_workqueue)
@@ -602,9 +602,11 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
                        goto error;
        }
 
-       if (kbd_led_read(asus, NULL, NULL) >= 0) {
+       led_val = kbd_led_read(asus, NULL, NULL);
+       if (led_val >= 0) {
                INIT_WORK(&asus->kbd_led_work, kbd_led_update);
 
+               asus->kbd_led_wk = led_val;
                asus->kbd_led.name = "asus::kbd_backlight";
                asus->kbd_led.brightness_set = kbd_led_set;
                asus->kbd_led.brightness_get = kbd_led_get;
@@ -2160,6 +2162,16 @@ static int asus_hotk_thaw(struct device *device)
        return 0;
 }
 
+static int asus_hotk_resume(struct device *device)
+{
+       struct asus_wmi *asus = dev_get_drvdata(device);
+
+       if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
+               queue_work(asus->led_workqueue, &asus->kbd_led_work);
+
+       return 0;
+}
+
 static int asus_hotk_restore(struct device *device)
 {
        struct asus_wmi *asus = dev_get_drvdata(device);
@@ -2190,6 +2202,8 @@ static int asus_hotk_restore(struct device *device)
                bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB);
                rfkill_set_sw_state(asus->uwb.rfkill, bl);
        }
+       if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
+               queue_work(asus->led_workqueue, &asus->kbd_led_work);
 
        return 0;
 }
@@ -2197,6 +2211,7 @@ static int asus_hotk_restore(struct device *device)
 static const struct dev_pm_ops asus_pm_ops = {
        .thaw = asus_hotk_thaw,
        .restore = asus_hotk_restore,
+       .resume = asus_hotk_resume,
 };
 
 static int asus_wmi_probe(struct platform_device *pdev)
index f2706d27adff39fe93f77ff7a4204ef34664d928..e1c2b6d4b24ab5959d816dc1cc772678c42dccb3 100644 (file)
 #define BAT_STATUS2                    0xF1
 #define BAT_STOP_CHARGE1               0xF2
 #define BAT_STOP_CHARGE2               0xF3
+#define BAT_CHARGE_LIMIT               0x03
+#define BAT_CHARGE_LIMIT_MAX           100
 
 #define BAT_S0_DISCHARGE               (1 << 0)
 #define BAT_S0_DISCHRG_CRITICAL                (1 << 2)
@@ -601,6 +603,12 @@ static int bat_get_property(struct power_supply *psy,
        case POWER_SUPPLY_PROP_CHARGE_NOW:
                val->intval = ec_read_u16(BAT_CHARGE_NOW) * 1000;
                break;
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               val->intval = ec_read_u8(BAT_CHARGE_LIMIT);
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX:
+               val->intval = BAT_CHARGE_LIMIT_MAX;
+               break;
        case POWER_SUPPLY_PROP_CAPACITY:
                val->intval = ec_read_u8(BAT_CAPACITY);
                break;
@@ -634,6 +642,36 @@ static int bat_get_property(struct power_supply *psy,
        return 0;
 }
 
+static int bat_set_property(struct power_supply *psy,
+                               enum power_supply_property psp,
+                               const union power_supply_propval *val)
+{
+       int level;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               level = val->intval;
+               if (level < 0 || level > BAT_CHARGE_LIMIT_MAX)
+                       return -EINVAL;
+               if (ec_write(BAT_CHARGE_LIMIT, level) < 0)
+                       return -EIO;
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+static int bat_writeable_property(struct power_supply *psy,
+                               enum power_supply_property psp)
+{
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT:
+               return 1;
+       default:
+               return 0;
+       }
+}
 
 
 
@@ -726,6 +764,8 @@ static enum power_supply_property compal_bat_properties[] = {
        POWER_SUPPLY_PROP_POWER_NOW,
        POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
        POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT,
+       POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX,
        POWER_SUPPLY_PROP_CAPACITY,
        POWER_SUPPLY_PROP_CAPACITY_LEVEL,
        POWER_SUPPLY_PROP_TEMP,
@@ -880,11 +920,12 @@ static const struct power_supply_desc psy_bat_desc = {
        .properties     = compal_bat_properties,
        .num_properties = ARRAY_SIZE(compal_bat_properties),
        .get_property   = bat_get_property,
+       .set_property   = bat_set_property,
+       .property_is_writeable = bat_writeable_property,
 };
 
 static void initialize_power_supply_data(struct compal_data *data)
 {
-
        ec_read_sequence(BAT_MANUFACTURER_NAME_ADDR,
                                        data->bat_manufacturer_name,
                                        BAT_MANUFACTURER_NAME_LEN);
index 22606d6b2af3faeed925a00fb7488ccab36c8156..1fc0de870ff826e8b90956ab557cc83008e1ce68 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/platform_device.h>
 #include <linux/input.h>
 #include <linux/mfd/intel_msic.h>
+#include <linux/pm_wakeirq.h>
 
 #define DRIVER_NAME "msic_power_btn"
 
@@ -76,14 +77,17 @@ static int mfld_pb_probe(struct platform_device *pdev)
 
        input_set_capability(input, EV_KEY, KEY_POWER);
 
-       error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_NO_SUSPEND,
-                       DRIVER_NAME, input);
+       error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0,
+                                    DRIVER_NAME, input);
        if (error) {
                dev_err(&pdev->dev, "Unable to request irq %d for mfld power"
                                "button\n", irq);
                goto err_free_input;
        }
 
+       device_init_wakeup(&pdev->dev, true);
+       dev_pm_set_wake_irq(&pdev->dev, irq);
+
        error = input_register_device(input);
        if (error) {
                dev_err(&pdev->dev, "Unable to register input dev, error "
@@ -124,6 +128,8 @@ static int mfld_pb_remove(struct platform_device *pdev)
        struct input_dev *input = platform_get_drvdata(pdev);
        int irq = platform_get_irq(pdev, 0);
 
+       dev_pm_clear_wake_irq(&pdev->dev);
+       device_init_wakeup(&pdev->dev, false);
        free_irq(irq, input);
        input_unregister_device(input);
 
index 187d1086d15c3ddc4d939715cc65cd33b820409e..f94b730540e240334e5fe631bd9f60997f0b2dbc 100644 (file)
@@ -92,11 +92,8 @@ static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
        .irq_mode = 0,
 };
 
-static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
-static void ipc_remove(struct pci_dev *pdev);
-
 struct intel_scu_ipc_dev {
-       struct pci_dev *pdev;
+       struct device *dev;
        void __iomem *ipc_base;
        void __iomem *i2c_base;
        struct completion cmd_complete;
@@ -118,28 +115,30 @@ static struct intel_scu_ipc_dev  ipcdev; /* Only one for now */
 static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */
 
 /*
+ * Send ipc command
  * Command Register (Write Only):
  * A write to this register results in an interrupt to the SCU core processor
  * Format:
  * |rfu2(8) | size(8) | command id(4) | rfu1(3) | ioc(1) | command(8)|
  */
-static inline void ipc_command(u32 cmd) /* Send ipc command */
+static inline void ipc_command(struct intel_scu_ipc_dev *scu, u32 cmd)
 {
-       if (ipcdev.irq_mode) {
-               reinit_completion(&ipcdev.cmd_complete);
-               writel(cmd | IPC_IOC, ipcdev.ipc_base);
+       if (scu->irq_mode) {
+               reinit_completion(&scu->cmd_complete);
+               writel(cmd | IPC_IOC, scu->ipc_base);
        }
-       writel(cmd, ipcdev.ipc_base);
+       writel(cmd, scu->ipc_base);
 }
 
 /*
+ * Write ipc data
  * IPC Write Buffer (Write Only):
  * 16-byte buffer for sending data associated with IPC command to
  * SCU. Size of the data is specified in the IPC_COMMAND_REG register
  */
-static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
+static inline void ipc_data_writel(struct intel_scu_ipc_dev *scu, u32 data, u32 offset)
 {
-       writel(data, ipcdev.ipc_base + 0x80 + offset);
+       writel(data, scu->ipc_base + 0x80 + offset);
 }
 
 /*
@@ -149,35 +148,37 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
  * Format:
  * |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
  */
-static inline u8 ipc_read_status(void)
+static inline u8 ipc_read_status(struct intel_scu_ipc_dev *scu)
 {
-       return __raw_readl(ipcdev.ipc_base + 0x04);
+       return __raw_readl(scu->ipc_base + 0x04);
 }
 
-static inline u8 ipc_data_readb(u32 offset) /* Read ipc byte data */
+/* Read ipc byte data */
+static inline u8 ipc_data_readb(struct intel_scu_ipc_dev *scu, u32 offset)
 {
-       return readb(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
+       return readb(scu->ipc_base + IPC_READ_BUFFER + offset);
 }
 
-static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
+/* Read ipc u32 data */
+static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset)
 {
-       return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
+       return readl(scu->ipc_base + IPC_READ_BUFFER + offset);
 }
 
 /* Wait till scu status is busy */
-static inline int busy_loop(void)
+static inline int busy_loop(struct intel_scu_ipc_dev *scu)
 {
-       u32 status = ipc_read_status();
+       u32 status = ipc_read_status(scu);
        u32 loop_count = 100000;
 
        /* break if scu doesn't reset busy bit after huge retry */
        while ((status & BIT(0)) && --loop_count) {
                udelay(1); /* scu processing time is in few u secods */
-               status = ipc_read_status();
+               status = ipc_read_status(scu);
        }
 
        if (status & BIT(0)) {
-               dev_err(&ipcdev.pdev->dev, "IPC timed out");
+               dev_err(scu->dev, "IPC timed out");
                return -ETIMEDOUT;
        }
 
@@ -188,31 +189,31 @@ static inline int busy_loop(void)
 }
 
 /* Wait till ipc ioc interrupt is received or timeout in 3 HZ */
-static inline int ipc_wait_for_interrupt(void)
+static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu)
 {
        int status;
 
-       if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) {
-               struct device *dev = &ipcdev.pdev->dev;
-               dev_err(dev, "IPC timed out\n");
+       if (!wait_for_completion_timeout(&scu->cmd_complete, 3 * HZ)) {
+               dev_err(scu->dev, "IPC timed out\n");
                return -ETIMEDOUT;
        }
 
-       status = ipc_read_status();
+       status = ipc_read_status(scu);
        if (status & BIT(1))
                return -EIO;
 
        return 0;
 }
 
-static int intel_scu_ipc_check_status(void)
+static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu)
 {
-       return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop();
+       return scu->irq_mode ? ipc_wait_for_interrupt(scu) : busy_loop(scu);
 }
 
 /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
 static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 {
+       struct intel_scu_ipc_dev *scu = &ipcdev;
        int nc;
        u32 offset = 0;
        int err;
@@ -223,7 +224,7 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 
        mutex_lock(&ipclock);
 
-       if (ipcdev.pdev == NULL) {
+       if (scu->dev == NULL) {
                mutex_unlock(&ipclock);
                return -ENODEV;
        }
@@ -235,27 +236,27 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
 
        if (id == IPC_CMD_PCNTRL_R) {
                for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-                       ipc_data_writel(wbuf[nc], offset);
-               ipc_command((count * 2) << 16 | id << 12 | 0 << 8 | op);
+                       ipc_data_writel(scu, wbuf[nc], offset);
+               ipc_command(scu, (count * 2) << 16 | id << 12 | 0 << 8 | op);
        } else if (id == IPC_CMD_PCNTRL_W) {
                for (nc = 0; nc < count; nc++, offset += 1)
                        cbuf[offset] = data[nc];
                for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
-                       ipc_data_writel(wbuf[nc], offset);
-               ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op);
+                       ipc_data_writel(scu, wbuf[nc], offset);
+               ipc_command(scu, (count * 3) << 16 | id << 12 | 0 << 8 | op);
        } else if (id == IPC_CMD_PCNTRL_M) {
                cbuf[offset] = data[0];
                cbuf[offset + 1] = data[1];
-               ipc_data_writel(wbuf[0], 0); /* Write wbuff */
-               ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
+               ipc_data_writel(scu, wbuf[0], 0); /* Write wbuff */
+               ipc_command(scu, 4 << 16 | id << 12 | 0 << 8 | op);
        }
 
-       err = intel_scu_ipc_check_status();
+       err = intel_scu_ipc_check_status(scu);
        if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
                /* Workaround: values are read as 0 without memcpy_fromio */
-               memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
+               memcpy_fromio(cbuf, scu->ipc_base + 0x90, 16);
                for (nc = 0; nc < count; nc++)
-                       data[nc] = ipc_data_readb(nc);
+                       data[nc] = ipc_data_readb(scu, nc);
        }
        mutex_unlock(&ipclock);
        return err;
@@ -436,15 +437,16 @@ EXPORT_SYMBOL(intel_scu_ipc_update_register);
  */
 int intel_scu_ipc_simple_command(int cmd, int sub)
 {
+       struct intel_scu_ipc_dev *scu = &ipcdev;
        int err;
 
        mutex_lock(&ipclock);
-       if (ipcdev.pdev == NULL) {
+       if (scu->dev == NULL) {
                mutex_unlock(&ipclock);
                return -ENODEV;
        }
-       ipc_command(sub << 12 | cmd);
-       err = intel_scu_ipc_check_status();
+       ipc_command(scu, sub << 12 | cmd);
+       err = intel_scu_ipc_check_status(scu);
        mutex_unlock(&ipclock);
        return err;
 }
@@ -465,23 +467,24 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
 int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
                          u32 *out, int outlen)
 {
+       struct intel_scu_ipc_dev *scu = &ipcdev;
        int i, err;
 
        mutex_lock(&ipclock);
-       if (ipcdev.pdev == NULL) {
+       if (scu->dev == NULL) {
                mutex_unlock(&ipclock);
                return -ENODEV;
        }
 
        for (i = 0; i < inlen; i++)
-               ipc_data_writel(*in++, 4 * i);
+               ipc_data_writel(scu, *in++, 4 * i);
 
-       ipc_command((inlen << 16) | (sub << 12) | cmd);
-       err = intel_scu_ipc_check_status();
+       ipc_command(scu, (inlen << 16) | (sub << 12) | cmd);
+       err = intel_scu_ipc_check_status(scu);
 
        if (!err) {
                for (i = 0; i < outlen; i++)
-                       *out++ = ipc_data_readl(4 * i);
+                       *out++ = ipc_data_readl(scu, 4 * i);
        }
 
        mutex_unlock(&ipclock);
@@ -507,25 +510,26 @@ EXPORT_SYMBOL(intel_scu_ipc_command);
  */
 int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
 {
+       struct intel_scu_ipc_dev *scu = &ipcdev;
        u32 cmd = 0;
 
        mutex_lock(&ipclock);
-       if (ipcdev.pdev == NULL) {
+       if (scu->dev == NULL) {
                mutex_unlock(&ipclock);
                return -ENODEV;
        }
        cmd = (addr >> 24) & 0xFF;
        if (cmd == IPC_I2C_READ) {
-               writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+               writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
                /* Write not getting updated without delay */
                mdelay(1);
-               *data = readl(ipcdev.i2c_base + I2C_DATA_ADDR);
+               *data = readl(scu->i2c_base + I2C_DATA_ADDR);
        } else if (cmd == IPC_I2C_WRITE) {
-               writel(*data, ipcdev.i2c_base + I2C_DATA_ADDR);
+               writel(*data, scu->i2c_base + I2C_DATA_ADDR);
                mdelay(1);
-               writel(addr, ipcdev.i2c_base + IPC_I2C_CNTRL_ADDR);
+               writel(addr, scu->i2c_base + IPC_I2C_CNTRL_ADDR);
        } else {
-               dev_err(&ipcdev.pdev->dev,
+               dev_err(scu->dev,
                        "intel_scu_ipc: I2C INVALID_CMD = 0x%x\n", cmd);
 
                mutex_unlock(&ipclock);
@@ -545,63 +549,65 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
  */
 static irqreturn_t ioc(int irq, void *dev_id)
 {
-       if (ipcdev.irq_mode)
-               complete(&ipcdev.cmd_complete);
+       struct intel_scu_ipc_dev *scu = dev_id;
+
+       if (scu->irq_mode)
+               complete(&scu->cmd_complete);
 
        return IRQ_HANDLED;
 }
 
 /**
  *     ipc_probe       -       probe an Intel SCU IPC
- *     @dev: the PCI device matching
+ *     @pdev: the PCI device matching
  *     @id: entry in the match table
  *
  *     Enable and install an intel SCU IPC. This appears in the PCI space
  *     but uses some hard coded addresses as well.
  */
-static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
+static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
+       int platform;           /* Platform type */
        int err;
+       struct intel_scu_ipc_dev *scu = &ipcdev;
        struct intel_scu_ipc_pdata_t *pdata;
-       resource_size_t base;
 
-       if (ipcdev.pdev)                /* We support only one SCU */
+       platform = intel_mid_identify_cpu();
+       if (platform == 0)
+               return -ENODEV;
+
+       if (scu->dev)           /* We support only one SCU */
                return -EBUSY;
 
        pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data;
 
-       ipcdev.pdev = pci_dev_get(dev);
-       ipcdev.irq_mode = pdata->irq_mode;
+       scu->dev = &pdev->dev;
+       scu->irq_mode = pdata->irq_mode;
 
-       err = pci_enable_device(dev);
+       err = pcim_enable_device(pdev);
        if (err)
                return err;
 
-       err = pci_request_regions(dev, "intel_scu_ipc");
+       err = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev));
        if (err)
                return err;
 
-       base = pci_resource_start(dev, 0);
-       if (!base)
-               return -ENOMEM;
+       init_completion(&scu->cmd_complete);
 
-       init_completion(&ipcdev.cmd_complete);
+       err = devm_request_irq(&pdev->dev, pdev->irq, ioc, 0, "intel_scu_ipc",
+                              scu);
+       if (err)
+               return err;
 
-       if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
-               return -EBUSY;
+       scu->ipc_base = pcim_iomap_table(pdev)[0];
 
-       ipcdev.ipc_base = ioremap_nocache(base, pci_resource_len(dev, 0));
-       if (!ipcdev.ipc_base)
+       scu->i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
+       if (!scu->i2c_base)
                return -ENOMEM;
 
-       ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len);
-       if (!ipcdev.i2c_base) {
-               iounmap(ipcdev.ipc_base);
-               return -ENOMEM;
-       }
-
        intel_scu_devices_create();
 
+       pci_set_drvdata(pdev, scu);
        return 0;
 }
 
@@ -617,12 +623,13 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
  */
 static void ipc_remove(struct pci_dev *pdev)
 {
-       free_irq(pdev->irq, &ipcdev);
-       pci_release_regions(pdev);
-       pci_dev_put(ipcdev.pdev);
-       iounmap(ipcdev.ipc_base);
-       iounmap(ipcdev.i2c_base);
-       ipcdev.pdev = NULL;
+       struct intel_scu_ipc_dev *scu = pci_get_drvdata(pdev);
+
+       mutex_lock(&ipclock);
+       scu->dev = NULL;
+       mutex_unlock(&ipclock);
+
+       iounmap(scu->i2c_base);
        intel_scu_devices_destroy();
 }
 
@@ -652,24 +659,8 @@ static struct pci_driver ipc_driver = {
        .remove = ipc_remove,
 };
 
-static int __init intel_scu_ipc_init(void)
-{
-       int platform;           /* Platform type */
-
-       platform = intel_mid_identify_cpu();
-       if (platform == 0)
-               return -ENODEV;
-       return  pci_register_driver(&ipc_driver);
-}
-
-static void __exit intel_scu_ipc_exit(void)
-{
-       pci_unregister_driver(&ipc_driver);
-}
+module_pci_driver(ipc_driver);
 
 MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
 MODULE_DESCRIPTION("Intel SCU IPC driver");
 MODULE_LICENSE("GPL");
-
-module_init(intel_scu_ipc_init);
-module_exit(intel_scu_ipc_exit);
index aeb80d1c2b07e7d8d9ef17e540bab09c7c48a139..f73c29558cd3958105401d91fb37edf323e79b9c 100644 (file)
@@ -1204,6 +1204,8 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
        u32 real_ev = event;
        u8 ev_type = 0;
+       int ret;
+
        dprintk("sony_nc_notify, event: 0x%.2x\n", event);
 
        if (event >= 0x90) {
@@ -1225,13 +1227,12 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
                case 0x0100:
                case 0x0127:
                        ev_type = HOTKEY;
-                       real_ev = sony_nc_hotkeys_decode(event, handle);
+                       ret = sony_nc_hotkeys_decode(event, handle);
 
-                       if (real_ev > 0)
-                               sony_laptop_report_input_event(real_ev);
-                       else
-                               /* restore the original event for reporting */
-                               real_ev = event;
+                       if (ret > 0) {
+                               sony_laptop_report_input_event(ret);
+                               real_ev = ret;
+                       }
 
                        break;
 
diff --git a/drivers/platform/x86/toshiba-wmi.c b/drivers/platform/x86/toshiba-wmi.c
new file mode 100644 (file)
index 0000000..feac457
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * toshiba_wmi.c - Toshiba WMI Hotkey Driver
+ *
+ * Copyright (C) 2015 Azael Avalos <coproscefalo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/input.h>
+#include <linux/input/sparse-keymap.h>
+
+MODULE_AUTHOR("Azael Avalos");
+MODULE_DESCRIPTION("Toshiba WMI Hotkey Driver");
+MODULE_LICENSE("GPL");
+
+#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
+
+MODULE_ALIAS("wmi:"TOSHIBA_WMI_EVENT_GUID);
+
+static struct input_dev *toshiba_wmi_input_dev;
+
+static const struct key_entry toshiba_wmi_keymap[] __initconst = {
+       /* TODO: Add keymap values once found... */
+       /*{ KE_KEY, 0x00, { KEY_ } },*/
+       { KE_END, 0 }
+};
+
+static void toshiba_wmi_notify(u32 value, void *context)
+{
+       struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       acpi_status status;
+
+       status = wmi_get_event_data(value, &response);
+       if (ACPI_FAILURE(status)) {
+               pr_err("Bad event status 0x%x\n", status);
+               return;
+       }
+
+       obj = (union acpi_object *)response.pointer;
+       if (!obj)
+               return;
+
+       /* TODO: Add proper checks once we have data */
+       pr_debug("Unknown event received, obj type %x\n", obj->type);
+
+       kfree(response.pointer);
+}
+
+static int __init toshiba_wmi_input_setup(void)
+{
+       acpi_status status;
+       int err;
+
+       toshiba_wmi_input_dev = input_allocate_device();
+       if (!toshiba_wmi_input_dev)
+               return -ENOMEM;
+
+       toshiba_wmi_input_dev->name = "Toshiba WMI hotkeys";
+       toshiba_wmi_input_dev->phys = "wmi/input0";
+       toshiba_wmi_input_dev->id.bustype = BUS_HOST;
+
+       err = sparse_keymap_setup(toshiba_wmi_input_dev,
+                                 toshiba_wmi_keymap, NULL);
+       if (err)
+               goto err_free_dev;
+
+       status = wmi_install_notify_handler(TOSHIBA_WMI_EVENT_GUID,
+                                           toshiba_wmi_notify, NULL);
+       if (ACPI_FAILURE(status)) {
+               err = -EIO;
+               goto err_free_keymap;
+       }
+
+       err = input_register_device(toshiba_wmi_input_dev);
+       if (err)
+               goto err_remove_notifier;
+
+       return 0;
+
+ err_remove_notifier:
+       wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+ err_free_keymap:
+       sparse_keymap_free(toshiba_wmi_input_dev);
+ err_free_dev:
+       input_free_device(toshiba_wmi_input_dev);
+       return err;
+}
+
+static void toshiba_wmi_input_destroy(void)
+{
+       wmi_remove_notify_handler(TOSHIBA_WMI_EVENT_GUID);
+       sparse_keymap_free(toshiba_wmi_input_dev);
+       input_unregister_device(toshiba_wmi_input_dev);
+}
+
+static int __init toshiba_wmi_init(void)
+{
+       int ret;
+
+       if (!wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+               return -ENODEV;
+
+       ret = toshiba_wmi_input_setup();
+       if (ret) {
+               pr_err("Failed to setup input device\n");
+               return ret;
+       }
+
+       pr_info("Toshiba WMI Hotkey Driver\n");
+
+       return 0;
+}
+
+static void __exit toshiba_wmi_exit(void)
+{
+       if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
+               toshiba_wmi_input_destroy();
+}
+
+module_init(toshiba_wmi_init);
+module_exit(toshiba_wmi_exit);
index f2372f400ddbb406927efc71c843c05a0222c4c4..beb709f26fc4f88637b7f5a647961025ab3bd8bc 100644 (file)
@@ -131,7 +131,7 @@ MODULE_LICENSE("GPL");
 /* Field definitions */
 #define HCI_ACCEL_MASK                 0x7fff
 #define HCI_HOTKEY_DISABLE             0x0b
-#define HCI_HOTKEY_ENABLE              0x09
+#define HCI_HOTKEY_ENABLE              0x01
 #define HCI_HOTKEY_SPECIAL_FUNCTIONS   0x10
 #define HCI_LCD_BRIGHTNESS_BITS                3
 #define HCI_LCD_BRIGHTNESS_SHIFT       (16-HCI_LCD_BRIGHTNESS_BITS)
@@ -198,6 +198,7 @@ struct toshiba_acpi_dev {
        unsigned int panel_power_on_supported:1;
        unsigned int usb_three_supported:1;
        unsigned int sysfs_created:1;
+       unsigned int special_functions;
 
        bool kbd_led_registered;
        bool illumination_led_registered;
@@ -1668,10 +1669,10 @@ static ssize_t available_kbd_modes_show(struct device *dev,
        struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
 
        if (toshiba->kbd_type == 1)
-               return sprintf(buf, "%x %x\n",
+               return sprintf(buf, "0x%x 0x%x\n",
                               SCI_KBD_MODE_FNZ, SCI_KBD_MODE_AUTO);
 
-       return sprintf(buf, "%x %x %x\n",
+       return sprintf(buf, "0x%x 0x%x 0x%x\n",
                       SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
 }
 static DEVICE_ATTR_RO(available_kbd_modes);
@@ -2253,7 +2254,16 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
+       /*
+        * Enable the "Special Functions" mode only if they are
+        * supported and if they are activated.
+        */
+       if (dev->kbd_function_keys_supported && dev->special_functions)
+               result = hci_write(dev, HCI_HOTKEY_EVENT,
+                                  HCI_HOTKEY_SPECIAL_FUNCTIONS);
+       else
+               result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE);
+
        if (result == TOS_FAILURE)
                return -EIO;
        else if (result == TOS_NOT_SUPPORTED)
@@ -2262,20 +2272,6 @@ static int toshiba_acpi_enable_hotkeys(struct toshiba_acpi_dev *dev)
        return 0;
 }
 
-static void toshiba_acpi_enable_special_functions(struct toshiba_acpi_dev *dev)
-{
-       u32 result;
-
-       /*
-        * Re-activate the hotkeys, but this time, we are using the
-        * "Special Functions" mode.
-        */
-       result = hci_write(dev, HCI_HOTKEY_EVENT,
-                          HCI_HOTKEY_SPECIAL_FUNCTIONS);
-       if (result != TOS_SUCCESS)
-               pr_err("Could not enable the Special Function mode\n");
-}
-
 static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
                                      struct serio *port)
 {
@@ -2385,8 +2381,6 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
 {
        const struct key_entry *keymap = toshiba_acpi_keymap;
        acpi_handle ec_handle;
-       u32 events_type;
-       u32 hci_result;
        int error;
 
        if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) {
@@ -2398,11 +2392,9 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        if (error)
                return error;
 
-       if (toshiba_hotkey_event_type_get(dev, &events_type))
+       if (toshiba_hotkey_event_type_get(dev, &dev->hotkey_event_type))
                pr_notice("Unable to query Hotkey Event Type\n");
 
-       dev->hotkey_event_type = events_type;
-
        dev->hotkey_dev = input_allocate_device();
        if (!dev->hotkey_dev)
                return -ENOMEM;
@@ -2411,14 +2403,15 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
        dev->hotkey_dev->phys = "toshiba_acpi/input0";
        dev->hotkey_dev->id.bustype = BUS_HOST;
 
-       if (events_type == HCI_SYSTEM_TYPE1 ||
+       if (dev->hotkey_event_type == HCI_SYSTEM_TYPE1 ||
            !dev->kbd_function_keys_supported)
                keymap = toshiba_acpi_keymap;
-       else if (events_type == HCI_SYSTEM_TYPE2 ||
+       else if (dev->hotkey_event_type == HCI_SYSTEM_TYPE2 ||
                 dev->kbd_function_keys_supported)
                keymap = toshiba_acpi_alt_keymap;
        else
-               pr_info("Unknown event type received %x\n", events_type);
+               pr_info("Unknown event type received %x\n",
+                       dev->hotkey_event_type);
        error = sparse_keymap_setup(dev->hotkey_dev, keymap, NULL);
        if (error)
                goto err_free_dev;
@@ -2449,11 +2442,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
         */
        if (acpi_has_method(dev->acpi_dev->handle, "INFO"))
                dev->info_supported = 1;
-       else {
-               hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1);
-               if (hci_result == TOS_SUCCESS)
-                       dev->system_event_supported = 1;
-       }
+       else if (hci_write(dev, HCI_SYSTEM_EVENT, 1) == TOS_SUCCESS)
+               dev->system_event_supported = 1;
 
        if (!dev->info_supported && !dev->system_event_supported) {
                pr_warn("No hotkey query interface found\n");
@@ -2631,7 +2621,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
 {
        struct toshiba_acpi_dev *dev;
        const char *hci_method;
-       u32 special_functions;
        u32 dummy;
        int ret = 0;
 
@@ -2673,7 +2662,7 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
         * with the new keyboard layout, query for its presence to help
         * determine the keymap layout to use.
         */
-       ret = toshiba_function_keys_get(dev, &special_functions);
+       ret = toshiba_function_keys_get(dev, &dev->special_functions);
        dev->kbd_function_keys_supported = !ret;
 
        if (toshiba_acpi_setup_keyboard(dev))
@@ -2748,13 +2737,6 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
 
        print_supported_features(dev);
 
-       /*
-        * Enable the "Special Functions" mode only if they are
-        * supported and if they are activated.
-        */
-       if (dev->kbd_function_keys_supported && special_functions)
-               toshiba_acpi_enable_special_functions(dev);
-
        ret = sysfs_create_group(&dev->acpi_dev->dev.kobj,
                                 &toshiba_attr_group);
        if (ret) {