Skip to content

Commit d63609e

Browse files
committed
Merge tag 'platform-drivers-x86-v6.14-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver fixes from Ilpo Järvinen: - thinkpad_acpi: - Fix registration of tpacpi platform driver - Support fan speed in ticks per revolution (Thinkpad X120e) - Support V9 DYTC profiles (new Thinkpad AMD platforms) - int3472: Handle GPIO "enable" vs "reset" variation (ov7251) * tag 'platform-drivers-x86-v6.14-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: platform/x86: thinkpad_acpi: Fix registration of tpacpi platform driver platform/x86: int3472: Call "reset" GPIO "enable" for INT347E platform/x86: int3472: Use correct type for "polarity", call it gpio_flags platform/x86: thinkpad_acpi: Support for V9 DYTC platform profiles platform/x86: thinkpad_acpi: Fix invalid fan speed on ThinkPad X120e
2 parents 4dc1d1b + b3e127d commit d63609e

File tree

2 files changed

+110
-36
lines changed

2 files changed

+110
-36
lines changed

drivers/platform/x86/intel/int3472/discrete.c

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/* Author: Dan Scally <[email protected]> */
33

44
#include <linux/acpi.h>
5+
#include <linux/array_size.h>
56
#include <linux/bitfield.h>
67
#include <linux/device.h>
78
#include <linux/gpio/consumer.h>
@@ -55,7 +56,7 @@ static void skl_int3472_log_sensor_module_name(struct int3472_discrete_device *i
5556

5657
static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
5758
struct acpi_resource_gpio *agpio,
58-
const char *func, u32 polarity)
59+
const char *func, unsigned long gpio_flags)
5960
{
6061
char *path = agpio->resource_source.string_ptr;
6162
struct acpi_device *adev;
@@ -70,14 +71,14 @@ static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
7071
if (!adev)
7172
return -ENODEV;
7273

73-
*table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], func, polarity);
74+
*table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], func, gpio_flags);
7475

7576
return 0;
7677
}
7778

7879
static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
7980
struct acpi_resource_gpio *agpio,
80-
const char *func, u32 polarity)
81+
const char *func, unsigned long gpio_flags)
8182
{
8283
int ret;
8384

@@ -87,7 +88,7 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
8788
}
8889

8990
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
90-
agpio, func, polarity);
91+
agpio, func, gpio_flags);
9192
if (ret)
9293
return ret;
9394

@@ -100,7 +101,7 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
100101
static struct gpio_desc *
101102
skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
102103
struct acpi_resource_gpio *agpio,
103-
const char *func, u32 polarity)
104+
const char *func, unsigned long gpio_flags)
104105
{
105106
struct gpio_desc *desc;
106107
int ret;
@@ -111,7 +112,7 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
111112
return ERR_PTR(-ENOMEM);
112113

113114
lookup->dev_id = dev_name(int3472->dev);
114-
ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, polarity);
115+
ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, gpio_flags);
115116
if (ret)
116117
return ERR_PTR(ret);
117118

@@ -122,32 +123,76 @@ skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
122123
return desc;
123124
}
124125

