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 
35 struct max14526_priv {
36 	struct gpio_desc usif_gpio;
37 	struct gpio_desc dp2t_gpio;
38 	struct gpio_desc ifx_usb_vbus_gpio;
39 };
40 
max14526_set_mode(struct udevice * dev,int mode)41 static 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 
max14526_probe(struct udevice * dev)98 static 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 
139 static const struct udevice_id max14526_ids[] = {
140 	{ .compatible = "maxim,max14526-muic" },
141 	{ }
142 };
143 
144 U_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