MAX14526 is a powerful extcon chip which allows detection of various plugs like usb, mhl, uart, headset etc. This version of driver implements support of AP-usb and CP-usb/uart paths.
Tested-by: Andreas Westman Dorcsak <hed...@yahoo.com> # LG P880 T30 Tested-by: Svyatoslav Ryhel <clamo...@gmail.com> # LG P895 T30 Signed-off-by: Svyatoslav Ryhel <clamo...@gmail.com> --- drivers/misc/Kconfig | 2 + drivers/misc/Makefile | 1 + drivers/misc/extcon/Kconfig | 8 ++ drivers/misc/extcon/Makefile | 2 + drivers/misc/extcon/extcon-max14526.c | 151 ++++++++++++++++++++++++++ 5 files changed, 164 insertions(+) create mode 100644 drivers/misc/extcon/Kconfig create mode 100644 drivers/misc/extcon/Makefile create mode 100644 drivers/misc/extcon/extcon-max14526.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 4e1ae03e9f..1b49f3cf72 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -659,4 +659,6 @@ config SL28CPLD the base driver which provides common access methods for the sub-drivers. +source "drivers/misc/extcon/Kconfig" + endmenu diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 3b792f2a14..6d4fc8ddf9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -87,3 +87,4 @@ obj-$(CONFIG_K3_AVS0) += k3_avs.o obj-$(CONFIG_ESM_K3) += k3_esm.o obj-$(CONFIG_ESM_PMIC) += esm_pmic.o obj-$(CONFIG_SL28CPLD) += sl28cpld.o +obj-y += extcon/ diff --git a/drivers/misc/extcon/Kconfig b/drivers/misc/extcon/Kconfig new file mode 100644 index 0000000000..99c38224f3 --- /dev/null +++ b/drivers/misc/extcon/Kconfig @@ -0,0 +1,8 @@ +config EXTCON_MAX14526 + bool "Maxim MAX14526 EXTCON Support" + select DM_I2C + select DM_MISC + help + If you say yes here you get support for the MUIC device of + Maxim MAX14526. The MAX14526 MUIC is a USB port accessory + detector and switch. diff --git a/drivers/misc/extcon/Makefile b/drivers/misc/extcon/Makefile new file mode 100644 index 0000000000..f012b688ce --- /dev/null +++ b/drivers/misc/extcon/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0+ +obj-$(CONFIG_EXTCON_MAX14526) += extcon-max14526.o diff --git a/drivers/misc/extcon/extcon-max14526.c b/drivers/misc/extcon/extcon-max14526.c new file mode 100644 index 0000000000..b957d2575a --- /dev/null +++ b/drivers/misc/extcon/extcon-max14526.c @@ -0,0 +1,151 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2022 Svyatoslav Ryhel <clamo...@gmail.com> + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <log.h> +#include <misc.h> +#include <asm/gpio.h> + +#define CONTROL_1 0x01 +#define SW_CONTROL 0x03 + +#define ID_200 0x10 +#define ADC_EN 0x02 +#define CP_EN 0x01 + +#define DP_USB 0x00 +#define DP_UART 0x08 +#define DP_AUDIO 0x10 +#define DP_OPEN 0x38 + +#define DM_USB 0x00 +#define DM_UART 0x01 +#define DM_AUDIO 0x02 +#define DM_OPEN 0x07 + +#define AP_USB BIT(0) +#define CP_USB BIT(1) +#define CP_UART BIT(2) + +struct max14526_priv { + struct gpio_desc usif_gpio; + struct gpio_desc dp2t_gpio; + struct gpio_desc ifx_usb_vbus_gpio; +}; + +static void max14526_set_mode(struct udevice *dev, int mode) +{ + struct max14526_priv *priv = dev_get_priv(dev); + int ret; + + if ((mode & AP_USB) || (mode & CP_USB)) { + /* Connect CP UART signals to AP */ + ret = dm_gpio_set_value(&priv->usif_gpio, 0); + if (ret) + log_debug("cp-uart > ap failed (%d)\n", ret); + } + + if (mode & CP_UART) { + /* Connect CP UART signals to DP2T */ + ret = dm_gpio_set_value(&priv->usif_gpio, 1); + if (ret) + log_debug("cp-uart > dp2t failed (%d)\n", ret); + } + + if (mode & CP_USB) { + /* Connect CP USB to MUIC UART */ + ret = dm_gpio_set_value(&priv->ifx_usb_vbus_gpio, 1); + if (ret) + log_debug("usb-vbus-gpio enable failed (%d)\n", ret); + + ret = dm_gpio_set_value(&priv->dp2t_gpio, 1); + if (ret) + log_debug("cp-usb > muic-uart failed (%d)\n", ret); + } + + if ((mode & AP_USB) || (mode & CP_UART)) { + /* Connect CP UART to MUIC UART */ + ret = dm_gpio_set_value(&priv->dp2t_gpio, 0); + if (ret) + log_debug("cp-uart > muic-uart failed (%d)\n", ret); + } + + if (mode & AP_USB) { + /* Enables USB Path */ + ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_USB | DM_USB); + if (ret) + log_debug("USB path set failed: %d\n", ret); + } + + if ((mode & CP_USB) || (mode & CP_UART)) { + /* Enables UART Path */ + ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_UART | DM_UART); + if (ret) + log_debug("UART path set failed: %d\n", ret); + } + + /* Enables 200K, Charger Pump, and ADC */ + ret = dm_i2c_reg_write(dev, CONTROL_1, ID_200 | ADC_EN | CP_EN); + if (ret) + log_debug("200K, Charger Pump, and ADC set failed: %d\n", ret); +} + +static int max14526_probe(struct udevice *dev) +{ + struct max14526_priv *priv = dev_get_priv(dev); + int ret, mode = 0; + + ret = gpio_request_by_name(dev, "usif-gpios", 0, + &priv->usif_gpio, GPIOD_IS_OUT); + if (ret) { + log_err("could not decode usif-gpios (%d)\n", ret); + return ret; + } + + ret = gpio_request_by_name(dev, "dp2t-gpios", 0, + &priv->dp2t_gpio, GPIOD_IS_OUT); + if (ret) { + log_err("could not decode dp2t-gpios (%d)\n", ret); + return ret; + } + + if (dev_read_bool(dev, "maxim,ap-usb")) + mode |= AP_USB; + + if (dev_read_bool(dev, "maxim,cp-usb")) { + mode |= CP_USB; + + ret = gpio_request_by_name(dev, "usb-vbus-gpios", 0, + &priv->ifx_usb_vbus_gpio, GPIOD_IS_OUT); + if (ret) { + log_err("could not decode usb-vbus-gpios (%d)\n", ret); + return ret; + } + } + + if (dev_read_bool(dev, "maxim,cp-uart")) + mode |= CP_UART; + + max14526_set_mode(dev, mode); + + return 0; +} + +static const struct udevice_id max14526_ids[] = { + { .compatible = "maxim,max14526-muic" }, + { } +}; + +U_BOOT_DRIVER(extcon_max14526) = { + .name = "extcon_max14526", + .id = UCLASS_MISC, + .of_match = max14526_ids, + .probe = max14526_probe, + .priv_auto = sizeof(struct max14526_priv), +}; -- 2.37.2