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 device *dev = tty->dev; 186 struct upd78f0730_port_private *private; 187 struct usb_serial_port *port = tty->driver_data; 188 int signals; 189 int res; 190 191 private = usb_get_serial_port_data(port); 192 193 mutex_lock(&private->lock); 194 signals = private->line_signals; 195 mutex_unlock(&private->lock); 196 197 res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) | 198 ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0); 199 200 dev_dbg(dev, "%s - res = %x\n", __func__, res); 201 202 return res; 203 } 204 205 static int upd78f0730_tiocmset(struct tty_struct *tty, 206 unsigned int set, unsigned int clear) 207 { 208 struct device *dev = tty->dev; 209 struct usb_serial_port *port = tty->driver_data; 210 struct upd78f0730_port_private *private; 211 struct upd78f0730_set_dtr_rts request; 212 int res; 213 214 private = usb_get_serial_port_data(port); 215 216 mutex_lock(&private->lock); 217 if (set & TIOCM_DTR) { 218 private->line_signals |= UPD78F0730_DTR; 219 dev_dbg(dev, "%s - set DTR\n", __func__); 220 } 221 if (set & TIOCM_RTS) { 222 private->line_signals |= UPD78F0730_RTS; 223 dev_dbg(dev, "%s - set RTS\n", __func__); 224 } 225 if (clear & TIOCM_DTR) { 226 private->line_signals &= ~UPD78F0730_DTR; 227 dev_dbg(dev, "%s - clear DTR\n", __func__); 228 } 229 if (clear & TIOCM_RTS) { 230 private->line_signals &= ~UPD78F0730_RTS; 231 dev_dbg(dev, "%s - clear RTS\n", __func__); 232 } 233 request.opcode = UPD78F0730_CMD_SET_DTR_RTS; 234 request.params = private->line_signals; 235 236 res = upd78f0730_send_ctl(port, &request, sizeof(request)); 237 mutex_unlock(&private->lock); 238 239 return res; 240 } 241 242 static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) 243 { 244 struct device *dev = tty->dev; 245 struct upd78f0730_port_private *private; 246 struct usb_serial_port *port = tty->driver_data; 247 struct upd78f0730_set_dtr_rts request; 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 upd78f0730_send_ctl(port, &request, sizeof(request)); 263 mutex_unlock(&private->lock); 264 } 265 266 static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on) 267 { 268 struct tty_struct *tty = port->port.tty; 269 unsigned int set = 0; 270 unsigned int clear = 0; 271 272 if (on) 273 set = TIOCM_DTR | TIOCM_RTS; 274 else 275 clear = TIOCM_DTR | TIOCM_RTS; 276 277 upd78f0730_tiocmset(tty, set, clear); 278 } 279 280 static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty) 281 { 282 const speed_t baud_rate = tty_get_baud_rate(tty); 283 static const speed_t supported[] = { 284 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600 285 }; 286 int i; 287 288 for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) { 289 if (baud_rate == supported[i]) 290 return baud_rate; 291 } 292 293 /* If the baud rate is not supported, switch to the default one */ 294 tty_encode_baud_rate(tty, 9600, 9600); 295 296 return tty_get_baud_rate(tty); 297 } 298 299 static void upd78f0730_set_termios(struct tty_struct *tty, 300 struct usb_serial_port *port, 301 struct ktermios *old_termios) 302 { 303 struct device *dev = &port->dev; 304 struct upd78f0730_line_control request; 305 speed_t baud_rate; 306 307 if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) 308 return; 309 310 if (C_BAUD(tty) == B0) 311 upd78f0730_dtr_rts(port, 0); 312 else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) 313 upd78f0730_dtr_rts(port, 1); 314 315 baud_rate = upd78f0730_get_baud_rate(tty); 316 request.opcode = UPD78F0730_CMD_LINE_CONTROL; 317 request.baud_rate = cpu_to_le32(baud_rate); 318 request.params = 0; 319 dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate); 320 321 switch (C_CSIZE(tty)) { 322 case CS7: 323 request.params |= UPD78F0730_DATA_SIZE_7_BITS; 324 dev_dbg(dev, "%s - 7 data bits\n", __func__); 325 break; 326 default: 327 tty->termios.c_cflag &= ~CSIZE; 328 tty->termios.c_cflag |= CS8; 329 dev_warn(dev, "data size is not supported, using 8 bits\n"); 330 fallthrough; 331 case CS8: 332 request.params |= UPD78F0730_DATA_SIZE_8_BITS; 333 dev_dbg(dev, "%s - 8 data bits\n", __func__); 334 break; 335 } 336 337 if (C_PARENB(tty)) { 338 if (C_PARODD(tty)) { 339 request.params |= UPD78F0730_PARITY_ODD; 340 dev_dbg(dev, "%s - odd parity\n", __func__); 341 } else { 342 request.params |= UPD78F0730_PARITY_EVEN; 343 dev_dbg(dev, "%s - even parity\n", __func__); 344 } 345 346 if (C_CMSPAR(tty)) { 347 tty->termios.c_cflag &= ~CMSPAR; 348 dev_warn(dev, "MARK/SPACE parity is not supported\n"); 349 } 350 } else { 351 request.params |= UPD78F0730_PARITY_NONE; 352 dev_dbg(dev, "%s - no parity\n", __func__); 353 } 354 355 if (C_CSTOPB(tty)) { 356 request.params |= UPD78F0730_STOP_BIT_2_BIT; 357 dev_dbg(dev, "%s - 2 stop bits\n", __func__); 358 } else { 359 request.params |= UPD78F0730_STOP_BIT_1_BIT; 360 dev_dbg(dev, "%s - 1 stop bit\n", __func__); 361 } 362 363 if (C_CRTSCTS(tty)) { 364 tty->termios.c_cflag &= ~CRTSCTS; 365 dev_warn(dev, "RTSCTS flow control is not supported\n"); 366 } 367 if (I_IXOFF(tty) || I_IXON(tty)) { 368 tty->termios.c_iflag &= ~(IXOFF | IXON); 369 dev_warn(dev, "XON/XOFF flow control is not supported\n"); 370 } 371 request.params |= UPD78F0730_FLOW_CONTROL_NONE; 372 dev_dbg(dev, "%s - no flow control\n", __func__); 373 374 upd78f0730_send_ctl(port, &request, sizeof(request)); 375 } 376 377 static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port) 378 { 379 static const struct upd78f0730_open_close request = { 380 .opcode = UPD78F0730_CMD_OPEN_CLOSE, 381 .state = UPD78F0730_PORT_OPEN 382 }; 383 int res; 384 385 res = upd78f0730_send_ctl(port, &request, sizeof(request)); 386 if (res) 387 return res; 388 389 if (tty) 390 upd78f0730_set_termios(tty, port, NULL); 391 392 return usb_serial_generic_open(tty, port); 393 } 394 395 static void upd78f0730_close(struct usb_serial_port *port) 396 { 397 static const struct upd78f0730_open_close request = { 398 .opcode = UPD78F0730_CMD_OPEN_CLOSE, 399 .state = UPD78F0730_PORT_CLOSE 400 }; 401 402 usb_serial_generic_close(port); 403 upd78f0730_send_ctl(port, &request, sizeof(request)); 404 } 405 406 static struct usb_serial_driver upd78f0730_device = { 407 .driver = { 408 .owner = THIS_MODULE, 409 .name = "upd78f0730", 410 }, 411 .id_table = id_table, 412 .num_ports = 1, 413 .port_probe = upd78f0730_port_probe, 414 .port_remove = upd78f0730_port_remove, 415 .open = upd78f0730_open, 416 .close = upd78f0730_close, 417 .set_termios = upd78f0730_set_termios, 418 .tiocmget = upd78f0730_tiocmget, 419 .tiocmset = upd78f0730_tiocmset, 420 .dtr_rts = upd78f0730_dtr_rts, 421 .break_ctl = upd78f0730_break_ctl, 422 }; 423 424 static struct usb_serial_driver * const serial_drivers[] = { 425 &upd78f0730_device, 426 NULL 427 }; 428 429 module_usb_serial_driver(serial_drivers, id_table); 430 431 MODULE_DESCRIPTION(DRIVER_DESC); 432 MODULE_AUTHOR(DRIVER_AUTHOR); 433 MODULE_LICENSE("GPL v2"); 434