/*
* Driver for AT91RM9200 USART ports
*/
/*
* COPYRIGHT (c) 2006-2009.
* NCB - Sistemas Embarcados Ltda. (Brazil)
* Fernando Nicodemos <fgnicodemos@terra.com.br>
*
* and
*
* COPYRIGHT (c) 1989-2009.
* On-Line Applications Research Corporation (OAR).
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.org/license/LICENSE.
*/
#include <bsp.h>
#include <rtems/libio.h>
#include <termios.h>
#include <at91rm9200.h>
#include <at91rm9200_usart.h>
#include <at91rm9200_pmc.h>
#include <rtems/bspIo.h>
#include <libchip/serial.h>
#include <libchip/sersupp.h>
/* static function prototypes */
static int usart_first_open(int major, int minor, void *arg);
static int usart_last_close(int major, int minor, void *arg);
static int usart_read_polled(int minor);
static ssize_t usart_write_polled_support(int minor, const char *buf, size_t len);
static void usart_init(int minor);
static void usart_write_polled(int minor, char c);
static int usart_set_attributes(int minor, const struct termios *t);
at91rm9200_usart_regs_t *usart_get_base(int minor);
/* Pointers to functions for handling the UART polled. */
const console_fns usart_polling_fns = {
libchip_serial_default_probe, /* deviceProbe */
usart_first_open, /* deviceFirstOpen */
usart_last_close, /* deviceLastClose */
usart_read_polled, /* deviceRead */
usart_write_polled_support, /* deviceWrite */
usart_init, /* deviceInitialize */
usart_write_polled, /* deviceWritePolled */
usart_set_attributes, /* deviceSetAttributes */
FALSE /* TRUE if interrupt driven, FALSE if not. */
};
at91rm9200_usart_regs_t *usart_get_base(int minor)
{
console_tbl *console_entry;
at91rm9200_usart_regs_t *port;
console_entry = BSP_get_uart_from_minor(minor);
if (console_entry == NULL)
return 0;
port = (at91rm9200_usart_regs_t *) console_entry->ulCtrlPort1;
//printk( "minor=%d entry=%p port=%p\n", minor, console_entry, port );
return port;
}
/*
* Functions called via callbacks (i.e. the ones in uart_fns
*/
/*
* This is called the first time each device is opened. Since
* the driver is polled, we don't have to do anything. If the driver
* were interrupt driven, we'd enable interrupts here.
*/
static int usart_first_open(int major, int minor, void *arg)
{
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return -1;
/* XXX port isn't being initialized or enabled */
/* XXX I hope this is enough */
usart->cr = (US_CR_RXEN | US_CR_TXEN);
return 0;
}
/*
* This is called the last time each device is closed. Since
* the driver is polled, we don't have to do anything. If the driver
* were interrupt driven, we'd disable interrupts here.
*/
static int usart_last_close(int major, int minor, void *arg)
{
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return -1;
return 0;
}
/*
* Read one character from UART.
*
* return -1 if there's no data, otherwise return
* the character in lowest 8 bits of returned int.
*/
static int usart_read_polled(int minor)
{
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return -1;
/* if nothing ready return -1 */
if ( (usart->sr & US_IER_RXRDY) == 0 )
return -1;
return usart->rhr;
}
/*
* Write character out
*/
static void usart_write_polled(int minor, char c)
{
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return;
/* delay until TX empty */
while ( (usart->sr & US_IER_TXEMPTY) == 0 )
;
usart->thr = c;
}
/*
* Write buffer to UART
*
* return 1 on success, -1 on error
*/
static ssize_t usart_write_polled_support(int minor, const char *buf, size_t len)
{
at91rm9200_usart_regs_t *usart;
int nwrite=0;
/*
* Verify the minor number
*/
usart = usart_get_base(minor);
if ( !usart )
return -1;
/*
* poll each byte in the string out of the port.
*/
while (nwrite < len) {
usart_write_polled(minor, *buf++);
nwrite++;
}
/*
* return the number of bytes written.
*/
return nwrite;
return 1;
}
/* Set up the UART. */
static void usart_init(int minor)
{
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return;
}
/* This is for setting baud rate, bits, etc. */
static int usart_set_attributes(int minor, const struct termios *t)
{
uint32_t brgr;
uint32_t mode, baud, baud_requested;
at91rm9200_usart_regs_t *usart;
usart = usart_get_base(minor);
if ( !usart )
return -1;
/* Get current mode register */
mode = usart->mr & ~(US_MR_USMODE | US_MR_USCLKS | US_MR_CHRL
| US_MR_PAR | US_MR_NBSTOP);
/* Byte size */
switch (t->c_cflag & CSIZE){
case CS5:
mode |= US_MR_CHRL_5;
break;
case CS6:
mode |= US_MR_CHRL_6;
break;
case CS7:
mode |= US_MR_CHRL_7;
break;
default:
mode |= US_MR_CHRL_8;
break;
}
/* Stop bits */
if (t->c_cflag & CSTOPB){
mode |= US_MR_NBSTOP_2; /* 2 stop bits */
} else
mode |= US_MR_NBSTOP_1; /* 1 stop bits */
/* Parity */
if (t->c_cflag & PARENB){
/* Mark or Space parity */
if (t->c_cflag & PARODD){
mode |= US_MR_PAR_ODD;
} else
mode |= US_MR_PAR_EVEN;
} else
mode |= US_MR_PAR_NONE;
baud_requested = t->c_ospeed;
/* If not, set the dbgu console baud as USART baud default */
if (!baud_requested)
baud_requested = BSP_get_baud();
baud = rtems_termios_baud_to_number(baud_requested);
brgr = (at91rm9200_get_mck() / 16) / baud;
if (brgr > 65535){ /* BRGR is 16-bit, so switch to slower clock */
brgr /= 8;
mode |= US_MR_USCLKS_MCK_DIV8;
}
usart->mr = mode;
usart->brgr = brgr;
return 0;
}