Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Renesas Electronics uPD78F0730 USB to serial converter driver
0004  *
0005  * Copyright (C) 2014,2016 Maksim Salau <maksim.salau@gmail.com>
0006  *
0007  * Protocol of the adaptor is described in the application note U19660EJ1V0AN00
0008  * μPD78F0730 8-bit Single-Chip Microcontroller
0009  * USB-to-Serial Conversion Software
0010  * <https://www.renesas.com/en-eu/doc/DocumentServer/026/U19660EJ1V0AN00.pdf>
0011  *
0012  * The adaptor functionality is limited to the following:
0013  * - data bits: 7 or 8
0014  * - stop bits: 1 or 2
0015  * - parity: even, odd or none
0016  * - flow control: none
0017  * - baud rates: 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
0018  * - signals: DTR, RTS and BREAK
0019  */
0020 
0021 #include <linux/module.h>
0022 #include <linux/slab.h>
0023 #include <linux/tty.h>
0024 #include <linux/usb.h>
0025 #include <linux/usb/serial.h>
0026 
0027 #define DRIVER_DESC "Renesas uPD78F0730 USB to serial converter driver"
0028 
0029 #define DRIVER_AUTHOR "Maksim Salau <maksim.salau@gmail.com>"
0030 
0031 static const struct usb_device_id id_table[] = {
0032     { USB_DEVICE(0x0409, 0x0063) }, /* V850ESJX3-STICK */
0033     { USB_DEVICE(0x045B, 0x0212) }, /* YRPBRL78G13, YRPBRL78G14 */
0034     { USB_DEVICE(0x064B, 0x7825) }, /* Analog Devices EVAL-ADXL362Z-DB */
0035     {}
0036 };
0037 
0038 MODULE_DEVICE_TABLE(usb, id_table);
0039 
0040 /*
0041  * Each adaptor is associated with a private structure, that holds the current
0042  * state of control signals (DTR, RTS and BREAK).
0043  */
0044 struct upd78f0730_port_private {
0045     struct mutex    lock;       /* mutex to protect line_signals */
0046     u8      line_signals;
0047 };
0048 
0049 /* Op-codes of control commands */
0050 #define UPD78F0730_CMD_LINE_CONTROL 0x00
0051 #define UPD78F0730_CMD_SET_DTR_RTS  0x01
0052 #define UPD78F0730_CMD_SET_XON_XOFF_CHR 0x02
0053 #define UPD78F0730_CMD_OPEN_CLOSE   0x03
0054 #define UPD78F0730_CMD_SET_ERR_CHR  0x04
0055 
0056 /* Data sizes in UPD78F0730_CMD_LINE_CONTROL command */
0057 #define UPD78F0730_DATA_SIZE_7_BITS 0x00
0058 #define UPD78F0730_DATA_SIZE_8_BITS 0x01
0059 #define UPD78F0730_DATA_SIZE_MASK   0x01
0060 
0061 /* Stop-bit modes in UPD78F0730_CMD_LINE_CONTROL command */
0062 #define UPD78F0730_STOP_BIT_1_BIT   0x00
0063 #define UPD78F0730_STOP_BIT_2_BIT   0x02
0064 #define UPD78F0730_STOP_BIT_MASK    0x02
0065 
0066 /* Parity modes in UPD78F0730_CMD_LINE_CONTROL command */
0067 #define UPD78F0730_PARITY_NONE  0x00
0068 #define UPD78F0730_PARITY_EVEN  0x04
0069 #define UPD78F0730_PARITY_ODD   0x08
0070 #define UPD78F0730_PARITY_MASK  0x0C
0071 
0072 /* Flow control modes in UPD78F0730_CMD_LINE_CONTROL command */
0073 #define UPD78F0730_FLOW_CONTROL_NONE    0x00
0074 #define UPD78F0730_FLOW_CONTROL_HW  0x10
0075 #define UPD78F0730_FLOW_CONTROL_SW  0x20
0076 #define UPD78F0730_FLOW_CONTROL_MASK    0x30
0077 
0078 /* Control signal bits in UPD78F0730_CMD_SET_DTR_RTS command */
0079 #define UPD78F0730_RTS      0x01
0080 #define UPD78F0730_DTR      0x02
0081 #define UPD78F0730_BREAK    0x04
0082 
0083 /* Port modes in UPD78F0730_CMD_OPEN_CLOSE command */
0084 #define UPD78F0730_PORT_CLOSE   0x00
0085 #define UPD78F0730_PORT_OPEN    0x01
0086 
0087 /* Error character substitution modes in UPD78F0730_CMD_SET_ERR_CHR command */
0088 #define UPD78F0730_ERR_CHR_DISABLED 0x00
0089 #define UPD78F0730_ERR_CHR_ENABLED  0x01
0090 
0091 /*
0092  * Declaration of command structures
0093  */
0094 
0095 /* UPD78F0730_CMD_LINE_CONTROL command */
0096 struct upd78f0730_line_control {
0097     u8  opcode;
0098     __le32  baud_rate;
0099     u8  params;
0100 } __packed;
0101 
0102 /* UPD78F0730_CMD_SET_DTR_RTS command */
0103 struct upd78f0730_set_dtr_rts {
0104     u8 opcode;
0105     u8 params;
0106 };
0107 
0108 /* UPD78F0730_CMD_SET_XON_OFF_CHR command */
0109 struct upd78f0730_set_xon_xoff_chr {
0110     u8 opcode;
0111     u8 xon;
0112     u8 xoff;
0113 };
0114 
0115 /* UPD78F0730_CMD_OPEN_CLOSE command */
0116 struct upd78f0730_open_close {
0117     u8 opcode;
0118     u8 state;
0119 };
0120 
0121 /* UPD78F0730_CMD_SET_ERR_CHR command */
0122 struct upd78f0730_set_err_chr {
0123     u8 opcode;
0124     u8 state;
0125     u8 err_char;
0126 };
0127 
0128 static int upd78f0730_send_ctl(struct usb_serial_port *port,
0129             const void *data, int size)
0130 {
0131     struct usb_device *usbdev = port->serial->dev;
0132     void *buf;
0133     int res;
0134 
0135     if (size <= 0 || !data)
0136         return -EINVAL;
0137 
0138     buf = kmemdup(data, size, GFP_KERNEL);
0139     if (!buf)
0140         return -ENOMEM;
0141 
0142     res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x00,
0143             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
0144             0x0000, 0x0000, buf, size, USB_CTRL_SET_TIMEOUT);
0145 
0146     kfree(buf);
0147 
0148     if (res < 0) {
0149         struct device *dev = &port->dev;
0150 
0151         dev_err(dev, "failed to send control request %02x: %d\n",
0152             *(u8 *)data, res);
0153 
0154         return res;
0155     }
0156 
0157     return 0;
0158 }
0159 
0160 static int upd78f0730_port_probe(struct usb_serial_port *port)
0161 {
0162     struct upd78f0730_port_private *private;
0163 
0164     private = kzalloc(sizeof(*private), GFP_KERNEL);
0165     if (!private)
0166         return -ENOMEM;
0167 
0168     mutex_init(&private->lock);
0169     usb_set_serial_port_data(port, private);
0170 
0171     return 0;
0172 }
0173 
0174 static void upd78f0730_port_remove(struct usb_serial_port *port)
0175 {
0176     struct upd78f0730_port_private *private;
0177 
0178     private = usb_get_serial_port_data(port);
0179     mutex_destroy(&private->lock);
0180     kfree(private);
0181 }
0182 
0183 static int upd78f0730_tiocmget(struct tty_struct *tty)
0184 {
0185     struct upd78f0730_port_private *private;
0186     struct usb_serial_port *port = tty->driver_data;
0187     int signals;
0188     int res;
0189 
0190     private = usb_get_serial_port_data(port);
0191 
0192     mutex_lock(&private->lock);
0193     signals = private->line_signals;
0194     mutex_unlock(&private->lock);
0195 
0196     res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) |
0197         ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0);
0198 
0199     dev_dbg(&port->dev, "%s - res = %x\n", __func__, res);
0200 
0201     return res;
0202 }
0203 
0204 static int upd78f0730_tiocmset(struct tty_struct *tty,
0205             unsigned int set, unsigned int clear)
0206 {
0207     struct usb_serial_port *port = tty->driver_data;
0208     struct upd78f0730_port_private *private;
0209     struct upd78f0730_set_dtr_rts request;
0210     struct device *dev = &port->dev;
0211     int res;
0212 
0213     private = usb_get_serial_port_data(port);
0214 
0215     mutex_lock(&private->lock);
0216     if (set & TIOCM_DTR) {
0217         private->line_signals |= UPD78F0730_DTR;
0218         dev_dbg(dev, "%s - set DTR\n", __func__);
0219     }
0220     if (set & TIOCM_RTS) {
0221         private->line_signals |= UPD78F0730_RTS;
0222         dev_dbg(dev, "%s - set RTS\n", __func__);
0223     }
0224     if (clear & TIOCM_DTR) {
0225         private->line_signals &= ~UPD78F0730_DTR;
0226         dev_dbg(dev, "%s - clear DTR\n", __func__);
0227     }
0228     if (clear & TIOCM_RTS) {
0229         private->line_signals &= ~UPD78F0730_RTS;
0230         dev_dbg(dev, "%s - clear RTS\n", __func__);
0231     }
0232     request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
0233     request.params = private->line_signals;
0234 
0235     res = upd78f0730_send_ctl(port, &request, sizeof(request));
0236     mutex_unlock(&private->lock);
0237 
0238     return res;
0239 }
0240 
0241 static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state)
0242 {
0243     struct upd78f0730_port_private *private;
0244     struct usb_serial_port *port = tty->driver_data;
0245     struct upd78f0730_set_dtr_rts request;
0246     struct device *dev = &port->dev;
0247 
0248     private = usb_get_serial_port_data(port);
0249 
0250     mutex_lock(&private->lock);
0251     if (break_state) {
0252         private->line_signals |= UPD78F0730_BREAK;
0253         dev_dbg(dev, "%s - set BREAK\n", __func__);
0254     } else {
0255         private->line_signals &= ~UPD78F0730_BREAK;
0256         dev_dbg(dev, "%s - clear BREAK\n", __func__);
0257     }
0258     request.opcode = UPD78F0730_CMD_SET_DTR_RTS;
0259     request.params = private->line_signals;
0260 
0261     upd78f0730_send_ctl(port, &request, sizeof(request));
0262     mutex_unlock(&private->lock);
0263 }
0264 
0265 static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on)
0266 {
0267     struct tty_struct *tty = port->port.tty;
0268     unsigned int set = 0;
0269     unsigned int clear = 0;
0270 
0271     if (on)
0272         set = TIOCM_DTR | TIOCM_RTS;
0273     else
0274         clear = TIOCM_DTR | TIOCM_RTS;
0275 
0276     upd78f0730_tiocmset(tty, set, clear);
0277 }
0278 
0279 static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty)
0280 {
0281     const speed_t baud_rate = tty_get_baud_rate(tty);
0282     static const speed_t supported[] = {
0283         0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600
0284     };
0285     int i;
0286 
0287     for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) {
0288         if (baud_rate == supported[i])
0289             return baud_rate;
0290     }
0291 
0292     /* If the baud rate is not supported, switch to the default one */
0293     tty_encode_baud_rate(tty, 9600, 9600);
0294 
0295     return tty_get_baud_rate(tty);
0296 }
0297 
0298 static void upd78f0730_set_termios(struct tty_struct *tty,
0299                 struct usb_serial_port *port,
0300                 struct ktermios *old_termios)
0301 {
0302     struct device *dev = &port->dev;
0303     struct upd78f0730_line_control request;
0304     speed_t baud_rate;
0305 
0306     if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios))
0307         return;
0308 
0309     if (C_BAUD(tty) == B0)
0310         upd78f0730_dtr_rts(port, 0);
0311     else if (old_termios && (old_termios->c_cflag & CBAUD) == B0)
0312         upd78f0730_dtr_rts(port, 1);
0313 
0314     baud_rate = upd78f0730_get_baud_rate(tty);
0315     request.opcode = UPD78F0730_CMD_LINE_CONTROL;
0316     request.baud_rate = cpu_to_le32(baud_rate);
0317     request.params = 0;
0318     dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate);
0319 
0320     switch (C_CSIZE(tty)) {
0321     case CS7:
0322         request.params |= UPD78F0730_DATA_SIZE_7_BITS;
0323         dev_dbg(dev, "%s - 7 data bits\n", __func__);
0324         break;
0325     default:
0326         tty->termios.c_cflag &= ~CSIZE;
0327         tty->termios.c_cflag |= CS8;
0328         dev_warn(dev, "data size is not supported, using 8 bits\n");
0329         fallthrough;
0330     case CS8:
0331         request.params |= UPD78F0730_DATA_SIZE_8_BITS;
0332         dev_dbg(dev, "%s - 8 data bits\n", __func__);
0333         break;
0334     }
0335 
0336     if (C_PARENB(tty)) {
0337         if (C_PARODD(tty)) {
0338             request.params |= UPD78F0730_PARITY_ODD;
0339             dev_dbg(dev, "%s - odd parity\n", __func__);
0340         } else {
0341             request.params |= UPD78F0730_PARITY_EVEN;
0342             dev_dbg(dev, "%s - even parity\n", __func__);
0343         }
0344 
0345         if (C_CMSPAR(tty)) {
0346             tty->termios.c_cflag &= ~CMSPAR;
0347             dev_warn(dev, "MARK/SPACE parity is not supported\n");
0348         }
0349     } else {
0350         request.params |= UPD78F0730_PARITY_NONE;
0351         dev_dbg(dev, "%s - no parity\n", __func__);
0352     }
0353 
0354     if (C_CSTOPB(tty)) {
0355         request.params |= UPD78F0730_STOP_BIT_2_BIT;
0356         dev_dbg(dev, "%s - 2 stop bits\n", __func__);
0357     } else {
0358         request.params |= UPD78F0730_STOP_BIT_1_BIT;
0359         dev_dbg(dev, "%s - 1 stop bit\n", __func__);
0360     }
0361 
0362     if (C_CRTSCTS(tty)) {
0363         tty->termios.c_cflag &= ~CRTSCTS;
0364         dev_warn(dev, "RTSCTS flow control is not supported\n");
0365     }
0366     if (I_IXOFF(tty) || I_IXON(tty)) {
0367         tty->termios.c_iflag &= ~(IXOFF | IXON);
0368         dev_warn(dev, "XON/XOFF flow control is not supported\n");
0369     }
0370     request.params |= UPD78F0730_FLOW_CONTROL_NONE;
0371     dev_dbg(dev, "%s - no flow control\n", __func__);
0372 
0373     upd78f0730_send_ctl(port, &request, sizeof(request));
0374 }
0375 
0376 static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port)
0377 {
0378     static const struct upd78f0730_open_close request = {
0379         .opcode = UPD78F0730_CMD_OPEN_CLOSE,
0380         .state = UPD78F0730_PORT_OPEN
0381     };
0382     int res;
0383 
0384     res = upd78f0730_send_ctl(port, &request, sizeof(request));
0385     if (res)
0386         return res;
0387 
0388     if (tty)
0389         upd78f0730_set_termios(tty, port, NULL);
0390 
0391     return usb_serial_generic_open(tty, port);
0392 }
0393 
0394 static void upd78f0730_close(struct usb_serial_port *port)
0395 {
0396     static const struct upd78f0730_open_close request = {
0397         .opcode = UPD78F0730_CMD_OPEN_CLOSE,
0398         .state = UPD78F0730_PORT_CLOSE
0399     };
0400 
0401     usb_serial_generic_close(port);
0402     upd78f0730_send_ctl(port, &request, sizeof(request));
0403 }
0404 
0405 static struct usb_serial_driver upd78f0730_device = {
0406     .driver  = {
0407         .owner  = THIS_MODULE,
0408         .name   = "upd78f0730",
0409     },
0410     .id_table   = id_table,
0411     .num_ports  = 1,
0412     .port_probe = upd78f0730_port_probe,
0413     .port_remove    = upd78f0730_port_remove,
0414     .open       = upd78f0730_open,
0415     .close      = upd78f0730_close,
0416     .set_termios    = upd78f0730_set_termios,
0417     .tiocmget   = upd78f0730_tiocmget,
0418     .tiocmset   = upd78f0730_tiocmset,
0419     .dtr_rts    = upd78f0730_dtr_rts,
0420     .break_ctl  = upd78f0730_break_ctl,
0421 };
0422 
0423 static struct usb_serial_driver * const serial_drivers[] = {
0424     &upd78f0730_device,
0425     NULL
0426 };
0427 
0428 module_usb_serial_driver(serial_drivers, id_table);
0429 
0430 MODULE_DESCRIPTION(DRIVER_DESC);
0431 MODULE_AUTHOR(DRIVER_AUTHOR);
0432 MODULE_LICENSE("GPL v2");