extcon: add MAX14526 MUIC support
authorSvyatoslav Ryhel <clamor95@gmail.com>
Tue, 25 Apr 2023 07:57:22 +0000 (10:57 +0300)
committerTom Rini <trini@konsulko.com>
Tue, 2 May 2023 18:23:58 +0000 (14:23 -0400)
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 <hedmoo@yahoo.com> # LG P880 T30
Tested-by: Svyatoslav Ryhel <clamor95@gmail.com> # LG P895 T30
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
drivers/extcon/Kconfig
drivers/extcon/Makefile
drivers/extcon/extcon-max14526.c [new file with mode: 0644]

index 6fd3d2b..fbb7335 100644 (file)
@@ -19,4 +19,13 @@ config EXTCON_SANDBOX
          Enable extcon support for sandbox. This is an emulation of a real
          extcon. Currectly all configuration is done in the probe.
 
+config EXTCON_MAX14526
+       bool "Maxim MAX14526 EXTCON Support"
+       depends on DM_I2C
+       depends on EXTCON
+       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.
+
 endmenu
index c4223d9..3309f2a 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_EXTCON) += extcon-uclass.o
 obj-$(CONFIG_EXTCON_SANDBOX) += extcon-sandbox.o
+obj-$(CONFIG_EXTCON_MAX14526) += extcon-max14526.o
diff --git a/drivers/extcon/extcon-max14526.c b/drivers/extcon/extcon-max14526.c
new file mode 100644 (file)
index 0000000..a33b5ef
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <log.h>
+#include <extcon.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_EXTCON,
+       .of_match       = max14526_ids,
+       .probe          = max14526_probe,
+       .priv_auto      = sizeof(struct max14526_priv),
+};