Based on Linux-2.6.32.2 in mini2440 driver analysis one: serial port driver

Publisher:书香墨意Latest update time:2022-10-19 Source: csdnKeywords:Linux-2  6  mini2440 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The serial port driver file is located at: linux-2.6.32.2/drivers/serial/s3c2440.c, omitting the analysis of non-key parts.


#include

#include

#include

#include

#include

#include

#include


#include

#include


#include

#include


#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 %sn", 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, %08lxn", 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;

  } else if (ucon2 != 0) {

   clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;

   clk->divisor += 36;

  } else {

   /* manual calims 44, seems to be 9 */

   clk->divisor = 9;

  }


  clk->name = "fclk";

  break;

 }


 return 0;

}


static int s3c2440_serial_resetport(struct uart_port *port,

        struct s3c2410_uartcfg *cfg)

{

 unsigned long ucon = rd_regl(port, S3C2410_UCON);


 dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%pn",

     port, port->mapbase, cfg);


 /* ensure we don't change the clock settings... */


 ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));


 wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);

 wr_regl(port, S3C2410_ULCON, cfg->ulcon);


 /* reset both fifos */


 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);

 wr_regl(port, S3C2410_UFCON, cfg->ufcon);


 return 0;

}


static struct s3c24xx_uart_info s3c2440_uart_inf = {

 .name  = "Samsung S3C2440 UART",

 .type  = PORT_S3C2440,

 .fifosize = 64,

 .rx_fifomask = S3C2440_UFSTAT_RXMASK,

 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,

 .rx_fifofull = S3C2440_UFSTAT_RXFULL,

 .tx_fifofull = S3C2440_UFSTAT_TXFULL,

 .tx_fifomask = S3C2440_UFSTAT_TXMASK,

 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,

 .get_clksrc = s3c2440_serial_getsource,

 .set_clksrc = s3c2440_serial_setsource,

 .reset_port = s3c2440_serial_resetport,

};


/* device management */


static int s3c2440_serial_probe(struct platform_device *dev)

{

 dbg("s3c2440_serial_probe: dev=%pn", dev);

 return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);

}


static struct platform_driver s3c2440_serial_driver = {   //这个应该就是类似于file_operation结构体

 .probe  = s3c2440_serial_probe,

 .remove  = __devexit_p(s3c24xx_serial_remove),

 .driver  = {

  .name = "s3c2440-uart",

  .owner = THIS_MODULE,

 },

};


s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);


static int __init s3c2440_serial_init(void)

{

 return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);

}


static void __exit s3c2440_serial_exit(void)

{

 platform_driver_unregister(&s3c2440_serial_driver);

}


module_init(s3c2440_serial_init);

module_exit(s3c2440_serial_exit);


MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");

MODULE_AUTHOR("Ben Dooks ");

MODULE_LICENSE("GPL v2");

MODULE_ALIAS("platform:s3c2440-uart");


辅助理解:


1、s3c24xx_serial_init(struct platform_driver *drv, struct s3c24xx_uart_info *info) 函数


int s3c24xx_serial_init(struct platform_driver *drv,

   struct s3c24xx_uart_info *info)

{

 dbg("s3c24xx_serial_init(%p,%p)n", drv, info);


#ifdef CONFIG_PM

 drv->suspend = s3c24xx_serial_suspend;

 drv->resume = s3c24xx_serial_resume;

#endif


 return platform_driver_register(drv);

}


2、struct platform_driver 结构体


struct platform_driver {

 int (*probe)(struct platform_device *);

 int (*remove)(struct platform_device *);

 void (*shutdown)(struct platform_device *);

 int (*suspend)(struct platform_device *, pm_message_t state);

 int (*resume)(struct platform_device *);

 struct device_driver driver;

 struct platform_device_id *id_table;

};


以下部分涉及S3C2440芯片手册部分内容,附上宏的头文件


