diff options
Diffstat (limited to 'drivers/serial/amba-pl010.c')
-rw-r--r-- | drivers/serial/amba-pl010.c | 295 |
1 files changed, 170 insertions, 125 deletions
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index f69bd097166e..1a9a24b82636 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <linux/serial.h> | 48 | #include <linux/serial.h> |
49 | #include <linux/amba/bus.h> | 49 | #include <linux/amba/bus.h> |
50 | #include <linux/amba/serial.h> | 50 | #include <linux/amba/serial.h> |
51 | #include <linux/clk.h> | ||
51 | 52 | ||
52 | #include <asm/io.h> | 53 | #include <asm/io.h> |
53 | 54 | ||
@@ -70,6 +71,7 @@ | |||
70 | */ | 71 | */ |
71 | struct uart_amba_port { | 72 | struct uart_amba_port { |
72 | struct uart_port port; | 73 | struct uart_port port; |
74 | struct clk *clk; | ||
73 | struct amba_device *dev; | 75 | struct amba_device *dev; |
74 | struct amba_pl010_data *data; | 76 | struct amba_pl010_data *data; |
75 | unsigned int old_status; | 77 | unsigned int old_status; |
@@ -77,73 +79,77 @@ struct uart_amba_port { | |||
77 | 79 | ||
78 | static void pl010_stop_tx(struct uart_port *port) | 80 | static void pl010_stop_tx(struct uart_port *port) |
79 | { | 81 | { |
82 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
80 | unsigned int cr; | 83 | unsigned int cr; |
81 | 84 | ||
82 | cr = readb(port->membase + UART010_CR); | 85 | cr = readb(uap->port.membase + UART010_CR); |
83 | cr &= ~UART010_CR_TIE; | 86 | cr &= ~UART010_CR_TIE; |
84 | writel(cr, port->membase + UART010_CR); | 87 | writel(cr, uap->port.membase + UART010_CR); |
85 | } | 88 | } |
86 | 89 | ||
87 | static void pl010_start_tx(struct uart_port *port) | 90 | static void pl010_start_tx(struct uart_port *port) |
88 | { | 91 | { |
92 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
89 | unsigned int cr; | 93 | unsigned int cr; |
90 | 94 | ||
91 | cr = readb(port->membase + UART010_CR); | 95 | cr = readb(uap->port.membase + UART010_CR); |
92 | cr |= UART010_CR_TIE; | 96 | cr |= UART010_CR_TIE; |
93 | writel(cr, port->membase + UART010_CR); | 97 | writel(cr, uap->port.membase + UART010_CR); |
94 | } | 98 | } |
95 | 99 | ||
96 | static void pl010_stop_rx(struct uart_port *port) | 100 | static void pl010_stop_rx(struct uart_port *port) |
97 | { | 101 | { |
102 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
98 | unsigned int cr; | 103 | unsigned int cr; |
99 | 104 | ||
100 | cr = readb(port->membase + UART010_CR); | 105 | cr = readb(uap->port.membase + UART010_CR); |
101 | cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); | 106 | cr &= ~(UART010_CR_RIE | UART010_CR_RTIE); |
102 | writel(cr, port->membase + UART010_CR); | 107 | writel(cr, uap->port.membase + UART010_CR); |
103 | } | 108 | } |
104 | 109 | ||
105 | static void pl010_enable_ms(struct uart_port *port) | 110 | static void pl010_enable_ms(struct uart_port *port) |
106 | { | 111 | { |
112 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
107 | unsigned int cr; | 113 | unsigned int cr; |
108 | 114 | ||
109 | cr = readb(port->membase + UART010_CR); | 115 | cr = readb(uap->port.membase + UART010_CR); |
110 | cr |= UART010_CR_MSIE; | 116 | cr |= UART010_CR_MSIE; |
111 | writel(cr, port->membase + UART010_CR); | 117 | writel(cr, uap->port.membase + UART010_CR); |
112 | } | 118 | } |
113 | 119 | ||
114 | static void pl010_rx_chars(struct uart_port *port) | 120 | static void pl010_rx_chars(struct uart_amba_port *uap) |
115 | { | 121 | { |
116 | struct tty_struct *tty = port->info->tty; | 122 | struct tty_struct *tty = uap->port.info->tty; |
117 | unsigned int status, ch, flag, rsr, max_count = 256; | 123 | unsigned int status, ch, flag, rsr, max_count = 256; |
118 | 124 | ||
119 | status = readb(port->membase + UART01x_FR); | 125 | status = readb(uap->port.membase + UART01x_FR); |
120 | while (UART_RX_DATA(status) && max_count--) { | 126 | while (UART_RX_DATA(status) && max_count--) { |
121 | ch = readb(port->membase + UART01x_DR); | 127 | ch = readb(uap->port.membase + UART01x_DR); |
122 | flag = TTY_NORMAL; | 128 | flag = TTY_NORMAL; |
123 | 129 | ||
124 | port->icount.rx++; | 130 | uap->port.icount.rx++; |
125 | 131 | ||
126 | /* | 132 | /* |
127 | * Note that the error handling code is | 133 | * Note that the error handling code is |
128 | * out of the main execution path | 134 | * out of the main execution path |
129 | */ | 135 | */ |
130 | rsr = readb(port->membase + UART01x_RSR) | UART_DUMMY_RSR_RX; | 136 | rsr = readb(uap->port.membase + UART01x_RSR) | UART_DUMMY_RSR_RX; |
131 | if (unlikely(rsr & UART01x_RSR_ANY)) { | 137 | if (unlikely(rsr & UART01x_RSR_ANY)) { |
132 | writel(0, port->membase + UART01x_ECR); | 138 | writel(0, uap->port.membase + UART01x_ECR); |
133 | 139 | ||
134 | if (rsr & UART01x_RSR_BE) { | 140 | if (rsr & UART01x_RSR_BE) { |
135 | rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); | 141 | rsr &= ~(UART01x_RSR_FE | UART01x_RSR_PE); |
136 | port->icount.brk++; | 142 | uap->port.icount.brk++; |
137 | if (uart_handle_break(port)) | 143 | if (uart_handle_break(&uap->port)) |
138 | goto ignore_char; | 144 | goto ignore_char; |
139 | } else if (rsr & UART01x_RSR_PE) | 145 | } else if (rsr & UART01x_RSR_PE) |
140 | port->icount.parity++; | 146 | uap->port.icount.parity++; |
141 | else if (rsr & UART01x_RSR_FE) | 147 | else if (rsr & UART01x_RSR_FE) |
142 | port->icount.frame++; | 148 | uap->port.icount.frame++; |
143 | if (rsr & UART01x_RSR_OE) | 149 | if (rsr & UART01x_RSR_OE) |
144 | port->icount.overrun++; | 150 | uap->port.icount.overrun++; |
145 | 151 | ||
146 | rsr &= port->read_status_mask; | 152 | rsr &= uap->port.read_status_mask; |
147 | 153 | ||
148 | if (rsr & UART01x_RSR_BE) | 154 | if (rsr & UART01x_RSR_BE) |
149 | flag = TTY_BREAK; | 155 | flag = TTY_BREAK; |
@@ -153,53 +159,52 @@ static void pl010_rx_chars(struct uart_port *port) | |||
153 | flag = TTY_FRAME; | 159 | flag = TTY_FRAME; |
154 | } | 160 | } |
155 | 161 | ||
156 | if (uart_handle_sysrq_char(port, ch)) | 162 | if (uart_handle_sysrq_char(&uap->port, ch)) |
157 | goto ignore_char; | 163 | goto ignore_char; |
158 | 164 | ||
159 | uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag); | 165 | uart_insert_char(&uap->port, rsr, UART01x_RSR_OE, ch, flag); |
160 | 166 | ||
161 | ignore_char: | 167 | ignore_char: |
162 | status = readb(port->membase + UART01x_FR); | 168 | status = readb(uap->port.membase + UART01x_FR); |
163 | } | 169 | } |
164 | tty_flip_buffer_push(tty); | 170 | tty_flip_buffer_push(tty); |
165 | return; | 171 | return; |
166 | } | 172 | } |
167 | 173 | ||
168 | static void pl010_tx_chars(struct uart_port *port) | 174 | static void pl010_tx_chars(struct uart_amba_port *uap) |
169 | { | 175 | { |
170 | struct circ_buf *xmit = &port->info->xmit; | 176 | struct circ_buf *xmit = &uap->port.info->xmit; |
171 | int count; | 177 | int count; |
172 | 178 | ||
173 | if (port->x_char) { | 179 | if (uap->port.x_char) { |
174 | writel(port->x_char, port->membase + UART01x_DR); | 180 | writel(uap->port.x_char, uap->port.membase + UART01x_DR); |
175 | port->icount.tx++; | 181 | uap->port.icount.tx++; |
176 | port->x_char = 0; | 182 | uap->port.x_char = 0; |
177 | return; | 183 | return; |
178 | } | 184 | } |
179 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | 185 | if (uart_circ_empty(xmit) || uart_tx_stopped(&uap->port)) { |
180 | pl010_stop_tx(port); | 186 | pl010_stop_tx(&uap->port); |
181 | return; | 187 | return; |
182 | } | 188 | } |
183 | 189 | ||
184 | count = port->fifosize >> 1; | 190 | count = uap->port.fifosize >> 1; |
185 | do { | 191 | do { |
186 | writel(xmit->buf[xmit->tail], port->membase + UART01x_DR); | 192 | writel(xmit->buf[xmit->tail], uap->port.membase + UART01x_DR); |
187 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | 193 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); |
188 | port->icount.tx++; | 194 | uap->port.icount.tx++; |
189 | if (uart_circ_empty(xmit)) | 195 | if (uart_circ_empty(xmit)) |
190 | break; | 196 | break; |
191 | } while (--count > 0); | 197 | } while (--count > 0); |
192 | 198 | ||
193 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | 199 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) |
194 | uart_write_wakeup(port); | 200 | uart_write_wakeup(&uap->port); |
195 | 201 | ||
196 | if (uart_circ_empty(xmit)) | 202 | if (uart_circ_empty(xmit)) |
197 | pl010_stop_tx(port); | 203 | pl010_stop_tx(&uap->port); |
198 | } | 204 | } |
199 | 205 | ||
200 | static void pl010_modem_status(struct uart_port *port) | 206 | static void pl010_modem_status(struct uart_amba_port *uap) |
201 | { | 207 | { |
202 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
203 | unsigned int status, delta; | 208 | unsigned int status, delta; |
204 | 209 | ||
205 | writel(0, uap->port.membase + UART010_ICR); | 210 | writel(0, uap->port.membase + UART010_ICR); |
@@ -226,47 +231,50 @@ static void pl010_modem_status(struct uart_port *port) | |||
226 | 231 | ||
227 | static irqreturn_t pl010_int(int irq, void *dev_id) | 232 | static irqreturn_t pl010_int(int irq, void *dev_id) |
228 | { | 233 | { |
229 | struct uart_port *port = dev_id; | 234 | struct uart_amba_port *uap = dev_id; |
230 | unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; | 235 | unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; |
231 | int handled = 0; | 236 | int handled = 0; |
232 | 237 | ||
233 | spin_lock(&port->lock); | 238 | spin_lock(&uap->port.lock); |
234 | 239 | ||
235 | status = readb(port->membase + UART010_IIR); | 240 | status = readb(uap->port.membase + UART010_IIR); |
236 | if (status) { | 241 | if (status) { |
237 | do { | 242 | do { |
238 | if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) | 243 | if (status & (UART010_IIR_RTIS | UART010_IIR_RIS)) |
239 | pl010_rx_chars(port); | 244 | pl010_rx_chars(uap); |
240 | if (status & UART010_IIR_MIS) | 245 | if (status & UART010_IIR_MIS) |
241 | pl010_modem_status(port); | 246 | pl010_modem_status(uap); |
242 | if (status & UART010_IIR_TIS) | 247 | if (status & UART010_IIR_TIS) |
243 | pl010_tx_chars(port); | 248 | pl010_tx_chars(uap); |
244 | 249 | ||
245 | if (pass_counter-- == 0) | 250 | if (pass_counter-- == 0) |
246 | break; | 251 | break; |
247 | 252 | ||
248 | status = readb(port->membase + UART010_IIR); | 253 | status = readb(uap->port.membase + UART010_IIR); |
249 | } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | | 254 | } while (status & (UART010_IIR_RTIS | UART010_IIR_RIS | |
250 | UART010_IIR_TIS)); | 255 | UART010_IIR_TIS)); |
251 | handled = 1; | 256 | handled = 1; |
252 | } | 257 | } |
253 | 258 | ||
254 | spin_unlock(&port->lock); | 259 | spin_unlock(&uap->port.lock); |
255 | 260 | ||
256 | return IRQ_RETVAL(handled); | 261 | return IRQ_RETVAL(handled); |
257 | } | 262 | } |
258 | 263 | ||
259 | static unsigned int pl010_tx_empty(struct uart_port *port) | 264 | static unsigned int pl010_tx_empty(struct uart_port *port) |
260 | { | 265 | { |
261 | return readb(port->membase + UART01x_FR) & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; | 266 | struct uart_amba_port *uap = (struct uart_amba_port *)port; |
267 | unsigned int status = readb(uap->port.membase + UART01x_FR); | ||
268 | return status & UART01x_FR_BUSY ? 0 : TIOCSER_TEMT; | ||
262 | } | 269 | } |
263 | 270 | ||
264 | static unsigned int pl010_get_mctrl(struct uart_port *port) | 271 | static unsigned int pl010_get_mctrl(struct uart_port *port) |
265 | { | 272 | { |
273 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
266 | unsigned int result = 0; | 274 | unsigned int result = 0; |
267 | unsigned int status; | 275 | unsigned int status; |
268 | 276 | ||
269 | status = readb(port->membase + UART01x_FR); | 277 | status = readb(uap->port.membase + UART01x_FR); |
270 | if (status & UART01x_FR_DCD) | 278 | if (status & UART01x_FR_DCD) |
271 | result |= TIOCM_CAR; | 279 | result |= TIOCM_CAR; |
272 | if (status & UART01x_FR_DSR) | 280 | if (status & UART01x_FR_DSR) |
@@ -287,17 +295,18 @@ static void pl010_set_mctrl(struct uart_port *port, unsigned int mctrl) | |||
287 | 295 | ||
288 | static void pl010_break_ctl(struct uart_port *port, int break_state) | 296 | static void pl010_break_ctl(struct uart_port *port, int break_state) |
289 | { | 297 | { |
298 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
290 | unsigned long flags; | 299 | unsigned long flags; |
291 | unsigned int lcr_h; | 300 | unsigned int lcr_h; |
292 | 301 | ||
293 | spin_lock_irqsave(&port->lock, flags); | 302 | spin_lock_irqsave(&uap->port.lock, flags); |
294 | lcr_h = readb(port->membase + UART010_LCRH); | 303 | lcr_h = readb(uap->port.membase + UART010_LCRH); |
295 | if (break_state == -1) | 304 | if (break_state == -1) |
296 | lcr_h |= UART01x_LCRH_BRK; | 305 | lcr_h |= UART01x_LCRH_BRK; |
297 | else | 306 | else |
298 | lcr_h &= ~UART01x_LCRH_BRK; | 307 | lcr_h &= ~UART01x_LCRH_BRK; |
299 | writel(lcr_h, port->membase + UART010_LCRH); | 308 | writel(lcr_h, uap->port.membase + UART010_LCRH); |
300 | spin_unlock_irqrestore(&port->lock, flags); | 309 | spin_unlock_irqrestore(&uap->port.lock, flags); |
301 | } | 310 | } |
302 | 311 | ||
303 | static int pl010_startup(struct uart_port *port) | 312 | static int pl010_startup(struct uart_port *port) |
@@ -306,48 +315,70 @@ static int pl010_startup(struct uart_port *port) | |||
306 | int retval; | 315 | int retval; |
307 | 316 | ||
308 | /* | 317 | /* |
318 | * Try to enable the clock producer. | ||
319 | */ | ||
320 | retval = clk_enable(uap->clk); | ||
321 | if (retval) | ||
322 | goto out; | ||
323 | |||
324 | uap->port.uartclk = clk_get_rate(uap->clk); | ||
325 | |||
326 | /* | ||
309 | * Allocate the IRQ | 327 | * Allocate the IRQ |
310 | */ | 328 | */ |
311 | retval = request_irq(port->irq, pl010_int, 0, "uart-pl010", port); | 329 | retval = request_irq(uap->port.irq, pl010_int, 0, "uart-pl010", uap); |
312 | if (retval) | 330 | if (retval) |
313 | return retval; | 331 | goto clk_dis; |
314 | 332 | ||
315 | /* | 333 | /* |
316 | * initialise the old status of the modem signals | 334 | * initialise the old status of the modem signals |
317 | */ | 335 | */ |
318 | uap->old_status = readb(port->membase + UART01x_FR) & UART01x_FR_MODEM_ANY; | 336 | uap->old_status = readb(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; |
319 | 337 | ||
320 | /* | 338 | /* |
321 | * Finally, enable interrupts | 339 | * Finally, enable interrupts |
322 | */ | 340 | */ |
323 | writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, | 341 | writel(UART01x_CR_UARTEN | UART010_CR_RIE | UART010_CR_RTIE, |
324 | port->membase + UART010_CR); | 342 | uap->port.membase + UART010_CR); |
325 | 343 | ||
326 | return 0; | 344 | return 0; |
345 | |||
346 | clk_dis: | ||
347 | clk_disable(uap->clk); | ||
348 | out: | ||
349 | return retval; | ||
327 | } | 350 | } |
328 | 351 | ||
329 | static void pl010_shutdown(struct uart_port *port) | 352 | static void pl010_shutdown(struct uart_port *port) |
330 | { | 353 | { |
354 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
355 | |||
331 | /* | 356 | /* |
332 | * Free the interrupt | 357 | * Free the interrupt |
333 | */ | 358 | */ |
334 | free_irq(port->irq, port); | 359 | free_irq(uap->port.irq, uap); |
335 | 360 | ||
336 | /* | 361 | /* |
337 | * disable all interrupts, disable the port | 362 | * disable all interrupts, disable the port |
338 | */ | 363 | */ |
339 | writel(0, port->membase + UART010_CR); | 364 | writel(0, uap->port.membase + UART010_CR); |
340 | 365 | ||
341 | /* disable break condition and fifos */ | 366 | /* disable break condition and fifos */ |
342 | writel(readb(port->membase + UART010_LCRH) & | 367 | writel(readb(uap->port.membase + UART010_LCRH) & |
343 | ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), | 368 | ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN), |
344 | port->membase + UART010_LCRH); | 369 | uap->port.membase + UART010_LCRH); |
370 | |||
371 | /* | ||
372 | * Shut down the clock producer | ||
373 | */ | ||
374 | clk_disable(uap->clk); | ||
345 | } | 375 | } |
346 | 376 | ||
347 | static void | 377 | static void |
348 | pl010_set_termios(struct uart_port *port, struct ktermios *termios, | 378 | pl010_set_termios(struct uart_port *port, struct ktermios *termios, |
349 | struct ktermios *old) | 379 | struct ktermios *old) |
350 | { | 380 | { |
381 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
351 | unsigned int lcr_h, old_cr; | 382 | unsigned int lcr_h, old_cr; |
352 | unsigned long flags; | 383 | unsigned long flags; |
353 | unsigned int baud, quot; | 384 | unsigned int baud, quot; |
@@ -355,7 +386,7 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, | |||
355 | /* | 386 | /* |
356 | * Ask the core to calculate the divisor for us. | 387 | * Ask the core to calculate the divisor for us. |
357 | */ | 388 | */ |
358 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); | 389 | baud = uart_get_baud_rate(port, termios, old, 0, uap->port.uartclk/16); |
359 | quot = uart_get_divisor(port, baud); | 390 | quot = uart_get_divisor(port, baud); |
360 | 391 | ||
361 | switch (termios->c_cflag & CSIZE) { | 392 | switch (termios->c_cflag & CSIZE) { |
@@ -379,66 +410,66 @@ pl010_set_termios(struct uart_port *port, struct ktermios *termios, | |||
379 | if (!(termios->c_cflag & PARODD)) | 410 | if (!(termios->c_cflag & PARODD)) |
380 | lcr_h |= UART01x_LCRH_EPS; | 411 | lcr_h |= UART01x_LCRH_EPS; |
381 | } | 412 | } |
382 | if (port->fifosize > 1) | 413 | if (uap->port.fifosize > 1) |
383 | lcr_h |= UART01x_LCRH_FEN; | 414 | lcr_h |= UART01x_LCRH_FEN; |
384 | 415 | ||
385 | spin_lock_irqsave(&port->lock, flags); | 416 | spin_lock_irqsave(&uap->port.lock, flags); |
386 | 417 | ||
387 | /* | 418 | /* |
388 | * Update the per-port timeout. | 419 | * Update the per-port timeout. |
389 | */ | 420 | */ |
390 | uart_update_timeout(port, termios->c_cflag, baud); | 421 | uart_update_timeout(port, termios->c_cflag, baud); |
391 | 422 | ||
392 | port->read_status_mask = UART01x_RSR_OE; | 423 | uap->port.read_status_mask = UART01x_RSR_OE; |
393 | if (termios->c_iflag & INPCK) | 424 | if (termios->c_iflag & INPCK) |
394 | port->read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; | 425 | uap->port.read_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; |
395 | if (termios->c_iflag & (BRKINT | PARMRK)) | 426 | if (termios->c_iflag & (BRKINT | PARMRK)) |
396 | port->read_status_mask |= UART01x_RSR_BE; | 427 | uap->port.read_status_mask |= UART01x_RSR_BE; |
397 | 428 | ||
398 | /* | 429 | /* |
399 | * Characters to ignore | 430 | * Characters to ignore |
400 | */ | 431 | */ |
401 | port->ignore_status_mask = 0; | 432 | uap->port.ignore_status_mask = 0; |
402 | if (termios->c_iflag & IGNPAR) | 433 | if (termios->c_iflag & IGNPAR) |
403 | port->ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; | 434 | uap->port.ignore_status_mask |= UART01x_RSR_FE | UART01x_RSR_PE; |
404 | if (termios->c_iflag & IGNBRK) { | 435 | if (termios->c_iflag & IGNBRK) { |
405 | port->ignore_status_mask |= UART01x_RSR_BE; | 436 | uap->port.ignore_status_mask |= UART01x_RSR_BE; |
406 | /* | 437 | /* |
407 | * If we're ignoring parity and break indicators, | 438 | * If we're ignoring parity and break indicators, |
408 | * ignore overruns too (for real raw support). | 439 | * ignore overruns too (for real raw support). |
409 | */ | 440 | */ |
410 | if (termios->c_iflag & IGNPAR) | 441 | if (termios->c_iflag & IGNPAR) |
411 | port->ignore_status_mask |= UART01x_RSR_OE; | 442 | uap->port.ignore_status_mask |= UART01x_RSR_OE; |
412 | } | 443 | } |
413 | 444 | ||
414 | /* | 445 | /* |
415 | * Ignore all characters if CREAD is not set. | 446 | * Ignore all characters if CREAD is not set. |
416 | */ | 447 | */ |
417 | if ((termios->c_cflag & CREAD) == 0) | 448 | if ((termios->c_cflag & CREAD) == 0) |
418 | port->ignore_status_mask |= UART_DUMMY_RSR_RX; | 449 | uap->port.ignore_status_mask |= UART_DUMMY_RSR_RX; |
419 | 450 | ||
420 | /* first, disable everything */ | 451 | /* first, disable everything */ |
421 | old_cr = readb(port->membase + UART010_CR) & ~UART010_CR_MSIE; | 452 | old_cr = readb(uap->port.membase + UART010_CR) & ~UART010_CR_MSIE; |
422 | 453 | ||
423 | if (UART_ENABLE_MS(port, termios->c_cflag)) | 454 | if (UART_ENABLE_MS(port, termios->c_cflag)) |
424 | old_cr |= UART010_CR_MSIE; | 455 | old_cr |= UART010_CR_MSIE; |
425 | 456 | ||
426 | writel(0, port->membase + UART010_CR); | 457 | writel(0, uap->port.membase + UART010_CR); |
427 | 458 | ||
428 | /* Set baud rate */ | 459 | /* Set baud rate */ |
429 | quot -= 1; | 460 | quot -= 1; |
430 | writel((quot & 0xf00) >> 8, port->membase + UART010_LCRM); | 461 | writel((quot & 0xf00) >> 8, uap->port.membase + UART010_LCRM); |
431 | writel(quot & 0xff, port->membase + UART010_LCRL); | 462 | writel(quot & 0xff, uap->port.membase + UART010_LCRL); |
432 | 463 | ||
433 | /* | 464 | /* |
434 | * ----------v----------v----------v----------v----- | 465 | * ----------v----------v----------v----------v----- |
435 | * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L | 466 | * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L |
436 | * ----------^----------^----------^----------^----- | 467 | * ----------^----------^----------^----------^----- |
437 | */ | 468 | */ |
438 | writel(lcr_h, port->membase + UART010_LCRH); | 469 | writel(lcr_h, uap->port.membase + UART010_LCRH); |
439 | writel(old_cr, port->membase + UART010_CR); | 470 | writel(old_cr, uap->port.membase + UART010_CR); |
440 | 471 | ||
441 | spin_unlock_irqrestore(&port->lock, flags); | 472 | spin_unlock_irqrestore(&uap->port.lock, flags); |
442 | } | 473 | } |
443 | 474 | ||
444 | static const char *pl010_type(struct uart_port *port) | 475 | static const char *pl010_type(struct uart_port *port) |
@@ -514,47 +545,52 @@ static struct uart_amba_port *amba_ports[UART_NR]; | |||
514 | 545 | ||
515 | static void pl010_console_putchar(struct uart_port *port, int ch) | 546 | static void pl010_console_putchar(struct uart_port *port, int ch) |
516 | { | 547 | { |
548 | struct uart_amba_port *uap = (struct uart_amba_port *)port; | ||
517 | unsigned int status; | 549 | unsigned int status; |
518 | 550 | ||
519 | do { | 551 | do { |
520 | status = readb(port->membase + UART01x_FR); | 552 | status = readb(uap->port.membase + UART01x_FR); |
521 | barrier(); | 553 | barrier(); |
522 | } while (!UART_TX_READY(status)); | 554 | } while (!UART_TX_READY(status)); |
523 | writel(ch, port->membase + UART01x_DR); | 555 | writel(ch, uap->port.membase + UART01x_DR); |
524 | } | 556 | } |
525 | 557 | ||
526 | static void | 558 | static void |
527 | pl010_console_write(struct console *co, const char *s, unsigned int count) | 559 | pl010_console_write(struct console *co, const char *s, unsigned int count) |
528 | { | 560 | { |
529 | struct uart_port *port = &amba_ports[co->index]->port; | 561 | struct uart_amba_port *uap = amba_ports[co->index]; |
530 | unsigned int status, old_cr; | 562 | unsigned int status, old_cr; |
531 | 563 | ||
564 | clk_enable(uap->clk); | ||
565 | |||
532 | /* | 566 | /* |
533 | * First save the CR then disable the interrupts | 567 | * First save the CR then disable the interrupts |
534 | */ | 568 | */ |
535 | old_cr = readb(port->membase + UART010_CR); | 569 | old_cr = readb(uap->port.membase + UART010_CR); |
536 | writel(UART01x_CR_UARTEN, port->membase + UART010_CR); | 570 | writel(UART01x_CR_UARTEN, uap->port.membase + UART010_CR); |
537 | 571 | ||
538 | uart_console_write(port, s, count, pl010_console_putchar); | 572 | uart_console_write(&uap->port, s, count, pl010_console_putchar); |
539 | 573 | ||
540 | /* | 574 | /* |
541 | * Finally, wait for transmitter to become empty | 575 | * Finally, wait for transmitter to become empty |
542 | * and restore the TCR | 576 | * and restore the TCR |
543 | */ | 577 | */ |
544 | do { | 578 | do { |
545 | status = readb(port->membase + UART01x_FR); | 579 | status = readb(uap->port.membase + UART01x_FR); |
546 | barrier(); | 580 | barrier(); |
547 | } while (status & UART01x_FR_BUSY); | 581 | } while (status & UART01x_FR_BUSY); |
548 | writel(old_cr, port->membase + UART010_CR); | 582 | writel(old_cr, uap->port.membase + UART010_CR); |
583 | |||
584 | clk_disable(uap->clk); | ||
549 | } | 585 | } |
550 | 586 | ||
551 | static void __init | 587 | static void __init |
552 | pl010_console_get_options(struct uart_port *port, int *baud, | 588 | pl010_console_get_options(struct uart_amba_port *uap, int *baud, |
553 | int *parity, int *bits) | 589 | int *parity, int *bits) |
554 | { | 590 | { |
555 | if (readb(port->membase + UART010_CR) & UART01x_CR_UARTEN) { | 591 | if (readb(uap->port.membase + UART010_CR) & UART01x_CR_UARTEN) { |
556 | unsigned int lcr_h, quot; | 592 | unsigned int lcr_h, quot; |
557 | lcr_h = readb(port->membase + UART010_LCRH); | 593 | lcr_h = readb(uap->port.membase + UART010_LCRH); |
558 | 594 | ||
559 | *parity = 'n'; | 595 | *parity = 'n'; |
560 | if (lcr_h & UART01x_LCRH_PEN) { | 596 | if (lcr_h & UART01x_LCRH_PEN) { |
@@ -569,14 +605,15 @@ pl010_console_get_options(struct uart_port *port, int *baud, | |||
569 | else | 605 | else |
570 | *bits = 8; | 606 | *bits = 8; |
571 | 607 | ||
572 | quot = readb(port->membase + UART010_LCRL) | readb(port->membase + UART010_LCRM) << 8; | 608 | quot = readb(uap->port.membase + UART010_LCRL) | |
573 | *baud = port->uartclk / (16 * (quot + 1)); | 609 | readb(uap->port.membase + UART010_LCRM) << 8; |
610 | *baud = uap->port.uartclk / (16 * (quot + 1)); | ||
574 | } | 611 | } |
575 | } | 612 | } |
576 | 613 | ||
577 | static int __init pl010_console_setup(struct console *co, char *options) | 614 | static int __init pl010_console_setup(struct console *co, char *options) |
578 | { | 615 | { |
579 | struct uart_port *port; | 616 | struct uart_amba_port *uap; |
580 | int baud = 38400; | 617 | int baud = 38400; |
581 | int bits = 8; | 618 | int bits = 8; |
582 | int parity = 'n'; | 619 | int parity = 'n'; |
@@ -589,16 +626,18 @@ static int __init pl010_console_setup(struct console *co, char *options) | |||
589 | */ | 626 | */ |
590 | if (co->index >= UART_NR) | 627 | if (co->index >= UART_NR) |
591 | co->index = 0; | 628 | co->index = 0; |
592 | if (!amba_ports[co->index]) | 629 | uap = amba_ports[co->index]; |
630 | if (!uap) | ||
593 | return -ENODEV; | 631 | return -ENODEV; |
594 | port = &amba_ports[co->index]->port; | 632 | |
633 | uap->port.uartclk = clk_get_rate(uap->clk); | ||
595 | 634 | ||
596 | if (options) | 635 | if (options) |
597 | uart_parse_options(options, &baud, &parity, &bits, &flow); | 636 | uart_parse_options(options, &baud, &parity, &bits, &flow); |
598 | else | 637 | else |
599 | pl010_console_get_options(port, &baud, &parity, &bits); | 638 | pl010_console_get_options(uap, &baud, &parity, &bits); |
600 | 639 | ||
601 | return uart_set_options(port, co, baud, parity, bits, flow); | 640 | return uart_set_options(&uap->port, co, baud, parity, bits, flow); |
602 | } | 641 | } |
603 | 642 | ||
604 | static struct uart_driver amba_reg; | 643 | static struct uart_driver amba_reg; |
@@ -629,7 +668,7 @@ static struct uart_driver amba_reg = { | |||
629 | 668 | ||
630 | static int pl010_probe(struct amba_device *dev, void *id) | 669 | static int pl010_probe(struct amba_device *dev, void *id) |
631 | { | 670 | { |
632 | struct uart_amba_port *port; | 671 | struct uart_amba_port *uap; |
633 | void __iomem *base; | 672 | void __iomem *base; |
634 | int i, ret; | 673 | int i, ret; |
635 | 674 | ||
@@ -642,8 +681,8 @@ static int pl010_probe(struct amba_device *dev, void *id) | |||
642 | goto out; | 681 | goto out; |
643 | } | 682 | } |
644 | 683 | ||
645 | port = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); | 684 | uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL); |
646 | if (!port) { | 685 | if (!uap) { |
647 | ret = -ENOMEM; | 686 | ret = -ENOMEM; |
648 | goto out; | 687 | goto out; |
649 | } | 688 | } |
@@ -654,51 +693,57 @@ static int pl010_probe(struct amba_device *dev, void *id) | |||
654 | goto free; | 693 | goto free; |
655 | } | 694 | } |
656 | 695 | ||
657 | port->port.dev = &dev->dev; | 696 | uap->clk = clk_get(&dev->dev, "UARTCLK"); |
658 | port->port.mapbase = dev->res.start; | 697 | if (IS_ERR(uap->clk)) { |
659 | port->port.membase = base; | 698 | ret = PTR_ERR(uap->clk); |
660 | port->port.iotype = UPIO_MEM; | 699 | goto unmap; |
661 | port->port.irq = dev->irq[0]; | 700 | } |
662 | port->port.uartclk = 14745600; | 701 | |
663 | port->port.fifosize = 16; | 702 | uap->port.dev = &dev->dev; |
664 | port->port.ops = &amba_pl010_pops; | 703 | uap->port.mapbase = dev->res.start; |
665 | port->port.flags = UPF_BOOT_AUTOCONF; | 704 | uap->port.membase = base; |
666 | port->port.line = i; | 705 | uap->port.iotype = UPIO_MEM; |
667 | port->dev = dev; | 706 | uap->port.irq = dev->irq[0]; |
668 | port->data = dev->dev.platform_data; | 707 | uap->port.fifosize = 16; |
669 | 708 | uap->port.ops = &amba_pl010_pops; | |
670 | amba_ports[i] = port; | 709 | uap->port.flags = UPF_BOOT_AUTOCONF; |
671 | 710 | uap->port.line = i; | |
672 | amba_set_drvdata(dev, port); | 711 | uap->dev = dev; |
673 | ret = uart_add_one_port(&amba_reg, &port->port); | 712 | uap->data = dev->dev.platform_data; |
713 | |||
714 | amba_ports[i] = uap; | ||
715 | |||
716 | amba_set_drvdata(dev, uap); | ||
717 | ret = uart_add_one_port(&amba_reg, &uap->port); | ||
674 | if (ret) { | 718 | if (ret) { |
675 | amba_set_drvdata(dev, NULL); | 719 | amba_set_drvdata(dev, NULL); |
676 | amba_ports[i] = NULL; | 720 | amba_ports[i] = NULL; |
721 | clk_put(uap->clk); | ||
722 | unmap: | ||
677 | iounmap(base); | 723 | iounmap(base); |
678 | free: | 724 | free: |
679 | kfree(port); | 725 | kfree(uap); |
680 | } | 726 | } |
681 | |||
682 | out: | 727 | out: |
683 | return ret; | 728 | return ret; |
684 | } | 729 | } |
685 | 730 | ||
686 | static int pl010_remove(struct amba_device *dev) | 731 | static int pl010_remove(struct amba_device *dev) |
687 | { | 732 | { |
688 | struct uart_amba_port *port = amba_get_drvdata(dev); | 733 | struct uart_amba_port *uap = amba_get_drvdata(dev); |
689 | int i; | 734 | int i; |
690 | 735 | ||
691 | amba_set_drvdata(dev, NULL); | 736 | amba_set_drvdata(dev, NULL); |
692 | 737 | ||
693 | uart_remove_one_port(&amba_reg, &port->port); | 738 | uart_remove_one_port(&amba_reg, &uap->port); |
694 | 739 | ||
695 | for (i = 0; i < ARRAY_SIZE(amba_ports); i++) | 740 | for (i = 0; i < ARRAY_SIZE(amba_ports); i++) |
696 | if (amba_ports[i] == port) | 741 | if (amba_ports[i] == uap) |
697 | amba_ports[i] = NULL; | 742 | amba_ports[i] = NULL; |
698 | 743 | ||
699 | iounmap(port->port.membase); | 744 | iounmap(uap->port.membase); |
700 | kfree(port); | 745 | clk_put(uap->clk); |
701 | 746 | kfree(uap); | |
702 | return 0; | 747 | return 0; |
703 | } | 748 | } |
704 | 749 | ||