2012-03-30 22:38 OMAPL138 PRU SOFT-UART实现(二)

串口驱动另外两个重要结构体:
270 struct uart_port {
271         spinlock_t              lock;                   /* port lock */
272         unsigned long           iobase;                 /* in/out[bwl] */
273         unsigned char __iomem   *membase;               /* read/write[bwl]     */
274         unsigned int            (*serial_in)(struct uart_port *, int);
275         void                    (*serial_out)(struct uart_port *, int, int)    ;
276         unsigned int            irq;                    /* irq number */
277         unsigned long           irqflags;               /* irq flags  */
278         unsigned int            uartclk;                /* base uart clock     */
279         unsigned int            fifosize;               /* tx fifo size */
280         unsigned char           x_char;                 /* xon/xoff char */
 ......
    timeout */
335         unsigned int            type;                   /* port type */
336         const struct uart_ops   *ops;

};
UART驱动程序拥有的每个端口都存在uart_port结构的一个实例,而uart_ops是每个UART驱动所必须支持的硬件操作的入口函数集合。
具体要实现以下功能:
203  * This structure describes all the operations that can be
204  * done on the physical hardware.
205  */
206 struct uart_ops {
207         unsigned int    (*tx_empty)(struct uart_port *);
208         void            (*set_mctrl)(struct uart_port *, unsigned int mctrl    );
209         unsigned int    (*get_mctrl)(struct uart_port *);
210         void            (*stop_tx)(struct uart_port *);
211         void            (*start_tx)(struct uart_port *);
...
218         void            (*flush_buffer)(struct uart_port *);
219         void            (*set_termios)(struct uart_port *, struct ktermios     *new,
220                                        struct ktermios *old);
...
242         void            (*config_port)(struct uart_port *, int);
...
};
UART驱动注册:
1.通过uart_register_driver(struct uart_driver *);向串行核心注册。
2.调用uart_add_one_port(struct uart_driver *, struct uart_port *)注册其支持的每个端口。
而作为其他设备模拟UART,这里是PRU实现串口,也需要填充以上结构,PRU就可以看作一个CPLD,模拟配置
状态寄存器,读数据寄存器,写数据寄存器,及FIFO就可以实现一个基本的UART功能。

 906         for (i = 0; i < NR_SUART; i++) {
 907                 soft_uart->port[i].ops = &pru_suart_ops;
    ...
 921                 soft_uart->port[i].line = i;    /* need the id/line from pd     ev */
 922                 soft_uart->suart_hdl[i].uartNum = i + 1;
    ...
 938                 soft_uart->port[i].serial_out = NULL;
 939                 uart_add_one_port(&pru_suart_reg, &soft_uart->port[i]);
 940                 init_MUTEX(&soft_uart->port_sem[i]);

}
以上对uart_port进行了填充,只列出了其中几项,每个端口在进行填充后都必须向串口核心添加。调用uart_add_one_port(),一旦提交后,又会回调该端口OPS的config_port()入口,完成配置,一次注册才算完成。

跟踪了一下 NR_SUART == 3,因为McASP引脚被用作其他外设占用,比如采用RMII的EMAC接口,空闲的McASP引脚只有 7,8,9,10,13,14只能模拟三个串口,
所以在上面只运行来PRU0(最多支持4个),这里也只初始化了三个端口.0,1,2.
在/dev目录下也只会有三个串口设备。若需要扩展,修改引脚即可。
下面列出几个入口:
模块插入:
pru_suart_init()
    ->uart_register_driver()
    ->omapl_pru_suart_probe()
        ->uart_add_one_port()
        ->pru_suart_config_port()
             ->pru_suart_request_port()
              ->pru_suart_request_port()


模块卸载:
omapl_pru_suart_exit()
    ->platform_driver_unregister()
    ->omapl_pru_suart_remove()
        ->uart_remove_one_port()
        ->pru_suart_release_port()
            ->pru_softuart_close()

打开端口:
pru_suart_startup()
    ->suart_intr_clrmask()
    ->request_irq()

串行发送:
驱动程序收集和UART端口相关的循环缓冲区中待发数据,在驱动程序的start_tx的入口函数omapl_pru_rx_chars,数据存放于struct circ_buf xmit->buf中。
串行接收:
中断处理例程中omapl_pru_tx_chars()中,使用 tty_insert_flip_string()和
tty_flip_buffer_push(tty),将收到的数据推出到tty驱动程序。

PRU 扩展4路串口文档,平台设备相关部分。

