xref: /linux/drivers/tty/serdev/serdev-ttyport.c (revision e3b3d0f549c1d19b94e6ac55c66643166ea649ef)
1*e3b3d0f5SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2bed35c6dSRob Herring /*
3bed35c6dSRob Herring  * Copyright (C) 2016-2017 Linaro Ltd., Rob Herring <robh@kernel.org>
4bed35c6dSRob Herring  *
5bed35c6dSRob Herring  * This program is free software; you can redistribute it and/or modify
6bed35c6dSRob Herring  * it under the terms of the GNU General Public License version 2 and
7bed35c6dSRob Herring  * only version 2 as published by the Free Software Foundation.
8bed35c6dSRob Herring  *
9bed35c6dSRob Herring  * This program is distributed in the hope that it will be useful,
10bed35c6dSRob Herring  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11bed35c6dSRob Herring  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12bed35c6dSRob Herring  * GNU General Public License for more details.
13bed35c6dSRob Herring  */
14bed35c6dSRob Herring #include <linux/kernel.h>
15bed35c6dSRob Herring #include <linux/serdev.h>
16bed35c6dSRob Herring #include <linux/tty.h>
17bed35c6dSRob Herring #include <linux/tty_driver.h>
18b3f80c8fSSebastian Reichel #include <linux/poll.h>
19bed35c6dSRob Herring 
20bed35c6dSRob Herring #define SERPORT_ACTIVE		1
21bed35c6dSRob Herring 
22bed35c6dSRob Herring struct serport {
23bed35c6dSRob Herring 	struct tty_port *port;
24bed35c6dSRob Herring 	struct tty_struct *tty;
25bed35c6dSRob Herring 	struct tty_driver *tty_drv;
26bed35c6dSRob Herring 	int tty_idx;
27bed35c6dSRob Herring 	unsigned long flags;
28bed35c6dSRob Herring };
29bed35c6dSRob Herring 
30bed35c6dSRob Herring /*
31bed35c6dSRob Herring  * Callback functions from the tty port.
32bed35c6dSRob Herring  */
33bed35c6dSRob Herring 
34bed35c6dSRob Herring static int ttyport_receive_buf(struct tty_port *port, const unsigned char *cp,
35bed35c6dSRob Herring 				const unsigned char *fp, size_t count)
36bed35c6dSRob Herring {
37bed35c6dSRob Herring 	struct serdev_controller *ctrl = port->client_data;
38bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
39bed35c6dSRob Herring 
40bed35c6dSRob Herring 	if (!test_bit(SERPORT_ACTIVE, &serport->flags))
41bed35c6dSRob Herring 		return 0;
42bed35c6dSRob Herring 
43bed35c6dSRob Herring 	return serdev_controller_receive_buf(ctrl, cp, count);
44bed35c6dSRob Herring }
45bed35c6dSRob Herring 
46bed35c6dSRob Herring static void ttyport_write_wakeup(struct tty_port *port)
47bed35c6dSRob Herring {
48bed35c6dSRob Herring 	struct serdev_controller *ctrl = port->client_data;
49bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
50bed35c6dSRob Herring 
51b3f80c8fSSebastian Reichel 	if (test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &port->tty->flags) &&
52b3f80c8fSSebastian Reichel 	    test_bit(SERPORT_ACTIVE, &serport->flags))
53bed35c6dSRob Herring 		serdev_controller_write_wakeup(ctrl);
54b3f80c8fSSebastian Reichel 
55b3f80c8fSSebastian Reichel 	wake_up_interruptible_poll(&port->tty->write_wait, POLLOUT);
56bed35c6dSRob Herring }
57bed35c6dSRob Herring 
58bed35c6dSRob Herring static const struct tty_port_client_operations client_ops = {
59bed35c6dSRob Herring 	.receive_buf = ttyport_receive_buf,
60bed35c6dSRob Herring 	.write_wakeup = ttyport_write_wakeup,
61bed35c6dSRob Herring };
62bed35c6dSRob Herring 
63bed35c6dSRob Herring /*
64bed35c6dSRob Herring  * Callback functions from the serdev core.
65bed35c6dSRob Herring  */
66bed35c6dSRob Herring 
67bed35c6dSRob Herring static int ttyport_write_buf(struct serdev_controller *ctrl, const unsigned char *data, size_t len)
68bed35c6dSRob Herring {
69bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
70bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
71bed35c6dSRob Herring 
72bed35c6dSRob Herring 	if (!test_bit(SERPORT_ACTIVE, &serport->flags))
73bed35c6dSRob Herring 		return 0;
74bed35c6dSRob Herring 
75bed35c6dSRob Herring 	set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
76bed35c6dSRob Herring 	return tty->ops->write(serport->tty, data, len);
77bed35c6dSRob Herring }
78bed35c6dSRob Herring 
79bed35c6dSRob Herring static void ttyport_write_flush(struct serdev_controller *ctrl)
80bed35c6dSRob Herring {
81bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
82bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
83bed35c6dSRob Herring 
84bed35c6dSRob Herring 	tty_driver_flush_buffer(tty);
85bed35c6dSRob Herring }
86bed35c6dSRob Herring 
87bed35c6dSRob Herring static int ttyport_write_room(struct serdev_controller *ctrl)
88bed35c6dSRob Herring {
89bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
90bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
91bed35c6dSRob Herring 
92bed35c6dSRob Herring 	return tty_write_room(tty);
93bed35c6dSRob Herring }
94bed35c6dSRob Herring 
95bed35c6dSRob Herring static int ttyport_open(struct serdev_controller *ctrl)
96bed35c6dSRob Herring {
97bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
98bed35c6dSRob Herring 	struct tty_struct *tty;
99bed35c6dSRob Herring 	struct ktermios ktermios;
1007c63838eSJohan Hovold 	int ret;
101bed35c6dSRob Herring 
102bed35c6dSRob Herring 	tty = tty_init_dev(serport->tty_drv, serport->tty_idx);
10310d258c5SDan Carpenter 	if (IS_ERR(tty))
10410d258c5SDan Carpenter 		return PTR_ERR(tty);
105bed35c6dSRob Herring 	serport->tty = tty;
106bed35c6dSRob Herring 
1077c63838eSJohan Hovold 	if (!tty->ops->open || !tty->ops->close) {
1087c63838eSJohan Hovold 		ret = -ENODEV;
109dee7d0f3SJohan Hovold 		goto err_unlock;
1107c63838eSJohan Hovold 	}
111dee7d0f3SJohan Hovold 
1127c63838eSJohan Hovold 	ret = tty->ops->open(serport->tty, NULL);
1137c63838eSJohan Hovold 	if (ret)
1147c63838eSJohan Hovold 		goto err_close;
115bed35c6dSRob Herring 
116bed35c6dSRob Herring 	/* Bring the UART into a known 8 bits no parity hw fc state */
117bed35c6dSRob Herring 	ktermios = tty->termios;
118bed35c6dSRob Herring 	ktermios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP |
119bed35c6dSRob Herring 			      INLCR | IGNCR | ICRNL | IXON);
120bed35c6dSRob Herring 	ktermios.c_oflag &= ~OPOST;
121bed35c6dSRob Herring 	ktermios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
122bed35c6dSRob Herring 	ktermios.c_cflag &= ~(CSIZE | PARENB);
123bed35c6dSRob Herring 	ktermios.c_cflag |= CS8;
124bed35c6dSRob Herring 	ktermios.c_cflag |= CRTSCTS;
125bed35c6dSRob Herring 	tty_set_termios(tty, &ktermios);
126bed35c6dSRob Herring 
127bed35c6dSRob Herring 	set_bit(SERPORT_ACTIVE, &serport->flags);
128bed35c6dSRob Herring 
129bed35c6dSRob Herring 	tty_unlock(serport->tty);
130bed35c6dSRob Herring 	return 0;
131dee7d0f3SJohan Hovold 
1327c63838eSJohan Hovold err_close:
1337c63838eSJohan Hovold 	tty->ops->close(tty, NULL);
134dee7d0f3SJohan Hovold err_unlock:
135dee7d0f3SJohan Hovold 	tty_unlock(tty);
136dee7d0f3SJohan Hovold 	tty_release_struct(tty, serport->tty_idx);
137dee7d0f3SJohan Hovold 
1387c63838eSJohan Hovold 	return ret;
139bed35c6dSRob Herring }
140bed35c6dSRob Herring 
141bed35c6dSRob Herring static void ttyport_close(struct serdev_controller *ctrl)
142bed35c6dSRob Herring {
143bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
144bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
145bed35c6dSRob Herring 
146bed35c6dSRob Herring 	clear_bit(SERPORT_ACTIVE, &serport->flags);
147bed35c6dSRob Herring 
148bed35c6dSRob Herring 	if (tty->ops->close)
149bed35c6dSRob Herring 		tty->ops->close(tty, NULL);
150bed35c6dSRob Herring 
151bed35c6dSRob Herring 	tty_release_struct(tty, serport->tty_idx);
152bed35c6dSRob Herring }
153bed35c6dSRob Herring 
154bed35c6dSRob Herring static unsigned int ttyport_set_baudrate(struct serdev_controller *ctrl, unsigned int speed)
155bed35c6dSRob Herring {
156bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
157bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
158bed35c6dSRob Herring 	struct ktermios ktermios = tty->termios;
159bed35c6dSRob Herring 
160bed35c6dSRob Herring 	ktermios.c_cflag &= ~CBAUD;
161bed35c6dSRob Herring 	tty_termios_encode_baud_rate(&ktermios, speed, speed);
162bed35c6dSRob Herring 
163bed35c6dSRob Herring 	/* tty_set_termios() return not checked as it is always 0 */
164bed35c6dSRob Herring 	tty_set_termios(tty, &ktermios);
16556c607b5SStefan Wahren 	return ktermios.c_ospeed;
166bed35c6dSRob Herring }
167bed35c6dSRob Herring 
168bed35c6dSRob Herring static void ttyport_set_flow_control(struct serdev_controller *ctrl, bool enable)
169bed35c6dSRob Herring {
170bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
171bed35c6dSRob Herring 	struct tty_struct *tty = serport->tty;
172bed35c6dSRob Herring 	struct ktermios ktermios = tty->termios;
173bed35c6dSRob Herring 
174bed35c6dSRob Herring 	if (enable)
175bed35c6dSRob Herring 		ktermios.c_cflag |= CRTSCTS;
176bed35c6dSRob Herring 	else
177bed35c6dSRob Herring 		ktermios.c_cflag &= ~CRTSCTS;
178bed35c6dSRob Herring 
179bed35c6dSRob Herring 	tty_set_termios(tty, &ktermios);
180bed35c6dSRob Herring }
181bed35c6dSRob Herring 
182b3f80c8fSSebastian Reichel static void ttyport_wait_until_sent(struct serdev_controller *ctrl, long timeout)
183b3f80c8fSSebastian Reichel {
184b3f80c8fSSebastian Reichel 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
185b3f80c8fSSebastian Reichel 	struct tty_struct *tty = serport->tty;
186b3f80c8fSSebastian Reichel 
187b3f80c8fSSebastian Reichel 	tty_wait_until_sent(tty, timeout);
188b3f80c8fSSebastian Reichel }
189b3f80c8fSSebastian Reichel 
1905659dab2SSebastian Reichel static int ttyport_get_tiocm(struct serdev_controller *ctrl)
1915659dab2SSebastian Reichel {
1925659dab2SSebastian Reichel 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
1935659dab2SSebastian Reichel 	struct tty_struct *tty = serport->tty;
1945659dab2SSebastian Reichel 
1955659dab2SSebastian Reichel 	if (!tty->ops->tiocmget)
1965659dab2SSebastian Reichel 		return -ENOTSUPP;
1975659dab2SSebastian Reichel 
1985659dab2SSebastian Reichel 	return tty->driver->ops->tiocmget(tty);
1995659dab2SSebastian Reichel }
2005659dab2SSebastian Reichel 
2015659dab2SSebastian Reichel static int ttyport_set_tiocm(struct serdev_controller *ctrl, unsigned int set, unsigned int clear)
2025659dab2SSebastian Reichel {
2035659dab2SSebastian Reichel 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
2045659dab2SSebastian Reichel 	struct tty_struct *tty = serport->tty;
2055659dab2SSebastian Reichel 
2065659dab2SSebastian Reichel 	if (!tty->ops->tiocmset)
2075659dab2SSebastian Reichel 		return -ENOTSUPP;
2085659dab2SSebastian Reichel 
2095659dab2SSebastian Reichel 	return tty->driver->ops->tiocmset(tty, set, clear);
2105659dab2SSebastian Reichel }
2115659dab2SSebastian Reichel 
212bed35c6dSRob Herring static const struct serdev_controller_ops ctrl_ops = {
213bed35c6dSRob Herring 	.write_buf = ttyport_write_buf,
214bed35c6dSRob Herring 	.write_flush = ttyport_write_flush,
215bed35c6dSRob Herring 	.write_room = ttyport_write_room,
216bed35c6dSRob Herring 	.open = ttyport_open,
217bed35c6dSRob Herring 	.close = ttyport_close,
218bed35c6dSRob Herring 	.set_flow_control = ttyport_set_flow_control,
219bed35c6dSRob Herring 	.set_baudrate = ttyport_set_baudrate,
220b3f80c8fSSebastian Reichel 	.wait_until_sent = ttyport_wait_until_sent,
2215659dab2SSebastian Reichel 	.get_tiocm = ttyport_get_tiocm,
2225659dab2SSebastian Reichel 	.set_tiocm = ttyport_set_tiocm,
223bed35c6dSRob Herring };
224bed35c6dSRob Herring 
225bed35c6dSRob Herring struct device *serdev_tty_port_register(struct tty_port *port,
226bed35c6dSRob Herring 					struct device *parent,
227bed35c6dSRob Herring 					struct tty_driver *drv, int idx)
228bed35c6dSRob Herring {
229aee5da78SJohan Hovold 	const struct tty_port_client_operations *old_ops;
230bed35c6dSRob Herring 	struct serdev_controller *ctrl;
231bed35c6dSRob Herring 	struct serport *serport;
232bed35c6dSRob Herring 	int ret;
233bed35c6dSRob Herring 
234bed35c6dSRob Herring 	if (!port || !drv || !parent)
235bed35c6dSRob Herring 		return ERR_PTR(-ENODEV);
236bed35c6dSRob Herring 
237bed35c6dSRob Herring 	ctrl = serdev_controller_alloc(parent, sizeof(struct serport));
238bed35c6dSRob Herring 	if (!ctrl)
239bed35c6dSRob Herring 		return ERR_PTR(-ENOMEM);
240bed35c6dSRob Herring 	serport = serdev_controller_get_drvdata(ctrl);
241bed35c6dSRob Herring 
242bed35c6dSRob Herring 	serport->port = port;
243bed35c6dSRob Herring 	serport->tty_idx = idx;
244bed35c6dSRob Herring 	serport->tty_drv = drv;
245bed35c6dSRob Herring 
246bed35c6dSRob Herring 	ctrl->ops = &ctrl_ops;
247bed35c6dSRob Herring 
248aee5da78SJohan Hovold 	old_ops = port->client_ops;
249aee5da78SJohan Hovold 	port->client_ops = &client_ops;
250aee5da78SJohan Hovold 	port->client_data = ctrl;
251aee5da78SJohan Hovold 
252bed35c6dSRob Herring 	ret = serdev_controller_add(ctrl);
253bed35c6dSRob Herring 	if (ret)
254aee5da78SJohan Hovold 		goto err_reset_data;
255bed35c6dSRob Herring 
256bed35c6dSRob Herring 	dev_info(&ctrl->dev, "tty port %s%d registered\n", drv->name, idx);
257bed35c6dSRob Herring 	return &ctrl->dev;
258bed35c6dSRob Herring 
259aee5da78SJohan Hovold err_reset_data:
260aee5da78SJohan Hovold 	port->client_data = NULL;
261aee5da78SJohan Hovold 	port->client_ops = old_ops;
262bed35c6dSRob Herring 	serdev_controller_put(ctrl);
263aee5da78SJohan Hovold 
264bed35c6dSRob Herring 	return ERR_PTR(ret);
265bed35c6dSRob Herring }
266bed35c6dSRob Herring 
2678cde11b2SJohan Hovold int serdev_tty_port_unregister(struct tty_port *port)
268bed35c6dSRob Herring {
269bed35c6dSRob Herring 	struct serdev_controller *ctrl = port->client_data;
270bed35c6dSRob Herring 	struct serport *serport = serdev_controller_get_drvdata(ctrl);
271bed35c6dSRob Herring 
272bed35c6dSRob Herring 	if (!serport)
2738cde11b2SJohan Hovold 		return -ENODEV;
274bed35c6dSRob Herring 
275bed35c6dSRob Herring 	serdev_controller_remove(ctrl);
276bed35c6dSRob Herring 	port->client_ops = NULL;
277bed35c6dSRob Herring 	port->client_data = NULL;
278bed35c6dSRob Herring 	serdev_controller_put(ctrl);
2798cde11b2SJohan Hovold 
2808cde11b2SJohan Hovold 	return 0;
281bed35c6dSRob Herring }
282