xref: /netbsd-src/sys/arch/evbarm/mpcsa/mpcsa_usart.c (revision cbab9cadce21ae72fac13910001079fff214cc29)
1*cbab9cadSchs /*	$Id: mpcsa_usart.c,v 1.4 2012/10/27 17:17:48 chs Exp $	*/
2*cbab9cadSchs /*	$NetBSD: mpcsa_usart.c,v 1.4 2012/10/27 17:17:48 chs Exp $	*/
3c62a0ac4Smatt 
4c62a0ac4Smatt /*
5c62a0ac4Smatt  * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
6c62a0ac4Smatt  *
7c62a0ac4Smatt  * Redistribution and use in source and binary forms, with or without
8c62a0ac4Smatt  * modification, are permitted provided that the following conditions
9c62a0ac4Smatt  * are met:
10c62a0ac4Smatt  * 1. Redistributions of source code must retain the above copyright
11c62a0ac4Smatt  *    notice, this list of conditions and the following disclaimer.
12c62a0ac4Smatt  * 2. Redistributions in binary form must reproduce the above copyright
13c62a0ac4Smatt  *    notice, this list of conditions and the following disclaimer in the
14c62a0ac4Smatt  *    documentation and/or other materials provided with the distribution.
15c62a0ac4Smatt  *
16c62a0ac4Smatt  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17c62a0ac4Smatt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18c62a0ac4Smatt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19c62a0ac4Smatt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20c62a0ac4Smatt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21c62a0ac4Smatt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22c62a0ac4Smatt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23c62a0ac4Smatt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24c62a0ac4Smatt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25c62a0ac4Smatt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26c62a0ac4Smatt  * SUCH DAMAGE.
27c62a0ac4Smatt  */
28c62a0ac4Smatt 
29c62a0ac4Smatt #include <sys/cdefs.h>
30*cbab9cadSchs __KERNEL_RCSID(0, "$NetBSD: mpcsa_usart.c,v 1.4 2012/10/27 17:17:48 chs Exp $");
31c62a0ac4Smatt 
32c62a0ac4Smatt #include <sys/types.h>
33c62a0ac4Smatt #include <sys/param.h>
34c62a0ac4Smatt #include <sys/systm.h>
35c62a0ac4Smatt #include <sys/kernel.h>
36c62a0ac4Smatt #include <sys/device.h>
37c62a0ac4Smatt #include <sys/proc.h>
38c62a0ac4Smatt #include <arm/at91/at91reg.h>
39c62a0ac4Smatt #include <arm/at91/at91var.h>
40c62a0ac4Smatt #include <arm/at91/at91usartvar.h>
41c62a0ac4Smatt #include <arm/at91/at91piovar.h>
42c62a0ac4Smatt #include <arm/at91/at91rm9200reg.h>
43c62a0ac4Smatt #include <evbarm/mpcsa/mpcsa_io.h>
44c62a0ac4Smatt #include <evbarm/mpcsa/mpcsa_leds_var.h>
45c62a0ac4Smatt #include <sys/unistd.h>
46c62a0ac4Smatt 
47c62a0ac4Smatt #ifdef MPCSA_USART_DEBUG
48c62a0ac4Smatt int mpcsa_usart_debug = MPCSA_USART_DEBUG;
49c62a0ac4Smatt #define DPRINTFN(n,x)	if (mpcsa_usart_debug>(n)) printf x;
50c62a0ac4Smatt #else
51c62a0ac4Smatt #define DPRINTFN(n,x)
52c62a0ac4Smatt #endif
53c62a0ac4Smatt 
54c62a0ac4Smatt struct at91pio_softc;
55c62a0ac4Smatt 
56c62a0ac4Smatt struct mpcsa_usart_softc {
57c62a0ac4Smatt 	struct at91usart_softc	sc_dev;
58c62a0ac4Smatt 	struct at91pio_softc	*sc_pioa, *sc_piob, *sc_piod;
59c62a0ac4Smatt 	void *sc_cts_ih;
60c62a0ac4Smatt 	int sc_tx_busy, sc_rx_busy;
61c62a0ac4Smatt };
62c62a0ac4Smatt 
63*cbab9cadSchs static int mpcsa_usart_match(device_t, cfdata_t, void *);
64*cbab9cadSchs static void mpcsa_usart_attach(device_t, device_t, void *);
65c62a0ac4Smatt 
66*cbab9cadSchs CFATTACH_DECL_NEW(mpcsa_usart, sizeof(struct mpcsa_usart_softc),
67c62a0ac4Smatt 	      mpcsa_usart_match, mpcsa_usart_attach, NULL, NULL);
68c62a0ac4Smatt 
69c62a0ac4Smatt static int mpcsa_usart_enable(struct at91usart_softc *sc);
70c62a0ac4Smatt static int mpcsa_usart_disable(struct at91usart_softc *sc);
71c62a0ac4Smatt static void mpcsa_usart_hwflow(struct at91usart_softc *sc, int cflags);
72c62a0ac4Smatt static void mpcsa_usart_start_tx(struct at91usart_softc *sc);
73c62a0ac4Smatt static void mpcsa_usart_stop_tx(struct at91usart_softc *sc);
74c62a0ac4Smatt static void mpcsa_usart_rx_started(struct at91usart_softc *sc);
75c62a0ac4Smatt static void mpcsa_usart_rx_stopped(struct at91usart_softc *sc);
76c62a0ac4Smatt static void mpcsa_usart_rx_rts_ctl(struct at91usart_softc *sc, int enabled);
77c62a0ac4Smatt 
78c62a0ac4Smatt static int mpcsa_gsm_cts_intr(void *);
79c62a0ac4Smatt 
80c62a0ac4Smatt static __inline int
led_num(struct mpcsa_usart_softc * mpsc)81c62a0ac4Smatt led_num(struct mpcsa_usart_softc *mpsc)
82c62a0ac4Smatt {
83c62a0ac4Smatt 	return (mpsc->sc_dev.sc_pid == PID_US3 ? LED_GSM : LED_SER1 + mpsc->sc_dev.sc_pid - PID_US0);
84c62a0ac4Smatt }
85c62a0ac4Smatt 
86c62a0ac4Smatt static __inline void
comm_led(struct mpcsa_usart_softc * mpsc,int count)87c62a0ac4Smatt comm_led(struct mpcsa_usart_softc *mpsc, int count)
88c62a0ac4Smatt {
89c62a0ac4Smatt 	mpcsa_comm_led(led_num(mpsc), count);
90c62a0ac4Smatt }
91c62a0ac4Smatt 
92c62a0ac4Smatt static __inline void
conn_led(struct mpcsa_usart_softc * mpsc,int count)93c62a0ac4Smatt conn_led(struct mpcsa_usart_softc *mpsc, int count)
94c62a0ac4Smatt {
95c62a0ac4Smatt 	mpcsa_conn_led(led_num(mpsc), count);
96c62a0ac4Smatt }
97c62a0ac4Smatt 
98c62a0ac4Smatt static int
mpcsa_usart_match(device_t parent,cfdata_t match,void * aux)99*cbab9cadSchs mpcsa_usart_match(device_t parent, cfdata_t match, void *aux)
100c62a0ac4Smatt {
101c62a0ac4Smatt 	if (strcmp(match->cf_name, "at91usart") == 0 && strcmp(match->cf_atname, "mpcsa_usart") == 0)
102c62a0ac4Smatt 		return 2;
103c62a0ac4Smatt 	return 0;
104c62a0ac4Smatt }
105c62a0ac4Smatt 
106c62a0ac4Smatt 
107c62a0ac4Smatt static void
mpcsa_usart_attach(device_t parent,device_t self,void * aux)108*cbab9cadSchs mpcsa_usart_attach(device_t parent, device_t self, void *aux)
109c62a0ac4Smatt {
110*cbab9cadSchs 	struct mpcsa_usart_softc *sc = device_private(self);
111c62a0ac4Smatt 	struct at91bus_attach_args *sa = aux;
112c62a0ac4Smatt 
113*cbab9cadSchs 	sc->sc_dev.sc_dev = self;
114*cbab9cadSchs 
115c62a0ac4Smatt 	// initialize softc
116c62a0ac4Smatt 	if ((sc->sc_pioa = at91pio_sc(AT91_PIOA)) == NULL) {
117c62a0ac4Smatt 		printf("no PIOA!\n");
118c62a0ac4Smatt 		return;
119c62a0ac4Smatt 	}
120c62a0ac4Smatt 	if ((sc->sc_piob = at91pio_sc(AT91_PIOB)) == NULL) {
121c62a0ac4Smatt 		printf("no PIOB!\n");
122c62a0ac4Smatt 		return;
123c62a0ac4Smatt 	}
124c62a0ac4Smatt 	if ((sc->sc_piod = at91pio_sc(AT91_PIOD)) == NULL) {
125c62a0ac4Smatt 		printf("no PIOD!\n");
126c62a0ac4Smatt 		return;
127c62a0ac4Smatt 	}
128c62a0ac4Smatt 
129c62a0ac4Smatt 	// calculate unit number...
130c62a0ac4Smatt 	switch (sa->sa_pid) {
131c62a0ac4Smatt 	case PID_US0:
132c62a0ac4Smatt 	case PID_US1:
133c62a0ac4Smatt 	case PID_US2:
134c62a0ac4Smatt 	case PID_US3:
135c62a0ac4Smatt 		sc->sc_dev.enable = mpcsa_usart_enable;
136c62a0ac4Smatt 		sc->sc_dev.disable = mpcsa_usart_disable;
137c62a0ac4Smatt 		sc->sc_dev.hwflow = mpcsa_usart_hwflow;
138c62a0ac4Smatt 		sc->sc_dev.start_tx = mpcsa_usart_start_tx;
139c62a0ac4Smatt 		sc->sc_dev.stop_tx = mpcsa_usart_stop_tx;
140c62a0ac4Smatt 		sc->sc_dev.rx_started = mpcsa_usart_rx_started;
141c62a0ac4Smatt 		sc->sc_dev.rx_stopped = mpcsa_usart_rx_stopped;
142c62a0ac4Smatt 		sc->sc_dev.rx_rts_ctl = mpcsa_usart_rx_rts_ctl;
143c62a0ac4Smatt 		break;
144c62a0ac4Smatt 	}
145c62a0ac4Smatt 
146c62a0ac4Smatt 	/* configure pins */
147c62a0ac4Smatt 	switch (sa->sa_pid) {
148c62a0ac4Smatt 	case PID_US0:
149c62a0ac4Smatt 		at91pio_set(sc->sc_piob, PB_RTS1);
150c62a0ac4Smatt 		at91pio_set(sc->sc_piod, PD_DTR1);
151c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_CTS1);
152c62a0ac4Smatt 		at91pio_out(sc->sc_piob, PB_RTS1);
153c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DSR1);
154c62a0ac4Smatt 		at91pio_out(sc->sc_piod, PD_DTR1);
155c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_CTS1, -1);
156c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_RTS1, -1);
157c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DSR1, -1);
158c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DTR1, -1);
159c62a0ac4Smatt 		break;
160c62a0ac4Smatt 	case PID_US1:
161c62a0ac4Smatt 		at91pio_set(sc->sc_piob, PB_RTS2);
162c62a0ac4Smatt 		at91pio_set(sc->sc_piod, PD_DTR2);
163c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_CTS2);
164c62a0ac4Smatt 		at91pio_out(sc->sc_piob, PB_RTS2);
165c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DSR2);
166c62a0ac4Smatt 		at91pio_out(sc->sc_piod, PD_DTR2);
167c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_CTS2, -1);
168c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_RTS2, -1);
169c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DSR2, -1);
170c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DTR2, -1);
171c62a0ac4Smatt 		break;
172c62a0ac4Smatt 	case PID_US2:
173c62a0ac4Smatt 		at91pio_set(sc->sc_piob, PB_RTS3);
174c62a0ac4Smatt 		at91pio_set(sc->sc_piod, PD_DTR3);
175c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_CTS3);
176c62a0ac4Smatt 		at91pio_out(sc->sc_piob, PB_RTS3);
177c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DSR3);
178c62a0ac4Smatt 		at91pio_out(sc->sc_piod, PD_DTR3);
179c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_CTS3, -1);
180c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_RTS3, -1);
181c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DSR3, -1);
182c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DTR3, -1);
183c62a0ac4Smatt 		break;
184c62a0ac4Smatt 	case PID_US3:
185c62a0ac4Smatt 		/* configure pin states... */
186c62a0ac4Smatt 		at91pio_clear(sc->sc_pioa, PA_GSMON);
187c62a0ac4Smatt 		at91pio_set(sc->sc_pioa, PA_GSMOFF);
188c62a0ac4Smatt 		at91pio_set(sc->sc_piob, PB_RTS4);
189c62a0ac4Smatt 		at91pio_set(sc->sc_piod, PD_DTR4);
190c62a0ac4Smatt 
191c62a0ac4Smatt 		/* configure pin directions.. */
192c62a0ac4Smatt 		at91pio_out(sc->sc_pioa, PA_GSMOFF);
193c62a0ac4Smatt 		at91pio_out(sc->sc_pioa, PA_GSMON);
194c62a0ac4Smatt 		at91pio_in(sc->sc_pioa, PA_TXD4);
195c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_RTS4);
196c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_CTS4);
197c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DTR4);
198c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DSR4);
199c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DCD4);
200c62a0ac4Smatt 
201c62a0ac4Smatt 		/* make sure all related pins are configured as PIO */
202c62a0ac4Smatt 		at91pio_per(sc->sc_pioa, PA_GSMOFF, -1);
203c62a0ac4Smatt 		at91pio_per(sc->sc_pioa, PA_GSMON, -1);
204c62a0ac4Smatt 		at91pio_per(sc->sc_pioa, PA_TXD4, -1);
205c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_CTS4, -1);
206c62a0ac4Smatt 		at91pio_per(sc->sc_piob, PB_RTS4, -1);
207c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DSR4, -1);
208c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DTR4, -1);
209c62a0ac4Smatt 		at91pio_per(sc->sc_piod, PD_DCD4, -1);
210c62a0ac4Smatt 		break;
211c62a0ac4Smatt 	}
212c62a0ac4Smatt 
213c62a0ac4Smatt 	// and call common routine
214c62a0ac4Smatt 	at91usart_attach_subr(&sc->sc_dev, sa);
215c62a0ac4Smatt }
216c62a0ac4Smatt 
217c62a0ac4Smatt static int
mpcsa_usart_enable(struct at91usart_softc * dev)218c62a0ac4Smatt mpcsa_usart_enable(struct at91usart_softc *dev)
219c62a0ac4Smatt {
220c62a0ac4Smatt 	struct mpcsa_usart_softc *sc = (struct mpcsa_usart_softc *)dev;
221c62a0ac4Smatt 	conn_led(sc, 1);
222c62a0ac4Smatt 	switch (sc->sc_dev.sc_pid) {
223c62a0ac4Smatt 	case PID_US3:
224c62a0ac4Smatt 		/* turn gsm on */
225c62a0ac4Smatt 		at91pio_clear(sc->sc_pioa, PA_GSMOFF);
2266a0660a9Srmind 		kpause("gsmond", false, 4 * hz, NULL);
227c62a0ac4Smatt 		at91pio_set(sc->sc_pioa, PA_GSMON);
2286a0660a9Srmind 		kpause("gsmon", false, 2 * hz, NULL);
229c62a0ac4Smatt 		at91pio_clear(sc->sc_pioa, PA_GSMON);
230c62a0ac4Smatt 		/* then attach pins to devices etc */
231c62a0ac4Smatt 		at91pio_per(sc->sc_pioa, PA_TXD4, 1);
232c62a0ac4Smatt 		at91pio_clear(sc->sc_piob, PB_RTS4);
233c62a0ac4Smatt 		at91pio_clear(sc->sc_piod, PD_DTR4);
234c62a0ac4Smatt 		at91pio_out(sc->sc_piob, PB_RTS4);
235c62a0ac4Smatt 		at91pio_out(sc->sc_piod, PD_DTR4);
236c62a0ac4Smatt 		/* catch CTS interrupt */
237c62a0ac4Smatt 		sc->sc_cts_ih = at91pio_intr_establish(sc->sc_piob, PB_CTS4,
238c62a0ac4Smatt 						       IPL_TTY, mpcsa_gsm_cts_intr,
239c62a0ac4Smatt 						       sc);
240c62a0ac4Smatt 		break;
241c62a0ac4Smatt 	}
242c62a0ac4Smatt 	return 0;
243c62a0ac4Smatt }
244c62a0ac4Smatt 
245c62a0ac4Smatt static int
mpcsa_usart_disable(struct at91usart_softc * dev)246c62a0ac4Smatt mpcsa_usart_disable(struct at91usart_softc *dev)
247c62a0ac4Smatt {
248c62a0ac4Smatt 	struct mpcsa_usart_softc *sc = (struct mpcsa_usart_softc *)dev;
249c62a0ac4Smatt 	if (sc->sc_tx_busy || sc->sc_rx_busy) {
250c62a0ac4Smatt 		sc->sc_tx_busy = sc->sc_rx_busy = 0;
251c62a0ac4Smatt 		comm_led(sc, 1);
252c62a0ac4Smatt 	}
253c62a0ac4Smatt 	switch (sc->sc_dev.sc_pid) {
254c62a0ac4Smatt 	case PID_US3:
255c62a0ac4Smatt 		at91pio_intr_disestablish(sc->sc_piob, PB_CTS4, sc->sc_cts_ih);
256c62a0ac4Smatt 
257c62a0ac4Smatt 		at91pio_clear(sc->sc_pioa, PA_GSMON);
2586a0660a9Srmind 		kpause("gsmoffd", false, (hz * 350 + 999) / 1000, NULL);
259c62a0ac4Smatt 
260c62a0ac4Smatt 		at91pio_per(sc->sc_pioa, PA_TXD4, -1);
261c62a0ac4Smatt 		at91pio_in(sc->sc_piob, PB_RTS4);
262c62a0ac4Smatt 		at91pio_in(sc->sc_piod, PD_DTR4);
263c62a0ac4Smatt 
264c62a0ac4Smatt 		at91pio_set(sc->sc_pioa, PA_GSMOFF);
2656a0660a9Srmind 		kpause("gsmoff", false, hz * 4, NULL);
266c62a0ac4Smatt 		at91pio_clear(sc->sc_pioa, PA_GSMOFF);
267c62a0ac4Smatt 
268c62a0ac4Smatt 		break;
269c62a0ac4Smatt 	}
270c62a0ac4Smatt 	conn_led(sc, 0);
271c62a0ac4Smatt 	return 0;
272c62a0ac4Smatt }
273c62a0ac4Smatt 
mpcsa_gsm_cts_intr(void * cookie)274c62a0ac4Smatt static int mpcsa_gsm_cts_intr(void *cookie)
275c62a0ac4Smatt {
276c62a0ac4Smatt 	struct mpcsa_usart_softc *sc = (struct mpcsa_usart_softc *)cookie;
277c62a0ac4Smatt 	if (ISSET(sc->sc_dev.sc_swflags, TIOCFLAG_CRTSCTS)) {
278c62a0ac4Smatt 		/* hardware flow control is enabled */
279c62a0ac4Smatt 		if (!(PIOB_READ(PIO_PDSR) & (1U << PB_CTS4))) {
280c62a0ac4Smatt 			if (bus_space_read_4(sc->sc_dev.sc_iot, sc->sc_dev.sc_ioh,
281c62a0ac4Smatt 					     US_PDC + PDC_TCR) && !sc->sc_tx_busy) {
282c62a0ac4Smatt 				sc->sc_tx_busy = 1;
283c62a0ac4Smatt 				if (!sc->sc_rx_busy)
284c62a0ac4Smatt 					comm_led(sc, INFINITE_BLINK);
285c62a0ac4Smatt 			}
286c62a0ac4Smatt 
287c62a0ac4Smatt 			bus_space_write_4(sc->sc_dev.sc_iot, sc->sc_dev.sc_ioh,
288c62a0ac4Smatt 					  US_PDC + PDC_PTCR, PDC_PTCR_TXTEN);
289c62a0ac4Smatt 			SET(sc->sc_dev.sc_ier, US_CSR_TXEMPTY | US_CSR_ENDTX);
290c62a0ac4Smatt 			bus_space_write_4(sc->sc_dev.sc_iot, sc->sc_dev.sc_ioh,
291c62a0ac4Smatt 					  US_IER, US_CSR_ENDTX);
292c62a0ac4Smatt 		} else {
293c62a0ac4Smatt 			bus_space_write_4(sc->sc_dev.sc_iot, sc->sc_dev.sc_ioh,
294c62a0ac4Smatt 					  US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS);
295c62a0ac4Smatt 			if (sc->sc_tx_busy) {
296c62a0ac4Smatt 				sc->sc_tx_busy = 0;
297c62a0ac4Smatt 				if (!sc->sc_rx_busy)
298c62a0ac4Smatt 					comm_led(sc, 1);
299c62a0ac4Smatt 			}
300c62a0ac4Smatt 		}
301c62a0ac4Smatt 	}
302c62a0ac4Smatt 	return 0;
303c62a0ac4Smatt }
304c62a0ac4Smatt 
305c62a0ac4Smatt static void
mpcsa_usart_hwflow(struct at91usart_softc * dev,int flags)306c62a0ac4Smatt mpcsa_usart_hwflow(struct at91usart_softc *dev, int flags)
307c62a0ac4Smatt {
308c62a0ac4Smatt }
309c62a0ac4Smatt 
310c62a0ac4Smatt static void
mpcsa_usart_start_tx(struct at91usart_softc * sc)311c62a0ac4Smatt mpcsa_usart_start_tx(struct at91usart_softc *sc)
312c62a0ac4Smatt {
313c62a0ac4Smatt 	if (!ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)
314c62a0ac4Smatt 	    || bus_space_read_4(sc->sc_iot, sc->sc_ioh, US_PDC + PDC_PTSR) & PDC_PTSR_TXTEN) {
315c62a0ac4Smatt 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
316c62a0ac4Smatt 				  US_PDC + PDC_PTCR, PDC_PTCR_TXTEN);
317c62a0ac4Smatt 		struct mpcsa_usart_softc *mpsc = (void*)sc;
318c62a0ac4Smatt 		if (!mpsc->sc_tx_busy) {
319c62a0ac4Smatt 			mpsc->sc_tx_busy = 1;
320c62a0ac4Smatt 			if (!mpsc->sc_rx_busy)
321c62a0ac4Smatt 				comm_led(mpsc, INFINITE_BLINK);
322c62a0ac4Smatt 		}
323c62a0ac4Smatt 		return;
324c62a0ac4Smatt 	}
325c62a0ac4Smatt }
326c62a0ac4Smatt 
327c62a0ac4Smatt static void
mpcsa_usart_stop_tx(struct at91usart_softc * sc)328c62a0ac4Smatt mpcsa_usart_stop_tx(struct at91usart_softc *sc)
329c62a0ac4Smatt {
330c62a0ac4Smatt 	struct mpcsa_usart_softc *mpsc = (void*)sc;
331c62a0ac4Smatt 	mpsc->sc_tx_busy = 0;
332c62a0ac4Smatt 	if (!mpsc->sc_rx_busy)
333c62a0ac4Smatt 		comm_led(mpsc, 1);
334c62a0ac4Smatt 	if (!ISSET(sc->sc_swflags, TIOCFLAG_CRTSCTS)) {
335c62a0ac4Smatt 		bus_space_write_4(sc->sc_iot, sc->sc_ioh,
336c62a0ac4Smatt 				  US_PDC + PDC_PTCR, PDC_PTCR_TXTDIS);
337c62a0ac4Smatt 	}
338c62a0ac4Smatt }
339c62a0ac4Smatt 
340c62a0ac4Smatt static void
mpcsa_usart_rx_started(struct at91usart_softc * sc)341c62a0ac4Smatt mpcsa_usart_rx_started(struct at91usart_softc *sc)
342c62a0ac4Smatt {
343c62a0ac4Smatt 	struct mpcsa_usart_softc *mpsc = (void*)sc;
344c62a0ac4Smatt 	if (!mpsc->sc_rx_busy) {
345c62a0ac4Smatt 		mpsc->sc_rx_busy = 1;
346c62a0ac4Smatt 		if (!mpsc->sc_tx_busy)
347c62a0ac4Smatt 			comm_led(mpsc, INFINITE_BLINK);
348c62a0ac4Smatt 	}
349c62a0ac4Smatt }
350c62a0ac4Smatt 
351c62a0ac4Smatt static void
mpcsa_usart_rx_stopped(struct at91usart_softc * sc)352c62a0ac4Smatt mpcsa_usart_rx_stopped(struct at91usart_softc *sc)
353c62a0ac4Smatt {
354c62a0ac4Smatt 	struct mpcsa_usart_softc *mpsc = (void*)sc;
355c62a0ac4Smatt 	mpsc->sc_rx_busy = 0;
356c62a0ac4Smatt 	if (!mpsc->sc_tx_busy)
357c62a0ac4Smatt 		comm_led(mpsc, 1);
358c62a0ac4Smatt }
359c62a0ac4Smatt 
360c62a0ac4Smatt static void
mpcsa_usart_rx_rts_ctl(struct at91usart_softc * sc,int enabled)361c62a0ac4Smatt mpcsa_usart_rx_rts_ctl(struct at91usart_softc *sc, int enabled)
362c62a0ac4Smatt {
363c62a0ac4Smatt 	struct mpcsa_usart_softc *mpsc = (void*)sc;
364c62a0ac4Smatt 
365c62a0ac4Smatt 	switch (mpsc->sc_dev.sc_pid) {
366c62a0ac4Smatt 	case PID_US0:
367c62a0ac4Smatt 		if (enabled)
368c62a0ac4Smatt 			at91pio_set(mpsc->sc_piob, PB_RTS1);
369c62a0ac4Smatt 		else
370c62a0ac4Smatt 			at91pio_clear(mpsc->sc_piob, PB_RTS1);
371c62a0ac4Smatt 		break;
372c62a0ac4Smatt 
373c62a0ac4Smatt 	case PID_US1:
374c62a0ac4Smatt 		if (enabled)
375c62a0ac4Smatt 			at91pio_set(mpsc->sc_piob, PB_RTS2);
376c62a0ac4Smatt 		else
377c62a0ac4Smatt 			at91pio_clear(mpsc->sc_piob, PB_RTS2);
378c62a0ac4Smatt 		break;
379c62a0ac4Smatt 
380c62a0ac4Smatt 	case PID_US2:
381c62a0ac4Smatt 		if (enabled)
382c62a0ac4Smatt 			at91pio_set(mpsc->sc_piob, PB_RTS3);
383c62a0ac4Smatt 		else
384c62a0ac4Smatt 			at91pio_clear(mpsc->sc_piob, PB_RTS3);
385c62a0ac4Smatt 		break;
386c62a0ac4Smatt 
387c62a0ac4Smatt 	case PID_US3:
388c62a0ac4Smatt 		if (enabled)
389c62a0ac4Smatt 			at91pio_set(mpsc->sc_piob, PB_RTS4);
390c62a0ac4Smatt 		else
391c62a0ac4Smatt 			at91pio_clear(mpsc->sc_piob, PB_RTS4);
392c62a0ac4Smatt 		break;
393c62a0ac4Smatt 
394c62a0ac4Smatt 	}
395c62a0ac4Smatt 
396c62a0ac4Smatt }
397c62a0ac4Smatt 
398