mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
platform-drivers-x86 for v5.17-2
Highlights: - Bunch of fixes for the new x86-android-tablets module - Misc. other fixes - A couple of hw-id additions The following is an automated git shortlog grouped by driver: ISST: - Fix possible circular locking dependency detected amd-pmc: - Correct usage of SMU version - Make amd_pmc_stb_debugfs_fops static asus-tf103c-dock: - Make 2 global structs static intel_crystal_cove_charger: - Fix IRQ masking / unmasking platform/surface: - Reinstate platform dependency thinkpad_acpi: - Fix incorrect use of platform profile on AMD platforms - Add quirk for ThinkPads without a fan touchscreen_dmi: - Add info for the RWC NANOTE P8 AY07J 2-in-1 x86-android-tablets: - Trivial typo fix for MODULE_AUTHOR - Fix the buttons on CZC P10T tablet - Constify the gpiod_lookup_tables arrays - Add an init() callback to struct x86_dev_info - Add support for disabling ACPI _AEI handlers - Correct crystal_cove_charger module name -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmH5VKoUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9yw2AgAwIbIW+IU25AAQ828qapfTFCYM8Pr +MueVwrOcygNrqkl/qn02VPojubUv9ZRbYxWnFoSNqxI2/uiILE9d4vwaWu8TQqt h3MoyU8vaDkzkIqU+o8l5st1DBbtOdyY0n9lgK8QJc/W68VFanrVh2AkKcXBD3jM XuLtT9WDCadSE1C/YAoLxv+QKnn41gqzwC3NN+OIe+8ex/Nw3b3QIeT7Ku9nqNHb sB14MQq50c3ETDz4g1CGNowJodxq9y83wO5tABGlDxfH/6WwlEzexNYfoYnaKfK9 Yq/c0z78MX+ya8CaIVh3j10x4tmpYISFQJVOHwWhQ9/3YJquqqlPPU33pg== =ZAmn -----END PGP SIGNATURE----- Merge tag 'platform-drivers-x86-v5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86 Pull x86 platform driver fixes from Hans de Goede: "This consists of various build- and bug-fixes as well as a few hardware-id additions. Highlights: - Bunch of fixes for the new x86-android-tablets module - Misc other fixes - A couple of hw-id additions" * tag 'platform-drivers-x86-v5.17-2' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: platform/x86: thinkpad_acpi: Fix incorrect use of platform profile on AMD platforms platform/x86: amd-pmc: Correct usage of SMU version platform/x86: asus-tf103c-dock: Make 2 global structs static platform/x86: amd-pmc: Make amd_pmc_stb_debugfs_fops static platform/x86: ISST: Fix possible circular locking dependency detected platform/x86: intel_crystal_cove_charger: Fix IRQ masking / unmasking platform/x86: thinkpad_acpi: Add quirk for ThinkPads without a fan platform/x86: touchscreen_dmi: Add info for the RWC NANOTE P8 AY07J 2-in-1 platform/surface: Reinstate platform dependency platform/x86: x86-android-tablets: Trivial typo fix for MODULE_AUTHOR platform/x86: x86-android-tablets: Fix the buttons on CZC P10T tablet platform/x86: x86-android-tablets: Constify the gpiod_lookup_tables arrays platform/x86: x86-android-tablets: Add an init() callback to struct x86_dev_info platform/x86: x86-android-tablets: Add support for disabling ACPI _AEI handlers platform/x86: x86-android-tablets: Correct crystal_cove_charger module name
This commit is contained in:
commit
83c2713a67
@ -5,6 +5,7 @@
|
||||
|
||||
menuconfig SURFACE_PLATFORMS
|
||||
bool "Microsoft Surface Platform-Specific Device Drivers"
|
||||
depends on ARM64 || X86 || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
Say Y here to get to see options for platform-specific device drivers
|
||||
|
@ -124,9 +124,10 @@ struct amd_pmc_dev {
|
||||
u32 cpu_id;
|
||||
u32 active_ips;
|
||||
/* SMU version information */
|
||||
u16 major;
|
||||
u16 minor;
|
||||
u16 rev;
|
||||
u8 smu_program;
|
||||
u8 major;
|
||||
u8 minor;
|
||||
u8 rev;
|
||||
struct device *dev;
|
||||
struct pci_dev *rdev;
|
||||
struct mutex lock; /* generic mutex lock */
|
||||
@ -180,11 +181,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
dev->major = (val >> 16) & GENMASK(15, 0);
|
||||
dev->smu_program = (val >> 24) & GENMASK(7, 0);
|
||||
dev->major = (val >> 16) & GENMASK(7, 0);
|
||||
dev->minor = (val >> 8) & GENMASK(7, 0);
|
||||
dev->rev = (val >> 0) & GENMASK(7, 0);
|
||||
|
||||
dev_dbg(dev->dev, "SMU version is %u.%u.%u\n", dev->major, dev->minor, dev->rev);
|
||||
dev_dbg(dev->dev, "SMU program %u version is %u.%u.%u\n",
|
||||
dev->smu_program, dev->major, dev->minor, dev->rev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -226,7 +229,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations amd_pmc_stb_debugfs_fops = {
|
||||
static const struct file_operations amd_pmc_stb_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = amd_pmc_stb_debugfs_open,
|
||||
.read = amd_pmc_stb_debugfs_read,
|
||||
|
@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct hid_ll_driver tf103c_dock_hid_ll_driver = {
|
||||
static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
|
||||
.parse = tf103c_dock_hid_parse,
|
||||
.start = tf103c_dock_hid_start,
|
||||
.stop = tf103c_dock_hid_stop,
|
||||
@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
|
||||
static SIMPLE_DEV_PM_OPS(tf103c_dock_pm_ops, tf103c_dock_suspend, tf103c_dock_resume);
|
||||
|
||||
static const struct acpi_device_id tf103c_dock_acpi_match[] = {
|
||||
{"NPCE69A"},
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/regmap.h>
|
||||
|
||||
#define CHGRIRQ_REG 0x0a
|
||||
#define MCHGRIRQ_REG 0x17
|
||||
|
||||
struct crystal_cove_charger_data {
|
||||
struct mutex buslock; /* irq_bus_lock */
|
||||
@ -25,8 +26,8 @@ struct crystal_cove_charger_data {
|
||||
struct irq_domain *irq_domain;
|
||||
int irq;
|
||||
int charger_irq;
|
||||
bool irq_enabled;
|
||||
bool irq_is_enabled;
|
||||
u8 mask;
|
||||
u8 new_mask;
|
||||
};
|
||||
|
||||
static irqreturn_t crystal_cove_charger_irq(int irq, void *data)
|
||||
@ -53,13 +54,9 @@ static void crystal_cove_charger_irq_bus_sync_unlock(struct irq_data *data)
|
||||
{
|
||||
struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
|
||||
|
||||
if (charger->irq_is_enabled != charger->irq_enabled) {
|
||||
if (charger->irq_enabled)
|
||||
enable_irq(charger->irq);
|
||||
else
|
||||
disable_irq(charger->irq);
|
||||
|
||||
charger->irq_is_enabled = charger->irq_enabled;
|
||||
if (charger->mask != charger->new_mask) {
|
||||
regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
|
||||
charger->mask = charger->new_mask;
|
||||
}
|
||||
|
||||
mutex_unlock(&charger->buslock);
|
||||
@ -69,14 +66,14 @@ static void crystal_cove_charger_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
|
||||
|
||||
charger->irq_enabled = true;
|
||||
charger->new_mask &= ~BIT(data->hwirq);
|
||||
}
|
||||
|
||||
static void crystal_cove_charger_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
|
||||
|
||||
charger->irq_enabled = false;
|
||||
charger->new_mask |= BIT(data->hwirq);
|
||||
}
|
||||
|
||||
static void crystal_cove_charger_rm_irq_domain(void *data)
|
||||
@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev)
|
||||
irq_set_nested_thread(charger->charger_irq, true);
|
||||
irq_set_noprobe(charger->charger_irq);
|
||||
|
||||
/* Mask the single 2nd level IRQ before enabling the 1st level IRQ */
|
||||
charger->mask = charger->new_mask = BIT(0);
|
||||
regmap_write(charger->regmap, MCHGRIRQ_REG, charger->mask);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
|
||||
crystal_cove_charger_irq,
|
||||
IRQF_ONESHOT | IRQF_NO_AUTOEN,
|
||||
KBUILD_MODNAME, charger);
|
||||
IRQF_ONESHOT, KBUILD_MODNAME, charger);
|
||||
if (ret)
|
||||
return dev_err_probe(&pdev->dev, ret, "requesting irq\n");
|
||||
|
||||
|
@ -596,7 +596,10 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(punit_misc_dev_lock);
|
||||
/* Lock to prevent module registration when already opened by user space */
|
||||
static DEFINE_MUTEX(punit_misc_dev_open_lock);
|
||||
/* Lock to allow one share misc device for all ISST interace */
|
||||
static DEFINE_MUTEX(punit_misc_dev_reg_lock);
|
||||
static int misc_usage_count;
|
||||
static int misc_device_ret;
|
||||
static int misc_device_open;
|
||||
@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
|
||||
int i, ret = 0;
|
||||
|
||||
/* Fail open, if a module is going away */
|
||||
mutex_lock(&punit_misc_dev_lock);
|
||||
mutex_lock(&punit_misc_dev_open_lock);
|
||||
for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
|
||||
struct isst_if_cmd_cb *cb = &punit_callbacks[i];
|
||||
|
||||
@ -628,7 +631,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
|
||||
} else {
|
||||
misc_device_open++;
|
||||
}
|
||||
mutex_unlock(&punit_misc_dev_lock);
|
||||
mutex_unlock(&punit_misc_dev_open_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&punit_misc_dev_lock);
|
||||
mutex_lock(&punit_misc_dev_open_lock);
|
||||
misc_device_open--;
|
||||
for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
|
||||
struct isst_if_cmd_cb *cb = &punit_callbacks[i];
|
||||
@ -645,7 +648,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
|
||||
if (cb->registered)
|
||||
module_put(cb->owner);
|
||||
}
|
||||
mutex_unlock(&punit_misc_dev_lock);
|
||||
mutex_unlock(&punit_misc_dev_open_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = {
|
||||
.fops = &isst_if_char_driver_ops,
|
||||
};
|
||||
|
||||
static int isst_misc_reg(void)
|
||||
{
|
||||
mutex_lock(&punit_misc_dev_reg_lock);
|
||||
if (misc_device_ret)
|
||||
goto unlock_exit;
|
||||
|
||||
if (!misc_usage_count) {
|
||||
misc_device_ret = isst_if_cpu_info_init();
|
||||
if (misc_device_ret)
|
||||
goto unlock_exit;
|
||||
|
||||
misc_device_ret = misc_register(&isst_if_char_driver);
|
||||
if (misc_device_ret) {
|
||||
isst_if_cpu_info_exit();
|
||||
goto unlock_exit;
|
||||
}
|
||||
}
|
||||
misc_usage_count++;
|
||||
|
||||
unlock_exit:
|
||||
mutex_unlock(&punit_misc_dev_reg_lock);
|
||||
|
||||
return misc_device_ret;
|
||||
}
|
||||
|
||||
static void isst_misc_unreg(void)
|
||||
{
|
||||
mutex_lock(&punit_misc_dev_reg_lock);
|
||||
if (misc_usage_count)
|
||||
misc_usage_count--;
|
||||
if (!misc_usage_count && !misc_device_ret) {
|
||||
misc_deregister(&isst_if_char_driver);
|
||||
isst_if_cpu_info_exit();
|
||||
}
|
||||
mutex_unlock(&punit_misc_dev_reg_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* isst_if_cdev_register() - Register callback for IOCTL
|
||||
* @device_type: The device type this callback handling.
|
||||
@ -679,38 +719,31 @@ static struct miscdevice isst_if_char_driver = {
|
||||
*/
|
||||
int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
|
||||
{
|
||||
if (misc_device_ret)
|
||||
return misc_device_ret;
|
||||
int ret;
|
||||
|
||||
if (device_type >= ISST_IF_DEV_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&punit_misc_dev_lock);
|
||||
mutex_lock(&punit_misc_dev_open_lock);
|
||||
/* Device is already open, we don't want to add new callbacks */
|
||||
if (misc_device_open) {
|
||||
mutex_unlock(&punit_misc_dev_lock);
|
||||
mutex_unlock(&punit_misc_dev_open_lock);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (!misc_usage_count) {
|
||||
int ret;
|
||||
|
||||
misc_device_ret = misc_register(&isst_if_char_driver);
|
||||
if (misc_device_ret)
|
||||
goto unlock_exit;
|
||||
|
||||
ret = isst_if_cpu_info_init();
|
||||
if (ret) {
|
||||
misc_deregister(&isst_if_char_driver);
|
||||
misc_device_ret = ret;
|
||||
goto unlock_exit;
|
||||
}
|
||||
}
|
||||
memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
|
||||
punit_callbacks[device_type].registered = 1;
|
||||
misc_usage_count++;
|
||||
unlock_exit:
|
||||
mutex_unlock(&punit_misc_dev_lock);
|
||||
mutex_unlock(&punit_misc_dev_open_lock);
|
||||
|
||||
return misc_device_ret;
|
||||
ret = isst_misc_reg();
|
||||
if (ret) {
|
||||
/*
|
||||
* No need of mutex as the misc device register failed
|
||||
* as no one can open device yet. Hence no contention.
|
||||
*/
|
||||
punit_callbacks[device_type].registered = 0;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(isst_if_cdev_register);
|
||||
|
||||
@ -725,16 +758,12 @@ EXPORT_SYMBOL_GPL(isst_if_cdev_register);
|
||||
*/
|
||||
void isst_if_cdev_unregister(int device_type)
|
||||
{
|
||||
mutex_lock(&punit_misc_dev_lock);
|
||||
misc_usage_count--;
|
||||
isst_misc_unreg();
|
||||
mutex_lock(&punit_misc_dev_open_lock);
|
||||
punit_callbacks[device_type].registered = 0;
|
||||
if (device_type == ISST_IF_DEV_MBOX)
|
||||
isst_delete_hash();
|
||||
if (!misc_usage_count && !misc_device_ret) {
|
||||
misc_deregister(&isst_if_char_driver);
|
||||
isst_if_cpu_info_exit();
|
||||
}
|
||||
mutex_unlock(&punit_misc_dev_lock);
|
||||
mutex_unlock(&punit_misc_dev_open_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
|
||||
|
||||
|
@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = {
|
||||
.attrs = fan_driver_attributes,
|
||||
};
|
||||
|
||||
#define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */
|
||||
#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */
|
||||
#define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */
|
||||
#define TPACPI_FAN_Q1 0x0001 /* Uninitialized HFSP */
|
||||
#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */
|
||||
#define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */
|
||||
#define TPACPI_FAN_NOFAN 0x0008 /* no fan available */
|
||||
|
||||
static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
|
||||
TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
|
||||
@ -8702,6 +8703,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
|
||||
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', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
|
||||
};
|
||||
|
||||
static int __init fan_init(struct ibm_init_struct *iibm)
|
||||
@ -8730,6 +8732,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
|
||||
quirks = tpacpi_check_quirks(fan_quirk_table,
|
||||
ARRAY_SIZE(fan_quirk_table));
|
||||
|
||||
if (quirks & TPACPI_FAN_NOFAN) {
|
||||
pr_info("No integrated ThinkPad fan available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (gfan_handle) {
|
||||
/* 570, 600e/x, 770e, 770x */
|
||||
fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
|
||||
@ -10112,6 +10119,9 @@ static struct ibm_struct proxsensor_driver_data = {
|
||||
#define DYTC_CMD_MMC_GET 8 /* To get current MMC function and mode */
|
||||
#define DYTC_CMD_RESET 0x1ff /* To reset back to default */
|
||||
|
||||
#define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */
|
||||
#define DYTC_FC_MMC 27 /* MMC Mode supported */
|
||||
|
||||
#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */
|
||||
#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */
|
||||
|
||||
@ -10324,6 +10334,15 @@ 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 */
|
||||
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");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"DYTC version %d: thermal mode available\n", dytc_version);
|
||||
/*
|
||||
|
@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = {
|
||||
.properties = predia_basic_props,
|
||||
};
|
||||
|
||||
static const struct property_entry rwc_nanote_p8_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-min-y", 46),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1728),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
|
||||
PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
|
||||
PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-p8.fw"),
|
||||
PROPERTY_ENTRY_U32("silead,max-fingers", 10),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct ts_dmi_data rwc_nanote_p8_data = {
|
||||
.acpi_name = "MSSL1680:00",
|
||||
.properties = rwc_nanote_p8_props,
|
||||
};
|
||||
|
||||
static const struct property_entry schneider_sct101ctm_props[] = {
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
|
||||
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
|
||||
@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
|
||||
DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* RWC NANOTE P8 */
|
||||
.driver_data = (void *)&rwc_nanote_p8_data,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Default string"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "AY07J"),
|
||||
DMI_MATCH(DMI_PRODUCT_SKU, "0001")
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Schneider SCT101CTM */
|
||||
.driver_data = (void *)&schneider_sct101ctm_data,
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/string.h>
|
||||
/* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
|
||||
#include "../../gpio/gpiolib.h"
|
||||
#include "../../gpio/gpiolib-acpi.h"
|
||||
|
||||
/*
|
||||
* Helper code to get Linux IRQ numbers given a description of the IRQ source
|
||||
@ -47,7 +48,7 @@ struct x86_acpi_irq_data {
|
||||
int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
|
||||
};
|
||||
|
||||
static int x86_acpi_irq_helper_gpiochip_find(struct gpio_chip *gc, void *data)
|
||||
static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
|
||||
{
|
||||
return gc->label && !strcmp(gc->label, data);
|
||||
}
|
||||
@ -73,7 +74,7 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
|
||||
return irq;
|
||||
case X86_ACPI_IRQ_TYPE_GPIOINT:
|
||||
/* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
|
||||
chip = gpiochip_find(data->chip, x86_acpi_irq_helper_gpiochip_find);
|
||||
chip = gpiochip_find(data->chip, gpiochip_find_match_label);
|
||||
if (!chip) {
|
||||
pr_err("error cannot find GPIO chip %s\n", data->chip);
|
||||
return -ENODEV;
|
||||
@ -143,14 +144,17 @@ struct x86_serdev_info {
|
||||
};
|
||||
|
||||
struct x86_dev_info {
|
||||
char *invalid_aei_gpiochip;
|
||||
const char * const *modules;
|
||||
struct gpiod_lookup_table **gpiod_lookup_tables;
|
||||
struct gpiod_lookup_table * const *gpiod_lookup_tables;
|
||||
const struct x86_i2c_client_info *i2c_client_info;
|
||||
const struct platform_device_info *pdev_info;
|
||||
const struct x86_serdev_info *serdev_info;
|
||||
int i2c_client_count;
|
||||
int pdev_count;
|
||||
int serdev_count;
|
||||
int (*init)(void);
|
||||
void (*exit)(void);
|
||||
};
|
||||
|
||||
/* Generic / shared bq24190 settings */
|
||||
@ -187,8 +191,8 @@ static struct bq24190_platform_data bq24190_pdata = {
|
||||
};
|
||||
|
||||
static const char * const bq24190_modules[] __initconst = {
|
||||
"crystal_cove_charger", /* For the bq24190 IRQ */
|
||||
"bq24190_charger", /* For the Vbus regulator for intel-int3496 */
|
||||
"intel_crystal_cove_charger", /* For the bq24190 IRQ */
|
||||
"bq24190_charger", /* For the Vbus regulator for intel-int3496 */
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -302,7 +306,7 @@ static struct gpiod_lookup_table asus_me176c_goodix_gpios = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table *asus_me176c_gpios[] = {
|
||||
static struct gpiod_lookup_table * const asus_me176c_gpios[] = {
|
||||
&int3496_gpo2_pin22_gpios,
|
||||
&asus_me176c_goodix_gpios,
|
||||
NULL
|
||||
@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = {
|
||||
.serdev_count = ARRAY_SIZE(asus_me176c_serdevs),
|
||||
.gpiod_lookup_tables = asus_me176c_gpios,
|
||||
.modules = bq24190_modules,
|
||||
.invalid_aei_gpiochip = "INT33FC:02",
|
||||
};
|
||||
|
||||
/* Asus TF103C tablets have an Android factory img with everything hardcoded */
|
||||
@ -405,7 +410,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table *asus_tf103c_gpios[] = {
|
||||
static struct gpiod_lookup_table * const asus_tf103c_gpios[] = {
|
||||
&int3496_gpo2_pin22_gpios,
|
||||
NULL
|
||||
};
|
||||
@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = {
|
||||
.pdev_count = ARRAY_SIZE(int3496_pdevs),
|
||||
.gpiod_lookup_tables = asus_tf103c_gpios,
|
||||
.modules = bq24190_modules,
|
||||
.invalid_aei_gpiochip = "INT33FC:02",
|
||||
};
|
||||
|
||||
/*
|
||||
@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = {
|
||||
.i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients),
|
||||
};
|
||||
|
||||
#define CZC_EC_EXTRA_PORT 0x68
|
||||
#define CZC_EC_ANDROID_KEYS 0x63
|
||||
|
||||
static int __init czc_p10t_init(void)
|
||||
{
|
||||
/*
|
||||
* The device boots up in "Windows 7" mode, when the home button sends a
|
||||
* Windows specific key sequence (Left Meta + D) and the second button
|
||||
* sends an unknown one while also toggling the Radio Kill Switch.
|
||||
* This is a surprising behavior when the second button is labeled "Back".
|
||||
*
|
||||
* The vendor-supplied Android-x86 build switches the device to a "Android"
|
||||
* mode by writing value 0x63 to the I/O port 0x68. This just seems to just
|
||||
* set bit 6 on address 0x96 in the EC region; switching the bit directly
|
||||
* seems to achieve the same result. It uses a "p10t_switcher" to do the
|
||||
* job. It doesn't seem to be able to do anything else, and no other use
|
||||
* of the port 0x68 is known.
|
||||
*
|
||||
* In the Android mode, the home button sends just a single scancode,
|
||||
* which can be handled in Linux userspace more reasonably and the back
|
||||
* button only sends a scancode without toggling the kill switch.
|
||||
* The scancode can then be mapped either to Back or RF Kill functionality
|
||||
* in userspace, depending on how the button is labeled on that particular
|
||||
* model.
|
||||
*/
|
||||
outb(CZC_EC_ANDROID_KEYS, CZC_EC_EXTRA_PORT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct x86_dev_info czc_p10t __initconst = {
|
||||
.init = czc_p10t_init,
|
||||
};
|
||||
|
||||
/*
|
||||
* Whitelabel (sold as various brands) TM800A550L tablets.
|
||||
* These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
|
||||
@ -559,7 +598,7 @@ static struct gpiod_lookup_table whitelabel_tm800a550l_goodix_gpios = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct gpiod_lookup_table *whitelabel_tm800a550l_gpios[] = {
|
||||
static struct gpiod_lookup_table * const whitelabel_tm800a550l_gpios[] = {
|
||||
&whitelabel_tm800a550l_goodix_gpios,
|
||||
NULL
|
||||
};
|
||||
@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
|
||||
},
|
||||
.driver_data = (void *)&chuwi_hi8_info,
|
||||
},
|
||||
{
|
||||
/* CZC P10T */
|
||||
.ident = "CZC ODEON TPC-10 (\"P10T\")",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "CZC"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ODEON*TPC-10"),
|
||||
},
|
||||
.driver_data = (void *)&czc_p10t,
|
||||
},
|
||||
{
|
||||
/* A variant of CZC P10T */
|
||||
.ident = "ViewSonic ViewPad 10",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ViewSonic"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "VPAD10"),
|
||||
},
|
||||
.driver_data = (void *)&czc_p10t,
|
||||
},
|
||||
{
|
||||
/* Whitelabel (sold as various brands) TM800A550L */
|
||||
.matches = {
|
||||
@ -669,7 +726,8 @@ static int serdev_count;
|
||||
static struct i2c_client **i2c_clients;
|
||||
static struct platform_device **pdevs;
|
||||
static struct serdev_device **serdevs;
|
||||
static struct gpiod_lookup_table **gpiod_lookup_tables;
|
||||
static struct gpiod_lookup_table * const *gpiod_lookup_tables;
|
||||
static void (*exit_handler)(void);
|
||||
|
||||
static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
|
||||
int idx)
|
||||
@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void)
|
||||
|
||||
kfree(i2c_clients);
|
||||
|
||||
if (exit_handler)
|
||||
exit_handler();
|
||||
|
||||
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
|
||||
gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
|
||||
}
|
||||
@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void)
|
||||
{
|
||||
const struct x86_dev_info *dev_info;
|
||||
const struct dmi_system_id *id;
|
||||
struct gpio_chip *chip;
|
||||
int i, ret = 0;
|
||||
|
||||
id = dmi_first_match(x86_android_tablet_ids);
|
||||
@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void)
|
||||
|
||||
dev_info = id->driver_data;
|
||||
|
||||
/*
|
||||
* The broken DSDTs on these devices often also include broken
|
||||
* _AEI (ACPI Event Interrupt) handlers, disable these.
|
||||
*/
|
||||
if (dev_info->invalid_aei_gpiochip) {
|
||||
chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
|
||||
gpiochip_find_match_label);
|
||||
if (!chip) {
|
||||
pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
|
||||
return -ENODEV;
|
||||
}
|
||||
acpi_gpiochip_free_interrupts(chip);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this runs from module_init() it cannot use -EPROBE_DEFER,
|
||||
* instead pre-load any modules which are listed as requirements.
|
||||
@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void)
|
||||
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
|
||||
gpiod_add_lookup_table(gpiod_lookup_tables[i]);
|
||||
|
||||
if (dev_info->init) {
|
||||
ret = dev_info->init();
|
||||
if (ret < 0) {
|
||||
x86_android_tablet_cleanup();
|
||||
return ret;
|
||||
}
|
||||
exit_handler = dev_info->exit;
|
||||
}
|
||||
|
||||
i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
|
||||
if (!i2c_clients) {
|
||||
x86_android_tablet_cleanup();
|
||||
@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void)
|
||||
module_init(x86_android_tablet_init);
|
||||
module_exit(x86_android_tablet_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com");
|
||||
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
|
||||
MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
Loading…
Reference in New Issue
Block a user