Skip to content

Commit 2513563

Browse files
committed
platform/x86: Add new MeeGoPad ANX7428 Type-C Cross Switch driver
Some MeeGoPad top-set boxes have an ANX7428 Type-C Switch for USB3.1 Gen 1 and DisplayPort over Type-C alternate mode support. The ANX7428 has a microcontroller which takes care of the PD negotiation and automatically sets the builtin Crosspoint Switch to send the right signal to the 4 highspeed pairs of the Type-C connector. It also takes care of HPD and AUX channel routing for DP alternate mode. IOW the ANX7428 operates fully autonomous and to the x5-Z8350 SoC things look like there simple is a USB-3 Type-A connector and a separate DisplayPort connector. Except that the BIOS does not power on the ANX7428 at boot (meh). Add a driver to power on the ANX7428. This driver is added under drivers/platform/x86 rather than under drivers/usb/typec for 2 reasons: 1. This driver is specifically written to work with how the ANX7428 is described in the ACPI tables of the MeeGoPad x86 (Cherry Trail) devices. 2. This driver only powers on the ANX7428 and does not do anything wrt its Type-C functionality. It should be possible to tell the controller which data- and/or power-role to negotiate and to swap the role(s) after negotiation but the MeeGoPad top-set boxes always draw their power from a separate power-connector and they only support USB host-mode. So this functionality is unnecessary and due to lack of documentation this is tricky to support. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Link: https://lore.kernel.org/r/20240514180343.70795-1-hdegoede@redhat.com
1 parent b444dfc commit 2513563

File tree

3 files changed

+164
-0
lines changed

3 files changed

+164
-0
lines changed

drivers/platform/x86/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,17 @@ config ACPI_QUICKSTART
666666
To compile this driver as a module, choose M here: the module will be
667667
called quickstart.
668668

669+
config MEEGOPAD_ANX7428
670+
tristate "MeeGoPad ANX7428 Type-C Switch"
671+
depends on ACPI && GPIOLIB && I2C
672+
help
673+
Some MeeGoPad top-set boxes have an ANX7428 Type-C Switch for
674+
USB3.1 Gen 1 and DisplayPort over Type-C alternate mode support.
675+
676+
This driver takes care of powering on the ANX7428 on supported
677+
MeeGoPad top-set boxes. After this the ANX7428 takes care of Type-C
678+
connector orientation and PD alternate mode switching autonomously.
679+
669680
config MSI_EC
670681
tristate "MSI EC Extras"
671682
depends on ACPI

drivers/platform/x86/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ obj-y += intel/
7575
# Microsoft
7676
obj-$(CONFIG_ACPI_QUICKSTART) += quickstart.o
7777

