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