2 * (INCA) ASC UART support
7 #include <asm/inca-ip.h>
9 #include <linux/compiler.h>
10 #include "asc_serial.h"
13 #define SET_BIT(reg, mask) reg |= (mask)
14 #define CLEAR_BIT(reg, mask) reg &= (~mask)
15 #define CLEAR_BITS(reg, mask) CLEAR_BIT(reg, mask)
16 #define SET_BITS(reg, mask) SET_BIT(reg, mask)
17 #define SET_BITFIELD(reg, mask, off, val) {reg &= (~mask); reg |= (val << off);}
19 extern uint incaip_get_fpiclk(void);
21 static int serial_setopt (void);
23 /* pointer to ASC register base address */
24 static volatile incaAsc_t *pAsc = (incaAsc_t *)INCA_IP_ASC;
26 /******************************************************************************
28 * serial_init - initialize a INCAASC channel
30 * This routine initializes the number of data bits, parity
31 * and set the selected baud rate. Interrupts are disabled.
32 * Set the modem control signals if the option is selected.
37 static int asc_serial_init(void)
39 /* we have to set PMU.EN13 bit to enable an ASC device*/
40 INCAASC_PMU_ENABLE(13);
42 /* and we have to set CLC register*/
43 CLEAR_BIT(pAsc->asc_clc, ASCCLC_DISS);
44 SET_BITFIELD(pAsc->asc_clc, ASCCLC_RMCMASK, ASCCLC_RMCOFFSET, 0x0001);
46 /* initialy we are in async mode */
47 pAsc->asc_con = ASCCON_M_8ASYNC;
49 /* select input port */
50 pAsc->asc_pisel = (CONSOLE_TTY & 0x1);
52 /* TXFIFO's filling level */
53 SET_BITFIELD(pAsc->asc_txfcon, ASCTXFCON_TXFITLMASK,
54 ASCTXFCON_TXFITLOFF, INCAASC_TXFIFO_FL);
56 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXFEN);
58 /* RXFIFO's filling level */
59 SET_BITFIELD(pAsc->asc_txfcon, ASCRXFCON_RXFITLMASK,
60 ASCRXFCON_RXFITLOFF, INCAASC_RXFIFO_FL);
62 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXFEN);
64 /* enable error signals */
65 SET_BIT(pAsc->asc_con, ASCCON_FEN);
66 SET_BIT(pAsc->asc_con, ASCCON_OEN);
68 /* acknowledge ASC interrupts */
69 ASC_INTERRUPTS_CLEAR(INCAASC_IRQ_LINE_ALL);
71 /* disable ASC interrupts */
72 ASC_INTERRUPTS_DISABLE(INCAASC_IRQ_LINE_ALL);
74 /* set FIFOs into the transparent mode */
75 SET_BIT(pAsc->asc_txfcon, ASCTXFCON_TXTMEN);
76 SET_BIT(pAsc->asc_rxfcon, ASCRXFCON_RXTMEN);
87 static void asc_serial_setbrg(void)
89 ulong uiReloadValue, fdv;
92 f_ASC = incaip_get_fpiclk();
94 #ifndef INCAASC_USE_FDV
96 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
98 fdv = INCAASC_FDV_HIGH_BAUDRATE;
99 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
100 #endif /* INCAASC_USE_FDV */
102 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
104 #ifndef INCAASC_USE_FDV
106 uiReloadValue = (f_ASC / (fdv * 16 * CONFIG_BAUDRATE)) - 1;
108 fdv = INCAASC_FDV_LOW_BAUDRATE;
109 uiReloadValue = (f_ASC / (8192 * CONFIG_BAUDRATE / fdv)) - 1;
110 #endif /* INCAASC_USE_FDV */
112 if ( (uiReloadValue < 0) || (uiReloadValue > 8191) )
114 return; /* can't impossibly generate that baud rate */
118 /* Disable Baud Rate Generator; BG should only be written when R=0 */
119 CLEAR_BIT(pAsc->asc_con, ASCCON_R);
121 #ifndef INCAASC_USE_FDV
123 * Disable Fractional Divider (FDE)
124 * Divide clock by reload-value + constant (BRS)
127 CLEAR_BIT(pAsc->asc_con, ASCCON_FDE);
130 CLEAR_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 0 */
132 SET_BIT(pAsc->asc_con, ASCCON_BRS); /* BRS = 1 */
134 #else /* INCAASC_USE_FDV */
136 /* Enable Fractional Divider */
137 SET_BIT(pAsc->asc_con, ASCCON_FDE); /* FDE = 1 */
139 /* Set fractional divider value */
140 pAsc->asc_fdv = fdv & ASCFDV_VALUE_MASK;
142 #endif /* INCAASC_USE_FDV */
144 /* Set reload value in BG */
145 pAsc->asc_bg = uiReloadValue;
147 /* Enable Baud Rate Generator */
148 SET_BIT(pAsc->asc_con, ASCCON_R); /* R = 1 */
151 /*******************************************************************************
153 * serial_setopt - set the serial options
155 * Set the channel operating mode to that specified. Following options
156 * are supported: CREAD, CSIZE, PARENB, and PARODD.
158 * Note, this routine disables the transmitter. The calling routine
159 * may have to re-enable it.
162 * Returns 0 to indicate success, otherwise -1 is returned
165 static int serial_setopt (void)
169 switch ( ASC_OPTIONS & ASCOPT_CSIZE )
173 con = ASCCON_M_7ASYNCPAR; /* 7-bit-data and parity bit */
178 if ( ASC_OPTIONS & ASCOPT_PARENB )
179 con = ASCCON_M_8ASYNCPAR; /* 8-bit-data and parity bit */
181 con = ASCCON_M_8ASYNC; /* 8-bit-data no parity */
185 * only 7 and 8-bit frames are supported
186 * if we don't use IOCTL extensions
192 if ( ASC_OPTIONS & ASCOPT_STOPB )
193 SET_BIT(con, ASCCON_STP); /* 2 stop bits */
195 CLEAR_BIT(con, ASCCON_STP); /* 1 stop bit */
197 if ( ASC_OPTIONS & ASCOPT_PARENB )
198 SET_BIT(con, ASCCON_PEN); /* enable parity checking */
200 CLEAR_BIT(con, ASCCON_PEN); /* disable parity checking */
202 if ( ASC_OPTIONS & ASCOPT_PARODD )
203 SET_BIT(con, ASCCON_ODD); /* odd parity */
205 CLEAR_BIT(con, ASCCON_ODD); /* even parity */
207 if ( ASC_OPTIONS & ASCOPT_CREAD )
208 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_SETREN); /* Receiver enable */
210 pAsc->asc_con |= con;
215 static void asc_serial_putc(const char c)
219 if (c == '\n') serial_putc ('\r');
221 /* check do we have a free space in the TX FIFO */
222 /* get current filling level */
225 txFl = ( pAsc->asc_fstat & ASCFSTAT_TXFFLMASK ) >> ASCFSTAT_TXFFLOFF;
227 while ( txFl == INCAASC_TXFIFO_FULL );
229 pAsc->asc_tbuf = c; /* write char to Transmit Buffer Register */
231 /* check for errors */
232 if ( pAsc->asc_con & ASCCON_OE )
234 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
239 static int asc_serial_getc(void)
244 while (!serial_tstc());
247 ((ASC_OPTIONS & ASCOPT_CSIZE) == ASCOPT_CS7) ? (0x7f) : (0xff);
249 c = (char)(pAsc->asc_rbuf & symbol_mask);
254 static int asc_serial_tstc(void)
258 if ( (pAsc->asc_fstat & ASCFSTAT_RXFFLMASK) == 0 )
262 else if ( pAsc->asc_con & ASCCON_FE )
264 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRFE);
267 else if ( pAsc->asc_con & ASCCON_PE )
269 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLRPE);
272 else if ( pAsc->asc_con & ASCCON_OE )
274 SET_BIT(pAsc->asc_whbcon, ASCWHBCON_CLROE);
281 static struct serial_device asc_serial_drv = {
282 .name = "asc_serial",
283 .start = asc_serial_init,
285 .setbrg = asc_serial_setbrg,
286 .putc = asc_serial_putc,
287 .puts = default_serial_puts,
288 .getc = asc_serial_getc,
289 .tstc = asc_serial_tstc,
292 void asc_serial_initialize(void)
294 serial_register(&asc_serial_drv);
297 __weak struct serial_device *default_serial_console(void)
299 return &asc_serial_drv;