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