/* arch/arm/mach-s3c2410/include/mach/regs-serial.h

 *

 *  From linux/include/asm-arm/hardware/serial_s3c2410.h

 *

 *  Internal header file for Samsung S3C2410 serial ports (UART0-2)*/


#ifndef __ASM_ARM_REGS_SERIAL_H

#define __ASM_ARM_REGS_SERIAL_H


#define S3C24XX_VA_UART0      (S3C_VA_UART)

#define S3C24XX_VA_UART1      (S3C_VA_UART + 0x4000 )

#define S3C24XX_VA_UART2      (S3C_VA_UART + 0x8000 )

#define S3C24XX_VA_UART3      (S3C_VA_UART + 0xC000 )


#define S3C2410_PA_UART0      (S3C24XX_PA_UART)

#define S3C2410_PA_UART1      (S3C24XX_PA_UART + 0x4000 )

#define S3C2410_PA_UART2      (S3C24XX_PA_UART + 0x8000 )

#define S3C2443_PA_UART3      (S3C24XX_PA_UART + 0xC000 )


#define S3C2410_URXH   (0x24)

#define S3C2410_UTXH   (0x20)

#define S3C2410_ULCON   (0x00)

#define S3C2410_UCON   (0x04)

#define S3C2410_UFCON   (0x08)

#define S3C2410_UMCON   (0x0C)

#define S3C2410_UBRDIV   (0x28)

#define S3C2410_UTRSTAT   (0x10)

#define S3C2410_UERSTAT   (0x14)

#define S3C2410_UFSTAT   (0x18)

#define S3C2410_UMSTAT   (0x1C)


#define S3C2410_LCON_CFGMASK   ((0xF<<3)|(0x3))


#define S3C2410_LCON_CS5   (0x0)

#define S3C2410_LCON_CS6   (0x1)

#define S3C2410_LCON_CS7   (0x2)

#define S3C2410_LCON_CS8   (0x3)

#define S3C2410_LCON_CSMASK   (0x3)


#define S3C2410_LCON_PNONE   (0x0)

#define S3C2410_LCON_PEVEN   (0x5 << 3)

#define S3C2410_LCON_PODD   (0x4 << 3)

#define S3C2410_LCON_PMASK   (0x7 << 3)


#define S3C2410_LCON_STOPB   (1<<2)

#define S3C2410_LCON_IRM          (1<<6)


#define S3C2440_UCON_CLKMASK   (3<<10)

#define S3C2440_UCON_PCLK   (0<<10)

#define S3C2440_UCON_UCLK   (1<<10)

#define S3C2440_UCON_PCLK2   (2<<10)

#define S3C2440_UCON_FCLK   (3<<10)


#define S3C2440_UCON2_FCLK_EN   (1<<15)

#define S3C2440_UCON0_DIVMASK   (15 << 12)

#define S3C2440_UCON1_DIVMASK   (15 << 12)

#define S3C2440_UCON2_DIVMASK   (7 << 12)

#define S3C2440_UCON_DIVSHIFT   (12)


#define S3C2410_UCON_UCLK   (1<<10)

#define S3C2410_UCON_SBREAK   (1<<4)


#define S3C2410_UCON_TXILEVEL   (1<<9)

#define S3C2410_UCON_RXILEVEL   (1<<8)

#define S3C2410_UCON_TXIRQMODE   (1<<2)

#define S3C2410_UCON_RXIRQMODE   (1<<0)

#define S3C2410_UCON_RXFIFO_TOI   (1<<7)

#define S3C2443_UCON_RXERR_IRQEN  (1<<6)

#define S3C2443_UCON_LOOPBACK   (1<<5)


#define S3C2410_UCON_DEFAULT   (S3C2410_UCON_TXILEVEL  |

       S3C2410_UCON_RXILEVEL  |

       S3C2410_UCON_TXIRQMODE |

       S3C2410_UCON_RXIRQMODE |

       S3C2410_UCON_RXFIFO_TOI)


