Simple write to an UART mode register fails
Frey ext-FA, Maurus
maurus.frey.ext at siemens.com
Wed Mar 2 08:08:34 EST 2011
Hi,
I wrote a simple module, which should initialise an USART in RS485-mode
(RTS stays low after initialisation) and register it as platform_device.
Its on an Atmel at91sam9260 board, so I can re-use most of the mach
arm-sources (atmel_serial.c etc.)
When the module gets loaded I got the following output
$ modprobe axm_rs485_uart
Original ATMEL_US_MR=0
Write 1 to ATMEL_US_MR
After Write ATMEL_US_MR=0
axm_rs485_uart: registering uart port #3 in RS485 mode as atmel_usart3
- read the actual state from the USART Mode Register
- Put the mode into RS485 mode ("or" a bit)
- write the new mode into the register
- read the register again...and (what a surprise) see, that the write
operation didn't succeed
A simple write to a register seems to fail. In consequence the RTS line
gets high after the Pin has been "muxed" to its RTS-Rolle with
at91_set_B_periph().
I think, that I'm doing something wrong with request_mem() and ioremap()
No clue what? Can you help me with this?
Thanks for any advice.
Regards
maurus
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/atmel_serial.h>
#include <mach/board.h>
#define UART_PORT_WITH_RTS_MAX 4
#define UART_PORT_DEFAULT 3
#define UART_PORT_DEFAULT_DEVICE_NAME "atmel_usart3"
// USART ids / interrupts
static u32 at91sam9260_id_us[UART_PORT_WITH_RTS_MAX] =
{ AT91SAM9260_ID_US0, AT91SAM9260_ID_US1, AT91SAM9260_ID_US2,
AT91SAM9260_ID_US3 };
#define A_PERIPHERAL 0
#define B_PERIPHERAL 1
struct io_mux_pin
{
u32 io_line_addr; // I/O Line address
uint peripheral; // A or B Peripheral
} io_mux_pin;
struct io_mux_pin at91_rts_io_pin[UART_PORT_WITH_RTS_MAX] =
{
{ AT91_PIN_PB26, A_PERIPHERAL }, //RTS0
{ AT91_PIN_PB28, A_PERIPHERAL }, //RTS1
{ AT91_PIN_PA4, A_PERIPHERAL }, //RTS2
{ AT91_PIN_PC8, B_PERIPHERAL } //RTS3
};
//Define some module information.
MODULE_AUTHOR("Maus");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Initialize UART port in RS485 mode. RTS-Line stays
low.") ;
// Stores our pointer to the platform device, needed for release during
exit.
static struct platform_device *pdev;
// Remapped virtual base address
static void *vbaseaddr;
// get port_number as parameter, available in sysfs
// valid value from 0 to UART_PORT_MAX
static uint uart_port = UART_PORT_DEFAULT;
module_param( uart_port, uint, 0400 );
MODULE_PARM_DESC(uart_port, "UART port number to initialize in RS485
mode [0-" __MODULE_STRING(UART_PORT_WITH_RTS_MAX)"]");
// get device_name as parameter, available in sysfs
static char device_name[30] = UART_PORT_DEFAULT_DEVICE_NAME;
module_param_string( device_name, device_name, sizeof(device_name), 0400
);
/*
* Register UARTX as platform device.
*/
static int __init axm_rs485_uart_init(void)
{
int retValue = 0;
unsigned mode;
//check parameter input
if (uart_port >= UART_PORT_WITH_RTS_MAX)
{
printk(KERN_ERR "%s: uart_port=%u must be below %u\n",
THIS_MODULE->name,
uart_port, UART_PORT_WITH_RTS_MAX);
return -EINVAL;
}
/*
* Get platform_device struct from exported at91_register_uart
*
* - Don't configure RTS pin.
* - portnr = uart_port+1 (not necessary due call after boot-up)
*/
pdev = at91_register_uart(at91sam9260_id_us[uart_port], uart_port + 1,
ATMEL_UART_CTS);
if (pdev == NULL)
{
printk(KERN_ERR "%s: unable to register uart%u\n",
THIS_MODULE->name,
uart_port);
return -EINVAL;
}
//set platform_device_name according parameter or default value
if (!strcmp(pdev->name, device_name))
{
pdev->name = device_name;
//correct the device id
pdev->id = uart_port;
}
//if (!request_mem_region(at91sam9260_base_us[uart_port], SZ_16K ,
THIS_MODULE->name))
if
(!request_mem_region(pdev->resource[0].start,pdev->resource[0].end-
pdev->resource[0].start , THIS_MODULE->name))
{
printk(KERN_ERR "%s: unable to request memory region for uart%u \n",
THIS_MODULE->name, uart_port);
goto out_direct;
}
vbaseaddr = ioremap(pdev->resource[0].start,pdev->resource[0].end-
pdev->resource[0].start);
if (!vbaseaddr)
{
goto out_reqmem_io_pin;
}
mode =readl(vbaseaddr + ATMEL_US_MR);
printk("Original ATMEL_US_MR=%lX\n", mode);
mode |= ATMEL_US_USMODE_RS485;
printk("Write %lX to ATMEL_US_MR\n", mode);
/* put USART to RS485 mode */
writel(mode, vbaseaddr + ATMEL_US_MR);
/*check if mode has been written to register*/
mode = readl(vbaseaddr + ATMEL_US_MR);
printk("After Write ATMEL_US_MR=%lX\n", mode);
/* release all resources to be used by other drivers */
iounmap(vbaseaddr);
release_mem_region( pdev->resource[0].start, pdev->resource[0].end-
pdev->resource[0].start);
/* Decide whether pin is A or B peripheral and configure RTS pin to
stay low */
if (at91_rts_io_pin[uart_port].peripheral == A_PERIPHERAL)
{
at91_set_A_periph(at91_rts_io_pin[uart_port].io_line_addr, 0);
}
else
{
at91_set_B_periph(at91_rts_io_pin[uart_port].io_line_addr, 0);
}
retValue = platform_device_register(pdev);
if (retValue)
{
printk(KERN_ERR "%s: unable to register platform device\n",
THIS_MODULE->name);
return -EINVAL;
}
printk(KERN_NOTICE "%s: registering uart port #%u in RS485 mode as
%s\n",
THIS_MODULE->name, uart_port, device_name);
return retValue;
out_reqmem_io_pin:
release_mem_region( pdev->resource[0].start,
pdev->resource[0].end- pdev->resource[0].start);
out_direct: return -EINVAL;
}
/*
* Release (unregister device) UART
*/
static void __exit axm_rs485_uart_exit(void)
{
if (pdev != NULL)
{
platform_device_unregister(pdev);
}
printk(KERN_NOTICE "%s: releasing USART \n", THIS_MODULE->name);
}
module_init(axm_rs485_uart_init);
module_exit(axm_rs485_uart_exit);
More information about the Kernelnewbies
mailing list