Commit 83c2713a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v5.17-2' of...

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
parents 24d7f48c 836f35f7
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
menuconfig SURFACE_PLATFORMS menuconfig SURFACE_PLATFORMS
bool "Microsoft Surface Platform-Specific Device Drivers" bool "Microsoft Surface Platform-Specific Device Drivers"
depends on ARM64 || X86 || COMPILE_TEST
default y default y
help help
Say Y here to get to see options for platform-specific device drivers Say Y here to get to see options for platform-specific device drivers
......
...@@ -124,9 +124,10 @@ struct amd_pmc_dev { ...@@ -124,9 +124,10 @@ struct amd_pmc_dev {
u32 cpu_id; u32 cpu_id;
u32 active_ips; u32 active_ips;
/* SMU version information */ /* SMU version information */
u16 major; u8 smu_program;
u16 minor; u8 major;
u16 rev; u8 minor;
u8 rev;
struct device *dev; struct device *dev;
struct pci_dev *rdev; struct pci_dev *rdev;
struct mutex lock; /* generic mutex lock */ struct mutex lock; /* generic mutex lock */
...@@ -180,11 +181,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev) ...@@ -180,11 +181,13 @@ static int amd_pmc_get_smu_version(struct amd_pmc_dev *dev)
if (rc) if (rc)
return 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->minor = (val >> 8) & GENMASK(7, 0);
dev->rev = (val >> 0) & 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; return 0;
} }
...@@ -226,7 +229,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp) ...@@ -226,7 +229,7 @@ static int amd_pmc_stb_debugfs_release(struct inode *inode, struct file *filp)
return 0; return 0;
} }
const struct file_operations amd_pmc_stb_debugfs_fops = { static const struct file_operations amd_pmc_stb_debugfs_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = amd_pmc_stb_debugfs_open, .open = amd_pmc_stb_debugfs_open,
.read = amd_pmc_stb_debugfs_read, .read = amd_pmc_stb_debugfs_read,
......
...@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum, ...@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
return 0; 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, .parse = tf103c_dock_hid_parse,
.start = tf103c_dock_hid_start, .start = tf103c_dock_hid_start,
.stop = tf103c_dock_hid_stop, .stop = tf103c_dock_hid_stop,
...@@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev) ...@@ -921,7 +921,7 @@ static int __maybe_unused tf103c_dock_resume(struct device *dev)
return 0; 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[] = { static const struct acpi_device_id tf103c_dock_acpi_match[] = {
{"NPCE69A"}, {"NPCE69A"},
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#define CHGRIRQ_REG 0x0a #define CHGRIRQ_REG 0x0a
#define MCHGRIRQ_REG 0x17
struct crystal_cove_charger_data { struct crystal_cove_charger_data {
struct mutex buslock; /* irq_bus_lock */ struct mutex buslock; /* irq_bus_lock */
...@@ -25,8 +26,8 @@ struct crystal_cove_charger_data { ...@@ -25,8 +26,8 @@ struct crystal_cove_charger_data {
struct irq_domain *irq_domain; struct irq_domain *irq_domain;
int irq; int irq;
int charger_irq; int charger_irq;
bool irq_enabled; u8 mask;
bool irq_is_enabled; u8 new_mask;
}; };
static irqreturn_t crystal_cove_charger_irq(int irq, void *data) 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) ...@@ -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); struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_data(data);
if (charger->irq_is_enabled != charger->irq_enabled) { if (charger->mask != charger->new_mask) {
if (charger->irq_enabled) regmap_write(charger->regmap, MCHGRIRQ_REG, charger->new_mask);
enable_irq(charger->irq); charger->mask = charger->new_mask;
else
disable_irq(charger->irq);
charger->irq_is_enabled = charger->irq_enabled;
} }
mutex_unlock(&charger->buslock); mutex_unlock(&charger->buslock);
...@@ -69,14 +66,14 @@ static void crystal_cove_charger_irq_unmask(struct irq_data *data) ...@@ -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); 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) static void crystal_cove_charger_irq_mask(struct irq_data *data)
{ {
struct crystal_cove_charger_data *charger = irq_data_get_irq_chip_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) static void crystal_cove_charger_rm_irq_domain(void *data)
...@@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev) ...@@ -130,10 +127,13 @@ static int crystal_cove_charger_probe(struct platform_device *pdev)
irq_set_nested_thread(charger->charger_irq, true); irq_set_nested_thread(charger->charger_irq, true);
irq_set_noprobe(charger->charger_irq); 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, ret = devm_request_threaded_irq(&pdev->dev, charger->irq, NULL,
crystal_cove_charger_irq, crystal_cove_charger_irq,
IRQF_ONESHOT | IRQF_NO_AUTOEN, IRQF_ONESHOT, KBUILD_MODNAME, charger);
KBUILD_MODNAME, charger);
if (ret) if (ret)
return dev_err_probe(&pdev->dev, ret, "requesting irq\n"); 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, ...@@ -596,7 +596,10 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
return ret; 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_usage_count;
static int misc_device_ret; static int misc_device_ret;
static int misc_device_open; static int misc_device_open;
...@@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file) ...@@ -606,7 +609,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
int i, ret = 0; int i, ret = 0;
/* Fail open, if a module is going away */ /* 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) { for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
struct isst_if_cmd_cb *cb = &punit_callbacks[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) ...@@ -628,7 +631,7 @@ static int isst_if_open(struct inode *inode, struct file *file)
} else { } else {
misc_device_open++; misc_device_open++;
} }
mutex_unlock(&punit_misc_dev_lock); mutex_unlock(&punit_misc_dev_open_lock);
return ret; return ret;
} }
...@@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f) ...@@ -637,7 +640,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
{ {
int i; int i;
mutex_lock(&punit_misc_dev_lock); mutex_lock(&punit_misc_dev_open_lock);
misc_device_open--; misc_device_open--;
for (i = 0; i < ISST_IF_DEV_MAX; ++i) { for (i = 0; i < ISST_IF_DEV_MAX; ++i) {
struct isst_if_cmd_cb *cb = &punit_callbacks[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) ...@@ -645,7 +648,7 @@ static int isst_if_relase(struct inode *inode, struct file *f)
if (cb->registered) if (cb->registered)
module_put(cb->owner); module_put(cb->owner);
} }
mutex_unlock(&punit_misc_dev_lock); mutex_unlock(&punit_misc_dev_open_lock);
return 0; return 0;
} }
...@@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = { ...@@ -662,6 +665,43 @@ static struct miscdevice isst_if_char_driver = {
.fops = &isst_if_char_driver_ops, .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 * isst_if_cdev_register() - Register callback for IOCTL
* @device_type: The device type this callback handling. * @device_type: The device type this callback handling.
...@@ -679,38 +719,31 @@ static struct miscdevice isst_if_char_driver = { ...@@ -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) int isst_if_cdev_register(int device_type, struct isst_if_cmd_cb *cb)
{ {
if (misc_device_ret) int ret;
return misc_device_ret;
if (device_type >= ISST_IF_DEV_MAX) if (device_type >= ISST_IF_DEV_MAX)
return -EINVAL; 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) { if (misc_device_open) {
mutex_unlock(&punit_misc_dev_lock); mutex_unlock(&punit_misc_dev_open_lock);
return -EAGAIN; 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)); memcpy(&punit_callbacks[device_type], cb, sizeof(*cb));
punit_callbacks[device_type].registered = 1; punit_callbacks[device_type].registered = 1;
misc_usage_count++; mutex_unlock(&punit_misc_dev_open_lock);
unlock_exit:
mutex_unlock(&punit_misc_dev_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); EXPORT_SYMBOL_GPL(isst_if_cdev_register);
...@@ -725,16 +758,12 @@ 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) void isst_if_cdev_unregister(int device_type)
{ {
mutex_lock(&punit_misc_dev_lock); isst_misc_unreg();
misc_usage_count--; mutex_lock(&punit_misc_dev_open_lock);
punit_callbacks[device_type].registered = 0; punit_callbacks[device_type].registered = 0;
if (device_type == ISST_IF_DEV_MBOX) if (device_type == ISST_IF_DEV_MBOX)
isst_delete_hash(); isst_delete_hash();
if (!misc_usage_count && !misc_device_ret) { mutex_unlock(&punit_misc_dev_open_lock);
misc_deregister(&isst_if_char_driver);
isst_if_cpu_info_exit();
}
mutex_unlock(&punit_misc_dev_lock);
} }
EXPORT_SYMBOL_GPL(isst_if_cdev_unregister); EXPORT_SYMBOL_GPL(isst_if_cdev_unregister);
......
...@@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = { ...@@ -8679,9 +8679,10 @@ static const struct attribute_group fan_driver_attr_group = {
.attrs = fan_driver_attributes, .attrs = fan_driver_attributes,
}; };
#define TPACPI_FAN_Q1 0x0001 /* Unitialized HFSP */ #define TPACPI_FAN_Q1 0x0001 /* Uninitialized HFSP */
#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */ #define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */
#define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */ #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 = { static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1), TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
...@@ -8702,6 +8703,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { ...@@ -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', '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', '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', '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) static int __init fan_init(struct ibm_init_struct *iibm)
...@@ -8730,6 +8732,11 @@ 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, quirks = tpacpi_check_quirks(fan_quirk_table,
ARRAY_SIZE(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) { if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */ /* 570, 600e/x, 770e, 770x */
fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
...@@ -10112,6 +10119,9 @@ static struct ibm_struct proxsensor_driver_data = { ...@@ -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_MMC_GET 8 /* To get current MMC function and mode */
#define DYTC_CMD_RESET 0x1ff /* To reset back to default */ #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_FUNCTION_BIT 8 /* Bits 8-11 - function setting */
#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode 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) ...@@ -10324,6 +10334,15 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
if (dytc_version < 5) if (dytc_version < 5)
return -ENODEV; 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, dbg_printk(TPACPI_DBG_INIT,
"DYTC version %d: thermal mode available\n", dytc_version); "DYTC version %d: thermal mode available\n", dytc_version);
/* /*
......
...@@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = { ...@@ -770,6 +770,21 @@ static const struct ts_dmi_data predia_basic_data = {
.properties = predia_basic_props, .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[] = { static const struct property_entry schneider_sct101ctm_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1715), PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
...@@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { ...@@ -1394,6 +1409,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
DMI_EXACT_MATCH(DMI_BOARD_NAME, "0E57"), 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 */ /* Schneider SCT101CTM */
.driver_data = (void *)&schneider_sct101ctm_data, .driver_data = (void *)&schneider_sct101ctm_data,
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/string.h> #include <linux/string.h>
/* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */ /* For gpio_get_desc() which is EXPORT_SYMBOL_GPL() */
#include "../../gpio/gpiolib.h" #include "../../gpio/gpiolib.h"
#include "../../gpio/gpiolib-acpi.h"
/* /*
* Helper code to get Linux IRQ numbers given a description of the IRQ source * Helper code to get Linux IRQ numbers given a description of the IRQ source
...@@ -47,7 +48,7 @@ struct x86_acpi_irq_data { ...@@ -47,7 +48,7 @@ struct x86_acpi_irq_data {
int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */ 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); 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) ...@@ -73,7 +74,7 @@ static int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
return irq; return irq;
case X86_ACPI_IRQ_TYPE_GPIOINT: case X86_ACPI_IRQ_TYPE_GPIOINT:
/* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */ /* 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) { if (!chip) {
pr_err("error cannot find GPIO chip %s\n", data->chip); pr_err("error cannot find GPIO chip %s\n", data->chip);
return -ENODEV; return -ENODEV;
...@@ -143,14 +144,17 @@ struct x86_serdev_info { ...@@ -143,14 +144,17 @@ struct x86_serdev_info {
}; };
struct x86_dev_info { struct x86_dev_info {
char *invalid_aei_gpiochip;
const char * const *modules; 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 x86_i2c_client_info *i2c_client_info;
const struct platform_device_info *pdev_info; const struct platform_device_info *pdev_info;
const struct x86_serdev_info *serdev_info; const struct x86_serdev_info *serdev_info;
int i2c_client_count; int i2c_client_count;
int pdev_count; int pdev_count;
int serdev_count; int serdev_count;
int (*init)(void);
void (*exit)(void);
}; };
/* Generic / shared bq24190 settings */ /* Generic / shared bq24190 settings */
...@@ -187,7 +191,7 @@ static struct bq24190_platform_data bq24190_pdata = { ...@@ -187,7 +191,7 @@ static struct bq24190_platform_data bq24190_pdata = {
}; };
static const char * const bq24190_modules[] __initconst = { static const char * const bq24190_modules[] __initconst = {
"crystal_cove_charger", /* For the bq24190 IRQ */ "intel_crystal_cove_charger", /* For the bq24190 IRQ */
"bq24190_charger", /* For the Vbus regulator for intel-int3496 */ "bq24190_charger", /* For the Vbus regulator for intel-int3496 */
NULL NULL
}; };
...@@ -302,7 +306,7 @@ static struct gpiod_lookup_table asus_me176c_goodix_gpios = { ...@@ -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, &int3496_gpo2_pin22_gpios,
&asus_me176c_goodix_gpios, &asus_me176c_goodix_gpios,
NULL NULL
...@@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = { ...@@ -317,6 +321,7 @@ static const struct x86_dev_info asus_me176c_info __initconst = {
.serdev_count = ARRAY_SIZE(asus_me176c_serdevs), .serdev_count = ARRAY_SIZE(asus_me176c_serdevs),
.gpiod_lookup_tables = asus_me176c_gpios, .gpiod_lookup_tables = asus_me176c_gpios,
.modules = bq24190_modules, .modules = bq24190_modules,
.invalid_aei_gpiochip = "INT33FC:02",
}; };
/* Asus TF103C tablets have an Android factory img with everything hardcoded */ /* 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 = ...@@ -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, &int3496_gpo2_pin22_gpios,
NULL NULL
}; };
...@@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = { ...@@ -417,6 +422,7 @@ static const struct x86_dev_info asus_tf103c_info __initconst = {
.pdev_count = ARRAY_SIZE(int3496_pdevs), .pdev_count = ARRAY_SIZE(int3496_pdevs),
.gpiod_lookup_tables = asus_tf103c_gpios, .gpiod_lookup_tables = asus_tf103c_gpios,
.modules = bq24190_modules, .modules = bq24190_modules,
.invalid_aei_gpiochip = "INT33FC:02",
}; };
/* /*
...@@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = { ...@@ -490,6 +496,39 @@ static const struct x86_dev_info chuwi_hi8_info __initconst = {
.i2c_client_count = ARRAY_SIZE(chuwi_hi8_i2c_clients), .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. * Whitelabel (sold as various brands) TM800A550L tablets.
* These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices * 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 = { ...@@ -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, &whitelabel_tm800a550l_goodix_gpios,
NULL NULL
}; };
...@@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = { ...@@ -641,6 +680,24 @@ static const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
}, },
.driver_data = (void *)&chuwi_hi8_info, .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 */ /* Whitelabel (sold as various brands) TM800A550L */
.matches = { .matches = {
...@@ -669,7 +726,8 @@ static int serdev_count; ...@@ -669,7 +726,8 @@ static int serdev_count;
static struct i2c_client **i2c_clients; static struct i2c_client **i2c_clients;
static struct platform_device **pdevs; static struct platform_device **pdevs;
static struct serdev_device **serdevs; 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, static __init int x86_instantiate_i2c_client(const struct x86_dev_info *dev_info,
int idx) int idx)
...@@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void) ...@@ -787,6 +845,9 @@ static void x86_android_tablet_cleanup(void)
kfree(i2c_clients); kfree(i2c_clients);
if (exit_handler)
exit_handler();
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
gpiod_remove_lookup_table(gpiod_lookup_tables[i]); gpiod_remove_lookup_table(gpiod_lookup_tables[i]);
} }
...@@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void) ...@@ -795,6 +856,7 @@ static __init int x86_android_tablet_init(void)
{ {
const struct x86_dev_info *dev_info; const struct x86_dev_info *dev_info;
const struct dmi_system_id *id; const struct dmi_system_id *id;
struct gpio_chip *chip;
int i, ret = 0; int i, ret = 0;
id = dmi_first_match(x86_android_tablet_ids); id = dmi_first_match(x86_android_tablet_ids);
...@@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void) ...@@ -803,6 +865,20 @@ static __init int x86_android_tablet_init(void)
dev_info = id->driver_data; 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, * Since this runs from module_init() it cannot use -EPROBE_DEFER,
* instead pre-load any modules which are listed as requirements. * instead pre-load any modules which are listed as requirements.
...@@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void) ...@@ -814,6 +890,15 @@ static __init int x86_android_tablet_init(void)
for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++) for (i = 0; gpiod_lookup_tables && gpiod_lookup_tables[i]; i++)
gpiod_add_lookup_table(gpiod_lookup_tables[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); i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
if (!i2c_clients) { if (!i2c_clients) {
x86_android_tablet_cleanup(); x86_android_tablet_cleanup();
...@@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void) ...@@ -865,6 +950,6 @@ static __init int x86_android_tablet_init(void)
module_init(x86_android_tablet_init); module_init(x86_android_tablet_init);
module_exit(x86_android_tablet_cleanup); 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_DESCRIPTION("X86 Android tablets DSDT fixups driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment