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