125-
static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
126+
/**
127+
* struct int3472_gpio_map - Map GPIOs to whatever is expected by the
128+
* sensor driver (as in DT bindings)
129+
* @hid: The ACPI HID of the device without the instance number e.g. INT347E
130+
* @type_from: The GPIO type from ACPI ?SDT
131+
* @type_to: The assigned GPIO type, typically same as @type_from
132+
* @func: The function, e.g. "enable"
133+
* @polarity_low: GPIO_ACTIVE_LOW true if the @polarity_low is true,
134+
* GPIO_ACTIVE_HIGH otherwise
135+
*/
136+
struct int3472_gpio_map {
137+
const char *hid;
138+
u8 type_from;
139+
u8 type_to;
140+
bool polarity_low;
141+
const char *func;
142+
};
143+
144+
static const struct int3472_gpio_map int3472_gpio_map[] = {
145+
{ "INT347E", INT3472_GPIO_TYPE_RESET, INT3472_GPIO_TYPE_RESET, false, "enable" },
146+
};
147+
148+
static void int3472_get_func_and_polarity(struct acpi_device *adev, u8 *type,
149+
const char **func, unsigned long *gpio_flags)
126150
{
127-
switch (type) {
151+
unsigned int i;
152+
153+
for (i = 0; i < ARRAY_SIZE(int3472_gpio_map); i++) {
154+
/*
155+
* Map the firmware-provided GPIO to whatever a driver expects
156+
* (as in DT bindings). First check if the type matches with the
157+
* GPIO map, then further check that the device _HID matches.
158+
*/
159+
if (*type != int3472_gpio_map[i].type_from)
160+
continue;
161+
162+
if (!acpi_dev_hid_uid_match(adev, int3472_gpio_map[i].hid, NULL))
163+
continue;
164+
165+
*type = int3472_gpio_map[i].type_to;
166+
*gpio_flags = int3472_gpio_map[i].polarity_low ?
167+
GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH;
168+
*func = int3472_gpio_map[i].func;
169+
return;
170+
}
171+
172+
switch (*type) {
128173
case INT3472_GPIO_TYPE_RESET:
129174
*func = "reset";
130-
*polarity = GPIO_ACTIVE_LOW;
175+
*gpio_flags = GPIO_ACTIVE_LOW;
131176
break;
132177
case INT3472_GPIO_TYPE_POWERDOWN:
133178
*func = "powerdown";
134-
*polarity = GPIO_ACTIVE_LOW;
179+
*gpio_flags = GPIO_ACTIVE_LOW;
135180
break;
136181
case INT3472_GPIO_TYPE_CLK_ENABLE:
137182
*func = "clk-enable";
138-
*polarity = GPIO_ACTIVE_HIGH;
183+
*gpio_flags = GPIO_ACTIVE_HIGH;
139184
break;
140185
case INT3472_GPIO_TYPE_PRIVACY_LED:
141186
*func = "privacy-led";
142-
*polarity = GPIO_ACTIVE_HIGH;
187+
*gpio_flags = GPIO_ACTIVE_HIGH;
143188
break;
144189
case INT3472_GPIO_TYPE_POWER_ENABLE:
145190
*func = "power-enable";
146-
*polarity = GPIO_ACTIVE_HIGH;
191+
*gpio_flags = GPIO_ACTIVE_HIGH;
147192
break;
148193
default:
149194
*func = "unknown";
150-
*polarity = GPIO_ACTIVE_HIGH;
195+
*gpio_flags = GPIO_ACTIVE_HIGH;
151196
break;
152197
}
153198
}
@@ -194,7 +239,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
194239
struct gpio_desc *gpio;
195240
const char *err_msg;
196241
const char *func;
197-
u32 polarity;
242+
unsigned long gpio_flags;
198243
int ret;
199244

200245
if (!acpi_gpio_get_io_resource(ares, &agpio))
@@ -217,7 +262,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
217262

218263
type = FIELD_GET(INT3472_GPIO_DSM_TYPE, obj->integer.value);
219264

220-
int3472_get_func_and_polarity(type, &func, &polarity);
265+
int3472_get_func_and_polarity(int3472->sensor, &type, &func, &gpio_flags);
221266

222267
pin = FIELD_GET(INT3472_GPIO_DSM_PIN, obj->integer.value);
223268
/* Pin field is not really used under Windows and wraps around at 8 bits */
@@ -227,24 +272,24 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
227272

228273
active_value = FIELD_GET(INT3472_GPIO_DSM_SENSOR_ON_VAL, obj->integer.value);
229274
if (!active_value)
230-
polarity ^= GPIO_ACTIVE_LOW;
275+
gpio_flags ^= GPIO_ACTIVE_LOW;
231276

232277
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func,
233278
agpio->resource_source.string_ptr, agpio->pin_table[0],
234-
str_high_low(polarity == GPIO_ACTIVE_HIGH));
279+
str_high_low(gpio_flags == GPIO_ACTIVE_HIGH));
235280

236281
switch (type) {
237282
case INT3472_GPIO_TYPE_RESET:
238283
case INT3472_GPIO_TYPE_POWERDOWN:
239-
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, polarity);
284+
ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, gpio_flags);
240285
if (ret)
241286
err_msg = "Failed to map GPIO pin to sensor\n";
242287