NOTE: 带‘+’为添加内容,‘-’为删去内容
1.添加mcasp/pru时钟
arch/arm/mach-davinci/da850.c

1).
#include <linux/cpufreq.h>
+#include <linux/delay.h>
2).
+static struct clk pru_clk = {
+       .name           = "pru_ck",
+       .parent         = &pll0_sysclk2,
+       .lpsc           = DA8XX_LPSC0_DMAX,
+       .flags      = ALWAYS_ENABLED,
+};
+
+static struct clk mcasp_pru_clk = {
+       .name           = "mcasp_pru",
+       .parent         = &pll0_sysclk2,
+       .lpsc           = DA8XX_LPSC1_McASP0,
+       .gpsc           = 1,
+       .flags          = DA850_CLK_ASYNC3,
+};
3).
+       CLK(NULL,               "pru_ck",       &pru_clk),
        CLK(NULL,               "uart1",        &uart1_clk),
        CLK(NULL,               "uart2",        &uart2_clk),
        CLK(NULL,               "aintc",        &aintc_clk),
        CLK(NULL,               "arm",          &arm_clk),
        CLK(NULL,               "rmii",         &rmii_clk),
        CLK("davinci_emac.1",   NULL,           &emac_clk),
+       CLK(NULL,       "mcasp_pru",    &mcasp_pru_clk),

2.配置引脚
1).
static const struct mux_config da850_pins[] = {
 #ifdef CONFIG_DAVINCI_MUX

-       MUX_CFG(DA850, EMA_A_8,         11,     28,     15,    1,      false)
+       MUX_CFG(DA850, EMA_A_8,         11,     28,     15,    8,      false)



2).
+const short da850_pru_suart_pins[] __initdata = {
+       DA850_AHCLKX, DA850_ACLKX, DA850_AFSX,
+    DA850_AHCLKR, DA850_ACLKR, DA850_AFSR,
+    DA850_AXR_11 DA850_AXR_9,
+       DA850_AXR_12 DA850_AXR_10,
+       -1
+};
+
 const short da850_uart1_pins[] __initdata = {
 ...
-       DA850_EMA_A_10, DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,
+       /*DA850_EMA_A_10,*/ DA850_EMA_A_11, DA850_EMA_A_12, DA850_EMA_A_13,

3.添加platform结构
arch/arm/mach-davinci/devices-da8xx.c

1).
 #include <linux/serial_8250.h>
+#include <linux/ti_omapl_pru_suart.h>
+#include <linux/can/platform/ti_omapl_pru_can.h>

