X-Git-Url: http://git.monstr.eu/?a=blobdiff_plain;f=drivers%2Fplatform%2Fx86%2Fthinkpad_acpi.c;h=c568fae56db29ab979c8dfbdb30f9dd852627559;hb=1464677662943738741500a6f16b85d36bbde2be;hp=3424b080db7729b257b1b67cd00e8c39fc5f0833;hpb=31035f3e20af4ede5f1c8162068327ea0b35a96e;p=linux-2.6-microblaze.git diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 3424b080db77..c568fae56db2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -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(¤t_level) < 0)) + fan_get_status_safe(¤t_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(); }