1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
4 */
5
6#include <dm.h>
7#include <i2c.h>
8#include <linux/delay.h>
9#include <linux/err.h>
10#include <log.h>
11#include <extcon.h>
12#include <asm/gpio.h>
13
14#define CONTROL_1	0x01
15#define SW_CONTROL	0x03
16
17#define ID_200		0x10
18#define ADC_EN		0x02
19#define CP_EN		0x01
20
21#define DP_USB		0x00
22#define DP_UART		0x08
23#define DP_AUDIO	0x10
24#define DP_OPEN		0x38
25
26#define DM_USB		0x00
27#define DM_UART		0x01
28#define DM_AUDIO	0x02
29#define DM_OPEN		0x07
30
31#define AP_USB		BIT(0)
32#define CP_USB		BIT(1)
33#define CP_UART		BIT(2)
34
35struct max14526_priv {
36	struct gpio_desc usif_gpio;
37	struct gpio_desc dp2t_gpio;
38	struct gpio_desc ifx_usb_vbus_gpio;
39};
40
41static void max14526_set_mode(struct udevice *dev, int mode)
42{
43	struct max14526_priv *priv = dev_get_priv(dev);
44	int ret;
45
46	if ((mode & AP_USB) || (mode & CP_USB)) {
47		/* Connect CP UART signals to AP */
48		ret = dm_gpio_set_value(&priv->usif_gpio, 0);
49		if (ret)
50			log_debug("cp-uart > ap failed (%d)\n", ret);
51	}
52
53	if (mode & CP_UART) {
54		/* Connect CP UART signals to DP2T */
55		ret = dm_gpio_set_value(&priv->usif_gpio, 1);
56		if (ret)
57			log_debug("cp-uart > dp2t failed (%d)\n", ret);
58	}
59
60	if (mode & CP_USB) {
61		/* Connect CP USB to MUIC UART */
62		ret = dm_gpio_set_value(&priv->ifx_usb_vbus_gpio, 1);
63		if (ret)
64			log_debug("usb-vbus-gpio enable failed (%d)\n", ret);
65
66		ret = dm_gpio_set_value(&priv->dp2t_gpio, 1);
67		if (ret)
68			log_debug("cp-usb > muic-uart failed (%d)\n", ret);
69	}
70
71	if ((mode & AP_USB) || (mode & CP_UART)) {
72		/* Connect CP UART to MUIC UART */
73		ret = dm_gpio_set_value(&priv->dp2t_gpio, 0);
74		if (ret)
75			log_debug("cp-uart > muic-uart failed (%d)\n", ret);
76	}
77
78	if (mode & AP_USB) {
79		/* Enables USB Path */
80		ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_USB | DM_USB);
81		if (ret)
82			log_debug("USB path set failed: %d\n", ret);
83	}
84
85	if ((mode & CP_USB) || (mode & CP_UART)) {
86		/* Enables UART Path */
87		ret = dm_i2c_reg_write(dev, SW_CONTROL, DP_UART | DM_UART);
88		if (ret)
89			log_debug("UART path set failed: %d\n", ret);
90	}
91
92	/* Enables 200K, Charger Pump, and ADC */
93	ret = dm_i2c_reg_write(dev, CONTROL_1, ID_200 | ADC_EN | CP_EN);
94	if (ret)
95		log_debug("200K, Charger Pump, and ADC set failed: %d\n", ret);
96}
97
98static int max14526_probe(struct udevice *dev)
99{
100	struct max14526_priv *priv = dev_get_priv(dev);
101	int ret, mode = 0;
102
103	ret = gpio_request_by_name(dev, "usif-gpios", 0,
104				   &priv->usif_gpio, GPIOD_IS_OUT);
105	if (ret) {
106		log_err("could not decode usif-gpios (%d)\n", ret);
107		return ret;
108	}
109
110	ret = gpio_request_by_name(dev, "dp2t-gpios", 0,
111				   &priv->dp2t_gpio, GPIOD_IS_OUT);
112	if (ret) {
113		log_err("could not decode dp2t-gpios (%d)\n", ret);
114		return ret;
115	}
116
117	if (dev_read_bool(dev, "maxim,ap-usb"))
118		mode |= AP_USB;
119
120	if (dev_read_bool(dev, "maxim,cp-usb")) {
121		mode |= CP_USB;
122
123		ret = gpio_request_by_name(dev, "usb-vbus-gpios", 0,
124					   &priv->ifx_usb_vbus_gpio, GPIOD_IS_OUT);
125		if (ret) {
126			log_err("could not decode usb-vbus-gpios (%d)\n", ret);
127			return ret;
128		}
129	}
130
131	if (dev_read_bool(dev, "maxim,cp-uart"))
132		mode |= CP_UART;
133
134	max14526_set_mode(dev, mode);
135
136	return 0;
137}
138
139static const struct udevice_id max14526_ids[] = {
140	{ .compatible = "maxim,max14526-muic" },
141	{ }
142};
143
144U_BOOT_DRIVER(extcon_max14526) = {
145	.name		= "extcon_max14526",
146	.id		= UCLASS_EXTCON,
147	.of_match	= max14526_ids,
148	.probe		= max14526_probe,
149	.priv_auto	= sizeof(struct max14526_priv),
150};
151