Merge tag 'platform-drivers-x86-v5.18-1' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / platform / x86 / thinkpad_acpi.c
index 3424b08..c568fae 100644 (file)
@@ -728,11 +728,10 @@ static void __init drv_acpi_handle_init(const char *name,
 static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle,
                        u32 level, void *context, void **return_value)
 {
-       struct acpi_device *dev;
        if (!strcmp(context, "video")) {
-               if (acpi_bus_get_device(handle, &dev))
-                       return AE_OK;
-               if (strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev)))
+               struct acpi_device *dev = acpi_fetch_acpi_dev(handle);
+
+               if (!dev || strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev)))
                        return AE_OK;
        }
 
@@ -786,7 +785,6 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
 static int __init setup_acpi_notify(struct ibm_struct *ibm)
 {
        acpi_status status;
-       int rc;
 
        BUG_ON(!ibm->acpi);
 
@@ -796,9 +794,9 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
        vdbg_printk(TPACPI_DBG_INIT,
                "setting up ACPI notify for %s\n", ibm->name);
 
-       rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
-       if (rc < 0) {
-               pr_err("acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc);
+       ibm->acpi->device = acpi_fetch_acpi_dev(*ibm->acpi->handle);
+       if (!ibm->acpi->device) {
+               pr_err("acpi_fetch_acpi_dev(%s) failed\n", ibm->name);
                return -ENODEV;
        }
 
@@ -6723,7 +6721,8 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
        struct acpi_device *device, *child;
        int rc;
 
-       if (acpi_bus_get_device(handle, &device))
+       device = acpi_fetch_acpi_dev(handle);
+       if (!device)
                return 0;
 
        rc = 0;
@@ -8286,7 +8285,7 @@ static int fan_set_enable(void)
        case TPACPI_FAN_WR_ACPI_FANS:
        case TPACPI_FAN_WR_TPEC:
                rc = fan_get_status(&s);
-               if (rc < 0)
+               if (rc)
                        break;
 
                /* Don't go out of emergency fan mode */
@@ -8305,7 +8304,7 @@ static int fan_set_enable(void)
 
        case TPACPI_FAN_WR_ACPI_SFAN:
                rc = fan_get_status(&s);
-               if (rc < 0)
+               if (rc)
                        break;
 
                s &= 0x07;
@@ -8699,10 +8698,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
        TPACPI_Q_LNV3('N', '2', 'N', TPACPI_FAN_2CTL),  /* P53 / P73 */
        TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (1st gen) */
        TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (2nd gen) */
-       TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (3nd gen) */
-       TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL),  /* P1 / X1 Extreme (4nd gen) */
        TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL),  /* P15 (1st gen) / P15v (1st gen) */
-       TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL),  /* X1 Carbon (9th gen) */
        TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL),  /* T15g (2nd gen) */
        TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
 };
@@ -8746,6 +8742,9 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                 * ThinkPad ECs supports the fan control register */
                if (likely(acpi_ec_read(fan_status_offset,
                                        &fan_control_initial_status))) {
+                       int res;
+                       unsigned int speed;
+
                        fan_status_access_mode = TPACPI_FAN_RD_TPEC;
                        if (quirks & TPACPI_FAN_Q1)
                                fan_quirk1_setup();
@@ -8758,6 +8757,15 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                                tp_features.second_fan_ctl = 1;
                                pr_info("secondary fan control enabled\n");
                        }