243288
break;
244289
case INT3472_GPIO_TYPE_CLK_ENABLE:
245290
case INT3472_GPIO_TYPE_PRIVACY_LED:
246291
case INT3472_GPIO_TYPE_POWER_ENABLE:
247-
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, polarity);
292+
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, gpio_flags);
248293
if (IS_ERR(gpio)) {
249294
ret = PTR_ERR(gpio);
250295
err_msg = "Failed to get GPIO\n";

drivers/platform/x86/thinkpad_acpi.c

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7885,6 +7885,7 @@ static struct ibm_struct volume_driver_data = {
78857885

78867886
#define FAN_NS_CTRL_STATUS BIT(2) /* Bit which determines control is enabled or not */
78877887
#define FAN_NS_CTRL BIT(4) /* Bit which determines control is by host or EC */
7888+
#define FAN_CLOCK_TPM (22500*60) /* Ticks per minute for a 22.5 kHz clock */
78887889

78897890
enum { /* Fan control constants */
78907891
fan_status_offset = 0x2f, /* EC register 0x2f */
@@ -7940,6 +7941,7 @@ static int fan_watchdog_maxinterval;
79407941

79417942
static bool fan_with_ns_addr;
79427943
static bool ecfw_with_fan_dec_rpm;
7944+
static bool fan_speed_in_tpr;
79437945

79447946
static struct mutex fan_mutex;
79457947

@@ -8142,8 +8144,11 @@ static int fan_get_speed(unsigned int *speed)
81428144
!acpi_ec_read(fan_rpm_offset + 1, &hi)))
81438145
return -EIO;
81448146

8145-
if (likely(speed))
8147+
if (likely(speed)) {
81468148
*speed = (hi << 8) | lo;
8149+
if (fan_speed_in_tpr && *speed != 0)
8150+
*speed = FAN_CLOCK_TPM / *speed;
8151+
}
81478152
break;
81488153
case TPACPI_FAN_RD_TPEC_NS:
81498154
if (!acpi_ec_read(fan_rpm_status_ns, &lo))
@@ -8176,8 +8181,11 @@ static int fan2_get_speed(unsigned int *speed)
81768181
if (rc)
81778182
return -EIO;
81788183

8179-
if (likely(speed))
8184+
if (likely(speed)) {
81808185
*speed = (hi << 8) | lo;
8186+
if (fan_speed_in_tpr && *speed != 0)
8187+
*speed = FAN_CLOCK_TPM / *speed;
8188+
}
81818189
break;
81828190

81838191
case TPACPI_FAN_RD_TPEC_NS:
@@ -8788,6 +8796,7 @@ static const struct attribute_group fan_driver_attr_group = {
87888796
#define TPACPI_FAN_NOFAN 0x0008 /* no fan available */
87898797
#define TPACPI_FAN_NS 0x0010 /* For EC with non-Standard register addresses */
87908798
#define TPACPI_FAN_DECRPM 0x0020 /* For ECFW's with RPM in register as decimal */
8799+
#define TPACPI_FAN_TPR 0x0040 /* Fan speed is in Ticks Per Revolution */
87918800

87928801
static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
87938802
TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
@@ -8817,6 +8826,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
88178826
TPACPI_Q_LNV3('R', '0', 'V', TPACPI_FAN_NS), /* 11e Gen5 KL-Y */
88188827
TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
88198828
TPACPI_Q_LNV3('R', '0', 'Q', TPACPI_FAN_DECRPM),/* L480 */
8829+
TPACPI_Q_LNV('8', 'F', TPACPI_FAN_TPR), /* ThinkPad x120e */
88208830
};
88218831

88228832
static int __init fan_init(struct ibm_init_struct *iibm)
@@ -8887,6 +8897,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
88878897

88888898
if (quirks & TPACPI_FAN_Q1)
88898899
fan_quirk1_setup();
8900+
if (quirks & TPACPI_FAN_TPR)
8901+
fan_speed_in_tpr = true;
88908902
/* Try and probe the 2nd fan */
88918903
tp_features.second_fan = 1; /* needed for get_speed to work */
88928904
res = fan2_get_speed(&speed);
@@ -10319,6 +10331,10 @@ static struct ibm_struct proxsensor_driver_data = {
1031910331
#define DYTC_MODE_PSC_BALANCE 5 /* Default mode aka balanced */
1032010332
#define DYTC_MODE_PSC_PERFORM 7 /* High power mode aka performance */
1032110333

10334+
#define DYTC_MODE_PSCV9_LOWPOWER 1 /* Low power mode */
10335+
#define DYTC_MODE_PSCV9_BALANCE 3 /* Default mode aka balanced */
10336+
#define DYTC_MODE_PSCV9_PERFORM 4 /* High power mode aka performance */
10337+
1032210338
#define DYTC_ERR_MASK 0xF /* Bits 0-3 in cmd result are the error result */
1032310339
#define DYTC_ERR_SUCCESS 1 /* CMD completed successful */
1032410340

@@ -10339,6 +10355,10 @@ static int dytc_capabilities;
1033910355
static bool dytc_mmc_get_available;
1034010356
static int profile_force;
1034110357

10358+
static int platform_psc_profile_lowpower = DYTC_MODE_PSC_LOWPOWER;
10359+
static int platform_psc_profile_balanced = DYTC_MODE_PSC_BALANCE;
10360+
static int platform_psc_profile_performance = DYTC_MODE_PSC_PERFORM;
10361+
1034210362
static int convert_dytc_to_profile(int funcmode, int dytcmode,
1034310363
enum platform_profile_option *profile)
1034410364
{
@@ -10360,19 +10380,15 @@ static int convert_dytc_to_profile(int funcmode, int dytcmode,
1036010380
}
1036110381
return 0;
1036210382
case DYTC_FUNCTION_PSC:
10363-
switch (dytcmode) {
10364-
case DYTC_MODE_PSC_LOWPOWER:
10383+
if (dytcmode == platform_psc_profile_lowpower)
1036510384
*profile = PLATFORM_PROFILE_LOW_POWER;
10366-
break;
10367-
case DYTC_MODE_PSC_BALANCE:
10385+
else if (dytcmode == platform_psc_profile_balanced)
1036810386
*profile = PLATFORM_PROFILE_BALANCED;
10369-
break;
10370-
case DYTC_MODE_PSC_PERFORM:
10387+
else if (dytcmode == platform_psc_profile_performance)
1037110388
*profile = PLATFORM_PROFILE_PERFORMANCE;
10372-
break;
10373-
default: /* Unknown mode */
10389+
else
1037410390
return -EINVAL;
10375-
}
10391+
1037610392
return 0;
1037710393
case DYTC_FUNCTION_AMT:
1037810394
/* For now return balanced. It's the closest we have to 'auto' */
@@ -10393,19 +10409,19 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
1039310409
if (dytc_capabilities & BIT(DYTC_FC_MMC))
1039410410
*perfmode = DYTC_MODE_MMC_LOWPOWER;
1039510411
else if (dytc_capabilities & BIT(DYTC_FC_PSC))
10396-
*perfmode = DYTC_MODE_PSC_LOWPOWER;
10412+
*perfmode = platform_psc_profile_lowpower;
1039710413
break;
1039810414
case PLATFORM_PROFILE_BALANCED:
1039910415
if (dytc_capabilities & BIT(DYTC_FC_MMC))
1040010416
*perfmode = DYTC_MODE_MMC_BALANCE;
1040110417
else if (dytc_capabilities & BIT(DYTC_FC_PSC))
10402-
*perfmode = DYTC_MODE_PSC_BALANCE;
10418+
*perfmode = platform_psc_profile_balanced;
1040310419
break;
1040410420
case PLATFORM_PROFILE_PERFORMANCE:
1040510421
if (dytc_capabilities & BIT(DYTC_FC_MMC))
1040610422
*perfmode = DYTC_MODE_MMC_PERFORM;
1040710423
else if (dytc_capabilities & BIT(DYTC_FC_PSC))
10408-
*perfmode = DYTC_MODE_PSC_PERFORM;
10424+
*perfmode = platform_psc_profile_performance;
1040910425
break;
1041010426
default: /* Unknown profile */
1041110427
return -EOPNOTSUPP;
@@ -10599,6 +10615,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1059910615
if (output & BIT(DYTC_QUERY_ENABLE_BIT))
1060010616
dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
1060110617

10618+
dbg_printk(TPACPI_DBG_INIT, "DYTC version %d\n", dytc_version);
1060210619
/* Check DYTC is enabled and supports mode setting */
1060310620
if (dytc_version < 5)
1060410621
return -ENODEV;
@@ -10637,6 +10654,11 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1063710654
}
1063810655
} else if (dytc_capabilities & BIT(DYTC_FC_PSC)) { /* PSC MODE */
1063910656
pr_debug("PSC is supported\n");
10657+
if (dytc_version >= 9) { /* update profiles for DYTC 9 and up */
10658+
platform_psc_profile_lowpower = DYTC_MODE_PSCV9_LOWPOWER;
10659+
platform_psc_profile_balanced = DYTC_MODE_PSCV9_BALANCE;
10660+
platform_psc_profile_performance = DYTC_MODE_PSCV9_PERFORM;
10661+
}
1064010662
} else {
1064110663
dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
1064210664
return -ENODEV;
@@ -10646,8 +10668,8 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1064610668
"DYTC version %d: thermal mode available\n", dytc_version);
1064710669

1064810670
/* Create platform_profile structure and register */
10649-
tpacpi_pprof = devm_platform_profile_register(&tpacpi_pdev->dev, "thinkpad-acpi",
10650-
NULL, &dytc_profile_ops);
10671+
tpacpi_pprof = platform_profile_register(&tpacpi_pdev->dev, "thinkpad-acpi-profile",
10672+
NULL, &dytc_profile_ops);
1065110673
/*
1065210674
* If for some reason platform_profiles aren't enabled
1065310675
* don't quit terminally.
@@ -10665,8 +10687,15 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
1066510687
return 0;
1066610688
}
1066710689

10690+
static void dytc_profile_exit(void)
10691+
{
10692+
if (!IS_ERR_OR_NULL(tpacpi_pprof))
10693+
platform_profile_remove(tpacpi_pprof);
10694+
}
10695+
1066810696
static struct ibm_struct dytc_profile_driver_data = {
1066910697
.name = "dytc-profile",
10698+
.exit = dytc_profile_exit,
1067010699
};
1067110700

1067210701
/*************************************************************************

0 commit comments

Comments
 (0)