#define S3C2410_UFCON_FIFOMODE   (1<<0)

#define S3C2410_UFCON_TXTRIG0   (0<<6)

#define S3C2410_UFCON_RXTRIG8   (1<<4)

#define S3C2410_UFCON_RXTRIG12   (2<<4)


/* S3C2440 FIFO trigger levels */

#define S3C2440_UFCON_RXTRIG1   (0<<4)

#define S3C2440_UFCON_RXTRIG8   (1<<4)

#define S3C2440_UFCON_RXTRIG16   (2<<4)

#define S3C2440_UFCON_RXTRIG32   (3<<4)


#define S3C2440_UFCON_TXTRIG0   (0<<6)

#define S3C2440_UFCON_TXTRIG16   (1<<6)

#define S3C2440_UFCON_TXTRIG32   (2<<6)

#define S3C2440_UFCON_TXTRIG48   (3<<6)


#define S3C2410_UFCON_RESETBOTH   (3<<1)

#define S3C2410_UFCON_RESETTX   (1<<2)

#define S3C2410_UFCON_RESETRX   (1<<1)


#define S3C2410_UFCON_DEFAULT   (S3C2410_UFCON_FIFOMODE |

       S3C2410_UFCON_TXTRIG0  |

       S3C2410_UFCON_RXTRIG8 )


#define S3C2410_UMCOM_AFC   (1<<4)

#define S3C2410_UMCOM_RTS_LOW   (1<<0)


#define S3C2410_UFSTAT_TXFULL   (1<<9)

#define S3C2410_UFSTAT_RXFULL   (1<<8)

#define S3C2410_UFSTAT_TXMASK   (15<<4)

#define S3C2410_UFSTAT_TXSHIFT   (4)

#define S3C2410_UFSTAT_RXMASK   (15<<0)

#define S3C2410_UFSTAT_RXSHIFT   (0)


/* UFSTAT S3C2443 same as S3C2440 */

#define S3C2440_UFSTAT_TXFULL   (1<<14)

#define S3C2440_UFSTAT_RXFULL   (1<<6)

#define S3C2440_UFSTAT_TXSHIFT   (8)

#define S3C2440_UFSTAT_RXSHIFT   (0)

#define S3C2440_UFSTAT_TXMASK   (63<<8)

#define S3C2440_UFSTAT_RXMASK   (63)


#define S3C2410_UTRSTAT_TXE (1<<2)

#define S3C2410_UTRSTAT_TXFE   (1<<1)

#define S3C2410_UTRSTAT_RXDR   (1<<0)


#define S3C2410_UERSTAT_OVERRUN (1<<0)

#define S3C2410_UERSTAT_FRAME (1<<2)

#define S3C2410_UERSTAT_BREAK   (1<<3)

#define S3C2443_UERSTAT_PARITY   (1<<1)


#define S3C2410_UERSTAT_ANY (S3C2410_UERSTAT_OVERRUN |

       S3C2410_UERSTAT_FRAME |

       S3C2410_UERSTAT_BREAK)


#define S3C2410_UMSTAT_CTS   (1<<0)

#define S3C2410_UMSTAT_DeltaCTS   (1<<2)


#ifndef __ASSEMBLY__


/* struct s3c24xx_uart_clksrc

 *

 * this structure defines a named clock source that can be used for the

 * uart, so that the best clock can be selected for the requested baud

 * rate.

 *

 * min_baud and max_baud define the range of baud-rates this clock is

 * acceptable for, if they are both zero, it is assumed any baud rate that

 * can be generated from this clock will be used.

 *

 * divisor gives the divisor from the clock to the one seen by the uart

[1] [2]
Keywords:Linux-2  6  mini2440 Reference address:Based on Linux-2.6.32.2 in mini2440 driver analysis one: serial port driver

Previous article:Friendly Arm Mini2440 Nor Flash driver design under embedded Linux
Next article:S3C2440 U-Boot transplantation--Norflash driver support-S29AL016

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号