1 /* 2 * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 and 6 * only version 2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 #include <linux/kernel.h> 14 #include <linux/serdev.h> 15 #include <linux/tty.h> 16 #include <linux/tty_driver.h> 17 18 #define SERPORT_ACTIVE 1 19 20 struct serport { 21 struct tty_port *port; 22 struct tty_struct *tty; 23 struct tty_driver *tty_drv; 24 int tty_idx; 25 unsigned long flags; 26 }; 27 28 /* 29 * Callback functions from the tty port. 30 */ 31 32 static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp, 33 const unsigned char *fp, size_t count) 34 { 35 struct serdev_controller *ctrl = port->client_data; 36 struct serport *serport = serdev_controller_get_drvdata(ctrl); 37 38 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 39 return 0; 40 41 return serdev_controller_receive_buf(ctrl, cp, count); 42 } 43 44 static void ttyport_write_wakeup(struct tty_port *port) 45 { 46 struct serdev_controller *ctrl = port->client_data; 47 struct serport *serport = serdev_controller_get_drvdata(ctrl); 48 49 if (!test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags)) 50 return; 51 52 if (test_bit(SERPORT_ACTIVE, &serport->flags)) 53 serdev_controller_write_wakeup(ctrl); 54 } 55 56 static const struct tty_port_client_operations client_ops = { 57 .receive_buf = ttyport_receive_buf, 58 .write_wakeup = ttyport_write_wakeup, 59 }; 60 61 /* 62 * Callback functions from the serdev core. 63 */ 64 65 static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len) 66 { 67 struct serport *serport = serdev_controller_get_drvdata(ctrl); 68 struct tty_struct *tty = serport->tty; 69 70 if (!test_bit(SERPORT_ACTIVE, &serport->flags)) 71 return 0; 72 73 set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 74 return tty->ops->write(serport->tty, data, len); 75 } 76 77 static void ttyport_write_flush(struct serdev_controller *ctrl) 78 { 79 struct serport *serport = serdev_controller_get_drvdata(ctrl); 80 struct tty_struct *tty = serport->tty; 81 82 tty_driver_flush_buffer(tty); 83 } 84 85 static int ttyport_write_room(struct serdev_controller *ctrl) 86 { 87 struct serport *serport = serdev_controller_get_drvdata(ctrl); 88 struct tty_struct *tty = serport->tty; 89 90 return tty_write_room(tty); 91 } 92 93 static int ttyport_open(struct serdev_controller *ctrl) 94 { 95 struct serport *serport = serdev_controller_get_drvdata(ctrl); 96 struct tty_struct *tty; 97 struct ktermios ktermios; 98 99 tty = tty_init_dev(serport->tty_drv, serport->tty_idx); 100 if (IS_ERR(tty)) 101 return PTR_ERR(tty); 102 serport->tty = tty; 103 104 serport->port->client_ops = &client_ops; 105 serport->port->client_data = ctrl; 106 107 if (tty->ops->open) 108 tty->ops->open(serport->tty, NULL); 109 else 110 tty_port_open(serport->port, tty, NULL); 111 112 /* Bring the UART into a known 8 bits no parity hw fc state */ 113 ktermios = tty->termios; 114 ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | 115 INLCR | IGNCR | ICRNL | IXON); 116 ktermios.c_oflag &= ~OPOST; 117 ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 118 ktermios.c_cflag &= ~(CSIZE | PARENB); 119 ktermios.c_cflag |= CS8; 120 ktermios.c_cflag |= CRTSCTS; 121 tty_set_termios(tty, &ktermios); 122 123 set_bit(SERPORT_ACTIVE, &serport->flags); 124 125 tty_unlock(serport->tty); 126 return 0; 127 } 128 129 static void ttyport_close(struct serdev_controller *ctrl) 130 { 131 struct serport *serport = serdev_controller_get_drvdata(ctrl); 132 struct tty_struct *tty = serport->tty; 133 134 clear_bit(SERPORT_ACTIVE, &serport->flags); 135 136 if (tty->ops->close) 137 tty->ops->close(tty, NULL); 138 139 tty_release_struct(tty, serport->tty_idx); 140 } 141 142 static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed) 143 { 144 struct serport *serport = serdev_controller_get_drvdata(ctrl); 145 struct tty_struct *tty = serport->tty; 146 struct ktermios ktermios = tty->termios; 147 148 ktermios.c_cflag &= ~CBAUD; 149 tty_termios_encode_baud_rate(&ktermios, speed, speed); 150 151 /* tty_set_termios() return not checked as it is always 0 */ 152 tty_set_termios(tty, &ktermios); 153 return speed; 154 } 155 156 static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable) 157 { 158 struct serport *serport = serdev_controller_get_drvdata(ctrl); 159 struct tty_struct *tty = serport->tty; 160 struct ktermios ktermios = tty->termios; 161 162 if (enable) 163 ktermios.c_cflag |= CRTSCTS; 164 else 165 ktermios.c_cflag &= ~CRTSCTS; 166 167 tty_set_termios(tty, &ktermios); 168 } 169 170 static const struct serdev_controller_ops ctrl_ops = { 171 .write_buf = ttyport_write_buf, 172 .write_flush = ttyport_write_flush, 173 .write_room = ttyport_write_room, 174 .open = ttyport_open, 175 .close = ttyport_close, 176 .set_flow_control = ttyport_set_flow_control, 177 .set_baudrate = ttyport_set_baudrate, 178 }; 179 180 struct device *serdev_tty_port_register(struct tty_port *port, 181 struct device *parent, 182 struct tty_driver *drv, int idx) 183 { 184 struct serdev_controller *ctrl; 185 struct serport *serport; 186 int ret; 187 188 if (!port || !drv || !parent) 189 return ERR_PTR(-ENODEV); 190 191 ctrl = serdev_controller_alloc(parent, sizeof(struct serport)); 192 if (!ctrl) 193 return ERR_PTR(-ENOMEM); 194 serport = serdev_controller_get_drvdata(ctrl); 195 196 serport->port = port; 197 serport->tty_idx = idx; 198 serport->tty_drv = drv; 199 200 ctrl->ops = &ctrl_ops; 201 202 ret = serdev_controller_add(ctrl); 203 if (ret) 204 goto err_controller_put; 205 206 dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx); 207 return &ctrl->dev; 208 209 err_controller_put: 210 serdev_controller_put(ctrl); 211 return ERR_PTR(ret); 212 } 213 214 void serdev_tty_port_unregister(struct tty_port *port) 215 { 216 struct serdev_controller *ctrl = port->client_data; 217 struct serport *serport = serdev_controller_get_drvdata(ctrl); 218 219 if (!serport) 220 return; 221 222 serdev_controller_remove(ctrl); 223 port->client_ops = NULL; 224 port->client_data = NULL; 225 serdev_controller_put(ctrl); 226 } 227