Chinaunix首页 | 论坛 | 博客
  • 博客访问: 970158
  • 博文数量: 214
  • 博客积分: 10173
  • 博客等级: 上将
  • 技术积分: 1867
  • 用 户 组: 普通用户
  • 注册时间: 2007-06-18 13:48
文章分类

全部博文(214)

文章存档

2012年(1)

2010年(13)

2009年(5)

2008年(98)

2007年(97)

分类: LINUX

2010-12-01 18:00:35

16C554在LINUX上的移植(AT91)

linux版本:2.6.30
AT91SAM9263

修改串口扩展驱动:

1,在/drivers/serial/下以8250_exar_st16c554.c文件为模板创建8250_at91_xr16v554.c文件;修改相应的PORT和中断号,修改Platform device ID为
PLAT8250_DEV_AT91_XR16V554;在init函数中加入了对总线,及中断口的初始化操作;;在文件/include/linux/serial_8250.h ID列表中加入该ID;


/drivers/serial/Kconfig加入:
config SERIAL_8250_AT91_XR16V554
tristate "Support Exar XR16V554/554D Quad UART for AT91"
depends on SERIAL_8250 != n
help
 My PSMU-C4M11 uses xr16v554d to form Quad UART.  If you are
 using these UARTs,
 say Y here.

 To compile this driver as a module, choose M here: the module
 will be called 8250_at91_xr16v554.

/drivers/serial/makefile加入:
obj-$(CONFIG_SERIAL_8250_AT91_XR16V554) += 8250_at91_xr16v554.o

2,8250.c无须修改!!

需要注意的地方:
1,
#define PORT(_base,_irq)    \
{        \
.mapbase = _base, \
.irq = _irq, \
.uartclk = 7372800, \
.iotype = UPIO_MEM, \
        .regshift = 0,            \
.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,\
}
宏中,.mapbase指的是16C554的物理基地址,注意不是membase;.uartclk是16C554晶振的频率,其最高波特率为.uartclk/16;.iotype指的是访问类型,与硬件的连接相关,UPIO_MEM指的是8位总线连接,而UPIO_MEM32表示为32位总线访问方式,即访问16C554的寄存器时,读取32位数,取低8位;.regshift也跟硬件的物理连接相关,指的是访问16C554的每个地址时的偏移,也就是16C554的A0对应CPU的A几;UPF_IOREMAP指16C554寄存器需要映射到虚拟地址访问;

2,
.dev = {
.platform_data = xxx_data,
},
设备结构声明中的xxx_data因为是个多维数组,从而.platform_data = xxx_data与.platform_data = &xxx_data意义是一样的,都可以;

3,
platform_device无须在板极初始化中注册,使用module_init声明即可;
链接的次序,对应执行的次序,与makefile中的次序一致;而注册platform_device与注册platform_driver的次序无关,注册成功时都会匹配,匹配成功,都会调用probe函数,probe设备,只有probe成功才会进行地址映射,分配资源等等的操作;

4,
通过阅读参考1及8250.c serial_core.c源代码,发现:
在serial8250_init(void)函数中总会注册一ID为PLAT8250_DEV_LEGACY的platform_device,而该设备的资源在old_serial_port[]中定义,
而该数组依赖于SERIAL_PORT_DFNS的定义,如果定义为空则,该device不会添加port;而其他device调用platform_device_register()函数时,如果匹配
驱动,会调用serial8250_probe(),该函数会从该设备的资源中读出数据,检测每个port,如果存在则申请中断号,映射物理地址等等,并添加port。
从而添加新的设备无须修改8250.c,初始化时默认添加的设备只要不定义SERIAL_PORT_DFNS,并不会有影响。

5,如果使用了GPIO中断,则需要注意AT91的普通IO口不能设置为上升沿或下降沿触发,而只能定义为边沿触发,即每次有效电平触发2次,只是浪费了CPU,并不会
影响使用,如果想修改,则可在修改8250.c中的中断函数,无效中断直接返回即可,参考如下:
+#define AT91_GPIO_IRQ_HACK
+
+#ifdef AT91_GPIO_IRQ_HACK
+#include
+#endif 
+#ifdef AT91_GPIO_IRQ_HACK
+#define NR_TRIES 10
+ int ntries = 0;
+ int pin_val1, pin_val2;
+ do {
+ pin_val1 = at91_get_gpio_value(AT91_PIN_PB20);
+ pin_val2 = at91_get_gpio_value(AT91_PIN_PB20);
+ } while (pin_val1 != pin_val2 && ntries++ < NR_TRIES);
+
+ udelay(20); // XXX: this need to be here otherwise IDE layer losts interrups, don't know why !!!
+ if (pin_val1 == 0 || ntries > NR_TRIES)
+ return IRQ_HANDLED;
+#undef NR_TIRES
+#endif

6,
如果开机检测成功,添加端口成功,会打印:
serial8250.11: ttyS0 at MMIO 0x30000000 (irq = 83) is a 16550A
serial8250.11: ttyS1 at MMIO 0x30000008 (irq = 84) is a 16550A
serial8250.11: ttyS2 at MMIO 0x30000010 (irq = 85) is a 16550A
serial8250.11: ttyS3 at MMIO 0x30000018 (irq = 86) is a 16550A

几个有用的命令:
查看各个串口的资源,如果不正常肯定初始化有问题
cat /proc/tty/driver/serial
从串口读出数据(波特率是上次设定的)
cat /dev/ttyS0 
查看IOMEM
cat /proc/iomem
 

参考:
1,《linux设备模型之uart驱动分析》
http://blog.chinaunix.net/u1/51562/showart.php?id=1110903
2,《我在Linux-2.6.32.2下为ST16C554移植驱动的经历》
http://blog.chinaunix.net/u3/106983/showart_2148343.html
3,《linux2.6.14内核下移植16C554驱动》
http://blog.chinaunix.net/u3/92401/showart_2253514.html
4,
/arch/arm/mach-at91/board-tms.c
该文件中有添加16C550驱动定义

阅读(2912) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

zhangyuzan2013-03-29 15:33:32

你好,我按照你的方法在sam9260上移植16C554,可是没有成功,启动信息显示 Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled,是不是初始化中断口不对啊?我该怎样初始化中断口呢?(不好意思,我是新手),我用的中断口是 PB16 PB17 PB18 和PB19。