78+
# MeeGoPad
79+
obj-$(CONFIG_MEEGOPAD_ANX7428) += meegopad_anx7428.o
80+
7881
# MSI
7982
obj-$(CONFIG_MSI_EC) += msi-ec.o
8083
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
/*
3+
* Driver to power on the Analogix ANX7428 USB Type-C crosspoint switch
4+
* on MeeGoPad top-set boxes.
5+
*
6+
* The MeeGoPad T8 and T9 are Cherry Trail top-set boxes which
7+
* use an ANX7428 to provide a Type-C port with USB3.1 Gen 1 and
8+
* DisplayPort over Type-C alternate mode support.
9+
*
10+
* The ANX7428 has a microcontroller which takes care of the PD
11+
* negotiation and automatically sets the builtin Crosspoint Switch
12+
* to send the right signal to the 4 highspeed pairs of the Type-C
13+
* connector. It also takes care of HPD and AUX channel routing for
14+
* DP alternate mode.
15+
*
16+
* IOW the ANX7428 operates fully autonomous and to the x5-Z8350 SoC
17+
* things look like there simply is a USB-3 Type-A connector and a
18+
* separate DisplayPort connector. Except that the BIOS does not
19+
* power on the ANX7428 at boot. This driver takes care of powering
20+
* on the ANX7428.
21+
*
22+
* It should be possible to tell the micro-controller which data- and/or
23+
* power-role to negotiate and to swap the role(s) after negotiation
24+
* but the MeeGoPad top-set boxes always draw their power from a separate
25+
* power-connector and they only support USB host-mode. So this functionality
26+
* is unnecessary and due to lack of documentation this is tricky to support.
27+
*
28+
* For a more complete ANX7428 driver see drivers/usb/misc/anx7418/ of
29+
* the LineageOS kernel for the LG G5 (International) aka the LG H850:
30+
* https://github.com/LineageOS/android_kernel_lge_msm8996/
31+
*
32+
* (C) Copyright 2024 Hans de Goede <hansg@kernel.org>
33+
*/
34+
35+
#include <linux/acpi.h>
36+
#include <linux/bits.h>
37+
#include <linux/delay.h>
38+
#include <linux/dev_printk.h>
39+
#include <linux/dmi.h>
40+
#include <linux/err.h>
41+
#include <linux/gpio/consumer.h>
42+
#include <linux/i2c.h>
43+
#include <linux/iopoll.h>
44+
#include <linux/module.h>
45+
#include <linux/types.h>
46+
47+
/* Register addresses and fields */
48+
#define VENDOR_ID 0x00
49+
#define DEVICE_ID 0x02
50+
51+
#define TX_STATUS 0x16
52+
#define STATUS_SUCCESS BIT(0)
53+
#define STATUS_ERROR BIT(1)
54+
#define OCM_STARTUP BIT(7)
55+
56+
static bool force;
57+
module_param(force, bool, 0444);
58+
MODULE_PARM_DESC(force, "Force the driver to probe on unknown boards");
59+
60+
static const struct acpi_gpio_params enable_gpio = { 0, 0, false };
61+
static const struct acpi_gpio_params reset_gpio = { 1, 0, true };
62+
63+
static const struct acpi_gpio_mapping meegopad_anx7428_gpios[] = {
64+
{ "enable-gpios", &enable_gpio, 1 },
65+
{ "reset-gpios", &reset_gpio, 1 },
66+
{ }
67+
};
68+
69+
static const struct dmi_system_id meegopad_anx7428_ids[] = {
70+
{
71+
/* Meegopad T08 */
72+
.matches = {
73+
DMI_MATCH(DMI_SYS_VENDOR, "Default string"),
74+
DMI_MATCH(DMI_PRODUCT_NAME, "Default string"),
75+
DMI_MATCH(DMI_BOARD_NAME, "T3 MRD"),
76+
DMI_MATCH(DMI_BOARD_VERSION, "V1.1"),
77+
},
78+
},
79+
{ }
80+
};
81+
82+
static int anx7428_probe(struct i2c_client *client)
83+
{
84+
struct device *dev = &client->dev;
85+
struct gpio_desc *gpio;
86+
int ret, val;
87+
88+
if (!dmi_check_system(meegopad_anx7428_ids) && !force) {
89+
dev_warn(dev, "Not probing unknown board, pass meegopad_anx7428.force=1 to probe");
90+
return -ENODEV;
91+
}
92+
93+
ret = devm_acpi_dev_add_driver_gpios(dev, meegopad_anx7428_gpios);
94+
if (ret)
95+
return ret;
96+
97+
/*
98+
* Set GPIOs to desired values while getting them, they are not needed
99+
* afterwards. Ordering and delays come from android_kernel_lge_msm8996.
100+
*/
101+
gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
102+
if (IS_ERR(gpio))
103+
return dev_err_probe(dev, PTR_ERR(gpio), "getting enable GPIO\n");
104+
105+
fsleep(10000);
106+
107+
gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
108+
if (IS_ERR(gpio))
109+
return dev_err_probe(dev, PTR_ERR(gpio), "getting reset GPIO\n");
110+
111+
/* Wait for the OCM (On Chip Microcontroller) to start */
112+
ret = read_poll_timeout(i2c_smbus_read_byte_data, val,
113+
val >= 0 && (val & OCM_STARTUP),
114+
5000, 50000, true, client, TX_STATUS);
115+
if (ret)
116+
return dev_err_probe(dev, ret,
117+
"On Chip Microcontroller did not start, status: 0x%02x\n",
118+
val);
119+
120+
ret = i2c_smbus_read_word_data(client, VENDOR_ID);
121+
if (ret < 0)
122+
return dev_err_probe(dev, ret, "reading vendor-id register\n");
123+
val = ret;
124+
125+
ret = i2c_smbus_read_word_data(client, DEVICE_ID);
126+
if (ret < 0)
127+
return dev_err_probe(dev, ret, "reading device-id register\n");
128+
129+
dev_dbg(dev, "Powered on ANX7428 id %04x:%04x\n", val, ret);
130+
return 0;
131+
}
132+
133+
static const struct acpi_device_id anx7428_acpi_match[] = {
134+
{ "ANXO7418" }, /* ACPI says 7418 (max 2 DP lanes version) but HW is 7428 */
135+
{ }
136+
};
137+
MODULE_DEVICE_TABLE(acpi, anx7428_acpi_match);
138+
139+
static struct i2c_driver anx7428_driver = {
140+
.driver = {
141+
.name = "meegopad_anx7428",
142+
.acpi_match_table = anx7428_acpi_match,
143+
},
144+
.probe = anx7428_probe,
145+
};
146+
module_i2c_driver(anx7428_driver);
147+
148+
MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
149+
MODULE_DESCRIPTION("MeeGoPad ANX7428 driver");
150+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)