| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079 |
- // SPDX-License-Identifier: GPL-2.0-or-later
- /*
- * Board info for Lenovo X86 tablets which ship with Android as the factory image
- * and which have broken DSDT tables. The factory kernels shipped on these
- * devices typically have a bunch of things hardcoded, rather than specified
- * in their DSDT.
- *
- * Copyright (C) 2021-2023 Hans de Goede <hansg@kernel.org>
- */
- #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
- #include <linux/efi.h>
- #include <linux/gpio/machine.h>
- #include <linux/gpio/property.h>
- #include <linux/input-event-codes.h>
- #include <linux/mfd/arizona/pdata.h>
- #include <linux/mfd/arizona/registers.h>
- #include <linux/mfd/intel_soc_pmic.h>
- #include <linux/pinctrl/consumer.h>
- #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>
- #include "shared-psy-info.h"
- #include "x86-android-tablets.h"
- /*
- * Various Lenovo models use a TI LP8557 LED backlight controller with its PWM
- * input connected to a PWM output coming from the LCD panel's controller.
- * The Android kernels have a hack in the i915 driver to write a non-standard
- * panel specific DSI register to set the duty-cycle of the LCD's PWM output.
- *
- * To avoid having to have a similar hack in the mainline kernel program the
- * LP8557 to directly set the level and use the lp855x_bl driver for control.
- *
- * The LP8557 can either be configured to multiply its PWM input and
- * the I2C register set level (requiring both to be at 100% for 100% output);
- * or to only take the I2C register set level into account.
- *
- * Multiplying the 2 levels is useful because this will turn off the backlight
- * when the panel goes off and turns off its PWM output.
- *
- * But on some models the panel's PWM output defaults to a duty-cycle of
- * much less then 100%, severely limiting max brightness. In this case
- * the LP8557 should be configured to only take the I2C register into
- * account and the i915 driver must turn off the panel and the backlight
- * separately using e.g. VBT MIPI sequences to turn off the backlight.
- */
- static struct lp855x_platform_data lenovo_lp8557_pwm_and_reg_pdata = {
- .device_control = 0x86,
- .initial_brightness = 128,
- };
- static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = {
- .device_control = 0x85,
- .initial_brightness = 128,
- };
- static const struct software_node arizona_gpiochip_node = {
- .name = "arizona",
- };
- static const struct software_node crystalcove_gpiochip_node = {
- .name = "gpio_crystalcove",
- };
- /* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */
- static const struct property_entry lenovo_yb1_x90_goodix_props[] = {
- PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[1], 53, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("irq-gpios", &cherryview_gpiochip_nodes[1], 56, GPIO_ACTIVE_HIGH),
- { }
- };
- static const struct software_node lenovo_yb1_x90_goodix_node = {
- .properties = lenovo_yb1_x90_goodix_props,
- };
- static const struct property_entry lenovo_yb1_x90_wacom_props[] = {
- PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001),
- PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 150),
- PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_LOW),
- { }
- };
- static const struct software_node lenovo_yb1_x90_wacom_node = {
- .properties = lenovo_yb1_x90_wacom_props,
- };
- /*
- * The HiDeep IST940E touchscreen comes up in I2C-HID mode. The native protocol
- * reports ABS_MT_PRESSURE and ABS_MT_TOUCH_MAJOR which are not reported in HID
- * mode, so using native mode is preferred.
- * It could alternatively be used in HID mode by changing the properties to:
- * PROPERTY_ENTRY_U32("hid-descr-addr", 0x0020),
- * PROPERTY_ENTRY_U32("post-reset-deassert-delay-ms", 120),
- * and changing board_info.type to "hid-over-i2c".
- */
- static const struct property_entry lenovo_yb1_x90_hideep_ts_props[] = {
- PROPERTY_ENTRY_U32("touchscreen-size-x", 1200),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 1920),
- PROPERTY_ENTRY_U32("touchscreen-max-pressure", 16384),
- PROPERTY_ENTRY_BOOL("hideep,force-native-protocol"),
- PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 7, GPIO_ACTIVE_LOW),
- { }
- };
- static const struct software_node lenovo_yb1_x90_hideep_ts_node = {
- .properties = lenovo_yb1_x90_hideep_ts_props,
- };
- static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst = {
- {
- /* BQ27542 fuel-gauge */
- .board_info = {
- .type = "bq27542",
- .addr = 0x55,
- .dev_name = "bq27542",
- .swnode = &fg_bq25890_supply_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C1",
- }, {
- /* Goodix Touchscreen in keyboard half */
- .board_info = {
- .type = "GDIX1001:00",
- .addr = 0x14,
- .dev_name = "goodix_ts",
- .swnode = &lenovo_yb1_x90_goodix_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C2",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:01",
- .index = 56,
- .trigger = ACPI_EDGE_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "goodix_ts_irq",
- .free_gpio = true,
- },
- }, {
- /* Wacom Digitizer in keyboard half */
- .board_info = {
- .type = "hid-over-i2c",
- .addr = 0x09,
- .dev_name = "wacom",
- .swnode = &lenovo_yb1_x90_wacom_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C4",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:01",
- .index = 49,
- .trigger = ACPI_LEVEL_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "wacom_irq",
- },
- }, {
- /* LP8557 Backlight controller */
- .board_info = {
- .type = "lp8557",
- .addr = 0x2c,
- .dev_name = "lp8557",
- .platform_data = &lenovo_lp8557_pwm_and_reg_pdata,
- },
- .adapter_path = "\\_SB_.PCI0.I2C4",
- }, {
- /* HiDeep IST940E Touchscreen in display half */
- .board_info = {
- .type = "hideep_ts",
- .addr = 0x6c,
- .dev_name = "hideep_ts",
- .swnode = &lenovo_yb1_x90_hideep_ts_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C6",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:03",
- .index = 77,
- .trigger = ACPI_LEVEL_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "hideep_ts_irq",
- },
- },
- };
- static const struct platform_device_info lenovo_yb1_x90_pdevs[] __initconst = {
- {
- .name = "yogabook-touch-kbd-digitizer-switch",
- .id = PLATFORM_DEVID_NONE,
- },
- };
- /*
- * DSDT says UART path is "\\_SB.PCIO.URT1" with a letter 'O' instead of
- * the number '0' add the link manually.
- */
- static const struct x86_serdev_info lenovo_yb1_x90_serdevs[] __initconst = {
- {
- .ctrl.acpi.hid = "8086228A",
- .ctrl.acpi.uid = "1",
- .ctrl_devname = "serial0",
- .serdev_hid = "BCM2E1A",
- },
- };
- /*
- * Software node attached to gpio-keys device representing the LID and
- * serving as a parent to software nodes representing individual keys/buttons
- * as required by the device tree binding.
- */
- static const struct software_node lenovo_lid_gpio_keys_node = {
- .name = "lid_sw",
- };
- static const struct property_entry lenovo_yb1_x90_lid_props[] = {
- PROPERTY_ENTRY_U32("linux,input-type", EV_SW),
- PROPERTY_ENTRY_U32("linux,code", SW_LID),
- PROPERTY_ENTRY_STRING("label", "lid_sw"),
- PROPERTY_ENTRY_GPIO("gpios", &cherryview_gpiochip_nodes[2], 19, GPIO_ACTIVE_LOW),
- PROPERTY_ENTRY_U32("debounce-interval", 50),
- PROPERTY_ENTRY_BOOL("wakeup-source"),
- { }
- };
- static const struct software_node lenovo_yb1_x90_lid_node = {
- .parent = &lenovo_lid_gpio_keys_node,
- .properties = lenovo_yb1_x90_lid_props,
- };
- static const struct software_node *lenovo_yb1_x90_lid_swnodes[] = {
- &lenovo_lid_gpio_keys_node,
- &lenovo_yb1_x90_lid_node,
- NULL
- };
- static int __init lenovo_yb1_x90_init(struct device *dev)
- {
- /* Enable the regulators used by the touchscreens */
- /* Vprog3B 3.0V used by the goodix touchscreen in the keyboard half */
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff);
- /* Vprog4D 3.0V used by the HiDeep touchscreen in the display half */
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9f, 0x02, 0xff);
- /* Vprog5A 1.8V used by the HiDeep touchscreen in the display half */
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff);
- /* Vprog5B 1.8V used by the goodix touchscreen in the keyboard half */
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa1, 0x02, 0xff);
- return 0;
- }
- const struct x86_dev_info lenovo_yogabook_x90_info __initconst = {
- .i2c_client_info = lenovo_yb1_x90_i2c_clients,
- .i2c_client_count = ARRAY_SIZE(lenovo_yb1_x90_i2c_clients),
- .pdev_info = lenovo_yb1_x90_pdevs,
- .pdev_count = ARRAY_SIZE(lenovo_yb1_x90_pdevs),
- .serdev_info = lenovo_yb1_x90_serdevs,
- .serdev_count = ARRAY_SIZE(lenovo_yb1_x90_serdevs),
- .gpio_button_swnodes = lenovo_yb1_x90_lid_swnodes,
- .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW,
- .init = lenovo_yb1_x90_init,
- };
- /* Lenovo Yoga Book X91F/L Windows tablet needs manual instantiation of the fuel-gauge client */
- static const struct x86_i2c_client_info lenovo_yogabook_x91_i2c_clients[] __initconst = {
- {
- /* BQ27542 fuel-gauge */
- .board_info = {
- .type = "bq27542",
- .addr = 0x55,
- .dev_name = "bq27542",
- .swnode = &fg_bq25890_supply_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C1",
- },
- };
- const struct x86_dev_info lenovo_yogabook_x91_info __initconst = {
- .i2c_client_info = lenovo_yogabook_x91_i2c_clients,
- .i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x91_i2c_clients),
- };
- /* Lenovo Yoga Tablet 2 1050F/L's Android factory image has everything hardcoded */
- static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = {
- PROPERTY_ENTRY_STRING_ARRAY_LEN("supplied-from", tusb1211_chg_det_psy, 1),
- 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_830_1050_bq24190_node = {
- .properties = lenovo_yoga_tab2_830_1050_bq24190_props,
- };
- static const struct property_entry lenovo_yoga_tab2_830_1050_lid_props[] = {
- PROPERTY_ENTRY_U32("linux,input-type", EV_SW),
- PROPERTY_ENTRY_U32("linux,code", SW_LID),
- PROPERTY_ENTRY_STRING("label", "lid_sw"),
- PROPERTY_ENTRY_GPIO("gpios", &baytrail_gpiochip_nodes[2], 26, GPIO_ACTIVE_LOW),
- PROPERTY_ENTRY_U32("debounce-interval", 50),
- PROPERTY_ENTRY_BOOL("wakeup-source"),
- { }
- };
- static const struct software_node lenovo_yoga_tab2_830_1050_lid_node = {
- .parent = &lenovo_lid_gpio_keys_node,
- .properties = lenovo_yoga_tab2_830_1050_lid_props,
- };
- static const struct software_node *lenovo_yoga_tab2_830_1050_lid_swnodes[] = {
- &lenovo_lid_gpio_keys_node,
- &lenovo_yoga_tab2_830_1050_lid_node,
- NULL
- };
- /* This gets filled by lenovo_yoga_tab2_830_1050_init() */
- static struct rmi_device_platform_data lenovo_yoga_tab2_830_1050_rmi_pdata = { };
- static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __initdata = {
- {
- /*
- * This must be the first entry because lenovo_yoga_tab2_830_1050_init()
- * may update its swnode. LSM303DA accelerometer + magnetometer.
- */
- .board_info = {
- .type = "lsm303d",
- .addr = 0x1d,
- .dev_name = "lsm303d",
- },
- .adapter_path = "\\_SB_.I2C5",
- }, {
- /* AL3320A ambient light sensor */
- .board_info = {
- .type = "al3320a",
- .addr = 0x1c,
- .dev_name = "al3320a",
- },
- .adapter_path = "\\_SB_.I2C5",
- }, {
- /* bq24292i battery charger */
- .board_info = {
- .type = "bq24190",
- .addr = 0x6b,
- .dev_name = "bq24292i",
- .swnode = &lenovo_yoga_tab2_830_1050_bq24190_node,
- .platform_data = &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",
- },
- }, {
- /* BQ27541 fuel-gauge */
- .board_info = {
- .type = "bq27541",
- .addr = 0x55,
- .dev_name = "bq27541",
- .swnode = &fg_bq24190_supply_node,
- },
- .adapter_path = "\\_SB_.I2C1",
- }, {
- /* 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,
- },
- }, {
- /* LP8557 Backlight controller */
- .board_info = {
- .type = "lp8557",
- .addr = 0x2c,
- .dev_name = "lp8557",
- .platform_data = &lenovo_lp8557_pwm_and_reg_pdata,
- },
- .adapter_path = "\\_SB_.I2C3",
- },
- };
- static const struct property_entry lenovo_yoga_tab2_830_1050_int3496_props[] __initconst = {
- PROPERTY_ENTRY_GPIO("mux-gpios", &baytrail_gpiochip_nodes[2], 1, GPIO_ACTIVE_LOW),
- PROPERTY_ENTRY_GPIO("id-gpios", &baytrail_gpiochip_nodes[2], 24, GPIO_ACTIVE_HIGH),
- { }
- };
- static const struct platform_device_info lenovo_yoga_tab2_830_1050_pdevs[] __initconst = {
- {
- /* For micro USB ID pin handling */
- .name = "intel-int3496",
- .id = PLATFORM_DEVID_NONE,
- .properties = lenovo_yoga_tab2_830_1050_int3496_props,
- },
- };
- #define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00"
- static const struct property_entry lenovo_yoga_tab2_830_1050_wm1502_props[] = {
- PROPERTY_ENTRY_GPIO("reset-gpios",
- &crystalcove_gpiochip_node, 3, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios",
- &baytrail_gpiochip_nodes[1], 23, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios",
- &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios",
- &arizona_gpiochip_node, 4, GPIO_ACTIVE_LOW),
- { }
- };
- static const struct software_node lenovo_yoga_tab2_830_1050_wm5102 = {
- .properties = lenovo_yoga_tab2_830_1050_wm1502_props,
- };
- static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = {
- &crystalcove_gpiochip_node,
- &arizona_gpiochip_node,
- &lenovo_yoga_tab2_830_1050_wm5102,
- &generic_lipo_hv_4v35_battery_node,
- NULL
- };
- static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev);
- static void lenovo_yoga_tab2_830_1050_exit(void);
- static const char * const lenovo_yoga_tab2_modules[] __initconst = {
- "spi_pxa2xx_platform", /* For the SPI codec device */
- "bq24190_charger", /* For the Vbus regulator for int3496/lc824206xa */
- NULL
- };
- const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = {
- .i2c_client_info = lenovo_yoga_tab2_830_1050_i2c_clients,
- .i2c_client_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_i2c_clients),
- .pdev_info = lenovo_yoga_tab2_830_1050_pdevs,
- .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs),
- .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes,
- .swnode_group = lenovo_yoga_tab2_830_1050_swnodes,
- .modules = lenovo_yoga_tab2_modules,
- .gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
- .init = lenovo_yoga_tab2_830_1050_init,
- .exit = lenovo_yoga_tab2_830_1050_exit,
- };
- /*
- * The Lenovo Yoga Tablet 2 830 and 1050 (8" vs 10") versions use the same
- * mainboard, but the 830 uses a portrait LCD panel with a landscape touchscreen,
- * requiring the touchscreen driver to adjust the touch-coords to match the LCD.
- * And requiring the accelerometer to have a mount-matrix set to correct for
- * the 90° rotation of the LCD vs the frame.
- */
- static const char * const lenovo_yoga_tab2_830_lms303d_mount_matrix[] = {
- "0", "1", "0",
- "-1", "0", "0",
- "0", "0", "1"
- };
- static const struct property_entry lenovo_yoga_tab2_830_lms303d_props[] = {
- PROPERTY_ENTRY_STRING_ARRAY("mount-matrix", lenovo_yoga_tab2_830_lms303d_mount_matrix),
- { }
- };
- static const struct software_node lenovo_yoga_tab2_830_lms303d_node = {
- .properties = lenovo_yoga_tab2_830_lms303d_props,
- };
- static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
- {
- struct gpio_desc *gpiod;
- int ret;
- /* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
- ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, "yoga_bootstrap",
- false, GPIOD_ASIS, &gpiod);
- if (ret)
- return ret;
- ret = gpiod_get_value_cansleep(gpiod);
- if (ret) {
- pr_info("detected Lenovo Yoga Tablet 2 1050F/L\n");
- } else {
- pr_info("detected Lenovo Yoga Tablet 2 830F/L\n");
- lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.swap_axes = true;
- lenovo_yoga_tab2_830_1050_rmi_pdata.sensor_pdata.axis_align.flip_y = true;
- lenovo_yoga_tab2_830_1050_i2c_clients[0].board_info.swnode =
- &lenovo_yoga_tab2_830_lms303d_node;
- }
- return 0;
- }
- /* SUS (INT33FC:02) pin 6 needs to be configured as pmu_clk for the audio codec */
- static const struct pinctrl_map lenovo_yoga_tab2_830_1050_codec_pinctrl_map =
- PIN_MAP_MUX_GROUP(LENOVO_YOGA_TAB2_830_1050_CODEC_NAME, "codec_32khz_clk",
- "INT33FC:02", "pmu_clk2_grp", "pmu_clk");
- static struct device *lenovo_yoga_tab2_830_1050_codec_dev;
- static struct pinctrl *lenovo_yoga_tab2_830_1050_codec_pinctrl;
- static struct sys_off_handler *lenovo_yoga_tab2_830_1050_sys_off_handler;
- static int __init lenovo_yoga_tab2_830_1050_init_codec(void)
- {
- struct device *codec_dev;
- struct pinctrl *pinctrl;
- int ret;
- codec_dev = bus_find_device_by_name(&spi_bus_type, NULL,
- LENOVO_YOGA_TAB2_830_1050_CODEC_NAME);
- if (!codec_dev) {
- pr_err("error cannot find %s device\n", LENOVO_YOGA_TAB2_830_1050_CODEC_NAME);
- return -ENODEV;
- }
- ret = pinctrl_register_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map, 1);
- if (ret)
- goto err_put_device;
- pinctrl = pinctrl_get_select(codec_dev, "codec_32khz_clk");
- if (IS_ERR(pinctrl)) {
- ret = dev_err_probe(codec_dev, PTR_ERR(pinctrl), "selecting codec_32khz_clk\n");
- goto err_unregister_mappings;
- }
- ret = device_add_software_node(codec_dev, &lenovo_yoga_tab2_830_1050_wm5102);
- if (ret) {
- dev_err_probe(codec_dev, ret, "adding software node\n");
- goto err_put_pinctrl;
- }
- lenovo_yoga_tab2_830_1050_codec_dev = codec_dev;
- lenovo_yoga_tab2_830_1050_codec_pinctrl = pinctrl;
- return 0;
- err_put_pinctrl:
- pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl);
- err_unregister_mappings:
- pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map);
- err_put_device:
- put_device(codec_dev);
- return ret;
- }
- /*
- * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off()
- * gets used as pm_power_off handler. This causes "poweroff" on these tablets
- * to hang hard. Requiring pressing the power button for 30 seconds *twice*
- * followed by a normal 3 second press to recover. Avoid this by doing an EFI
- * poweroff instead.
- */
- static int lenovo_yoga_tab2_830_1050_power_off(struct sys_off_data *data)
- {
- efi.reset_system(EFI_RESET_SHUTDOWN, EFI_SUCCESS, 0, NULL);
- return NOTIFY_DONE;
- }
- static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev)
- {
- int ret;
- ret = lenovo_yoga_tab2_830_1050_init_touchscreen();
- if (ret)
- return ret;
- 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 void lenovo_yoga_tab2_830_1050_exit(void)
- {
- unregister_sys_off_handler(lenovo_yoga_tab2_830_1050_sys_off_handler);
- device_remove_software_node(lenovo_yoga_tab2_830_1050_codec_dev);
- pinctrl_put(lenovo_yoga_tab2_830_1050_codec_pinctrl);
- pinctrl_unregister_mappings(&lenovo_yoga_tab2_830_1050_codec_pinctrl_map);
- put_device(lenovo_yoga_tab2_830_1050_codec_dev);
- }
- /*
- * 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,
- };
- static 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 property_entry lenovo_yoga_tab2_1380_fc_props[] __initconst = {
- PROPERTY_ENTRY_GPIO("uart3_txd-gpios", &baytrail_gpiochip_nodes[0], 57, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("uart3_rxd-gpios", &baytrail_gpiochip_nodes[0], 61, GPIO_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,
- .properties = lenovo_yoga_tab2_1380_fc_props,
- },
- };
- 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;
- }
- 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_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes,
- .swnode_group = lenovo_yoga_tab2_830_1050_swnodes,
- .modules = lenovo_yoga_tab2_modules,
- .gpiochip_type = X86_GPIOCHIP_BAYTRAIL,
- .init = lenovo_yoga_tab2_1380_init,
- .exit = lenovo_yoga_tab2_830_1050_exit,
- };
- /* Lenovo Yoga Tab 3 Pro YT3-X90F */
- /*
- * There are 2 batteries, with 2 bq27500 fuel-gauges and 2 bq25892 chargers,
- * "bq25890-charger-1" is instantiated from: drivers/i2c/busses/i2c-cht-wc.c.
- */
- static const char * const lenovo_yt3_bq25892_0_suppliers[] = { "cht_wcove_pwrsrc" };
- static const char * const bq25890_1_psy[] = { "bq25890-charger-1" };
- static const struct property_entry fg_bq25890_1_supply_props[] = {
- PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq25890_1_psy),
- { }
- };
- static const struct software_node fg_bq25890_1_supply_node = {
- .properties = fg_bq25890_1_supply_props,
- };
- /* bq25892 charger settings for the flat LiPo battery behind the screen */
- static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
- PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
- PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
- PROPERTY_ENTRY_BOOL("linux,skip-reset"),
- /* Values taken from Android Factory Image */
- PROPERTY_ENTRY_U32("ti,charge-current", 2048000),
- PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000),
- PROPERTY_ENTRY_U32("ti,termination-current", 128000),
- PROPERTY_ENTRY_U32("ti,precharge-current", 128000),
- PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000),
- PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000),
- PROPERTY_ENTRY_U32("ti,boost-max-current", 500000),
- PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"),
- { }
- };
- static const struct software_node lenovo_yt3_bq25892_0_node = {
- .properties = lenovo_yt3_bq25892_0_props,
- };
- static const struct property_entry lenovo_yt3_hideep_ts_props[] = {
- PROPERTY_ENTRY_U32("touchscreen-size-x", 1600),
- PROPERTY_ENTRY_U32("touchscreen-size-y", 2560),
- PROPERTY_ENTRY_U32("touchscreen-max-pressure", 255),
- PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 7, GPIO_ACTIVE_LOW),
- { }
- };
- static const struct software_node lenovo_yt3_hideep_ts_node = {
- .properties = lenovo_yt3_hideep_ts_props,
- };
- static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
- {
- /* bq27500 fuel-gauge for the flat LiPo battery behind the screen */
- .board_info = {
- .type = "bq27500",
- .addr = 0x55,
- .dev_name = "bq27500_0",
- .swnode = &fg_bq25890_supply_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C1",
- }, {
- /* bq25892 charger for the flat LiPo battery behind the screen */
- .board_info = {
- .type = "bq25892",
- .addr = 0x6b,
- .dev_name = "bq25892_0",
- .swnode = &lenovo_yt3_bq25892_0_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C1",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:01",
- .index = 5,
- .trigger = ACPI_EDGE_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "bq25892_0_irq",
- },
- }, {
- /* bq27500 fuel-gauge for the round Li-ion cells in the hinge */
- .board_info = {
- .type = "bq27500",
- .addr = 0x55,
- .dev_name = "bq27500_1",
- .swnode = &fg_bq25890_1_supply_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C2",
- }, {
- /* HiDeep IST520E Touchscreen */
- .board_info = {
- .type = "hideep_ts",
- .addr = 0x6c,
- .dev_name = "hideep_ts",
- .swnode = &lenovo_yt3_hideep_ts_node,
- },
- .adapter_path = "\\_SB_.PCI0.I2C6",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:03",
- .index = 77,
- .trigger = ACPI_LEVEL_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "hideep_ts_irq",
- },
- }, {
- /* LP8557 Backlight controller */
- .board_info = {
- .type = "lp8557",
- .addr = 0x2c,
- .dev_name = "lp8557",
- .platform_data = &lenovo_lp8557_reg_only_pdata,
- },
- .adapter_path = "\\_SB_.PCI0.I2C1",
- }
- };
- /*
- * The AOSP 3.5 mm Headset: Accessory Specification gives the following values:
- * Function A Play/Pause: 0 ohm
- * Function D Voice assistant: 135 ohm
- * Function B Volume Up 240 ohm
- * Function C Volume Down 470 ohm
- * Minimum Mic DC resistance 1000 ohm
- * Minimum Ear speaker impedance 16 ohm
- * Note the first max value below must be less then the min. speaker impedance,
- * to allow CTIA/OMTP detection to work. The other max values are the closest
- * value from extcon-arizona.c:arizona_micd_levels halfway 2 button resistances.
- */
- static const struct arizona_micd_range arizona_micd_aosp_ranges[] = {
- { .max = 11, .key = KEY_PLAYPAUSE },
- { .max = 186, .key = KEY_VOICECOMMAND },
- { .max = 348, .key = KEY_VOLUMEUP },
- { .max = 752, .key = KEY_VOLUMEDOWN },
- };
- /* YT3 WM5102 arizona_micd_config comes from Android kernel sources */
- static struct arizona_micd_config lenovo_yt3_wm5102_micd_config[] = {
- { 0, 1, 0 },
- { ARIZONA_ACCDET_SRC, 2, 1 },
- };
- static struct arizona_pdata lenovo_yt3_wm5102_pdata = {
- .irq_flags = IRQF_TRIGGER_LOW,
- .micd_detect_debounce = 200,
- .micd_ranges = arizona_micd_aosp_ranges,
- .num_micd_ranges = ARRAY_SIZE(arizona_micd_aosp_ranges),
- .hpdet_channel = ARIZONA_ACCDET_MODE_HPL,
- /* Below settings come from Android kernel sources */
- .micd_bias_start_time = 1,
- .micd_rate = 6,
- .micd_configs = lenovo_yt3_wm5102_micd_config,
- .num_micd_configs = ARRAY_SIZE(lenovo_yt3_wm5102_micd_config),
- .micbias = {
- [0] = { /* MICBIAS1 */
- .mV = 2800,
- .ext_cap = 1,
- .discharge = 1,
- .soft_start = 0,
- .bypass = 0,
- },
- [1] = { /* MICBIAS2 */
- .mV = 2800,
- .ext_cap = 1,
- .discharge = 1,
- .soft_start = 0,
- .bypass = 0,
- },
- [2] = { /* MICBIAS2 */
- .mV = 2800,
- .ext_cap = 1,
- .discharge = 1,
- .soft_start = 0,
- .bypass = 0,
- },
- },
- };
- static const struct property_entry lenovo_yt3_wm1502_props[] = {
- PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios",
- &cherryview_gpiochip_nodes[0], 75, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios",
- &cherryview_gpiochip_nodes[0], 81, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_HIGH),
- PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH),
- { }
- };
- static const struct software_node lenovo_yt3_wm5102 = {
- .properties = lenovo_yt3_wm1502_props,
- .name = "wm5102",
- };
- static const struct software_node *lenovo_yt3_swnodes[] = {
- &arizona_gpiochip_node,
- &lenovo_yt3_wm5102,
- NULL
- };
- static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = {
- {
- /* WM5102 codec */
- .board_info = {
- .modalias = "wm5102",
- .platform_data = &lenovo_yt3_wm5102_pdata,
- .swnode = &lenovo_yt3_wm5102,
- .max_speed_hz = 5000000,
- },
- .ctrl_path = "\\_SB_.PCI0.SPI1",
- .irq_data = {
- .type = X86_ACPI_IRQ_TYPE_GPIOINT,
- .chip = "INT33FF:00",
- .index = 91,
- .trigger = ACPI_LEVEL_SENSITIVE,
- .polarity = ACPI_ACTIVE_LOW,
- .con_id = "wm5102_irq",
- },
- }
- };
- static int __init lenovo_yt3_init(struct device *dev)
- {
- int ret;
- /*
- * The "bq25892_0" charger IC has its /CE (Charge-Enable) and OTG pins
- * connected to GPIOs, rather then having them hardwired to the correct
- * values as is normally done.
- *
- * The bq25890_charger driver controls these through I2C, but this only
- * works if not overridden by the pins. Set these pins here:
- * 1. Set /CE to 1 to allow charging.
- * 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
- * the main "bq25892_1" charger is used when necessary.
- */
- /* /CE pin */
- ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, "bq25892_0_ce",
- true, GPIOD_OUT_HIGH, NULL);
- if (ret < 0)
- return ret;
- /* OTG pin */
- ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, "bq25892_0_otg",
- false, GPIOD_OUT_LOW, NULL);
- if (ret < 0)
- return ret;
- /* Enable the regulators used by the touchscreen */
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff);
- intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff);
- return 0;
- }
- static const char * const lenovo_yt3_modules[] __initconst = {
- "spi_pxa2xx_platform", /* For the SPI codec device */
- NULL
- };
- const struct x86_dev_info lenovo_yt3_info __initconst = {
- .i2c_client_info = lenovo_yt3_i2c_clients,
- .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients),
- .spi_dev_info = lenovo_yt3_spi_devs,
- .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs),
- .swnode_group = lenovo_yt3_swnodes,
- .modules = lenovo_yt3_modules,
- .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW,
- .init = lenovo_yt3_init,
- };
|