2).
+#define OMAPL138_PRU_MEM_BASE     0x01C30000
+
+#define OMAPL138_INT_PRU_SUART_1 IRQ_DA8XX_EVTOUT0
+#define OMAPL138_INT_PRU_SUART_2 IRQ_DA8XX_EVTOUT1
+#define OMAPL138_INT_PRU_SUART_3 IRQ_DA8XX_EVTOUT2
+#define OMAPL138_INT_PRU_SUART_4 IRQ_DA8XX_EVTOUT3
+#define OMAPL138_INT_PRU_SUART_5 IRQ_DA8XX_EVTOUT4
+#define OMAPL138_INT_PRU_SUART_6 IRQ_DA8XX_EVTOUT5
+#define OMAPL138_INT_PRU_SUART_7 IRQ_DA8XX_EVTOUT6
+#define OMAPL138_INT_PRU_SUART_8 IRQ_DA8XX_EVTOUT7
+#ifndef CONFIG_OMAPL_SUART_MCASP
+#define CONFIG_OMAPL_SUART_MCASP 0
+#endif
+static struct resource omapl138_pru_suart_resources[] = {
+        {
+                               .name   = "omapl_pru_suart",
+                .start  = OMAPL138_PRU_MEM_BASE,
+                .end    = OMAPL138_PRU_MEM_BASE + 0xFFFF,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+#if (CONFIG_OMAPL_SUART_MCASP == 0)
+                               .start  = DAVINCI_DA8XX_MCASP0_REG_BASE,
+                       .end    = DAVINCI_DA8XX_MCASP0_REG_BASE + (SZ_1K * 12) - 1,
+                .flags  = IORESOURCE_MEM,
+#elif (CONFIG_OMAPL_SUART_MCASP == 1)
+                               .start  = DAVINCI_DA830_MCASP1_REG_BASE,
+                       .end    = DAVINCI_DA830_MCASP1_REG_BASE + (SZ_1K * 12) - 1,
+                .flags  = IORESOURCE_MEM,
+#elif (CONFIG_OMAPL_SUART_MCASP == 2)
+                               .start  = DAVINCI_DA830_MCASP2_REG_BASE,
+                       .end    = DAVINCI_DA830_MCASP2_REG_BASE + (SZ_1K * 12) - 1,
+                .flags  = IORESOURCE_MEM,
+#endif
+        },
+
+        {
+                               .start  = DA8XX_PSC0_BASE,
+                       .end    = DA8XX_PSC0_BASE + (SZ_1K * 3) - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                               .start  = DA8XX_PSC1_BASE,
+                       .end    = DA8XX_PSC1_BASE + (SZ_1K * 3) - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                               .start  = DA8XX_SHARED_RAM_BASE,
+                       .end    = DA8XX_SHARED_RAM_BASE + (SZ_1K * 8) - 1,
+                .flags  = IORESOURCE_MEM,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_1,
+                .end    = OMAPL138_INT_PRU_SUART_1,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_2,
+                .end    = OMAPL138_INT_PRU_SUART_2,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_3,
+                .end    = OMAPL138_INT_PRU_SUART_3,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_4,
+                .end    = OMAPL138_INT_PRU_SUART_4,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_5,
+                .end    = OMAPL138_INT_PRU_SUART_5,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_6,
+                .end    = OMAPL138_INT_PRU_SUART_6,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_7,
+                .end    = OMAPL138_INT_PRU_SUART_7,
+                .flags  = IORESOURCE_IRQ,
+        },
+        {
+                .start  = OMAPL138_INT_PRU_SUART_8,
+                .end    = OMAPL138_INT_PRU_SUART_8,
+                .flags  = IORESOURCE_IRQ,
+        },
+};
+
+struct platform_device omapl_pru_suart_device = {
+    .name   = "ti_omapl_pru_suart",
+    .id             = 1,
+    .num_resources  = ARRAY_SIZE(omapl138_pru_suart_resources),
+    .resource       = omapl138_pru_suart_resources,
+};
+
+#define OMAPL138_PRU_SUART_VERSION           1
+
+static struct ti_pru_suart_platform_data ti_pru_suart_pdata = {
+        .version                = OMAPL138_PRU_SUART_VERSION,
+};
+
+int __init da8xx_register_pru_suart(void)
+{
+        omapl_pru_suart_device.dev.platform_data = &ti_pru_suart_pdata;
+        return platform_device_register(&omapl_pru_suart_device);
+}

4.添加声明
arch/arm/mach-davinci/include/mach/da8xx.h
+int da8xx_register_pru_suart(void);
 int da8xx_register_lcdc(struct da8xx_lcdc_platform_data *pdata);

+extern const short da850_pru_suart_pins[];
 extern const short da850_mcasp_pins[];

5.
arch/arm/mach-davinci/include/mach/memory.h
 #define DAVINCI_DDR_BASE       0x80000000
 #define DA8XX_DDR_BASE         0xc0000000
+#define DA8XX_SHARED_RAM_BASE 0x80000000

6.平台注册
arch/arm/mach-davinci/board-omapl138-hawk.c
1).
+static int __init da850_evm_config_pru_suart(void)
+{
+    int ret;
+
+    if (!machine_is_davinci_da850_evm())
+        return 0;
+
+    ret = da8xx_pinmux_setup(da850_pru_suart_pins);
+    if (ret)
+        pr_warning("da850_evm_init: da850_pru_suart_pins mux setup failed: %d\n",
+                ret);
+
+    ret = da8xx_register_pru_suart();
+    if (ret)
+        pr_warning("da850_evm_init: pru suart registration failed: %d\n", ret);
+    return ret;
+}

2)omapl138_hawk_init(void)中调用注册函数,首先要屏蔽MCASP的注册函数,否则
资源会出现冲突。
531 /*      if (HAS_MCASP) {
532                 if ((HAS_MCBSP0 || HAS_MCBSP1))
533                         pr_warning("WARNING: both McASP and McBSP are enable    d, "
534                                         "but they share pins.\n"
535                                         "\tDisable one of them.\n");
536
537                 ret = da8xx_pinmux_setup(da850_mcasp_pins);
538                 if (ret)
539                         pr_warning("hawk_init: mcasp mux setup failed:"
540                                         "%d\n", ret);
541
542                 da8xx_register_mcasp(0, &omapl138_hawk_snd_data);
543         }
544 */
545 //           pru_suart_init
546         omapl138_hawk_config_pru_suart();

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值