Merge tag 'platform-drivers-x86-v4.19-1' of git://git.infradead.org/linux-platform...
[sfrench/cifs-2.6.git] / drivers / platform / x86 / thinkpad_acpi.c
index d556e95c532c09221bd7db6a6ebd3c577396b409..fde08a997557fed3aeef16b3729ef1b8c85efe75 100644 (file)
@@ -336,6 +336,7 @@ static struct {
        u32 second_fan:1;
        u32 beep_needs_two_args:1;
        u32 mixer_no_level_control:1;
+       u32 battery_force_primary:1;
        u32 input_device_registered:1;
        u32 platform_drv_registered:1;
        u32 platform_drv_attrs_registered:1;
@@ -344,7 +345,6 @@ static struct {
        u32 sensors_pdev_attrs_registered:1;
        u32 hotkey_poll_active:1;
        u32 has_adaptive_kbd:1;
-       u32 battery:1;
 } tp_features;
 
 static struct {
@@ -359,9 +359,9 @@ struct thinkpad_id_data {
        char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
        char *ec_version_str;   /* Something like 1ZHT51WW-1.04a */
 
-       u16 bios_model;         /* 1Y = 0x5931, 0 = unknown */
-       u16 ec_model;
-       u16 bios_release;       /* 1ZETK1WW = 0x314b, 0 = unknown */
+       u32 bios_model;         /* 1Y = 0x3159, 0 = unknown */
+       u32 ec_model;
+       u16 bios_release;       /* 1ZETK1WW = 0x4b31, 0 = unknown */
        u16 ec_release;
 
        char *model_str;        /* ThinkPad T43 */
@@ -445,17 +445,20 @@ do {                                                                      \
 /*
  * Quirk handling helpers
  *
- * ThinkPad IDs and versions seen in the field so far
- * are two-characters from the set [0-9A-Z], i.e. base 36.
+ * ThinkPad IDs and versions seen in the field so far are
+ * two or three characters from the set [0-9A-Z], i.e. base 36.
  *
  * We use values well outside that range as specials.
  */
 
-#define TPACPI_MATCH_ANY               0xffffU
+#define TPACPI_MATCH_ANY               0xffffffffU
+#define TPACPI_MATCH_ANY_VERSION       0xffffU
 #define TPACPI_MATCH_UNKNOWN           0U
 
-/* TPID('1', 'Y') == 0x5931 */
-#define TPID(__c1, __c2) (((__c2) << 8) | (__c1))
+/* TPID('1', 'Y') == 0x3159 */
+#define TPID(__c1, __c2)       (((__c1) << 8) | (__c2))
+#define TPID3(__c1, __c2, __c3)        (((__c1) << 16) | ((__c2) << 8) | (__c3))
+#define TPVER TPID
 
 #define TPACPI_Q_IBM(__id1, __id2, __quirk)    \
        { .vendor = PCI_VENDOR_ID_IBM,          \
@@ -469,6 +472,12 @@ do {                                                                       \
          .ec = TPACPI_MATCH_ANY,               \
          .quirks = (__quirk) }
 
+#define TPACPI_Q_LNV3(__id1, __id2, __id3, __quirk) \
+       { .vendor = PCI_VENDOR_ID_LENOVO,       \
+         .bios = TPID3(__id1, __id2, __id3),   \
+         .ec = TPACPI_MATCH_ANY,               \
+         .quirks = (__quirk) }
+
 #define TPACPI_QEC_LNV(__id1, __id2, __quirk)  \
        { .vendor = PCI_VENDOR_ID_LENOVO,       \
          .bios = TPACPI_MATCH_ANY,             \
@@ -477,8 +486,8 @@ do {                                                                        \
 
 struct tpacpi_quirk {
        unsigned int vendor;
-       u16 bios;
-       u16 ec;
+       u32 bios;
+       u32 ec;
        unsigned long quirks;
 };
 
@@ -1648,16 +1657,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
        { .vendor       = (__v),                        \
          .bios         = TPID(__id1, __id2),           \
          .ec           = TPACPI_MATCH_ANY,             \
-         .quirks       = TPACPI_MATCH_ANY << 16        \
-                         | (__bv1) << 8 | (__bv2) }
+         .quirks       = TPACPI_MATCH_ANY_VERSION << 16 \
+                         | TPVER(__bv1, __bv2) }
 
 #define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2,     \
                __eid, __ev1, __ev2)                    \
        { .vendor       = (__v),                        \
          .bios         = TPID(__bid1, __bid2),         \
          .ec           = __eid,                        \
-         .quirks       = (__ev1) << 24 | (__ev2) << 16 \
-                         | (__bv1) << 8 | (__bv2) }
+         .quirks       = TPVER(__ev1, __ev2) << 16     \
+                         | TPVER(__bv1, __bv2) }
 
 #define TPV_QI0(__id1, __id2, __bv1, __bv2) \
        TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2)
@@ -1799,7 +1808,7 @@ static void __init tpacpi_check_outdated_fw(void)
        /* note that unknown versions are set to 0x0000 and we use that */
        if ((bios_version > thinkpad_id.bios_release) ||
            (ec_version > thinkpad_id.ec_release &&
-                               ec_version != TPACPI_MATCH_ANY)) {
+                               ec_version != TPACPI_MATCH_ANY_VERSION)) {
                /*
                 * The changelogs would let us track down the exact
                 * reason, but it is just too much of a pain to track
@@ -1929,7 +1938,7 @@ enum {    /* hot key scan codes (derived from ACPI DSDT) */
        /* first new observed key (star, favorites) is 0x1311 */
        TP_ACPI_HOTKEYSCAN_STAR = 69,
        TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2,
-       TP_ACPI_HOTKEYSCAN_UNK25,
+       TP_ACPI_HOTKEYSCAN_CALCULATOR,
        TP_ACPI_HOTKEYSCAN_BLUETOOTH,
        TP_ACPI_HOTKEYSCAN_KEYBOARD,
 
@@ -3450,7 +3459,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
 
                KEY_FAVORITES,       /* Favorite app, 0x311 */
                KEY_RESERVED,        /* Clipping tool */
-               KEY_RESERVED,
+               KEY_CALC,            /* Calculator (above numpad, P52) */
                KEY_BLUETOOTH,       /* Bluetooth */
                KEY_KEYBOARD         /* Keyboard, 0x315 */
                },
@@ -9366,7 +9375,9 @@ static int tpacpi_battery_probe(int battery)
 {
        int ret = 0;
 
-       memset(&battery_info, 0, sizeof(struct tpacpi_battery_driver_data));
+       memset(&battery_info.batteries[battery], 0,
+               sizeof(battery_info.batteries[battery]));
+
        /*
         * 1) Get the current start threshold
         * 2) Check for support
@@ -9421,7 +9432,8 @@ static int tpacpi_battery_probe(int battery)
 static int tpacpi_battery_get_id(const char *battery_name)
 {
 
-       if (strcmp(battery_name, "BAT0") == 0)
+       if (strcmp(battery_name, "BAT0") == 0 ||
+           tp_features.battery_force_primary)
                return BAT_PRIMARY;
        if (strcmp(battery_name, "BAT1") == 0)
                return BAT_SECONDARY;
@@ -9597,8 +9609,26 @@ static struct acpi_battery_hook battery_hook = {
 
 /* Subdriver init/exit */
 
+static const struct tpacpi_quirk battery_quirk_table[] __initconst = {
+       /*
+        * Individual addressing is broken on models that expose the
+        * primary battery as BAT1.
+        */
+       TPACPI_Q_LNV('J', '7', true),       /* B5400 */
+       TPACPI_Q_LNV('J', 'I', true),       /* Thinkpad 11e */
+       TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */
+       TPACPI_Q_LNV3('R', '0', 'C', true), /* Thinkpad 13 */
+       TPACPI_Q_LNV3('R', '0', 'J', true), /* Thinkpad 13 gen 2 */
+};
+
 static int __init tpacpi_battery_init(struct ibm_init_struct *ibm)
 {
+       memset(&battery_info, 0, sizeof(battery_info));
+
+       tp_features.battery_force_primary = tpacpi_check_quirks(
+                                       battery_quirk_table,
+                                       ARRAY_SIZE(battery_quirk_table));
+
        battery_hook_register(&battery_hook);
        return 0;
 }
@@ -9809,36 +9839,37 @@ err_out:
 
 /* Probing */
 
-static bool __pure __init tpacpi_is_fw_digit(const char c)
+static char __init tpacpi_parse_fw_id(const char * const s,
+                                     u32 *model, u16 *release)
 {
-       return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
-}
+       int i;
+
+       if (!s || strlen(s) < 8)
+               goto invalid;
+
+       for (i = 0; i < 8; i++)
+               if (!((s[i] >= '0' && s[i] <= '9') ||
+                     (s[i] >= 'A' && s[i] <= 'Z')))
+                       goto invalid;
 
-static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
-                                               const char t)
-{
        /*
         * Most models: xxyTkkWW (#.##c)
         * Ancient 570/600 and -SL lacks (#.##c)
         */
-       if (s && strlen(s) >= 8 &&
-               tpacpi_is_fw_digit(s[0]) &&
-               tpacpi_is_fw_digit(s[1]) &&
-               s[2] == t &&
-               (s[3] == 'T' || s[3] == 'N') &&
-               tpacpi_is_fw_digit(s[4]) &&
-               tpacpi_is_fw_digit(s[5]))
-               return true;
+       if (s[3] == 'T' || s[3] == 'N') {
+               *model = TPID(s[0], s[1]);
+               *release = TPVER(s[4], s[5]);
+               return s[2];
 
        /* New models: xxxyTkkW (#.##c); T550 and some others */
-       return s && strlen(s) >= 8 &&
-               tpacpi_is_fw_digit(s[0]) &&
-               tpacpi_is_fw_digit(s[1]) &&
-               tpacpi_is_fw_digit(s[2]) &&
-               s[3] == t &&
-               (s[4] == 'T' || s[4] == 'N') &&
-               tpacpi_is_fw_digit(s[5]) &&
-               tpacpi_is_fw_digit(s[6]);
+       } else if (s[4] == 'T' || s[4] == 'N') {
+               *model = TPID3(s[0], s[1], s[2]);
+               *release = TPVER(s[5], s[6]);
+               return s[3];
+       }
+
+invalid:
+       return '\0';
 }
 
 /* returns 0 - probe ok, or < 0 - probe error.
@@ -9850,6 +9881,7 @@ static int __must_check __init get_thinkpad_model_data(
        const struct dmi_device *dev = NULL;
        char ec_fw_string[18];
        char const *s;
+       char t;
 
        if (!tp)
                return -EINVAL;
@@ -9869,15 +9901,11 @@ static int __must_check __init get_thinkpad_model_data(
                return -ENOMEM;
 
        /* Really ancient ThinkPad 240X will fail this, which is fine */
-       if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') ||
-             tpacpi_is_valid_fw_id(tp->bios_version_str, 'C')))
+       t = tpacpi_parse_fw_id(tp->bios_version_str,
+                              &tp->bios_model, &tp->bios_release);
+       if (t != 'E' && t != 'C')
                return 0;
 
-       tp->bios_model = tp->bios_version_str[0]
-                        | (tp->bios_version_str[1] << 8);
-       tp->bios_release = (tp->bios_version_str[4] << 8)
-                        | tp->bios_version_str[5];
-
        /*
         * ThinkPad T23 or newer, A31 or newer, R50e or newer,
         * X32 or newer, all Z series;  Some models must have an
@@ -9896,12 +9924,9 @@ static int __must_check __init get_thinkpad_model_data(
                        if (!tp->ec_version_str)
                                return -ENOMEM;
 
-                       if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) {
-                               tp->ec_model = ec_fw_string[0]
-                                               | (ec_fw_string[1] << 8);
-                               tp->ec_release = (ec_fw_string[4] << 8)
-                                               | ec_fw_string[5];
-                       } else {
+                       t = tpacpi_parse_fw_id(ec_fw_string,
+                                              &tp->ec_model, &tp->ec_release);
+                       if (t != 'H') {
                                pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n",
                                          ec_fw_string);
                                pr_notice("please report this to %s\n",