⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410.c.txt

📁 本源码是对三星S3C24xx系列的UART的驱动程序.
💻 TXT
📖 第 1 页 / 共 5 页
字号:
  1 /*
  2  * linux/drivers/serial/s3c2410.c
  3  *
  4  * Driver for onboard UARTs on the Samsung S3C24XX
  5  *
  6  * Based on drivers/char/serial.c and drivers/char/21285.c
  7  *
  8  * Ben Dooks, (c) 2003-2005 Simtec Electronics
  9  *      http://www.simtec.co.uk/products/SWLINUX/
 10  *
 11  * Changelog:
 12  *
 13  * 22-Jul-2004  BJD  Finished off device rewrite
 14  *
 15  * 21-Jul-2004  BJD  Thanks to <herbet@13thfloor.at> for pointing out
 16  *                   problems with baud rate and loss of IR settings. Update
 17  *                   to add configuration via platform_device structure
 18  *
 19  * 28-Sep-2004  BJD  Re-write for the following items
 20  *                   - S3C2410 and S3C2440 serial support
 21  *                   - Power Management support
 22  *                   - Fix console via IrDA devices
 23  *                   - SysReq (Herbert P?tzl)
 24  *                   - Break character handling (Herbert P?tzl)
 25  *                   - spin-lock initialisation (Dimitry Andric)
 26  *                   - added clock control
 27  *                   - updated init code to use platform_device info
 28  *
 29  * 06-Mar-2005  BJD  Add s3c2440 fclk clock source
 30  *
 31  * 09-Mar-2005  BJD  Add s3c2400 support
 32  *
 33  * 10-Mar-2005  LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
 34 */
 35 
 36 /* Note on 2440 fclk clock source handling
 37  *
 38  * Whilst it is possible to use the fclk as clock source, the method
 39  * of properly switching too/from this is currently un-implemented, so
 40  * whichever way is configured at startup is the one that will be used.
 41 */
 42 
 43 /* Hote on 2410 error handling
 44  *
 45  * The s3c2410 manual has a love/hate affair with the contents of the
 46  * UERSTAT register in the UART blocks, and keeps marking some of the
 47  * error bits as reserved. Having checked with the s3c2410x01,
 48  * it copes with BREAKs properly, so I am happy to ignore the RESERVED
 49  * feature from the latter versions of the manual.
 50  *
 51  * If it becomes aparrent that latter versions of the 2410 remove these
 52  * bits, then action will have to be taken to differentiate the versions
 53  * and change the policy on BREAK
 54  *
 55  * BJD, 04-Nov-2004
 56 */
 57 
 58 #include <linux/config.h>
 59 
 60 #if defined(CONFIG_SERIAL_S3C2410_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 61 #define SUPPORT_SYSRQ
 62 #endif
 63 
 64 #include <linux/module.h>
 65 #include <linux/ioport.h>
 66 #include <linux/platform_device.h>
 67 #include <linux/init.h>
 68 #include <linux/sysrq.h>
 69 #include <linux/console.h>
 70 #include <linux/tty.h>
 71 #include <linux/tty_flip.h>
 72 #include <linux/serial_core.h>
 73 #include <linux/serial.h>
 74 #include <linux/delay.h>
 75 #include <linux/clk.h>
 76 
 77 #include <asm/io.h>
 78 #include <asm/irq.h>
 79 
 80 #include <asm/hardware.h>
 81 
 82 #include <asm/arch/regs-serial.h>
 83 #include <asm/arch/regs-gpio.h>
 84 
 85 /* structures */
 86 
 87 struct s3c24xx_uart_info {
 88         char                    *name;
 89         unsigned int            type;
 90         unsigned int            fifosize;
 91         unsigned long           rx_fifomask;
 92         unsigned long           rx_fifoshift;
 93         unsigned long           rx_fifofull;
 94         unsigned long           tx_fifomask;
 95         unsigned long           tx_fifoshift;
 96         unsigned long           tx_fifofull;
 97 
 98         /* clock source control */
 99 
100         int (*get_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
101         int (*set_clksrc)(struct uart_port *, struct s3c24xx_uart_clksrc *clk);
102 
103         /* uart controls */
104         int (*reset_port)(struct uart_port *, struct s3c2410_uartcfg *);
105 };
106 
107 struct s3c24xx_uart_port {
108         unsigned char                   rx_claimed;
109         unsigned char                   tx_claimed;
110 
111         struct s3c24xx_uart_info        *info;
112         struct s3c24xx_uart_clksrc      *clksrc;
113         struct clk                      *clk;
114         struct clk                      *baudclk;
115         struct uart_port                port;
116 };
117 
118 
119 /* configuration defines */
120 
121 #if 0
122 #if 1
123 /* send debug to the low-level output routines */
124 
125 extern void printascii(const char *);
126 
127 static void
128 s3c24xx_serial_dbg(const char *fmt, ...)
129 {
130         va_list va;
131         char buff[256];
132 
133         va_start(va, fmt);
134         vsprintf(buff, fmt, va);
135         va_end(va);
136 
137         printascii(buff);
138 }
139 
140 #define dbg(x...) s3c24xx_serial_dbg(x)
141 
142 #else
143 #define dbg(x...) printk(KERN_DEBUG "s3c24xx: ");
144 #endif
145 #else /* no debug */
146 #define dbg(x...) do {} while(0)
147 #endif
148 
149 /* UART name and device definitions */
150 
151 #define S3C24XX_SERIAL_NAME     "ttySAC"
152 #define S3C24XX_SERIAL_DEVFS    "tts/"
153 #define S3C24XX_SERIAL_MAJOR    204
154 #define S3C24XX_SERIAL_MINOR    64
155 
156 
157 /* conversion functions */
158 
159 #define s3c24xx_dev_to_port(__dev) (struct uart_port *)dev_get_drvdata(__dev)
160 #define s3c24xx_dev_to_cfg(__dev) (struct s3c2410_uartcfg *)((__dev)->platform_data)
161 
162 /* we can support 3 uarts, but not always use them */
163 
164 #ifdef CONFIG_CPU_S3C2400
165 #define NR_PORTS (2)
166 #else
167 #define NR_PORTS (3)
168 #endif
169 
170 /* port irq numbers */
171 
172 #define TX_IRQ(port) ((port)->irq + 1)
173 #define RX_IRQ(port) ((port)->irq)
174 
175 /* register access controls */
176 
177 #define portaddr(port, reg) ((port)->membase + (reg))
178 
179 #define rd_regb(port, reg) (__raw_readb(portaddr(port, reg)))
180 #define rd_regl(port, reg) (__raw_readl(portaddr(port, reg)))
181 
182 #define wr_regb(port, reg, val) \
183   do { __raw_writeb(val, portaddr(port, reg)); } while(0)
184 
185 #define wr_regl(port, reg, val) \
186   do { __raw_writel(val, portaddr(port, reg)); } while(0)
187 
188 /* macros to change one thing to another */
189 
190 #define tx_enabled(port) ((port)->unused[0])
191 #define rx_enabled(port) ((port)->unused[1])
192 
193 /* flag to ignore all characters comming in */
194 #define RXSTAT_DUMMY_READ (0x10000000)
195 
196 static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
197 {
198         return container_of(port, struct s3c24xx_uart_port, port);
199 }
200 
201 /* translate a port to the device name */
202 
203 static inline const char *s3c24xx_serial_portname(struct uart_port *port)
204 {
205         return to_platform_device(port->dev)->name;
206 }
207 
208 static int s3c24xx_serial_txempty_nofifo(struct uart_port *port)
209 {
210         return (rd_regl(port, S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXE);
211 }
212 
213 static void s3c24xx_serial_rx_enable(struct uart_port *port)
214 {
215         unsigned long flags;
216         unsigned int ucon, ufcon;
217         int count = 10000;
218 
219         spin_lock_irqsave(&port->lock, flags);
220 
221         while (--count && !s3c24xx_serial_txempty_nofifo(port))
222                 udelay(100);
223 
224         ufcon = rd_regl(port, S3C2410_UFCON);
225         ufcon |= S3C2410_UFCON_RESETRX;
226         wr_regl(port, S3C2410_UFCON, ufcon);
227 
228         ucon = rd_regl(port, S3C2410_UCON);
229         ucon |= S3C2410_UCON_RXIRQMODE;
230         wr_regl(port, S3C2410_UCON, ucon);
231 
232         rx_enabled(port) = 1;
233         spin_unlock_irqrestore(&port->lock, flags);
234 }
235 
236 static void s3c24xx_serial_rx_disable(struct uart_port *port)
237 {
238         unsigned long flags;
239         unsigned int ucon;
240 
241         spin_lock_irqsave(&port->lock, flags);
242 
243         ucon = rd_regl(port, S3C2410_UCON);
244         ucon &= ~S3C2410_UCON_RXIRQMODE;
245         wr_regl(port, S3C2410_UCON, ucon);
246 
247         rx_enabled(port) = 0;
248         spin_unlock_irqrestore(&port->lock, flags);
249 }
250 
251 static void s3c24xx_serial_stop_tx(struct uart_port *port)
252 {
253         if (tx_enabled(port)) {
254                 disable_irq(TX_IRQ(port));
255                 tx_enabled(port) = 0;
256                 if (port->flags & UPF_CONS_FLOW)
257                         s3c24xx_serial_rx_enable(port);
258         }
259 }
260 
261 static void s3c24xx_serial_start_tx(struct uart_port *port)
262 {
263         if (!tx_enabled(port)) {
264                 if (port->flags & UPF_CONS_FLOW)
265                         s3c24xx_serial_rx_disable(port);
266 
267                 enable_irq(TX_IRQ(port));
268                 tx_enabled(port) = 1;
269         }
270 }
271 
272 
273 static void s3c24xx_serial_stop_rx(struct uart_port *port)
274 {
275         if (rx_enabled(port)) {
276                 dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
277                 disable_irq(RX_IRQ(port));
278                 rx_enabled(port) = 0;
279         }
280 }
281 
282 static void s3c24xx_serial_enable_ms(struct uart_port *port)
283 {
284 }
285 
286 static inline struct s3c24xx_uart_info *s3c24xx_port_to_info(struct uart_port *port)
287 {
288         return to_ourport(port)->info;
289 }
290 
291 static inline struct s3c2410_uartcfg *s3c24xx_port_to_cfg(struct uart_port *port)
292 {
293         if (port->dev == NULL)
294                 return NULL;
295 
296         return (struct s3c2410_uartcfg *)port->dev->platform_data;
297 }
298 
299 static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
300                                      unsigned long ufstat)
301 {
302         struct s3c24xx_uart_info *info = ourport->info;
303 
304         if (ufstat & info->rx_fifofull)
305                 return info->fifosize;
306 
307         return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
308 }
309 
310 
311 /* ? - where has parity gone?? */
312 #define S3C2410_UERSTAT_PARITY (0x1000)
313 
314 static irqreturn_t
315 s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
316 {
317         struct s3c24xx_uart_port *ourport = dev_id;
318         struct uart_port *port = &ourport->port;
319         struct tty_struct *tty = port->info->tty;
320         unsigned int ufcon, ch, flag, ufstat, uerstat;
321         int max_count = 64;
322 
323         while (max_count-- > 0) {
324                 ufcon = rd_regl(port, S3C2410_UFCON);
325                 ufstat = rd_regl(port, S3C2410_UFSTAT);
326 
327                 if (s3c24xx_serial_rx_fifocnt(ourport, ufstat) == 0)
328                         break;
329 
330                 uerstat = rd_regl(port, S3C2410_UERSTAT);
331                 ch = rd_regb(port, S3C2410_URXH);
332 
333                 if (port->flags & UPF_CONS_FLOW) {
334                         int txe = s3c24xx_serial_txempty_nofifo(port);
335 
336                         if (rx_enabled(port)) {
337                                 if (!txe) {
338                                         rx_enabled(port) = 0;
339                                         continue;
340                                 }
341                         } else {
342                                 if (txe) {
343                                         ufcon |= S3C2410_UFCON_RESETRX;
344                                         wr_regl(port, S3C2410_UFCON, ufcon);
345                                         rx_enabled(port) = 1;
346                                         goto out;
347                                 }
348                                 continue;
349                         }
350                 }
351 
352                 /* insert the character into the buffer */
353 
354                 flag = TTY_NORMAL;
355                 port->icount.rx++;
356 
357                 if (unlikely(uerstat & S3C2410_UERSTAT_ANY)) {
358                         dbg("rxerr: port ch=0x%02x, rxs=0x%08x\n",
359                             ch, uerstat);
360 
361                         /* check for break */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -