xref: /openbmc/linux/drivers/usb/serial/upd78f0730.c (revision 5fd54ace4721fc5ce2bb5aef6318fcf17f421460)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Renesas Electronics uPD78F0730 USB to serial converter driver
4  *
5  * Copyright (C) 2014,2016 Maksim Salau <maksim.salau@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2
9  * as published by the Free Software Foundation.
10  *
11  * Protocol of the adaptor is described in the application note U19660EJ1V0AN00
12  * μPD78F0730 8-bit Single-Chip Microcontroller
13  * USB-to-Serial Conversion Software
14  * <https://www.renesas.com/en-eu/doc/DocumentServer/026/U19660EJ1V0AN00.pdf>
15  *
16  * The adaptor functionality is limited to the following:
17  * - data bits: 7 or 8
18  * - stop bits: 1 or 2
19  * - parity: even, odd or none
20  * - flow control: none
21  * - baud rates: 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
22  * - signals: DTR, RTS and BREAK
23  */
24 
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/tty.h>
28 #include <linux/usb.h>
29 #include <linux/usb/serial.h>
30 
31 #define DRIVER_DESC "Renesas uPD78F0730 USB to serial converter driver"
32 
33 #define DRIVER_AUTHOR "Maksim Salau <maksim.salau@gmail.com>"
34 
35 static const struct usb_device_id id_table[] = {
36 	{ USB_DEVICE(0x0409, 0x0063) }, /* V850ESJX3-STICK */
37 	{ USB_DEVICE(0x045B, 0x0212) }, /* YRPBRL78G13, YRPBRL78G14 */
38 	{ USB_DEVICE(0x064B, 0x7825) }, /* Analog Devices EVAL-ADXL362Z-DB */
39 	{}
40 };
41 
42 MODULE_DEVICE_TABLE(usb, id_table);
43 
44 /*
45  * Each adaptor is associated with a private structure, that holds the current
46  * state of control signals (DTR, RTS and BREAK).
47  */
48 struct upd78f0730_port_private {
49 	struct mutex	lock;		/* mutex to protect line_signals */
50 	u8		line_signals;
51 };
52 
53 /* Op-codes of control commands */
54 #define UPD78F0730_CMD_LINE_CONTROL	0x00
55 #define UPD78F0730_CMD_SET_DTR_RTS	0x01
56 #define UPD78F0730_CMD_SET_XON_XOFF_CHR	0x02
57 #define UPD78F0730_CMD_OPEN_CLOSE	0x03
58 #define UPD78F0730_CMD_SET_ERR_CHR	0x04
59 
60 /* Data sizes in UPD78F0730_CMD_LINE_CONTROL command */
61 #define UPD78F0730_DATA_SIZE_7_BITS	0x00
62 #define UPD78F0730_DATA_SIZE_8_BITS	0x01
63 #define UPD78F0730_DATA_SIZE_MASK	0x01
64 
65 /* Stop-bit modes in UPD78F0730_CMD_LINE_CONTROL command */
66 #define UPD78F0730_STOP_BIT_1_BIT	0x00
67 #define UPD78F0730_STOP_BIT_2_BIT	0x02
68 #define UPD78F0730_STOP_BIT_MASK	0x02
69 
70 /* Parity modes in UPD78F0730_CMD_LINE_CONTROL command */
71 #define UPD78F0730_PARITY_NONE	0x00
72 #define UPD78F0730_PARITY_EVEN	0x04
73 #define UPD78F0730_PARITY_ODD	0x08
74 #define UPD78F0730_PARITY_MASK	0x0C
75 
76 /* Flow control modes in UPD78F0730_CMD_LINE_CONTROL command */
77 #define UPD78F0730_FLOW_CONTROL_NONE	0x00
78 #define UPD78F0730_FLOW_CONTROL_HW	0x10
79 #define UPD78F0730_FLOW_CONTROL_SW	0x20
80 #define UPD78F0730_FLOW_CONTROL_MASK	0x30
81 
82 /* Control signal bits in UPD78F0730_CMD_SET_DTR_RTS command */
83 #define UPD78F0730_RTS		0x01
84 #define UPD78F0730_DTR		0x02
85 #define UPD78F0730_BREAK	0x04
86 
87 /* Port modes in UPD78F0730_CMD_OPEN_CLOSE command */
88 #define UPD78F0730_PORT_CLOSE	0x00
89 #define UPD78F0730_PORT_OPEN	0x01
90 
91 /* Error character substitution modes in UPD78F0730_CMD_SET_ERR_CHR command */
92 #define UPD78F0730_ERR_CHR_DISABLED	0x00
93 #define UPD78F0730_ERR_CHR_ENABLED	0x01
94 
95 /*
96  * Declaration of command structures
97  */
98 
99 /* UPD78F0730_CMD_LINE_CONTROL command */
100 struct upd78f0730_line_control {
101 	u8	opcode;
102 	__le32	baud_rate;
103 	u8	params;
104 } __packed;
105 
106 /* UPD78F0730_CMD_SET_DTR_RTS command */
107 struct upd78f0730_set_dtr_rts {
108 	u8 opcode;
109 	u8 params;
110 };
111 
112 /* UPD78F0730_CMD_SET_XON_OFF_CHR command */
113 struct upd78f0730_set_xon_xoff_chr {
114 	u8 opcode;
115 	u8 xon;
116 	u8 xoff;
117 };
118 
119 /* UPD78F0730_CMD_OPEN_CLOSE command */
120 struct upd78f0730_open_close {
121 	u8 opcode;
122 	u8 state;
123 };
124 
125 /* UPD78F0730_CMD_SET_ERR_CHR command */
126 struct upd78f0730_set_err_chr {
127 	u8 opcode;
128 	u8 state;
129 	u8 err_char;
130 };
131 
132 static int upd78f0730_send_ctl(struct usb_serial_port *port,
133 			const void *data, int size)
134 {
135 	struct usb_device *usbdev = port->serial->dev;
136 	void *buf;
137 	int res;
138 
139 	if (size <= 0 || !data)
140 		return -EINVAL;
141 
142 	buf = kmemdup(data, size, GFP_KERNEL);
143 	if (!buf)
144 		return -ENOMEM;
145 
146 	res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x00,
147 			USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
148 			0x0000, 0x0000, buf, size, USB_CTRL_SET_TIMEOUT);
149 
150 	kfree(buf);
151 
152 	if (res != size) {
153 		struct device *dev = &port->dev;
154 
155 		dev_err(dev, "failed to send control request %02x: %d\n",
156 			*(u8 *)data, res);
157 		/* The maximum expected length of a transfer is 6 bytes */
158 		if (res >= 0)
159 			res = -EIO;
160 
161 		return res;
162 	}
163 
164 	return 0;
165 }
166 
167 static int upd78f0730_port_probe(struct usb_serial_port *port)
168 {
169 	struct upd78f0730_port_private *private;
170 
171 	private = kzalloc(sizeof(*private), GFP_KERNEL);
172 	if (!private)
173 		return -ENOMEM;
174 
175 	mutex_init(&private->lock);
176 	usb_set_serial_port_data(port, private);
177 
178 	return 0;
179 }
180 
181 static int upd78f0730_port_remove(struct usb_serial_port *port)
182 {
183 	struct upd78f0730_port_private *private;
184 
185 	private = usb_get_serial_port_data(port);
186 	mutex_destroy(&private->lock);
187 	kfree(private);
188 
189 	return 0;
190 }
191 
192 static int upd78f0730_tiocmget(struct tty_struct *tty)
193 {
194 	struct device *dev = tty->dev;
195 	struct upd78f0730_port_private *private;
196 	struct usb_serial_port *port = tty->driver_data;
197 	int signals;
198 	int res;
199 
200 	private = usb_get_serial_port_data(port);
201 
202 	mutex_lock(&private->lock);
203 	signals = private->line_signals;
204 	mutex_unlock(&private->lock);
205 
206 	res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) |
207 		((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0);
208 
209 	dev_dbg(dev, "%s - res = %x\n", __func__, res);
210 
211 	return res;
212 }
213 
214 static int upd78f0730_tiocmset(struct tty_struct *tty,
215 			unsigned int set, unsigned int clear)
216 {
217 	struct device *dev = tty->dev;
218 	struct usb_serial_port *port = tty->driver_data;
219 	struct upd78f0730_port_private *private;
220 	struct upd78f0730_set_dtr_rts request;
221 	int res;
222 
223 	private = usb_get_serial_port_data(port);
224 
225 	mutex_lock(&private->lock);
226 	if (set & TIOCM_DTR) {
227 		private->line_signals |= UPD78F0730_DTR;
228 		dev_dbg(dev, "%s - set DTR\n", __func__);
229 	}
230 	if (set & TIOCM_RTS) {
231 		private->line_signals |= UPD78F0730_RTS;
232 		dev_dbg(dev, "%s - set RTS\n", __func__);
233 	}
234 	if (clear & TIOCM_DTR) {
235 		private->line_signals &= ~UPD78F0730_DTR;
236 		dev_dbg(dev, "%s - clear DTR\n", __func__);
237 	}
238 	if (clear & TIOCM_RTS) {
239 		private->line_signals &= ~UPD78F0730_RTS;
240 		dev_dbg(dev, "%s - clear RTS\n", __func__);
241 	}
242 	request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
243 	request.params = private->line_signals;
244 
245 	res = upd78f0730_send_ctl(port, &request, sizeof(request));
246 	mutex_unlock(&private->lock);
247 
248 	return res;
249 }
250 
251 static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state)
252 {
253 	struct device *dev = tty->dev;
254 	struct upd78f0730_port_private *private;
255 	struct usb_serial_port *port = tty->driver_data;
256 	struct upd78f0730_set_dtr_rts request;
257 
258 	private = usb_get_serial_port_data(port);
259 
260 	mutex_lock(&private->lock);
261 	if (break_state) {
262 		private->line_signals |= UPD78F0730_BREAK;
263 		dev_dbg(dev, "%s - set BREAK\n", __func__);
264 	} else {
265 		private->line_signals &= ~UPD78F0730_BREAK;
266 		dev_dbg(dev, "%s - clear BREAK\n", __func__);
267 	}
268 	request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
269 	request.params = private->line_signals;
270 
271 	upd78f0730_send_ctl(port, &request, sizeof(request));
272 	mutex_unlock(&private->lock);
273 }
274 
275 static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on)
276 {
277 	struct tty_struct *tty = port->port.tty;
278 	unsigned int set = 0;
279 	unsigned int clear = 0;
280 
281 	if (on)
282 		set = TIOCM_DTR | TIOCM_RTS;
283 	else
284 		clear = TIOCM_DTR | TIOCM_RTS;
285 
286 	upd78f0730_tiocmset(tty, set, clear);
287 }
288 
289 static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty)
290 {
291 	const speed_t baud_rate = tty_get_baud_rate(tty);
292 	static const speed_t supported[] = {
293 		0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
294 	};
295 	int i;
296 
297 	for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) {
298 		if (baud_rate == supported[i])
299 			return baud_rate;
300 	}
301 
302 	/* If the baud rate is not supported, switch to the default one */
303 	tty_encode_baud_rate(tty, 9600, 9600);
304 
305 	return tty_get_baud_rate(tty);
306 }
307 
308 static void upd78f0730_set_termios(struct tty_struct *tty,
309 				struct usb_serial_port *port,
310 				struct ktermios *old_termios)
311 {
312 	struct device *dev = &port->dev;
313 	struct upd78f0730_line_control request;
314 	speed_t baud_rate;
315 
316 	if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
317 		return;
318 
319 	if (C_BAUD(tty) == B0)
320 		upd78f0730_dtr_rts(port, 0);
321 	else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
322 		upd78f0730_dtr_rts(port, 1);
323 
324 	baud_rate = upd78f0730_get_baud_rate(tty);
325 	request.opcode = UPD78F0730_CMD_LINE_CONTROL;
326 	request.baud_rate = cpu_to_le32(baud_rate);
327 	request.params = 0;
328 	dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate);
329 
330 	switch (C_CSIZE(tty)) {
331 	case CS7:
332 		request.params |= UPD78F0730_DATA_SIZE_7_BITS;
333 		dev_dbg(dev, "%s - 7 data bits\n", __func__);
334 		break;
335 	default:
336 		tty->termios.c_cflag &= ~CSIZE;
337 		tty->termios.c_cflag |= CS8;
338 		dev_warn(dev, "data size is not supported, using 8 bits\n");
339 		/* fall through */
340 	case CS8:
341 		request.params |= UPD78F0730_DATA_SIZE_8_BITS;
342 		dev_dbg(dev, "%s - 8 data bits\n", __func__);
343 		break;
344 	}
345 
346 	if (C_PARENB(tty)) {
347 		if (C_PARODD(tty)) {
348 			request.params |= UPD78F0730_PARITY_ODD;
349 			dev_dbg(dev, "%s - odd parity\n", __func__);
350 		} else {
351 			request.params |= UPD78F0730_PARITY_EVEN;
352 			dev_dbg(dev, "%s - even parity\n", __func__);
353 		}
354 
355 		if (C_CMSPAR(tty)) {
356 			tty->termios.c_cflag &= ~CMSPAR;
357 			dev_warn(dev, "MARK/SPACE parity is not supported\n");
358 		}
359 	} else {
360 		request.params |= UPD78F0730_PARITY_NONE;
361 		dev_dbg(dev, "%s - no parity\n", __func__);
362 	}
363 
364 	if (C_CSTOPB(tty)) {
365 		request.params |= UPD78F0730_STOP_BIT_2_BIT;
366 		dev_dbg(dev, "%s - 2 stop bits\n", __func__);
367 	} else {
368 		request.params |= UPD78F0730_STOP_BIT_1_BIT;
369 		dev_dbg(dev, "%s - 1 stop bit\n", __func__);
370 	}
371 
372 	if (C_CRTSCTS(tty)) {
373 		tty->termios.c_cflag &= ~CRTSCTS;
374 		dev_warn(dev, "RTSCTS flow control is not supported\n");
375 	}
376 	if (I_IXOFF(tty) || I_IXON(tty)) {
377 		tty->termios.c_iflag &= ~(IXOFF | IXON);
378 		dev_warn(dev, "XON/XOFF flow control is not supported\n");
379 	}
380 	request.params |= UPD78F0730_FLOW_CONTROL_NONE;
381 	dev_dbg(dev, "%s - no flow control\n", __func__);
382 
383 	upd78f0730_send_ctl(port, &request, sizeof(request));
384 }
385 
386 static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
387 {
388 	static const struct upd78f0730_open_close request = {
389 		.opcode = UPD78F0730_CMD_OPEN_CLOSE,
390 		.state = UPD78F0730_PORT_OPEN
391 	};
392 	int res;
393 
394 	res = upd78f0730_send_ctl(port, &request, sizeof(request));
395 	if (res)
396 		return res;
397 
398 	if (tty)
399 		upd78f0730_set_termios(tty, port, NULL);
400 
401 	return usb_serial_generic_open(tty, port);
402 }
403 
404 static void upd78f0730_close(struct usb_serial_port *port)
405 {
406 	static const struct upd78f0730_open_close request = {
407 		.opcode = UPD78F0730_CMD_OPEN_CLOSE,
408 		.state = UPD78F0730_PORT_CLOSE
409 	};
410 
411 	usb_serial_generic_close(port);
412 	upd78f0730_send_ctl(port, &request, sizeof(request));
413 }
414 
415 static struct usb_serial_driver upd78f0730_device = {
416 	.driver	 = {
417 		.owner	= THIS_MODULE,
418 		.name	= "upd78f0730",
419 	},
420 	.id_table	= id_table,
421 	.num_ports	= 1,
422 	.port_probe	= upd78f0730_port_probe,
423 	.port_remove	= upd78f0730_port_remove,
424 	.open		= upd78f0730_open,
425 	.close		= upd78f0730_close,
426 	.set_termios	= upd78f0730_set_termios,
427 	.tiocmget	= upd78f0730_tiocmget,
428 	.tiocmset	= upd78f0730_tiocmset,
429 	.dtr_rts	= upd78f0730_dtr_rts,
430 	.break_ctl	= upd78f0730_break_ctl,
431 };
432 
433 static struct usb_serial_driver * const serial_drivers[] = {
434 	&upd78f0730_device,
435 	NULL
436 };
437 
438 module_usb_serial_driver(serial_drivers, id_table);
439 
440 MODULE_DESCRIPTION(DRIVER_DESC);
441 MODULE_AUTHOR(DRIVER_AUTHOR);
442 MODULE_LICENSE("GPL v2");
443