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