uart_dev_pl011.c revision 248965
1239919Sgonzo/*-
2239919Sgonzo * Copyright (c) 2012 Semihalf.
3239919Sgonzo * All rights reserved.
4239919Sgonzo *
5239919Sgonzo * Redistribution and use in source and binary forms, with or without
6239919Sgonzo * modification, are permitted provided that the following conditions
7239919Sgonzo * are met:
8239919Sgonzo * 1. Redistributions of source code must retain the above copyright
9239919Sgonzo *    notice, this list of conditions and the following disclaimer.
10239919Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11239919Sgonzo *    notice, this list of conditions and the following disclaimer in the
12239919Sgonzo *    documentation and/or other materials provided with the distribution.
13239919Sgonzo *
14239919Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15239919Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16239919Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17239919Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18239919Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19239919Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20239919Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21239919Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22239919Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23239919Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24239919Sgonzo * SUCH DAMAGE.
25239919Sgonzo */
26239919Sgonzo
27239919Sgonzo#include <sys/cdefs.h>
28239919Sgonzo__FBSDID("$FreeBSD: head/sys/dev/uart/uart_dev_pl011.c 248965 2013-04-01 00:44:20Z ian $");
29239919Sgonzo
30239919Sgonzo#include <sys/param.h>
31239919Sgonzo#include <sys/systm.h>
32239919Sgonzo#include <sys/kernel.h>
33239919Sgonzo#include <sys/bus.h>
34239919Sgonzo#include <machine/bus.h>
35239919Sgonzo
36239919Sgonzo#include <dev/uart/uart.h>
37239919Sgonzo#include <dev/uart/uart_cpu.h>
38239919Sgonzo#include <dev/uart/uart_bus.h>
39239919Sgonzo#include "uart_if.h"
40239919Sgonzo
41239919Sgonzo#include <sys/kdb.h>
42239919Sgonzo
43239919Sgonzo/* PL011 UART registers and masks*/
44239919Sgonzo#define	UART_DR		0x00		/* Data register */
45239919Sgonzo#define	DR_FE		(1 << 8)	/* Framing error */
46239919Sgonzo#define	DR_PE		(1 << 9)	/* Parity error */
47239919Sgonzo#define	DR_BE		(1 << 10)	/* Break error */
48239919Sgonzo#define	DR_OE		(1 << 11)	/* Overrun error */
49239919Sgonzo
50239919Sgonzo#define	UART_FR		0x06		/* Flag register */
51239919Sgonzo#define	FR_RXFF		(1 << 6)	/* Receive FIFO/reg full */
52239919Sgonzo#define	FR_TXFE		(1 << 7)	/* Transmit FIFO/reg empty */
53239919Sgonzo
54239919Sgonzo#define	UART_IBRD	0x09		/* Integer baud rate register */
55239919Sgonzo#define	IBRD_BDIVINT	0xffff	/* Significant part of int. divisor value */
56239919Sgonzo
57239919Sgonzo#define	UART_FBRD	0x0a		/* Fractional baud rate register */
58239919Sgonzo#define	FBRD_BDIVFRAC	0x3f	/* Significant part of frac. divisor value */
59239919Sgonzo
60239919Sgonzo#define	UART_LCR_H	0x0b		/* Line control register */
61239919Sgonzo#define	LCR_H_WLEN8	(0x3 << 5)
62239919Sgonzo#define	LCR_H_WLEN7	(0x2 << 5)
63239919Sgonzo#define	LCR_H_WLEN6	(0x1 << 5)
64239919Sgonzo#define	LCR_H_FEN	(1 << 4)	/* FIFO mode enable */
65239919Sgonzo#define	LCR_H_STP2	(1 << 3)	/* 2 stop frames at the end */
66239919Sgonzo#define	LCR_H_EPS	(1 << 2)	/* Even parity select */
67239919Sgonzo#define	LCR_H_PEN	(1 << 1)	/* Parity enable */
68239919Sgonzo
69239919Sgonzo#define	UART_CR		0x0c		/* Control register */
70239919Sgonzo#define	CR_RXE		(1 << 9)	/* Receive enable */
71239919Sgonzo#define	CR_TXE		(1 << 8)	/* Transmit enable */
72239919Sgonzo#define	CR_UARTEN	(1 << 0)	/* UART enable */
73239919Sgonzo
74239919Sgonzo#define	UART_IMSC	0x0e		/* Interrupt mask set/clear register */
75239919Sgonzo#define	IMSC_MASK_ALL	0x7ff		/* Mask all interrupts */
76239919Sgonzo
77239919Sgonzo#define	UART_RIS	0x0f		/* Raw interrupt status register */
78239919Sgonzo#define	UART_RXREADY	(1 << 4)	/* RX buffer full */
79239919Sgonzo#define	UART_TXEMPTY	(1 << 5)	/* TX buffer empty */
80239919Sgonzo#define	RIS_FE		(1 << 7)	/* Framing error interrupt status */
81239919Sgonzo#define	RIS_PE		(1 << 8)	/* Parity error interrupt status */
82239919Sgonzo#define	RIS_BE		(1 << 9)	/* Break error interrupt status */
83239919Sgonzo#define	RIS_OE		(1 << 10)	/* Overrun interrupt status */
84239919Sgonzo
85239919Sgonzo#define	UART_MIS	0x10		/* Masked interrupt status register */
86239919Sgonzo#define	UART_ICR	0x11		/* Interrupt clear register */
87239919Sgonzo
88239919Sgonzo/*
89239919Sgonzo * FIXME: actual register size is SoC-dependent, we need to handle it
90239919Sgonzo */
91239919Sgonzo#define	__uart_getreg(bas, reg)		\
92239919Sgonzo	bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg))
93239919Sgonzo#define	__uart_setreg(bas, reg, value)	\
94239919Sgonzo	bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs(bas, reg), value)
95239919Sgonzo
96239919Sgonzo/*
97239919Sgonzo * Low-level UART interface.
98239919Sgonzo */
99239919Sgonzostatic int uart_pl011_probe(struct uart_bas *bas);
100239919Sgonzostatic void uart_pl011_init(struct uart_bas *bas, int, int, int, int);
101239919Sgonzostatic void uart_pl011_term(struct uart_bas *bas);
102239919Sgonzostatic void uart_pl011_putc(struct uart_bas *bas, int);
103239919Sgonzostatic int uart_pl011_rxready(struct uart_bas *bas);
104239919Sgonzostatic int uart_pl011_getc(struct uart_bas *bas, struct mtx *);
105239919Sgonzo
106239919Sgonzostatic struct uart_ops uart_pl011_ops = {
107239919Sgonzo	.probe = uart_pl011_probe,
108239919Sgonzo	.init = uart_pl011_init,
109239919Sgonzo	.term = uart_pl011_term,
110239919Sgonzo	.putc = uart_pl011_putc,
111239919Sgonzo	.rxready = uart_pl011_rxready,
112239919Sgonzo	.getc = uart_pl011_getc,
113239919Sgonzo};
114239919Sgonzo
115239919Sgonzostatic int
116239919Sgonzouart_pl011_probe(struct uart_bas *bas)
117239919Sgonzo{
118239919Sgonzo
119239919Sgonzo	return (0);
120239919Sgonzo}
121239919Sgonzo
122239919Sgonzostatic void
123242333Sgonzouart_pl011_param(struct uart_bas *bas, int baudrate, int databits, int stopbits,
124239919Sgonzo    int parity)
125239919Sgonzo{
126239919Sgonzo	uint32_t ctrl, line;
127239919Sgonzo	uint32_t baud;
128239919Sgonzo
129239919Sgonzo	/*
130239919Sgonzo	 * Zero all settings to make sure
131239919Sgonzo	 * UART is disabled and not configured
132239919Sgonzo	 */
133239919Sgonzo	ctrl = line = 0x0;
134239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
135239919Sgonzo
136239919Sgonzo	/* As we know UART is disabled we may setup the line */
137239919Sgonzo	switch (databits) {
138239919Sgonzo	case 7:
139239919Sgonzo		line |= LCR_H_WLEN7;
140239919Sgonzo		break;
141239919Sgonzo	case 6:
142239919Sgonzo		line |= LCR_H_WLEN6;
143239919Sgonzo		break;
144239919Sgonzo	case 8:
145239919Sgonzo	default:
146239919Sgonzo		line |= LCR_H_WLEN8;
147239919Sgonzo		break;
148239919Sgonzo	}
149239919Sgonzo
150239919Sgonzo	/* TODO: Calculate divisors */
151239919Sgonzo	baud = (0x1 << 16) | 0x28;
152239919Sgonzo
153239919Sgonzo	if (stopbits == 2)
154239919Sgonzo		line |= LCR_H_STP2;
155239919Sgonzo	else
156239919Sgonzo		line &= ~LCR_H_STP2;
157239919Sgonzo
158239919Sgonzo	if (parity)
159239919Sgonzo		line |= LCR_H_PEN;
160239919Sgonzo	else
161239919Sgonzo		line &= ~LCR_H_PEN;
162239919Sgonzo
163239919Sgonzo	/* Configure the rest */
164239919Sgonzo	line &=  ~LCR_H_FEN;
165239919Sgonzo	ctrl |= (CR_RXE | CR_TXE | CR_UARTEN);
166239919Sgonzo
167239919Sgonzo	__uart_setreg(bas, UART_IBRD, ((uint32_t)(baud >> 16)) & IBRD_BDIVINT);
168239919Sgonzo	__uart_setreg(bas, UART_FBRD, (uint32_t)(baud) & FBRD_BDIVFRAC);
169239919Sgonzo
170239919Sgonzo	/* Add config. to line before reenabling UART */
171239919Sgonzo	__uart_setreg(bas, UART_LCR_H, (__uart_getreg(bas, UART_LCR_H) &
172239919Sgonzo	    ~0xff) | line);
173239919Sgonzo
174239919Sgonzo	__uart_setreg(bas, UART_CR, ctrl);
175239919Sgonzo}
176239919Sgonzo
177239919Sgonzostatic void
178242333Sgonzouart_pl011_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
179242333Sgonzo    int parity)
180242333Sgonzo{
181242333Sgonzo	/* Mask all interrupts */
182242333Sgonzo	__uart_setreg(bas, UART_IMSC, __uart_getreg(bas, UART_IMSC) &
183242333Sgonzo	    ~IMSC_MASK_ALL);
184242333Sgonzo
185242333Sgonzo	uart_pl011_param(bas, baudrate, databits, stopbits, parity);
186242333Sgonzo}
187242333Sgonzo
188242333Sgonzostatic void
189239919Sgonzouart_pl011_term(struct uart_bas *bas)
190239919Sgonzo{
191239919Sgonzo}
192239919Sgonzo
193239919Sgonzostatic void
194239919Sgonzouart_pl011_putc(struct uart_bas *bas, int c)
195239919Sgonzo{
196239919Sgonzo
197239919Sgonzo	while (!(__uart_getreg(bas, UART_FR) & FR_TXFE))
198239919Sgonzo		;
199239919Sgonzo	__uart_setreg(bas, UART_DR, c & 0xff);
200239919Sgonzo}
201239919Sgonzo
202239919Sgonzostatic int
203239919Sgonzouart_pl011_rxready(struct uart_bas *bas)
204239919Sgonzo{
205239919Sgonzo
206239919Sgonzo	return (__uart_getreg(bas, UART_FR) & FR_RXFF);
207239919Sgonzo}
208239919Sgonzo
209239919Sgonzostatic int
210239919Sgonzouart_pl011_getc(struct uart_bas *bas, struct mtx *hwmtx)
211239919Sgonzo{
212239919Sgonzo	int c;
213239919Sgonzo
214239919Sgonzo	while (!uart_pl011_rxready(bas))
215239919Sgonzo		;
216239919Sgonzo	c = __uart_getreg(bas, UART_DR) & 0xff;
217239919Sgonzo
218239919Sgonzo	return (c);
219239919Sgonzo}
220239919Sgonzo
221239919Sgonzo/*
222239919Sgonzo * High-level UART interface.
223239919Sgonzo */
224239919Sgonzostruct uart_pl011_softc {
225239919Sgonzo	struct uart_softc base;
226239919Sgonzo	uint8_t		fcr;
227239919Sgonzo	uint8_t		ier;
228239919Sgonzo	uint8_t		mcr;
229239919Sgonzo
230239919Sgonzo	uint8_t		ier_mask;
231239919Sgonzo	uint8_t		ier_rxbits;
232239919Sgonzo};
233239919Sgonzo
234239919Sgonzostatic int uart_pl011_bus_attach(struct uart_softc *);
235239919Sgonzostatic int uart_pl011_bus_detach(struct uart_softc *);
236239919Sgonzostatic int uart_pl011_bus_flush(struct uart_softc *, int);
237239919Sgonzostatic int uart_pl011_bus_getsig(struct uart_softc *);
238239919Sgonzostatic int uart_pl011_bus_ioctl(struct uart_softc *, int, intptr_t);
239239919Sgonzostatic int uart_pl011_bus_ipend(struct uart_softc *);
240239919Sgonzostatic int uart_pl011_bus_param(struct uart_softc *, int, int, int, int);
241239919Sgonzostatic int uart_pl011_bus_probe(struct uart_softc *);
242239919Sgonzostatic int uart_pl011_bus_receive(struct uart_softc *);
243239919Sgonzostatic int uart_pl011_bus_setsig(struct uart_softc *, int);
244239919Sgonzostatic int uart_pl011_bus_transmit(struct uart_softc *);
245239919Sgonzo
246239919Sgonzostatic kobj_method_t uart_pl011_methods[] = {
247239919Sgonzo	KOBJMETHOD(uart_attach,		uart_pl011_bus_attach),
248239919Sgonzo	KOBJMETHOD(uart_detach,		uart_pl011_bus_detach),
249239919Sgonzo	KOBJMETHOD(uart_flush,		uart_pl011_bus_flush),
250239919Sgonzo	KOBJMETHOD(uart_getsig,		uart_pl011_bus_getsig),
251239919Sgonzo	KOBJMETHOD(uart_ioctl,		uart_pl011_bus_ioctl),
252239919Sgonzo	KOBJMETHOD(uart_ipend,		uart_pl011_bus_ipend),
253239919Sgonzo	KOBJMETHOD(uart_param,		uart_pl011_bus_param),
254239919Sgonzo	KOBJMETHOD(uart_probe,		uart_pl011_bus_probe),
255239919Sgonzo	KOBJMETHOD(uart_receive,	uart_pl011_bus_receive),
256239919Sgonzo	KOBJMETHOD(uart_setsig,		uart_pl011_bus_setsig),
257239919Sgonzo	KOBJMETHOD(uart_transmit,	uart_pl011_bus_transmit),
258239919Sgonzo	{ 0, 0 }
259239919Sgonzo};
260239919Sgonzo
261239919Sgonzostruct uart_class uart_pl011_class = {
262239919Sgonzo	"uart_pl011",
263239919Sgonzo	uart_pl011_methods,
264239919Sgonzo	sizeof(struct uart_pl011_softc),
265239919Sgonzo	.uc_ops = &uart_pl011_ops,
266239919Sgonzo	.uc_range = 0x48,
267239919Sgonzo	.uc_rclk = 0
268239919Sgonzo};
269239919Sgonzo
270239919Sgonzostatic int
271239919Sgonzouart_pl011_bus_attach(struct uart_softc *sc)
272239919Sgonzo{
273239919Sgonzo	struct uart_bas *bas;
274239919Sgonzo
275239919Sgonzo	bas = &sc->sc_bas;
276239919Sgonzo	/* Enable RX & TX interrupts */
277239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
278239919Sgonzo	/* Clear RX & TX interrupts */
279239919Sgonzo	__uart_setreg(bas, UART_ICR, IMSC_MASK_ALL);
280239919Sgonzo
281239919Sgonzo	return (0);
282239919Sgonzo}
283239919Sgonzo
284239919Sgonzostatic int
285239919Sgonzouart_pl011_bus_detach(struct uart_softc *sc)
286239919Sgonzo{
287239919Sgonzo
288239919Sgonzo	return (0);
289239919Sgonzo}
290239919Sgonzo
291239919Sgonzostatic int
292239919Sgonzouart_pl011_bus_flush(struct uart_softc *sc, int what)
293239919Sgonzo{
294239919Sgonzo
295239919Sgonzo	return (0);
296239919Sgonzo}
297239919Sgonzo
298239919Sgonzostatic int
299239919Sgonzouart_pl011_bus_getsig(struct uart_softc *sc)
300239919Sgonzo{
301239919Sgonzo
302239919Sgonzo	return (0);
303239919Sgonzo}
304239919Sgonzo
305239919Sgonzostatic int
306239919Sgonzouart_pl011_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
307239919Sgonzo{
308239919Sgonzo	struct uart_bas *bas;
309239919Sgonzo	int error;
310239919Sgonzo
311239919Sgonzo	bas = &sc->sc_bas;
312239919Sgonzo	error = 0;
313239919Sgonzo	uart_lock(sc->sc_hwmtx);
314239919Sgonzo	switch (request) {
315239919Sgonzo	case UART_IOCTL_BREAK:
316239919Sgonzo		break;
317239919Sgonzo	case UART_IOCTL_BAUD:
318239919Sgonzo		*(int*)data = 115200;
319239919Sgonzo		break;
320239919Sgonzo	default:
321239919Sgonzo		error = EINVAL;
322239919Sgonzo		break;
323239919Sgonzo	}
324239919Sgonzo	uart_unlock(sc->sc_hwmtx);
325239919Sgonzo
326239919Sgonzo	return (error);
327239919Sgonzo}
328239919Sgonzo
329239919Sgonzostatic int
330239919Sgonzouart_pl011_bus_ipend(struct uart_softc *sc)
331239919Sgonzo{
332239919Sgonzo	struct uart_bas *bas;
333239919Sgonzo	int ipend;
334239919Sgonzo	uint32_t ints;
335239919Sgonzo
336239919Sgonzo	bas = &sc->sc_bas;
337239919Sgonzo	uart_lock(sc->sc_hwmtx);
338239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
339239919Sgonzo	ipend = 0;
340239919Sgonzo
341239919Sgonzo	if (ints & UART_RXREADY)
342239919Sgonzo		ipend |= SER_INT_RXREADY;
343239919Sgonzo	if (ints & RIS_BE)
344239919Sgonzo		ipend |= SER_INT_BREAK;
345239919Sgonzo	if (ints & RIS_OE)
346239919Sgonzo		ipend |= SER_INT_OVERRUN;
347239919Sgonzo	if (ints & UART_TXEMPTY) {
348239919Sgonzo		if (sc->sc_txbusy)
349239919Sgonzo			ipend |= SER_INT_TXIDLE;
350239919Sgonzo
351239919Sgonzo		__uart_setreg(bas, UART_IMSC, UART_RXREADY);
352239919Sgonzo	}
353239919Sgonzo
354239919Sgonzo	uart_unlock(sc->sc_hwmtx);
355239919Sgonzo
356239919Sgonzo	return (ipend);
357239919Sgonzo}
358239919Sgonzo
359239919Sgonzostatic int
360239919Sgonzouart_pl011_bus_param(struct uart_softc *sc, int baudrate, int databits,
361239919Sgonzo    int stopbits, int parity)
362239919Sgonzo{
363239919Sgonzo
364239919Sgonzo	uart_lock(sc->sc_hwmtx);
365242333Sgonzo	uart_pl011_param(&sc->sc_bas, baudrate, databits, stopbits, parity);
366239919Sgonzo	uart_unlock(sc->sc_hwmtx);
367239919Sgonzo
368239919Sgonzo	return (0);
369239919Sgonzo}
370239919Sgonzo
371239919Sgonzostatic int
372239919Sgonzouart_pl011_bus_probe(struct uart_softc *sc)
373239919Sgonzo{
374239919Sgonzo
375239919Sgonzo	device_set_desc(sc->sc_dev, "PrimeCell UART (PL011)");
376239919Sgonzo
377248965Sian	sc->sc_rxfifosz = 1;
378248965Sian	sc->sc_txfifosz = 1;
379248965Sian
380239919Sgonzo	return (0);
381239919Sgonzo}
382239919Sgonzo
383239919Sgonzostatic int
384239919Sgonzouart_pl011_bus_receive(struct uart_softc *sc)
385239919Sgonzo{
386239919Sgonzo	struct uart_bas *bas;
387239919Sgonzo	int rx;
388239919Sgonzo	uint32_t ints, xc;
389239919Sgonzo
390239919Sgonzo	bas = &sc->sc_bas;
391239919Sgonzo	uart_lock(sc->sc_hwmtx);
392239919Sgonzo
393239919Sgonzo	ints = __uart_getreg(bas, UART_MIS);
394239919Sgonzo	while (ints & UART_RXREADY) {
395239919Sgonzo		if (uart_rx_full(sc)) {
396239919Sgonzo			sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
397239919Sgonzo			break;
398239919Sgonzo		}
399239919Sgonzo		xc = __uart_getreg(bas, UART_DR);
400239919Sgonzo		rx = xc & 0xff;
401239919Sgonzo
402239919Sgonzo		if (xc & DR_FE)
403239919Sgonzo			rx |= UART_STAT_FRAMERR;
404239919Sgonzo		if (xc & DR_PE)
405239919Sgonzo			rx |= UART_STAT_PARERR;
406239919Sgonzo
407239919Sgonzo		__uart_setreg(bas, UART_ICR, UART_RXREADY);
408239919Sgonzo
409239919Sgonzo		uart_rx_put(sc, rx);
410239919Sgonzo		ints = __uart_getreg(bas, UART_MIS);
411239919Sgonzo	}
412239919Sgonzo
413239919Sgonzo	uart_unlock(sc->sc_hwmtx);
414239919Sgonzo
415239919Sgonzo	return (0);
416239919Sgonzo}
417239919Sgonzo
418239919Sgonzostatic int
419239919Sgonzouart_pl011_bus_setsig(struct uart_softc *sc, int sig)
420239919Sgonzo{
421239919Sgonzo
422239919Sgonzo	return (0);
423239919Sgonzo}
424239919Sgonzo
425239919Sgonzostatic int
426239919Sgonzouart_pl011_bus_transmit(struct uart_softc *sc)
427239919Sgonzo{
428239919Sgonzo	struct uart_bas *bas;
429239919Sgonzo	int i;
430239919Sgonzo
431239919Sgonzo	bas = &sc->sc_bas;
432239919Sgonzo	uart_lock(sc->sc_hwmtx);
433239919Sgonzo
434239919Sgonzo	for (i = 0; i < sc->sc_txdatasz; i++) {
435239919Sgonzo		__uart_setreg(bas, UART_DR, sc->sc_txbuf[i]);
436239919Sgonzo		uart_barrier(bas);
437239919Sgonzo	}
438239919Sgonzo	sc->sc_txbusy = 1;
439239919Sgonzo	__uart_setreg(bas, UART_IMSC, (UART_RXREADY | UART_TXEMPTY));
440239919Sgonzo	uart_unlock(sc->sc_hwmtx);
441239919Sgonzo
442239919Sgonzo	return (0);
443239919Sgonzo}
444