Blackrose's Blog Blackrose's Blog

imx535串口驱动分析一

in technologyread (17) 文章转载请注明来源!

之前一直觉得驱动很难学,也很难写。这两天一直在看驱动,又觉得驱动有时候比app更好写一些,硬件资源有限时,功能也比较单一,做好突发时的数据处理就可以了,复杂的功能都是由app来完成。从功能上看,app的功能最多,可能要同时对多个设备操作,然后对数据处理后,才能完成一个功能。很多人说培养一个软件工程师需要五年,而培养一个硬件工程师需要十年。硬件工程师的难度大,是因为要把人类的思维抽象成机械流程,尽可能的把所有的事情有限的步骤内完成。而现的软件工程师来看,他所完成的就是人类所思考的,并不需要多少转化。

linux中的驱动,已经把module的思想做的很好了,不用重新写很多东西,代码复用度很高。裸机程序的目的就是驱动硬件,并完成相应app的功能,所以linux驱动的目的也是如此。正是基于这个原因,驱动中有各种理论和skills,但终究是要配置硬件管脚,启动,数据收发等的操作。裸机中的配置寄存器代码和数据处理代码在一起,而驱动是分开来写,所以有device得driver两个结构体,分别存放各自的属性信息。

imx535的串口属于platform_device,所以要注册成platform。同时,硬件资源是放在resource结构中,所以要填充这个结构体。对于物理串口的描述,用uart_port结构来描述。uart_port只描述了基本的信息,所以用uart_mxc_port来包含它,并加入DMA,IRQ,CLK等信息。


 67 typedef struct {
 68     /*!
 69      * The port structure holds all the information about the UART
 70      * port like base address, and so on.
 71      */
 72     struct uart_port port;
 73     /*!
 74      * Flag to determine if the interrupts are muxed.
 75      */
 76     int ints_muxed;
 77     /*!
 78      * Array that holds the receive and master interrupt numbers
 79      * when the interrupts are not muxed.
 80      */
 81     int irqs[2];
 82     /*!
 83      * Flag to determine the DTE/DCE mode.
 84      */
 85     int mode;
 86     /*!
 87      * Flag to hold the IR mode of the port.
 88      */
 89     int ir_mode;
 90     /*!
 91      * Flag to enable/disable the UART port.
 92      */
 93     int enabled;

 94     /*!
 95      * Flag to indicate if we wish to use hardware-driven hardware
 96      * flow control.
 97      */
 98     int hardware_flow;
 99     /*!
100      * Holds the threshold value at which the CTS line is deasserted in
101      * case we use hardware-driven hardware flow control.
102      */
103     unsigned int cts_threshold;
104     /*!
105      * Flag to enable/disable DMA data transfer.
106      */
107     int dma_enabled;
108     /*!
109      * Holds the DMA receive buffer size.
110      */
111     int dma_rxbuf_size;
112     /*!
113      * DMA Receive buffers information
114      */
115     mxc_uart_rxdmamap *rx_dmamap;
116     /*!
117      * DMA RX buffer id
118      */
119     int dma_rxbuf_id;
120     /*!
121      * DMA Transmit buffer virtual address
122      */
123     char *tx_buf;
124     /*!
125      * DMA Transmit buffer physical address
126      */
127     dma_addr_t tx_handle;

128     /*!
129      * Holds the RxFIFO threshold value.
130      */
131     unsigned int rx_threshold;
132     /*!
133      * Holds the TxFIFO threshold value.
134      */
135     unsigned int tx_threshold;
136     /*!
137      * Information whether this is a shared UART
138      */
139     unsigned int shared;
140     /*!
141      * Clock id for UART clock
142      */
143     struct clk *clk;
144     /*!
145      * Information whether RXDMUXSEL must be set or not for IR port
146      */
147     int rxd_mux;
148     int ir_tx_inv;
149     int ir_rx_inv;
150     /*!
151      * DMA ID for transmit
152      */
153     mxc_dma_device_t dma_tx_id;
154     /*!
155      * DMA ID for receive
156      */
157     mxc_dma_device_t dma_rx_id;
158 } uart_mxc_port;

这样,每个物理串口都填充uart_mxc_port结构,描述串口的模式,IO端口映射方式,复用功能,DMA通道等。


 36 static uart_mxc_port mxc_ports[] = {
 37     [0] = {
 38            .port = {
 39             .iotype = SERIAL_IO_MEM,
 40             .fifosize = 32,
 41             .flags = ASYNC_BOOT_AUTOCONF,
 42             .line = 0,
 43             },
 44            .ints_muxed = 1,
 45            .mode = MODE_DCE,
 46            .ir_mode = NO_IRDA,
 47            .enabled = 1,
 48            .cts_threshold = UART1_UCR4_CTSTL,
 49            .dma_enabled = UART1_DMA_ENABLE,
 50            .dma_rxbuf_size = UART1_DMA_RXBUFSIZE,
 51            .rx_threshold = UART1_UFCR_RXTL,
 52            .tx_threshold = UART1_UFCR_TXTL,
 53            .dma_tx_id = MXC_DMA_UART1_TX,
 54            .dma_rx_id = MXC_DMA_UART1_RX,
 55            .rxd_mux = MXC_UART_RXDMUX,
 56            },
.....

SOC把串口集成在芯片中,所以串口要注册在platform_device上


139 static struct resource mxc_uart_resources1[] = {
140 {
141 .start = UART1_BASE_ADDR,
142 .end = UART1_BASE_ADDR + 0x0B5,
143 .flags = IORESOURCE_MEM,
144 },
145 {
146 .start = MXC_INT_UART1,
147 .flags = IORESOURCE_IRQ,
148 },
149 };

151 static struct platform_device mxc_uart_device1 = {
152 .name = "mxcintuart",
153 .id = 0,
154 .num_resources = ARRAY_SIZE(mxc_uart_resources1),
155 .resource = mxc_uart_resources1,
156 .dev = {
157 .platform_data = &mxc_ports[0],
158 },
159 };


上面的代码就是填充platform_device结构,并且把串口寄存器操作地址填充在resource中。
所有的数据都填充好后,就是调用platform_device_register(&mxc_uart_device1)就可以了,但是device会在什么时候来注册呢?所以用arch_initcall(mxc_init_uart)来启动即可。具体的initcall什么时候会调用,有个对应关系

core_initcall(fn) --->.initcall1.init
postcore_initcall(fn) --->.initcall2.init
arch_initcall(fn) --->.initcall3.init
subsys_initcall(fn) --->.initcall4.init
fs_initcall(fn) --->.initcall5.init
device_initcall(fn) --->.initcall6.init
late_initcall(fn) --->.initcall7.init

昨天看到base地址是0x73f00000,这里UART1_BASE_ADDR也是一样,但是在调用platform_device_register前所有的base都减去0x20000000,这样就和datasheet中的地址相同了。IOMUXC中的寄存器映射还是有些差异的。

参考资源
leave - kernel init call

文章二维码

扫描二维码,在手机上阅读!

发表新评论
博客已萌萌哒运行
© 2018 由 Typecho 强力驱动.Theme by Yodu
前篇 后篇
雷姆
拉姆