xref: /linux/drivers/platform/x86/lenovo-yoga-tab2-pro-1380-fastcharger.c (revision 775a15eaf71d8624024ad91b719ba47d4b04cd2b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Support for the custom fast charging protocol found on the Lenovo Yoga
4  * Tablet 2 1380F / 1380L models.
5  *
6  * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
7  */
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/delay.h>
11 #include <linux/err.h>
12 #include <linux/errno.h>
13 #include <linux/extcon.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/module.h>
16 #include <linux/notifier.h>
17 #include <linux/pinctrl/consumer.h>
18 #include <linux/pinctrl/machine.h>
19 #include <linux/platform_device.h>
20 #include <linux/serdev.h>
21 #include <linux/time.h>
22 #include <linux/types.h>
23 #include <linux/workqueue.h>
24 #include "serdev_helpers.h"
25 
26 #define YT2_1380_FC_PDEV_NAME		"lenovo-yoga-tab2-pro-1380-fastcharger"
27 #define YT2_1380_FC_SERDEV_CTRL		"serial0"
28 #define YT2_1380_FC_SERDEV_NAME		"serial0-0"
29 #define YT2_1380_FC_EXTCON_NAME		"i2c-lc824206xa"
30 
31 #define YT2_1380_FC_MAX_TRIES		5
32 #define YT2_1380_FC_PIN_SW_DELAY_US	(10 * USEC_PER_MSEC)
33 #define YT2_1380_FC_UART_DRAIN_DELAY_US	(50 * USEC_PER_MSEC)
34 #define YT2_1380_FC_VOLT_SW_DELAY_US	(1000 * USEC_PER_MSEC)
35 
36 struct yt2_1380_fc {
37 	struct device *dev;
38 	struct pinctrl *pinctrl;
39 	struct pinctrl_state *gpio_state;
40 	struct pinctrl_state *uart_state;
41 	struct gpio_desc *uart3_txd;
42 	struct gpio_desc *uart3_rxd;
43 	struct extcon_dev *extcon;
44 	struct notifier_block nb;
45 	struct work_struct work;
46 	bool fast_charging;
47 };
48 
yt2_1380_fc_set_gpio_mode(struct yt2_1380_fc * fc,bool enable)49 static int yt2_1380_fc_set_gpio_mode(struct yt2_1380_fc *fc, bool enable)
50 {
51 	struct pinctrl_state *state = enable ? fc->gpio_state : fc->uart_state;
52 	int ret;
53 
54 	ret = pinctrl_select_state(fc->pinctrl, state);
55 	if (ret) {
56 		dev_err(fc->dev, "Error %d setting pinctrl state\n", ret);
57 		return ret;
58 	}
59 
60 	fsleep(YT2_1380_FC_PIN_SW_DELAY_US);
61 	return 0;
62 }
63 
yt2_1380_fc_dedicated_charger_connected(struct yt2_1380_fc * fc)64 static bool yt2_1380_fc_dedicated_charger_connected(struct yt2_1380_fc *fc)
65 {
66 	return extcon_get_state(fc->extcon, EXTCON_CHG_USB_DCP) > 0;
67 }
68 
yt2_1380_fc_fast_charger_connected(struct yt2_1380_fc * fc)69 static bool yt2_1380_fc_fast_charger_connected(struct yt2_1380_fc *fc)
70 {
71 	return extcon_get_state(fc->extcon, EXTCON_CHG_USB_FAST) > 0;
72 }
73 
yt2_1380_fc_worker(struct work_struct * work)74 static void yt2_1380_fc_worker(struct work_struct *work)
75 {
76 	struct yt2_1380_fc *fc = container_of(work, struct yt2_1380_fc, work);
77 	int i, ret;
78 
79 	/* Do nothing if already fast charging */
80 	if (yt2_1380_fc_fast_charger_connected(fc))
81 		return;
82 
83 	for (i = 0; i < YT2_1380_FC_MAX_TRIES; i++) {
84 		/* Set pins to UART mode (for charger disconnect and retries) */
85 		ret = yt2_1380_fc_set_gpio_mode(fc, false);
86 		if (ret)
87 			return;
88 
89 		/* Only try 12V charging if a dedicated charger is detected */
90 		if (!yt2_1380_fc_dedicated_charger_connected(fc))
91 			return;
92 
93 		/* Send the command to switch to 12V charging */
94 		ret = serdev_device_write_buf(to_serdev_device(fc->dev), "SC", strlen("SC"));
95 		if (ret != strlen("SC")) {
96 			dev_err(fc->dev, "Error %d writing to uart\n", ret);
97 			return;
98 		}
99 
100 		fsleep(YT2_1380_FC_UART_DRAIN_DELAY_US);
101 
102 		/* Re-check a charger is still connected */
103 		if (!yt2_1380_fc_dedicated_charger_connected(fc))
104 			return;
105 
106 		/*
107 		 * Now switch the lines to GPIO (output, high). The charger
108 		 * expects the lines being driven high after the command.
109 		 * Presumably this is used to detect the tablet getting
110 		 * unplugged (to switch back to 5V output on unplug).
111 		 */
112 		ret = yt2_1380_fc_set_gpio_mode(fc, true);
113 		if (ret)
114 			return;
115 
116 		fsleep(YT2_1380_FC_VOLT_SW_DELAY_US);
117 
118 		if (yt2_1380_fc_fast_charger_connected(fc))
119 			return; /* Success */
120 	}
121 
122 	dev_dbg(fc->dev, "Failed to switch to 12V charging (not the original charger?)\n");
123 	/* Failed to enable 12V fast charging, reset pins to default UART mode */
124 	yt2_1380_fc_set_gpio_mode(fc, false);
125 }
126 
yt2_1380_fc_extcon_evt(struct notifier_block * nb,unsigned long event,void * param)127 static int yt2_1380_fc_extcon_evt(struct notifier_block *nb,
128 				  unsigned long event, void *param)
129 {
130 	struct yt2_1380_fc *fc = container_of(nb, struct yt2_1380_fc, nb);
131 
132 	schedule_work(&fc->work);
133 	return NOTIFY_OK;
134 }
135 
yt2_1380_fc_receive(struct serdev_device * serdev,const u8 * data,size_t len)136 static size_t yt2_1380_fc_receive(struct serdev_device *serdev, const u8 *data, size_t len)
137 {
138 	/*
139 	 * Since the USB data lines are shorted for DCP detection, echos of
140 	 * the "SC" command send in yt2_1380_fc_worker() will be received.
141 	 */
142 	dev_dbg(&serdev->dev, "recv: %*ph\n", (int)len, data);
143 	return len;
144 }
145 
146 static const struct serdev_device_ops yt2_1380_fc_serdev_ops = {
147 	.receive_buf = yt2_1380_fc_receive,
148 	.write_wakeup = serdev_device_write_wakeup,
149 };
150 
yt2_1380_fc_serdev_probe(struct serdev_device * serdev)151 static int yt2_1380_fc_serdev_probe(struct serdev_device *serdev)
152 {
153 	struct device *dev = &serdev->dev;
154 	struct yt2_1380_fc *fc;
155 	int ret;
156 
157 	fc = devm_kzalloc(dev, sizeof(*fc), GFP_KERNEL);
158 	if (!fc)
159 		return -ENOMEM;
160 
161 	fc->dev = dev;
162 	fc->nb.notifier_call = yt2_1380_fc_extcon_evt;
163 	INIT_WORK(&fc->work, yt2_1380_fc_worker);
164 
165 	/*
166 	 * Do this first since it may return -EPROBE_DEFER.
167 	 * There is no extcon_put(), so there is no need to free this.
168 	 */
169 	fc->extcon = extcon_get_extcon_dev(YT2_1380_FC_EXTCON_NAME);
170 	if (IS_ERR(fc->extcon))
171 		return dev_err_probe(dev, PTR_ERR(fc->extcon), "getting extcon\n");
172 
173 	fc->pinctrl = devm_pinctrl_get(dev);
174 	if (IS_ERR(fc->pinctrl))
175 		return dev_err_probe(dev, PTR_ERR(fc->pinctrl), "getting pinctrl\n");
176 
177 	/*
178 	 * To switch the UART3 pins connected to the USB data lines between
179 	 * UART and GPIO modes.
180 	 */
181 	fc->gpio_state = pinctrl_lookup_state(fc->pinctrl, "uart3_gpio");
182 	fc->uart_state = pinctrl_lookup_state(fc->pinctrl, "uart3_uart");
183 	if (IS_ERR(fc->gpio_state) || IS_ERR(fc->uart_state))
184 		return dev_err_probe(dev, -EINVAL, "getting pinctrl states\n");
185 
186 	ret = yt2_1380_fc_set_gpio_mode(fc, true);
187 	if (ret)
188 		return ret;
189 
190 	fc->uart3_txd = devm_gpiod_get(dev, "uart3_txd", GPIOD_OUT_HIGH);
191 	if (IS_ERR(fc->uart3_txd))
192 		return dev_err_probe(dev, PTR_ERR(fc->uart3_txd), "getting uart3_txd gpio\n");
193 
194 	fc->uart3_rxd = devm_gpiod_get(dev, "uart3_rxd", GPIOD_OUT_HIGH);
195 	if (IS_ERR(fc->uart3_rxd))
196 		return dev_err_probe(dev, PTR_ERR(fc->uart3_rxd), "getting uart3_rxd gpio\n");
197 
198 	ret = yt2_1380_fc_set_gpio_mode(fc, false);
199 	if (ret)
200 		return ret;
201 
202 	serdev_device_set_drvdata(serdev, fc);
203 	serdev_device_set_client_ops(serdev, &yt2_1380_fc_serdev_ops);
204 
205 	ret = devm_serdev_device_open(dev, serdev);
206 	if (ret)
207 		return dev_err_probe(dev, ret, "opening UART device\n");
208 
209 	serdev_device_set_baudrate(serdev, 600);
210 	serdev_device_set_flow_control(serdev, false);
211 
212 	ret = devm_extcon_register_notifier_all(dev, fc->extcon, &fc->nb);
213 	if (ret)
214 		return dev_err_probe(dev, ret, "registering extcon notifier\n");
215 
216 	/* In case the extcon already has detected a DCP charger */
217 	schedule_work(&fc->work);
218 
219 	return 0;
220 }
221 
222 struct serdev_device_driver yt2_1380_fc_serdev_driver = {
223 	.probe = yt2_1380_fc_serdev_probe,
224 	.driver = {
225 		.name = KBUILD_MODNAME,
226 	},
227 };
228 
229 static const struct pinctrl_map yt2_1380_fc_pinctrl_map[] = {
230 	PIN_MAP_MUX_GROUP(YT2_1380_FC_SERDEV_NAME, "uart3_uart",
231 			  "INT33FC:00", "uart3_grp", "uart"),
232 	PIN_MAP_MUX_GROUP(YT2_1380_FC_SERDEV_NAME, "uart3_gpio",
233 			  "INT33FC:00", "uart3_grp_gpio", "gpio"),
234 };
235 
yt2_1380_fc_pdev_probe(struct platform_device * pdev)236 static int yt2_1380_fc_pdev_probe(struct platform_device *pdev)
237 {
238 	struct serdev_device *serdev;
239 	struct device *ctrl_dev;
240 	int ret;
241 
242 	/* Register pinctrl mappings for setting the UART3 pins mode */
243 	ret = pinctrl_register_mappings(yt2_1380_fc_pinctrl_map,
244 					ARRAY_SIZE(yt2_1380_fc_pinctrl_map));
245 	if (ret)
246 		return ret;
247 
248 	/* And create the serdev to talk to the charger over the UART3 pins */
249 	ctrl_dev = get_serdev_controller("PNP0501", "1", 0, YT2_1380_FC_SERDEV_CTRL);
250 	if (IS_ERR(ctrl_dev)) {
251 		ret = PTR_ERR(ctrl_dev);
252 		goto out_pinctrl_unregister_mappings;
253 	}
254 
255 	serdev = serdev_device_alloc(to_serdev_controller(ctrl_dev));
256 	put_device(ctrl_dev);
257 	if (!serdev) {
258 		ret = -ENOMEM;
259 		goto out_pinctrl_unregister_mappings;
260 	}
261 
262 	ret = serdev_device_add(serdev);
263 	if (ret) {
264 		dev_err_probe(&pdev->dev, ret, "adding serdev\n");
265 		serdev_device_put(serdev);
266 		goto out_pinctrl_unregister_mappings;
267 	}
268 
269 	/*
270 	 * serdev device <-> driver matching relies on OF or ACPI matches and
271 	 * neither is available here, manually bind the driver.
272 	 */
273 	ret = device_driver_attach(&yt2_1380_fc_serdev_driver.driver, &serdev->dev);
274 	if (ret) {
275 		/* device_driver_attach() maps EPROBE_DEFER to EAGAIN, map it back */
276 		ret = (ret == -EAGAIN) ? -EPROBE_DEFER : ret;
277 		dev_err_probe(&pdev->dev, ret, "attaching serdev driver\n");
278 		goto out_serdev_device_remove;
279 	}
280 
281 	/* So that yt2_1380_fc_pdev_remove() can remove the serdev */
282 	platform_set_drvdata(pdev, serdev);
283 	return 0;
284 
285 out_serdev_device_remove:
286 	serdev_device_remove(serdev);
287 out_pinctrl_unregister_mappings:
288 	pinctrl_unregister_mappings(yt2_1380_fc_pinctrl_map);
289 	return ret;
290 }
291 
yt2_1380_fc_pdev_remove(struct platform_device * pdev)292 static void yt2_1380_fc_pdev_remove(struct platform_device *pdev)
293 {
294 	struct serdev_device *serdev = platform_get_drvdata(pdev);
295 
296 	serdev_device_remove(serdev);
297 	pinctrl_unregister_mappings(yt2_1380_fc_pinctrl_map);
298 }
299 
300 static struct platform_driver yt2_1380_fc_pdev_driver = {
301 	.probe = yt2_1380_fc_pdev_probe,
302 	.remove = yt2_1380_fc_pdev_remove,
303 	.driver = {
304 		.name = YT2_1380_FC_PDEV_NAME,
305 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
306 	},
307 };
308 
yt2_1380_fc_module_init(void)309 static int __init yt2_1380_fc_module_init(void)
310 {
311 	int ret;
312 
313 	/*
314 	 * serdev driver MUST be registered first because pdev driver calls
315 	 * device_driver_attach() on the serdev, serdev-driver pair.
316 	 */
317 	ret = serdev_device_driver_register(&yt2_1380_fc_serdev_driver);
318 	if (ret)
319 		return ret;
320 
321 	ret = platform_driver_register(&yt2_1380_fc_pdev_driver);
322 	if (ret)
323 		serdev_device_driver_unregister(&yt2_1380_fc_serdev_driver);
324 
325 	return ret;
326 }
327 module_init(yt2_1380_fc_module_init);
328 
yt2_1380_fc_module_exit(void)329 static void __exit yt2_1380_fc_module_exit(void)
330 {
331 	platform_driver_unregister(&yt2_1380_fc_pdev_driver);
332 	serdev_device_driver_unregister(&yt2_1380_fc_serdev_driver);
333 }
334 module_exit(yt2_1380_fc_module_exit);
335 
336 MODULE_ALIAS("platform:" YT2_1380_FC_PDEV_NAME);
337 MODULE_DESCRIPTION("Lenovo Yoga Tablet 2 1380 fast charge driver");
338 MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
339 MODULE_LICENSE("GPL");
340