diff options
Diffstat (limited to 'drivers/platform/x86/x86-android-tablets')
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/core.c | 16 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/dmi.c | 18 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/lenovo.c | 224 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/other.c | 133 | ||||
-rw-r--r-- | drivers/platform/x86/x86-android-tablets/x86-android-tablets.h | 3 |
5 files changed, 378 insertions, 16 deletions
diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index a3415f1c0b5f..919ef4471229 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -52,10 +52,8 @@ int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id, return -ENOMEM; lookup->dev_id = KBUILD_MODNAME; - lookup->table[0].key = chip; - lookup->table[0].chip_hwnum = pin; - lookup->table[0].con_id = con_id; - lookup->table[0].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH; + lookup->table[0] = + GPIO_LOOKUP(chip, pin, con_id, active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH); gpiod_add_lookup_table(lookup); gpiod = devm_gpiod_get(&x86_android_tablet_device->dev, con_id, dflags); @@ -278,25 +276,25 @@ static void x86_android_tablet_remove(struct platform_device *pdev) { int i; - for (i = 0; i < serdev_count; i++) { + for (i = serdev_count - 1; i >= 0; i--) { if (serdevs[i]) serdev_device_remove(serdevs[i]); } kfree(serdevs); - for (i = 0; i < pdev_count; i++) + for (i = pdev_count - 1; i >= 0; i--) platform_device_unregister(pdevs[i]); kfree(pdevs); kfree(buttons); - for (i = 0; i < spi_dev_count; i++) + for (i = spi_dev_count - 1; i >= 0; i--) spi_unregister_device(spi_devs[i]); kfree(spi_devs); - for (i = 0; i < i2c_client_count; i++) + for (i = i2c_client_count - 1; i >= 0; i--) i2c_unregister_device(i2c_clients[i]); kfree(i2c_clients); @@ -343,7 +341,7 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) gpiod_add_lookup_table(gpiod_lookup_tables[i]); if (dev_info->init) { - ret = dev_info->init(); + ret = dev_info->init(&pdev->dev); if (ret < 0) { x86_android_tablet_remove(pdev); return ret; diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c index 5d6c12494f08..141a2d25e83b 100644 --- a/drivers/platform/x86/x86-android-tablets/dmi.c +++ b/drivers/platform/x86/x86-android-tablets/dmi.c @@ -106,6 +106,24 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = { }, { /* + * Lenovo Yoga Tablet 2 Pro 1380F/L (13") This has more or less + * the same BIOS as the 830F/L or 1050F/L (8" and 10") below, + * but unlike the 8" / 10" models which share the same mainboard + * this model has a different mainboard. + * This match for the 13" model MUST come before the 8" + 10" + * match since that one will also match the 13" model! + */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."), + DMI_MATCH(DMI_PRODUCT_NAME, "VALLEYVIEW C0 PLATFORM"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-T FFD8"), + /* Full match so as to NOT match the 830/1050 BIOS */ + DMI_MATCH(DMI_BIOS_VERSION, "BLADE_21.X64.0005.R00.1504101516"), + }, + .driver_data = (void *)&lenovo_yoga_tab2_1380_info, + }, + { + /* * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10" * Lenovo Yoga Tablet 2 use the same mainboard) */ diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index c297391955ad..74f39b658d2c 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -19,6 +19,7 @@ #include <linux/pinctrl/machine.h> #include <linux/platform_data/lp855x.h> #include <linux/platform_device.h> +#include <linux/power/bq24190_charger.h> #include <linux/reboot.h> #include <linux/rmi.h> #include <linux/spi/spi.h> @@ -229,7 +230,7 @@ static struct gpiod_lookup_table * const lenovo_yb1_x90_gpios[] = { NULL }; -static int __init lenovo_yb1_x90_init(void) +static int __init lenovo_yb1_x90_init(struct device *dev) { /* Enable the regulators used by the touchscreens */ @@ -411,7 +412,7 @@ static struct gpiod_lookup_table * const lenovo_yoga_tab2_830_1050_gpios[] = { NULL }; -static int __init lenovo_yoga_tab2_830_1050_init(void); +static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev); static void lenovo_yoga_tab2_830_1050_exit(void); const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { @@ -533,7 +534,7 @@ static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data) return NOTIFY_DONE; } -static int __init lenovo_yoga_tab2_830_1050_init(void) +static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev) { int ret; @@ -565,6 +566,221 @@ static void lenovo_yoga_tab2_830_1050_exit(void) } } +/* + * Lenovo Yoga Tablet 2 Pro 1380F/L + * + * The Lenovo Yoga Tablet 2 Pro 1380F/L mostly has the same design as the 830F/L + * and the 1050F/L so this re-uses some of the handling for that from above. + */ +static const char * const lc824206xa_chg_det_psy[] = { "lc824206xa-charger-detect" }; + +static const struct property_entry lenovo_yoga_tab2_1380_bq24190_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lc824206xa_chg_det_psy), + PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node), + PROPERTY_ENTRY_BOOL("omit-battery-class"), + PROPERTY_ENTRY_BOOL("disable-reset"), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_bq24190_node = { + .properties = lenovo_yoga_tab2_1380_bq24190_props, +}; + +/* For enabling the bq24190 5V boost based on id-pin */ +static struct regulator_consumer_supply lc824206xa_consumer = { + .supply = "vbus", + .dev_name = "i2c-lc824206xa", +}; + +static const struct regulator_init_data lenovo_yoga_tab2_1380_bq24190_vbus_init_data = { + .constraints = { + .name = "bq24190_vbus", + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &lc824206xa_consumer, + .num_consumer_supplies = 1, +}; + +struct bq24190_platform_data lenovo_yoga_tab2_1380_bq24190_pdata = { + .regulator_init_data = &lenovo_yoga_tab2_1380_bq24190_vbus_init_data, +}; + +static const struct property_entry lenovo_yoga_tab2_1380_lc824206xa_props[] = { + PROPERTY_ENTRY_BOOL("onnn,enable-miclr-for-dcp"), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_lc824206xa_node = { + .properties = lenovo_yoga_tab2_1380_lc824206xa_props, +}; + +static const char * const lenovo_yoga_tab2_1380_lms303d_mount_matrix[] = { + "0", "-1", "0", + "-1", "0", "0", + "0", "0", "1" +}; + +static const struct property_entry lenovo_yoga_tab2_1380_lms303d_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", lenovo_yoga_tab2_1380_lms303d_mount_matrix), + { } +}; + +static const struct software_node lenovo_yoga_tab2_1380_lms303d_node = { + .properties = lenovo_yoga_tab2_1380_lms303d_props, +}; + +static const struct x86_i2c_client_info lenovo_yoga_tab2_1380_i2c_clients[] __initconst = { + { + /* BQ27541 fuel-gauge */ + .board_info = { + .type = "bq27541", + .addr = 0x55, + .dev_name = "bq27541", + .swnode = &fg_bq24190_supply_node, + }, + .adapter_path = "\\_SB_.I2C1", + }, { + /* bq24292i battery charger */ + .board_info = { + .type = "bq24190", + .addr = 0x6b, + .dev_name = "bq24292i", + .swnode = &lenovo_yoga_tab2_1380_bq24190_node, + .platform_data = &lenovo_yoga_tab2_1380_bq24190_pdata, + }, + .adapter_path = "\\_SB_.I2C1", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 2, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + .con_id = "bq24292i_irq", + }, + }, { + /* LP8557 Backlight controller */ + .board_info = { + .type = "lp8557", + .addr = 0x2c, + .dev_name = "lp8557", + .platform_data = &lenovo_lp8557_pwm_and_reg_pdata, + }, + .adapter_path = "\\_SB_.I2C3", + }, { + /* LC824206XA Micro USB Switch */ + .board_info = { + .type = "lc824206xa", + .addr = 0x48, + .dev_name = "lc824206xa", + .swnode = &lenovo_yoga_tab2_1380_lc824206xa_node, + }, + .adapter_path = "\\_SB_.I2C3", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_GPIOINT, + .chip = "INT33FC:02", + .index = 1, + .trigger = ACPI_LEVEL_SENSITIVE, + .polarity = ACPI_ACTIVE_LOW, + .con_id = "lc824206xa_irq", + }, + }, { + /* AL3320A ambient light sensor */ + .board_info = { + .type = "al3320a", + .addr = 0x1c, + .dev_name = "al3320a", + }, + .adapter_path = "\\_SB_.I2C5", + }, { + /* LSM303DA accelerometer + magnetometer */ + .board_info = { + .type = "lsm303d", + .addr = 0x1d, + .dev_name = "lsm303d", + .swnode = &lenovo_yoga_tab2_1380_lms303d_node, + }, + .adapter_path = "\\_SB_.I2C5", + }, { + /* Synaptics RMI touchscreen */ + .board_info = { + .type = "rmi4_i2c", + .addr = 0x38, + .dev_name = "rmi4_i2c", + .platform_data = &lenovo_yoga_tab2_830_1050_rmi_pdata, + }, + .adapter_path = "\\_SB_.I2C6", + .irq_data = { + .type = X86_ACPI_IRQ_TYPE_APIC, + .index = 0x45, + .trigger = ACPI_EDGE_SENSITIVE, + .polarity = ACPI_ACTIVE_HIGH, + }, + } +}; + +static const struct platform_device_info lenovo_yoga_tab2_1380_pdevs[] __initconst = { + { + /* For the Tablet 2 Pro 1380's custom fast charging driver */ + .name = "lenovo-yoga-tab2-pro-1380-fastcharger", + .id = PLATFORM_DEVID_NONE, + }, +}; + +const char * const lenovo_yoga_tab2_1380_modules[] __initconst = { + "bq24190_charger", /* For the Vbus regulator for lc824206xa */ + NULL +}; + +static int __init lenovo_yoga_tab2_1380_init(struct device *dev) +{ + int ret; + + /* To verify that the DMI matching works vs the 830 / 1050 models */ + pr_info("detected Lenovo Yoga Tablet 2 Pro 1380F/L\n"); + + ret = lenovo_yoga_tab2_830_1050_init_codec(); + if (ret) + return ret; + + /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */ + lenovo_yoga_tab2_830_1050_sys_off_handler = + register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1, + lenovo_yoga_tab2_830_1050_power_off, NULL); + if (IS_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler)) + return PTR_ERR(lenovo_yoga_tab2_830_1050_sys_off_handler); + + return 0; +} + +static struct gpiod_lookup_table lenovo_yoga_tab2_1380_fc_gpios = { + .dev_id = "serial0-0", + .table = { + GPIO_LOOKUP("INT33FC:00", 57, "uart3_txd", GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("INT33FC:00", 61, "uart3_rxd", GPIO_ACTIVE_HIGH), + { } + }, +}; + +static struct gpiod_lookup_table * const lenovo_yoga_tab2_1380_gpios[] = { + &lenovo_yoga_tab2_830_1050_codec_gpios, + &lenovo_yoga_tab2_1380_fc_gpios, + NULL +}; + +const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { + .i2c_client_info = lenovo_yoga_tab2_1380_i2c_clients, + .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_i2c_clients), + .pdev_info = lenovo_yoga_tab2_1380_pdevs, + .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), + .gpio_button = &lenovo_yoga_tab2_830_1050_lid, + .gpio_button_count = 1, + .gpiod_lookup_tables = lenovo_yoga_tab2_1380_gpios, + .bat_swnode = &generic_lipo_hv_4v35_battery_node, + .modules = lenovo_yoga_tab2_1380_modules, + .init = lenovo_yoga_tab2_1380_init, + .exit = lenovo_yoga_tab2_830_1050_exit, +}; + /* Lenovo Yoga Tab 3 Pro YT3-X90F */ /* @@ -762,7 +978,7 @@ static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = { } }; -static int __init lenovo_yt3_init(void) +static int __init lenovo_yt3_init(struct device *dev) { int ret; diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c index 278402dcb808..eb0e55c69dfe 100644 --- a/drivers/platform/x86/x86-android-tablets/other.c +++ b/drivers/platform/x86/x86-android-tablets/other.c @@ -11,7 +11,11 @@ #include <linux/acpi.h> #include <linux/gpio/machine.h> #include <linux/input.h> +#include <linux/leds.h> #include <linux/platform_device.h> +#include <linux/pwm.h> + +#include <dt-bindings/leds/common.h> #include "shared-psy-info.h" #include "x86-android-tablets.h" @@ -181,7 +185,7 @@ static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = { }, }; -static int __init chuwi_hi8_init(void) +static int __init chuwi_hi8_init(struct device *dev) { /* * Avoid the acpi_unregister_gsi() call in x86_acpi_irq_helper_get() @@ -242,7 +246,7 @@ const struct x86_dev_info cyberbook_t116_info __initconst = { #define CZC_EC_EXTRA_PORT 0x68 #define CZC_EC_ANDROID_KEYS 0x63 -static int __init czc_p10t_init(void) +static int __init czc_p10t_init(struct device *dev) { /* * The device boots up in "Windows 7" mode, when the home button sends a @@ -594,6 +598,128 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = { }; /* + * The fwnode for ktd2026 on Xaomi pad2. It composed of a RGB LED node + * with three subnodes for each color (B/G/R). The RGB LED node is named + * "multi-led" to align with the name in the device tree. + */ + +/* main fwnode for ktd2026 */ +static const struct software_node ktd2026_node = { + .name = "ktd2026", +}; + +static const struct property_entry ktd2026_rgb_led_props[] = { + PROPERTY_ENTRY_U32("reg", 0), + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RGB), + PROPERTY_ENTRY_STRING("label", "mipad2:rgb:indicator"), + PROPERTY_ENTRY_STRING("linux,default-trigger", "bq27520-0-charging-orange-full-green"), + { } +}; + +static const struct software_node ktd2026_rgb_led_node = { + .name = "multi-led", + .properties = ktd2026_rgb_led_props, + .parent = &ktd2026_node, +}; + +static const struct property_entry ktd2026_blue_led_props[] = { + PROPERTY_ENTRY_U32("reg", 0), + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_BLUE), + { } +}; + +static const struct software_node ktd2026_blue_led_node = { + .properties = ktd2026_blue_led_props, + .parent = &ktd2026_rgb_led_node, +}; + +static const struct property_entry ktd2026_green_led_props[] = { + PROPERTY_ENTRY_U32("reg", 1), + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_GREEN), + { } +}; + +static const struct software_node ktd2026_green_led_node = { + .properties = ktd2026_green_led_props, + .parent = &ktd2026_rgb_led_node, +}; + +static const struct property_entry ktd2026_red_led_props[] = { + PROPERTY_ENTRY_U32("reg", 2), + PROPERTY_ENTRY_U32("color", LED_COLOR_ID_RED), + { } +}; + +static const struct software_node ktd2026_red_led_node = { + .properties = ktd2026_red_led_props, + .parent = &ktd2026_rgb_led_node, +}; + +static const struct software_node *ktd2026_node_group[] = { + &ktd2026_node, + &ktd2026_rgb_led_node, + &ktd2026_red_led_node, + &ktd2026_green_led_node, + &ktd2026_blue_led_node, + NULL +}; + +/* + * For the LEDs which backlight the menu / home / back capacitive buttons on + * the bottom bezel. These are attached to a TPS61158 LED controller which + * is controlled by the "pwm_soc_lpss_2" PWM output. + */ +#define XIAOMI_MIPAD2_LED_PERIOD_NS 19200 +#define XIAOMI_MIPAD2_LED_DEFAULT_DUTY 6000 /* From Android kernel */ + +static struct pwm_device *xiaomi_mipad2_led_pwm; + +static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev, + enum led_brightness val) +{ + struct pwm_state state = { + .period = XIAOMI_MIPAD2_LED_PERIOD_NS, + .duty_cycle = val, + /* Always set PWM enabled to avoid the pin floating */ + .enabled = true, + }; + + return pwm_apply_might_sleep(xiaomi_mipad2_led_pwm, &state); +} + +static int __init xiaomi_mipad2_init(struct device *dev) +{ + struct led_classdev *led_cdev; + int ret; + + xiaomi_mipad2_led_pwm = devm_pwm_get(dev, "pwm_soc_lpss_2"); + if (IS_ERR(xiaomi_mipad2_led_pwm)) + return dev_err_probe(dev, PTR_ERR(xiaomi_mipad2_led_pwm), "getting pwm\n"); + + led_cdev = devm_kzalloc(dev, sizeof(*led_cdev), GFP_KERNEL); + if (!led_cdev) + return -ENOMEM; + + led_cdev->name = "mipad2:white:touch-buttons-backlight"; + led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS; + /* "input-events" trigger uses blink_brightness */ + led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY; + led_cdev->default_trigger = "input-events"; + led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set; + + ret = devm_led_classdev_register(dev, led_cdev); + if (ret) + return dev_err_probe(dev, ret, "registering LED\n"); + + return software_node_register_node_group(ktd2026_node_group); +} + +static void xiaomi_mipad2_exit(void) +{ + software_node_unregister_node_group(ktd2026_node_group); +} + +/* * If the EFI bootloader is not Xiaomi's own signed Android loader, then the * Xiaomi Mi Pad 2 X86 tablet sets OSID in the DSDT to 1 (Windows), causing * a bunch of devices to be hidden. @@ -616,6 +742,7 @@ static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst .type = "ktd2026", .addr = 0x30, .dev_name = "ktd2026", + .swnode = &ktd2026_node, }, .adapter_path = "\\_SB_.PCI0.I2C3", }, @@ -624,4 +751,6 @@ static const struct x86_i2c_client_info xiaomi_mipad2_i2c_clients[] __initconst const struct x86_dev_info xiaomi_mipad2_info __initconst = { .i2c_client_info = xiaomi_mipad2_i2c_clients, .i2c_client_count = ARRAY_SIZE(xiaomi_mipad2_i2c_clients), + .init = xiaomi_mipad2_init, + .exit = xiaomi_mipad2_exit, }; diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index 468993edfeee..86402b9b46a3 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -89,7 +89,7 @@ struct x86_dev_info { int pdev_count; int serdev_count; int gpio_button_count; - int (*init)(void); + int (*init)(struct device *dev); void (*exit)(void); }; @@ -112,6 +112,7 @@ extern const struct x86_dev_info czc_p10t; extern const struct x86_dev_info lenovo_yogabook_x90_info; extern const struct x86_dev_info lenovo_yogabook_x91_info; extern const struct x86_dev_info lenovo_yoga_tab2_830_1050_info; +extern const struct x86_dev_info lenovo_yoga_tab2_1380_info; extern const struct x86_dev_info lenovo_yt3_info; extern const struct x86_dev_info medion_lifetab_s10346_info; extern const struct x86_dev_info nextbook_ares8_info; |