日期:2014-05-16  浏览次数:20826 次

基于Linux-2.6.32.2在mini2440驱动分析一:串口驱动

基于Linux-2.6.32.2在mini2440驱动分析一:串口驱动

 

串口驱动文件位于: linux-2.6.32.2/drivers/serial/s3c2440.c,省去非重点部分分析。

 

#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/serial.h>

#include <asm/irq.h>
#include <mach/hardware.h>

#include <plat/regs-serial.h>
#include <mach/regs-gpio.h>

#include "samsung.h"


static int s3c2440_serial_setsource(struct uart_port *port,
         struct s3c24xx_uart_clksrc *clk)
{
 unsigned long ucon = rd_regl(port, S3C2410_UCON);

 /* todo - proper fclk<>nonfclk switch. */

 ucon &= ~S3C2440_UCON_CLKMASK;

 if (strcmp(clk->name, "uclk") == 0)
  ucon |= S3C2440_UCON_UCLK;
 else if (strcmp(clk->name, "pclk") == 0)
  ucon |= S3C2440_UCON_PCLK;
 else if (strcmp(clk->name, "fclk") == 0)
  ucon |= S3C2440_UCON_FCLK;
 else {
  printk(KERN_ERR "unknown clock source %s\n", clk->name);
  return -EINVAL;
 }

 wr_regl(port, S3C2410_UCON, ucon);
 return 0;
}


static int s3c2440_serial_getsource(struct uart_port *port,
        struct s3c24xx_uart_clksrc *clk)
{
 unsigned long ucon = rd_regl(port, S3C2410_UCON);
 unsigned long ucon0, ucon1, ucon2;

 switch (ucon & S3C2440_UCON_CLKMASK) {
 case S3C2440_UCON_UCLK:
  clk->divisor = 1;
  clk->name = "uclk";
  break;

 case S3C2440_UCON_PCLK:
 case S3C2440_UCON_PCLK2:
  clk->divisor = 1;
  clk->name = "pclk";
  break;

 case S3C2440_UCON_FCLK:
  /* the fun of calculating the uart divisors on
   * the s3c2440 */

  ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
  ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
  ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);

  printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);

  ucon0 &= S3C2440_UCON0_DIVMASK;
  ucon1 &= S3C2440_UCON1_DIVMASK;
  ucon2 &= S3C2440_UCON2_DIVMASK;

  if (ucon0 != 0) {
   clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
   clk->divisor += 6;
  } else if (ucon1 != 0) {
   clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
   clk->divisor += 21