1 /* $Id: mpcsa_usart.c,v 1.2 2008/07/03 01:15:39 matt Exp $ */
5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD$");
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/device.h>
38 #include <arm/at91/at91reg.h>
39 #include <arm/at91/at91var.h>
40 #include <arm/at91/at91usartvar.h>
41 #include <arm/at91/at91piovar.h>
42 #include <arm/at91/at91rm9200reg.h>
43 #include <evbarm/mpcsa/mpcsa_io.h>
44 #include <evbarm/mpcsa/mpcsa_leds_var.h>
45 #include <sys/unistd.h>
47 #ifdef MPCSA_USART_DEBUG
48 int mpcsa_usart_debug
= MPCSA_USART_DEBUG
;
49 #define DPRINTFN(n,x) if (mpcsa_usart_debug>(n)) printf x;
56 struct mpcsa_usart_softc
{
57 struct at91usart_softc sc_dev
;
58 struct at91pio_softc
*sc_pioa
, *sc_piob
, *sc_piod
;
60 int sc_tx_busy
, sc_rx_busy
;
63 static int mpcsa_usart_match(struct device
*, struct cfdata
*, void *);
64 static void mpcsa_usart_attach(struct device
*, struct device
*, void *);
66 CFATTACH_DECL(mpcsa_usart
, sizeof(struct mpcsa_usart_softc
),
67 mpcsa_usart_match
, mpcsa_usart_attach
, NULL
, NULL
);
69 static int mpcsa_usart_enable(struct at91usart_softc
*sc
);
70 static int mpcsa_usart_disable(struct at91usart_softc
*sc
);
71 static void mpcsa_usart_hwflow(struct at91usart_softc
*sc
, int cflags
);
72 static void mpcsa_usart_start_tx(struct at91usart_softc
*sc
);
73 static void mpcsa_usart_stop_tx(struct at91usart_softc
*sc
);
74 static void mpcsa_usart_rx_started(struct at91usart_softc
*sc
);
75 static void mpcsa_usart_rx_stopped(struct at91usart_softc
*sc
);
76 static void mpcsa_usart_rx_rts_ctl(struct at91usart_softc
*sc
, int enabled
);
78 static int mpcsa_gsm_cts_intr(void *);
81 led_num(struct mpcsa_usart_softc
*mpsc
)
83 return (mpsc
->sc_dev
.sc_pid
== PID_US3
? LED_GSM
: LED_SER1
+ mpsc
->sc_dev
.sc_pid
- PID_US0
);
87 comm_led(struct mpcsa_usart_softc
*mpsc
, int count
)
89 mpcsa_comm_led(led_num(mpsc
), count
);
93 conn_led(struct mpcsa_usart_softc
*mpsc
, int count
)
95 mpcsa_conn_led(led_num(mpsc
), count
);
99 mpcsa_usart_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
101 if (strcmp(match
->cf_name
, "at91usart") == 0 && strcmp(match
->cf_atname
, "mpcsa_usart") == 0)
108 mpcsa_usart_attach(struct device
*parent
, struct device
*self
, void *aux
)
110 struct mpcsa_usart_softc
*sc
= (struct mpcsa_usart_softc
*)self
;
111 struct at91bus_attach_args
*sa
= aux
;
114 if ((sc
->sc_pioa
= at91pio_sc(AT91_PIOA
)) == NULL
) {
115 printf("no PIOA!\n");
118 if ((sc
->sc_piob
= at91pio_sc(AT91_PIOB
)) == NULL
) {
119 printf("no PIOB!\n");
122 if ((sc
->sc_piod
= at91pio_sc(AT91_PIOD
)) == NULL
) {
123 printf("no PIOD!\n");
127 // calculate unit number...
128 switch (sa
->sa_pid
) {
133 sc
->sc_dev
.enable
= mpcsa_usart_enable
;
134 sc
->sc_dev
.disable
= mpcsa_usart_disable
;
135 sc
->sc_dev
.hwflow
= mpcsa_usart_hwflow
;
136 sc
->sc_dev
.start_tx
= mpcsa_usart_start_tx
;
137 sc
->sc_dev
.stop_tx
= mpcsa_usart_stop_tx
;
138 sc
->sc_dev
.rx_started
= mpcsa_usart_rx_started
;
139 sc
->sc_dev
.rx_stopped
= mpcsa_usart_rx_stopped
;
140 sc
->sc_dev
.rx_rts_ctl
= mpcsa_usart_rx_rts_ctl
;
145 switch (sa
->sa_pid
) {
147 at91pio_set(sc
->sc_piob
, PB_RTS1
);
148 at91pio_set(sc
->sc_piod
, PD_DTR1
);
149 at91pio_in(sc
->sc_piob
, PB_CTS1
);
150 at91pio_out(sc
->sc_piob
, PB_RTS1
);
151 at91pio_in(sc
->sc_piod
, PD_DSR1
);
152 at91pio_out(sc
->sc_piod
, PD_DTR1
);
153 at91pio_per(sc
->sc_piob
, PB_CTS1
, -1);
154 at91pio_per(sc
->sc_piob
, PB_RTS1
, -1);
155 at91pio_per(sc
->sc_piod
, PD_DSR1
, -1);
156 at91pio_per(sc
->sc_piod
, PD_DTR1
, -1);
159 at91pio_set(sc
->sc_piob
, PB_RTS2
);
160 at91pio_set(sc
->sc_piod
, PD_DTR2
);
161 at91pio_in(sc
->sc_piob
, PB_CTS2
);
162 at91pio_out(sc
->sc_piob
, PB_RTS2
);
163 at91pio_in(sc
->sc_piod
, PD_DSR2
);
164 at91pio_out(sc
->sc_piod
, PD_DTR2
);
165 at91pio_per(sc
->sc_piob
, PB_CTS2
, -1);
166 at91pio_per(sc
->sc_piob
, PB_RTS2
, -1);
167 at91pio_per(sc
->sc_piod
, PD_DSR2
, -1);
168 at91pio_per(sc
->sc_piod
, PD_DTR2
, -1);
171 at91pio_set(sc
->sc_piob
, PB_RTS3
);
172 at91pio_set(sc
->sc_piod
, PD_DTR3
);
173 at91pio_in(sc
->sc_piob
, PB_CTS3
);
174 at91pio_out(sc
->sc_piob
, PB_RTS3
);
175 at91pio_in(sc
->sc_piod
, PD_DSR3
);
176 at91pio_out(sc
->sc_piod
, PD_DTR3
);
177 at91pio_per(sc
->sc_piob
, PB_CTS3
, -1);
178 at91pio_per(sc
->sc_piob
, PB_RTS3
, -1);
179 at91pio_per(sc
->sc_piod
, PD_DSR3
, -1);
180 at91pio_per(sc
->sc_piod
, PD_DTR3
, -1);
183 /* configure pin states... */
184 at91pio_clear(sc
->sc_pioa
, PA_GSMON
);
185 at91pio_set(sc
->sc_pioa
, PA_GSMOFF
);
186 at91pio_set(sc
->sc_piob
, PB_RTS4
);
187 at91pio_set(sc
->sc_piod
, PD_DTR4
);
189 /* configure pin directions.. */
190 at91pio_out(sc
->sc_pioa
, PA_GSMOFF
);
191 at91pio_out(sc
->sc_pioa
, PA_GSMON
);
192 at91pio_in(sc
->sc_pioa
, PA_TXD4
);
193 at91pio_in(sc
->sc_piob
, PB_RTS4
);
194 at91pio_in(sc
->sc_piob
, PB_CTS4
);
195 at91pio_in(sc
->sc_piod
, PD_DTR4
);
196 at91pio_in(sc
->sc_piod
, PD_DSR4
);
197 at91pio_in(sc
->sc_piod
, PD_DCD4
);
199 /* make sure all related pins are configured as PIO */
200 at91pio_per(sc
->sc_pioa
, PA_GSMOFF
, -1);
201 at91pio_per(sc
->sc_pioa
, PA_GSMON
, -1);
202 at91pio_per(sc
->sc_pioa
, PA_TXD4
, -1);
203 at91pio_per(sc
->sc_piob
, PB_CTS4
, -1);
204 at91pio_per(sc
->sc_piob
, PB_RTS4
, -1);
205 at91pio_per(sc
->sc_piod
, PD_DSR4
, -1);
206 at91pio_per(sc
->sc_piod
, PD_DTR4
, -1);
207 at91pio_per(sc
->sc_piod
, PD_DCD4
, -1);
211 // and call common routine
212 at91usart_attach_subr(&sc
->sc_dev
, sa
);
216 mpcsa_usart_enable(struct at91usart_softc
*dev
)
218 struct mpcsa_usart_softc
*sc
= (struct mpcsa_usart_softc
*)dev
;
220 switch (sc
->sc_dev
.sc_pid
) {
223 at91pio_clear(sc
->sc_pioa
, PA_GSMOFF
);
224 ltsleep(sc
, 0, "gsmond", 4 * hz
, NULL
);
225 at91pio_set(sc
->sc_pioa
, PA_GSMON
);
226 ltsleep(sc
, 0, "gsmon", 2 * hz
, NULL
);
227 at91pio_clear(sc
->sc_pioa
, PA_GSMON
);
228 /* then attach pins to devices etc */
229 at91pio_per(sc
->sc_pioa
, PA_TXD4
, 1);
230 at91pio_clear(sc
->sc_piob
, PB_RTS4
);
231 at91pio_clear(sc
->sc_piod
, PD_DTR4
);
232 at91pio_out(sc
->sc_piob
, PB_RTS4
);
233 at91pio_out(sc
->sc_piod
, PD_DTR4
);
234 /* catch CTS interrupt */
235 sc
->sc_cts_ih
= at91pio_intr_establish(sc
->sc_piob
, PB_CTS4
,
236 IPL_TTY
, mpcsa_gsm_cts_intr
,
244 mpcsa_usart_disable(struct at91usart_softc
*dev
)
246 struct mpcsa_usart_softc
*sc
= (struct mpcsa_usart_softc
*)dev
;
247 if (sc
->sc_tx_busy
|| sc
->sc_rx_busy
) {
248 sc
->sc_tx_busy
= sc
->sc_rx_busy
= 0;
251 switch (sc
->sc_dev
.sc_pid
) {
253 at91pio_intr_disestablish(sc
->sc_piob
, PB_CTS4
, sc
->sc_cts_ih
);
255 at91pio_clear(sc
->sc_pioa
, PA_GSMON
);
256 ltsleep(sc
, 0, "gsmoffd", (hz
* 350 + 999) / 1000, NULL
);
258 at91pio_per(sc
->sc_pioa
, PA_TXD4
, -1);
259 at91pio_in(sc
->sc_piob
, PB_RTS4
);
260 at91pio_in(sc
->sc_piod
, PD_DTR4
);
262 at91pio_set(sc
->sc_pioa
, PA_GSMOFF
);
263 ltsleep(sc
, 0, "gsmoff", hz
* 4, NULL
);
264 at91pio_clear(sc
->sc_pioa
, PA_GSMOFF
);
272 static int mpcsa_gsm_cts_intr(void *cookie
)
274 struct mpcsa_usart_softc
*sc
= (struct mpcsa_usart_softc
*)cookie
;
275 if (ISSET(sc
->sc_dev
.sc_swflags
, TIOCFLAG_CRTSCTS
)) {
276 /* hardware flow control is enabled */
277 if (!(PIOB_READ(PIO_PDSR
) & (1U << PB_CTS4
))) {
278 if (bus_space_read_4(sc
->sc_dev
.sc_iot
, sc
->sc_dev
.sc_ioh
,
279 US_PDC
+ PDC_TCR
) && !sc
->sc_tx_busy
) {
282 comm_led(sc
, INFINITE_BLINK
);
285 bus_space_write_4(sc
->sc_dev
.sc_iot
, sc
->sc_dev
.sc_ioh
,
286 US_PDC
+ PDC_PTCR
, PDC_PTCR_TXTEN
);
287 SET(sc
->sc_dev
.sc_ier
, US_CSR_TXEMPTY
| US_CSR_ENDTX
);
288 bus_space_write_4(sc
->sc_dev
.sc_iot
, sc
->sc_dev
.sc_ioh
,
289 US_IER
, US_CSR_ENDTX
);
291 bus_space_write_4(sc
->sc_dev
.sc_iot
, sc
->sc_dev
.sc_ioh
,
292 US_PDC
+ PDC_PTCR
, PDC_PTCR_TXTDIS
);
293 if (sc
->sc_tx_busy
) {
304 mpcsa_usart_hwflow(struct at91usart_softc
*dev
, int flags
)
309 mpcsa_usart_start_tx(struct at91usart_softc
*sc
)
311 if (!ISSET(sc
->sc_swflags
, TIOCFLAG_CRTSCTS
)
312 || bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
, US_PDC
+ PDC_PTSR
) & PDC_PTSR_TXTEN
) {
313 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
314 US_PDC
+ PDC_PTCR
, PDC_PTCR_TXTEN
);
315 struct mpcsa_usart_softc
*mpsc
= (void*)sc
;
316 if (!mpsc
->sc_tx_busy
) {
317 mpsc
->sc_tx_busy
= 1;
318 if (!mpsc
->sc_rx_busy
)
319 comm_led(mpsc
, INFINITE_BLINK
);
326 mpcsa_usart_stop_tx(struct at91usart_softc
*sc
)
328 struct mpcsa_usart_softc
*mpsc
= (void*)sc
;
329 mpsc
->sc_tx_busy
= 0;
330 if (!mpsc
->sc_rx_busy
)
332 if (!ISSET(sc
->sc_swflags
, TIOCFLAG_CRTSCTS
)) {
333 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
,
334 US_PDC
+ PDC_PTCR
, PDC_PTCR_TXTDIS
);
339 mpcsa_usart_rx_started(struct at91usart_softc
*sc
)
341 struct mpcsa_usart_softc
*mpsc
= (void*)sc
;
342 if (!mpsc
->sc_rx_busy
) {
343 mpsc
->sc_rx_busy
= 1;
344 if (!mpsc
->sc_tx_busy
)
345 comm_led(mpsc
, INFINITE_BLINK
);
350 mpcsa_usart_rx_stopped(struct at91usart_softc
*sc
)
352 struct mpcsa_usart_softc
*mpsc
= (void*)sc
;
353 mpsc
->sc_rx_busy
= 0;
354 if (!mpsc
->sc_tx_busy
)
359 mpcsa_usart_rx_rts_ctl(struct at91usart_softc
*sc
, int enabled
)
361 struct mpcsa_usart_softc
*mpsc
= (void*)sc
;
363 switch (mpsc
->sc_dev
.sc_pid
) {
366 at91pio_set(mpsc
->sc_piob
, PB_RTS1
);
368 at91pio_clear(mpsc
->sc_piob
, PB_RTS1
);
373 at91pio_set(mpsc
->sc_piob
, PB_RTS2
);
375 at91pio_clear(mpsc
->sc_piob
, PB_RTS2
);
380 at91pio_set(mpsc
->sc_piob
, PB_RTS3
);
382 at91pio_clear(mpsc
->sc_piob
, PB_RTS3
);
387 at91pio_set(mpsc
->sc_piob
, PB_RTS4
);
389 at91pio_clear(mpsc
->sc_piob
, PB_RTS4
);