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