Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 18:16:19 +0000 (10:16 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 3 Mar 2013 18:16:19 +0000 (10:16 -0800)
Pull x86 platform driver updates from Matthew Garrett:
 "Mostly relatively small updates, along with some hardware enablement
  for Sony hardware and a pile of updates to Google's Chromebook driver"

* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (49 commits)
  ideapad-laptop: Depend on BACKLIGHT_CLASS_DEVICE instead of selecting it
  ideapad: depends on backlight subsystem and update comment
  Platform: x86: chromeos_laptop - add i915 gmbuses to adapter names
  Platform: x86: chromeos_laptop - Add isl light sensor for Pixel
  Platform: x86: chromeos_laptop - Add a more general add_i2c_device
  Platform: x86: chromeos_laptop - Add Pixel Touchscreen
  Platform: x86: chromeos_laptop - Add support for probing devices
  Platform: x86: chromeos_laptop - Add Pixel Trackpad
  hp-wmi: fix handling of platform device
  sony-laptop: leak in error handling sony_nc_lid_resume_setup()
  hp-wmi: Add support for SMBus hotkeys
  asus-wmi: Fix unused function build warning
  acer-wmi: avoid the warning of 'devices' may be used uninitialized
  drivers/platform/x86/thinkpad_acpi.c: Handle HKEY event 0x6040
  Platform: x86: chromeos_laptop - Add HP Pavilion 14
  Platform: x86: chromeos_laptop - Add Taos tsl2583 device
  Platform: x86: chromeos_laptop - Add Taos tsl2563 device
  Platform: x86: chromeos_laptop - Add Acer C7 trackpad
  Platform: x86: chromeos_laptop - Rename setup_lumpy_tp to setup_cyapa_smbus_tp
  asus-laptop: always report brightness key events
  ...

1  2 
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c

@@@ -158,6 -158,11 +158,11 @@@ static void sony_nc_thermal_cleanup(str
  static int sony_nc_lid_resume_setup(struct platform_device *pd);
  static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
  
+ static int sony_nc_gfx_switch_setup(struct platform_device *pd,
+               unsigned int handle);
+ static void sony_nc_gfx_switch_cleanup(struct platform_device *pd);
+ static int __sony_nc_gfx_switch_status_get(void);
  static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
  static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
  
@@@ -1241,17 -1246,13 +1246,13 @@@ static void sony_nc_notify(struct acpi_
                        /* Hybrid GFX switching */
                        sony_call_snc_handle(handle, 0x0000, &result);
                        dprintk("GFX switch event received (reason: %s)\n",
-                                       (result & 0x01) ?
-                                       "switch change" : "unknown");
-                       /* verify the switch state
-                        * 1: discrete GFX
-                        * 0: integrated GFX
-                        */
-                       sony_call_snc_handle(handle, 0x0100, &result);
+                                       (result == 0x1) ? "switch change" :
+                                       (result == 0x2) ? "output switch" :
+                                       (result == 0x3) ? "output switch" :
+                                       "");
  
                        ev_type = GFX_SWITCH;
-                       real_ev = result & 0xff;
+                       real_ev = __sony_nc_gfx_switch_status_get();
                        break;
  
                default:
@@@ -1350,6 -1351,13 +1351,13 @@@ static void sony_nc_function_setup(stru
                                pr_err("couldn't set up thermal profile function (%d)\n",
                                                result);
                        break;
+               case 0x0128:
+               case 0x0146:
+                       result = sony_nc_gfx_switch_setup(pf_device, handle);
+                       if (result)
+                               pr_err("couldn't set up GFX Switch status (%d)\n",
+                                               result);
+                       break;
                case 0x0131:
                        result = sony_nc_highspeed_charging_setup(pf_device);
                        if (result)
                        break;
                case 0x0137:
                case 0x0143:
+               case 0x014b:
+               case 0x014c:
                        result = sony_nc_kbd_backlight_setup(pf_device, handle);
                        if (result)
                                pr_err("couldn't set up keyboard backlight function (%d)\n",
@@@ -1414,6 -1424,10 +1424,10 @@@ static void sony_nc_function_cleanup(st
                case 0x0122:
                        sony_nc_thermal_cleanup(pd);
                        break;
+               case 0x0128:
+               case 0x0146:
+                       sony_nc_gfx_switch_cleanup(pd);
+                       break;
                case 0x0131:
                        sony_nc_highspeed_charging_cleanup(pd);
                        break;
                        break;
                case 0x0137:
                case 0x0143:
+               case 0x014b:
+               case 0x014c:
                        sony_nc_kbd_backlight_cleanup(pd);
                        break;
                default:
@@@ -1467,6 -1483,8 +1483,8 @@@ static void sony_nc_function_resume(voi
                        break;
                case 0x0137:
                case 0x0143:
+               case 0x014b:
+               case 0x014c:
                        sony_nc_kbd_backlight_resume();
                        break;
                default:
@@@ -1534,7 -1552,7 +1552,7 @@@ static int sony_nc_rfkill_set(void *dat
        int argument = sony_rfkill_address[(long) data] + 0x100;
  
        if (!blocked)
-               argument |= 0x030000;
+               argument |= 0x070000;
  
        return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
  }
@@@ -2333,7 -2351,7 +2351,7 @@@ static int sony_nc_lid_resume_setup(str
        return 0;
  
  liderror:
-       for (; i > 0; i--)
+       for (i--; i >= 0; i--)
                device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
  
        kfree(lid_ctl);
@@@ -2355,6 -2373,97 +2373,97 @@@ static void sony_nc_lid_resume_cleanup(
        }
  }
  
+ /* GFX Switch position */
+ enum gfx_switch {
+       SPEED,
+       STAMINA,
+       AUTO
+ };
+ struct snc_gfx_switch_control {
+       struct device_attribute attr;
+       unsigned int handle;
+ };
+ static struct snc_gfx_switch_control *gfxs_ctl;
+ /* returns 0 for speed, 1 for stamina */
+ static int __sony_nc_gfx_switch_status_get(void)
+ {
+       unsigned int result;
+       if (sony_call_snc_handle(gfxs_ctl->handle, 0x0100, &result))
+               return -EIO;
+       switch (gfxs_ctl->handle) {
+       case 0x0146:
+               /* 1: discrete GFX (speed)
+                * 0: integrated GFX (stamina)
+                */
+               return result & 0x1 ? SPEED : STAMINA;
+               break;
+       case 0x0128:
+               /* it's a more elaborated bitmask, for now:
+                * 2: integrated GFX (stamina)
+                * 0: discrete GFX (speed)
+                */
+               dprintk("GFX Status: 0x%x\n", result);
+               return result & 0x80 ? AUTO :
+                       result & 0x02 ? STAMINA : SPEED;
+               break;
+       }
+       return -EINVAL;
+ }
+ static ssize_t sony_nc_gfx_switch_status_show(struct device *dev,
+                                      struct device_attribute *attr,
+                                      char *buffer)
+ {
+       int pos = __sony_nc_gfx_switch_status_get();
+       if (pos < 0)
+               return pos;
+       return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina");
+ }
+ static int sony_nc_gfx_switch_setup(struct platform_device *pd,
+               unsigned int handle)
+ {
+       unsigned int result;
+       gfxs_ctl = kzalloc(sizeof(struct snc_gfx_switch_control), GFP_KERNEL);
+       if (!gfxs_ctl)
+               return -ENOMEM;
+       gfxs_ctl->handle = handle;
+       sysfs_attr_init(&gfxs_ctl->attr.attr);
+       gfxs_ctl->attr.attr.name = "gfx_switch_status";
+       gfxs_ctl->attr.attr.mode = S_IRUGO;
+       gfxs_ctl->attr.show = sony_nc_gfx_switch_status_show;
+       result = device_create_file(&pd->dev, &gfxs_ctl->attr);
+       if (result)
+               goto gfxerror;
+       return 0;
+ gfxerror:
+       kfree(gfxs_ctl);
+       gfxs_ctl = NULL;
+       return result;
+ }
+ static void sony_nc_gfx_switch_cleanup(struct platform_device *pd)
+ {
+       if (gfxs_ctl) {
+               device_remove_file(&pd->dev, &gfxs_ctl->attr);
+               kfree(gfxs_ctl);
+               gfxs_ctl = NULL;
+       }
+ }
  /* High speed charging function */
  static struct device_attribute *hsc_handle;
  
@@@ -2533,6 -2642,8 +2642,8 @@@ static void sony_nc_backlight_ng_read_l
                lvl_table_len = 9;
                break;
        case 0x143:
+       case 0x14b:
+       case 0x14c:
                lvl_table_len = 16;
                break;
        }
@@@ -2584,6 -2695,18 +2695,18 @@@ static void sony_nc_backlight_setup(voi
                sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
                max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
  
+       } else if (sony_find_snc_handle(0x14b) >= 0) {
+               ops = &sony_backlight_ng_ops;
+               sony_bl_props.cmd_base = 0x3000;
+               sony_nc_backlight_ng_read_limits(0x14b, &sony_bl_props);
+               max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+       } else if (sony_find_snc_handle(0x14c) >= 0) {
+               ops = &sony_backlight_ng_ops;
+               sony_bl_props.cmd_base = 0x3000;
+               sony_nc_backlight_ng_read_limits(0x14c, &sony_bl_props);
+               max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
        } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
                                                &unused))) {
                ops = &sony_backlight_ops;
@@@ -3566,7 -3689,7 +3689,7 @@@ static ssize_t sonypi_misc_read(struct 
        }
  
        if (ret > 0) {
 -              struct inode *inode = file->f_path.dentry->d_inode;
 +              struct inode *inode = file_inode(file);
                inode->i_atime = current_fs_time(inode->i_sb);
        }
  
@@@ -209,9 -209,8 +209,8 @@@ enum tpacpi_hkey_event_t 
        TP_HKEY_EV_ALARM_SENSOR_XHOT    = 0x6022, /* sensor critically hot */
        TP_HKEY_EV_THM_TABLE_CHANGED    = 0x6030, /* thermal table changed */
  
-       TP_HKEY_EV_UNK_6040             = 0x6040, /* Related to AC change?
-                                                    some sort of APM hint,
-                                                    W520 */
+       /* AC-related events */
+       TP_HKEY_EV_AC_CHANGED           = 0x6040, /* AC status changed */
  
        /* Misc */
        TP_HKEY_EV_RFKILL_CHANGED       = 0x7000, /* rfkill switch changed */
@@@ -852,7 -851,7 +851,7 @@@ static ssize_t dispatch_proc_write(stru
                        const char __user *userbuf,
                        size_t count, loff_t *pos)
  {
 -      struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data;
 +      struct ibm_struct *ibm = PDE(file_inode(file))->data;
        char *kernbuf;
        int ret;
  
@@@ -3629,6 -3628,12 +3628,12 @@@ static bool hotkey_notify_6xxx(const u3
                         "a sensor reports something is extremely hot!\n");
                /* recommended action: immediate sleep/hibernate */
                break;
+       case TP_HKEY_EV_AC_CHANGED:
+               /* X120e, X121e, X220, X220i, X220t, X230, T420, T420s, W520:
+                * AC status changed; can be triggered by plugging or
+                * unplugging AC adapter, docking or undocking. */
+               /* fallthrough */
  
        case TP_HKEY_EV_KEY_NUMLOCK:
        case TP_HKEY_EV_KEY_FN:
@@@ -8574,7 -8579,8 +8579,8 @@@ static bool __pure __init tpacpi_is_val
        return s && strlen(s) >= 8 &&
                tpacpi_is_fw_digit(s[0]) &&
                tpacpi_is_fw_digit(s[1]) &&
-               s[2] == t && s[3] == 'T' &&
+               s[2] == t &&
+               (s[3] == 'T' || s[3] == 'N') &&
                tpacpi_is_fw_digit(s[4]) &&
                tpacpi_is_fw_digit(s[5]);
  }
@@@ -8607,7 -8613,8 +8613,8 @@@ static int __must_check __init get_thin
                return -ENOMEM;
  
        /* Really ancient ThinkPad 240X will fail this, which is fine */
-       if (!tpacpi_is_valid_fw_id(tp->bios_version_str, 'E'))
+       if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') ||
+             tpacpi_is_valid_fw_id(tp->bios_version_str, 'C')))
                return 0;
  
        tp->bios_model = tp->bios_version_str[0]