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