+                       /* Try and probe the 2nd fan */
+                       res = fan2_get_speed(&speed);
+                       if (res >= 0) {
+                               /* It responded - so let's assume it's there */
+                               tp_features.second_fan = 1;
+                               tp_features.second_fan_ctl = 1;
+                               pr_info("secondary fan control detected & enabled\n");
+                       }
+
                } else {
                        pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n");
                        return -ENODEV;
@@ -8835,7 +8843,7 @@ static void fan_suspend(void)
        /* Store fan status in cache */
        fan_control_resume_level = 0;
        rc = fan_get_status_safe(&fan_control_resume_level);
-       if (rc < 0)
+       if (rc)
                pr_notice("failed to read fan level for later restore during resume: %d\n",
                          rc);
 
@@ -8856,7 +8864,7 @@ static void fan_resume(void)
 
        if (!fan_control_allowed ||
            !fan_control_resume_level ||
-           (fan_get_status_safe(&current_level) < 0))
+           fan_get_status_safe(&current_level))
                return;
 
        switch (fan_control_access_mode) {
@@ -8910,7 +8918,7 @@ static int fan_read(struct seq_file *m)
        case TPACPI_FAN_RD_ACPI_GFAN:
                /* 570, 600e/x, 770e, 770x */
                rc = fan_get_status_safe(&status);
-               if (rc < 0)
+               if (rc)
                        return rc;
 
                seq_printf(m, "status:\t\t%s\n"
@@ -8921,7 +8929,7 @@ static int fan_read(struct seq_file *m)
        case TPACPI_FAN_RD_TPEC:
                /* all except 570, 600e/x, 770e, 770x */
                rc = fan_get_status_safe(&status);
-               if (rc < 0)
+               if (rc)
                        return rc;
 
                seq_printf(m, "status:\t\t%s\n",
@@ -9877,7 +9885,7 @@ static int tpacpi_lcdshadow_init(struct ibm_init_struct *iibm)
                return 0;
 
        lcdshadow_dev = drm_privacy_screen_register(&tpacpi_pdev->dev,
-                                                   &lcdshadow_ops);
+                                                   &lcdshadow_ops, NULL);
        if (IS_ERR(lcdshadow_dev))
                return PTR_ERR(lcdshadow_dev);
 
@@ -10122,6 +10130,7 @@ static struct ibm_struct proxsensor_driver_data = {
 
 #define DYTC_CMD_FUNC_CAP     3 /* To get DYTC capabilities */
 #define DYTC_FC_MMC           27 /* MMC Mode supported */
+#define DYTC_FC_PSC           29 /* PSC Mode supported */
 
 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
@@ -10132,12 +10141,17 @@ static struct ibm_struct proxsensor_driver_data = {
 
 #define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
 #define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
-#define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
+#define DYTC_FUNCTION_MMC     11 /* Function = 11, MMC mode */
+#define DYTC_FUNCTION_PSC     13 /* Function = 13, PSC mode */
+
+#define DYTC_MODE_MMC_PERFORM  2  /* High power mode aka performance */
+#define DYTC_MODE_MMC_LOWPOWER 3  /* Low power mode */
+#define DYTC_MODE_MMC_BALANCE  0xF  /* Default mode aka balanced */
+#define DYTC_MODE_MMC_DEFAULT  0  /* Default mode from MMC_GET, aka balanced */
 
-#define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
-#define DYTC_MODE_LOWPOWER    3  /* Low power mode */
-#define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
-#define DYTC_MODE_MMC_BALANCE 0  /* Default mode from MMC_GET, aka balanced */
+#define DYTC_MODE_PSC_LOWPOWER 3  /* Low power mode */
+#define DYTC_MODE_PSC_BALANCE  5  /* Default mode aka balanced */
+#define DYTC_MODE_PSC_PERFORM  7  /* High power mode aka performance */
 
 #define DYTC_ERR_MASK       0xF  /* Bits 0-3 in cmd result are the error result */
 #define DYTC_ERR_SUCCESS      1  /* CMD completed successful */
@@ -10147,10 +10161,16 @@ static struct ibm_struct proxsensor_driver_data = {
         (mode) << DYTC_SET_MODE_BIT | \
         (on) << DYTC_SET_VALID_BIT)
 
-#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
+#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
+#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
 
-#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
+enum dytc_profile_funcmode {
+       DYTC_FUNCMODE_NONE = 0,
+       DYTC_FUNCMODE_MMC,
+       DYTC_FUNCMODE_PSC,
+};
 
+static enum dytc_profile_funcmode dytc_profile_available;
 static enum platform_profile_option dytc_current_profile;
 static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
 static DEFINE_MUTEX(dytc_mutex);
@@ -10158,19 +10178,37 @@ static bool dytc_mmc_get_available;
 
 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
 {
-       switch (dytcmode) {
-       case DYTC_MODE_LOWPOWER:
-               *profile = PLATFORM_PROFILE_LOW_POWER;
-               break;
-       case DYTC_MODE_BALANCE:
-       case DYTC_MODE_MMC_BALANCE:
-               *profile =  PLATFORM_PROFILE_BALANCED;
-               break;
-       case DYTC_MODE_PERFORM:
-               *profile =  PLATFORM_PROFILE_PERFORMANCE;
-               break;
-       default: /* Unknown mode */
-               return -EINVAL;
+       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+               switch (dytcmode) {
+               case DYTC_MODE_MMC_LOWPOWER:
+                       *profile = PLATFORM_PROFILE_LOW_POWER;
+                       break;
+               case DYTC_MODE_MMC_DEFAULT:
+               case DYTC_MODE_MMC_BALANCE:
+                       *profile =  PLATFORM_PROFILE_BALANCED;
+                       break;
+               case DYTC_MODE_MMC_PERFORM:
+                       *profile =  PLATFORM_PROFILE_PERFORMANCE;
+                       break;
+               default: /* Unknown mode */
+                       return -EINVAL;
+               }
+               return 0;
+       }
+       if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+               switch (dytcmode) {
+               case DYTC_MODE_PSC_LOWPOWER:
+                       *profile = PLATFORM_PROFILE_LOW_POWER;
+                       break;
+               case DYTC_MODE_PSC_BALANCE:
+                       *profile =  PLATFORM_PROFILE_BALANCED;
+                       break;
+               case DYTC_MODE_PSC_PERFORM:
+                       *profile =  PLATFORM_PROFILE_PERFORMANCE;
+                       break;
+               default: /* Unknown mode */
+                       return -EINVAL;
+               }
        }
        return 0;
 }
@@ -10179,13 +10217,22 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
 {
        switch (profile) {
        case PLATFORM_PROFILE_LOW_POWER:
-               *perfmode = DYTC_MODE_LOWPOWER;
+               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+                       *perfmode = DYTC_MODE_MMC_LOWPOWER;
+               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+                       *perfmode = DYTC_MODE_PSC_LOWPOWER;
                break;
        case PLATFORM_PROFILE_BALANCED:
-               *perfmode = DYTC_MODE_BALANCE;
+               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+                       *perfmode = DYTC_MODE_MMC_BALANCE;
+               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+                       *perfmode = DYTC_MODE_PSC_BALANCE;
                break;
        case PLATFORM_PROFILE_PERFORMANCE:
-               *perfmode = DYTC_MODE_PERFORM;
+               if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+                       *perfmode = DYTC_MODE_MMC_PERFORM;
+               else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+                       *perfmode = DYTC_MODE_PSC_PERFORM;
                break;
        default: /* Unknown profile */
                return -EOPNOTSUPP;
@@ -10251,6 +10298,7 @@ static int dytc_cql_command(int command, int *output)
 static int dytc_profile_set(struct platform_profile_handler *pprof,
                            enum platform_profile_option profile)
 {
+       int perfmode;
        int output;
        int err;
 
@@ -10258,25 +10306,31 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
        if (err)
                return err;
 
-       if (profile == PLATFORM_PROFILE_BALANCED) {
-               /*
-                * To get back to balanced mode we need to issue a reset command.
-                * Note we still need to disable CQL mode before hand and re-enable
-                * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
-                * stuck at 0 for aprox. 30 minutes.
-                */
-               err = dytc_cql_command(DYTC_CMD_RESET, &output);
-               if (err)
-                       goto unlock;
-       } else {
-               int perfmode;
-
-               err = convert_profile_to_dytc(profile, &perfmode);
-               if (err)
-                       goto unlock;
+       err = convert_profile_to_dytc(profile, &perfmode);
+       if (err)
+               goto unlock;
 
-               /* Determine if we are in CQL mode. This alters the commands we do */
-               err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output);
+       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+               if (profile == PLATFORM_PROFILE_BALANCED) {
+                       /*
+                        * To get back to balanced mode we need to issue a reset command.
+                        * Note we still need to disable CQL mode before hand and re-enable
+                        * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
+                        * stuck at 0 for aprox. 30 minutes.
+                        */
+                       err = dytc_cql_command(DYTC_CMD_RESET, &output);
+                       if (err)
+                               goto unlock;
+               } else {
+                       /* Determine if we are in CQL mode. This alters the commands we do */
+                       err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
+                                               &output);
+                       if (err)
+                               goto unlock;
+               }
+       }
+       if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+               err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
                if (err)
                        goto unlock;
        }
@@ -10290,14 +10344,18 @@ unlock:
 static void dytc_profile_refresh(void)
 {
        enum platform_profile_option profile;
-       int output, err;
+       int output, err = 0;
        int perfmode;
 
        mutex_lock(&dytc_mutex);
-       if (dytc_mmc_get_available)
-               err = dytc_command(DYTC_CMD_MMC_GET, &output);
-       else
-               err = dytc_cql_command(DYTC_CMD_GET, &output);
+       if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+               if (dytc_mmc_get_available)
+                       err = dytc_command(DYTC_CMD_MMC_GET, &output);
+               else
+                       err = dytc_cql_command(DYTC_CMD_GET, &output);
+       } else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+               err = dytc_command(DYTC_CMD_GET, &output);
+
        mutex_unlock(&dytc_mutex);
        if (err)
                return;
@@ -10324,6 +10382,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
        set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
 
+       dytc_profile_available = DYTC_FUNCMODE_NONE;
        err = dytc_command(DYTC_CMD_QUERY, &output);
        if (err)
                return err;
@@ -10335,27 +10394,34 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
        if (dytc_version < 5)
                return -ENODEV;
 
-       /* Check what capabilities are supported. Currently MMC is needed */
+       /* Check what capabilities are supported */
        err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
        if (err)
                return err;
-       if (!(output & BIT(DYTC_FC_MMC))) {
-               dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+
+       if (output & BIT(DYTC_FC_MMC)) { /* MMC MODE */
+               dytc_profile_available = DYTC_FUNCMODE_MMC;
+
+               /*
+                * Check if MMC_GET functionality available
+                * Version > 6 and return success from MMC_GET command
+                */
+               dytc_mmc_get_available = false;
+               if (dytc_version >= 6) {
+                       err = dytc_command(DYTC_CMD_MMC_GET, &output);
+                       if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
+                               dytc_mmc_get_available = true;
+               }
+       } else if (output & BIT(DYTC_FC_PSC)) { /* PSC MODE */
+               dytc_profile_available = DYTC_FUNCMODE_PSC;
+       } else {
+               dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
                return -ENODEV;
        }
 
        dbg_printk(TPACPI_DBG_INIT,
                        "DYTC version %d: thermal mode available\n", dytc_version);
-       /*
-        * Check if MMC_GET functionality available
-        * Version > 6 and return success from MMC_GET command
-        */
-       dytc_mmc_get_available = false;
-       if (dytc_version >= 6) {
-               err = dytc_command(DYTC_CMD_MMC_GET, &output);
-               if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
-                       dytc_mmc_get_available = true;
-       }
+
        /* Create platform_profile structure and register */
        err = platform_profile_register(&dytc_profile);
        /*
@@ -10373,6 +10439,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
 
 static void dytc_profile_exit(void)
 {
+       dytc_profile_available = DYTC_FUNCMODE_NONE;
        platform_profile_remove();
 }