| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809 |
- --- /dev/null
- +++ b/drivers/serial/it8712.c
- @@ -0,0 +1,858 @@
- +/*
- + * linux/drivers/char/serial_uart00.c
- + *
- + * Driver for UART00 serial ports
- + *
- + * Based on drivers/char/serial_amba.c, by ARM Limited &
- + * Deep Blue Solutions Ltd.
- + * Copyright 2001 Altera Corporation
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- + *
- + * $Id: it8712.c,v 1.2 2006/06/06 06:36:04 middle Exp $
- + *
- + */
- +#include <linux/module.h>
- +#include <linux/tty.h>
- +#include <linux/ioport.h>
- +#include <linux/init.h>
- +#include <linux/serial.h>
- +#include <linux/console.h>
- +#include <linux/sysrq.h>
- +#include <asm/hardware.h>
- +#include <asm/system.h>
- +#include <asm/io.h>
- +#include <asm/irq.h>
- +#include <asm/uaccess.h>
- +#include <asm/bitops.h>
- +#include <asm/sizes.h>
- +
- +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- +#define SUPPORT_SYSRQ
- +#endif
- +
- +#include <linux/serial_core.h>
- +#include <asm/arch/sl2312.h>
- +#include <asm/arch/int_ctrl.h>
- +#include <asm/arch/it8712.h>
- +#include "it8712.h"
- +
- +//#define DEBUG 1
- +#define UART_NR 1
- +
- +#define SERIAL_IT8712_NAME "ttySI"
- +#define SERIAL_IT8712_MAJOR 204
- +#define SERIAL_IT8712_MINOR 41 /* Temporary - will change in future */
- +#define SERIAL_IT8712_NR UART_NR
- +#define UART_PORT_SIZE 0x50
- +#define LPC_HOST_CONTINUE_MODE 0x00000040
- +
- +#define IT8712_NO_PORTS UART_NR
- +#define IT8712_ISR_PASS_LIMIT 256
- +
- +#define LPC_BUS_CTRL *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
- +#define LPC_BUS_STATUS *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 4))
- +#define LPC_SERIAL_IRQ_CTRL *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 8))
- +#define LPC_SERIAL_IRQ_STATUS *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x0c))
- +#define LPC_SERIAL_IRQ_TRITYPE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x10))
- +#define LPC_SERIAL_IRQ_POLARITY *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x14))
- +#define LPC_SERIAL_IRQ_ENABLE *(unsigned int*)(IO_ADDRESS(SL2312_LPC_HOST_BASE + 0x18))
- +
- +
- +
- +
- +/*
- + * Access macros for the SL2312 UARTs
- + */
- +#define UART_GET_INT_STATUS(p) (inb(((p)->membase+UART_IIR)) & 0x0F) // interrupt identification
- +#define UART_PUT_IER(p, c) outb(c,((p)->membase+UART_IER)) // interrupt enable
- +#define UART_GET_IER(p) inb(((p)->membase+UART_IER))
- +#define UART_PUT_CHAR(p, c) outb(c,((p)->membase+UART_TX)) // transmitter holding
- +#define UART_GET_CHAR(p) inb(((p)->membase+UART_RX)) // receive buffer
- +#define UART_GET_LSR(p) inb(((p)->membase+UART_LSR)) // line status
- +#define UART_GET_MSR(p) inb(((p)->membase+UART_MSR)) // modem status
- +#define UART_GET_MCR(p) inb(((p)->membase+UART_MCR)) // modem control
- +#define UART_PUT_MCR(p, c) outb(c,((p)->membase+UART_MCR))
- +#define UART_GET_LCR(p) inb(((p)->membase+UART_LCR)) // mode control
- +#define UART_PUT_LCR(p, c) outb(c,((p)->membase+UART_LCR))
- +#define UART_PUT_FCR(p, c) outb(c,((p)->membase+UART_FCR)) // fifo control
- +#define UART_GET_DIV_HI(p) inb(((p)->membase+UART_DLM))
- +#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
- +#define UART_GET_DIV_LO(p) inb(((p)->membase+UART_DLL))
- +#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
- +#define UART_PUT_MDR(p, c) outb(c,UART_MDR((p)->membase))
- +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
- +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
- +
- +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
- +{
- + unsigned int reg;
- +
- + //printk("it8712 stop tx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_THRI);
- + UART_PUT_IER(port, reg);
- +}
- +
- +static void it8712_stop_rx(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- + //printk("it8712 stop rx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_RDI);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void it8712_enable_ms(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- + //printk("it8712 enable ms : \n");
- +
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_MSI);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void it8712_rx_chars(struct uart_port *port, struct pt_regs *regs)
- +{
- + struct tty_struct *tty = port->info->tty;
- + unsigned int status, mask, ch, flg, ignored = 0;
- +
- + // printk("it8712_rx_chars : \n");
- + status = UART_GET_LSR(port);
- + while (UART_RX_DATA(status)) {
- +
- + /*
- + * We need to read rds before reading the
- + * character from the fifo
- + */
- + ch = UART_GET_CHAR(port);
- + port->icount.rx++;
- +
- + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + goto ignore_char;
- +
- + flg = TTY_NORMAL;
- +
- + /*
- + * Note that the error handling code is
- + * out of the main execution path
- + */
- +
- + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
- + goto handle_error;
- + if (uart_handle_sysrq_char(port, ch, regs))
- + goto ignore_char;
- +
- + error_return:
- + *tty->flip.flag_buf_ptr++ = flg;
- + *tty->flip.char_buf_ptr++ = ch;
- + tty->flip.count++;
- + ignore_char:
- + status = UART_GET_LSR(port);
- + } // end of while
- +out:
- + tty_flip_buffer_push(tty);
- + return;
- +
- +handle_error:
- + if (status & UART_LSR_BI) {
- + status &= ~(UART_LSR_FE);
- + port->icount.brk++;
- +
- +#ifdef SUPPORT_SYSRQ
- + if (uart_handle_break(port))
- + goto ignore_char;
- +#endif
- + } else if (status & UART_LSR_PE)
- + port->icount.parity++;
- + else if (status & UART_LSR_FE)
- + port->icount.frame++;
- +
- + if (status & UART_LSR_OE)
- + port->icount.overrun++;
- +
- + if (status & port->ignore_status_mask) {
- + if (++ignored > 100)
- + goto out;
- + goto ignore_char;
- + }
- +
- + mask = status & port->read_status_mask;
- +
- + if (mask & UART_LSR_BI)
- + flg = TTY_BREAK;
- + else if (mask & UART_LSR_PE)
- + flg = TTY_PARITY;
- + else if (mask & UART_LSR_FE)
- + flg = TTY_FRAME;
- +
- + if (status & UART_LSR_OE) {
- + /*
- + * CHECK: does overrun affect the current character?
- + * ASSUMPTION: it does not.
- + */
- + *tty->flip.flag_buf_ptr++ = flg;
- + *tty->flip.char_buf_ptr++ = ch;
- + tty->flip.count++;
- + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + goto ignore_char;
- + ch = 0;
- + flg = TTY_OVERRUN;
- + }
- +#ifdef SUPPORT_SYSRQ
- + port->sysrq = 0;
- +#endif
- + goto error_return;
- +}
- +
- +static void it8712_tx_chars(struct uart_port *port)
- +{
- + struct circ_buf *xmit = &port->info->xmit;
- + int count;
- +
- + if (port->x_char) {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, port->x_char);
- + port->icount.tx++;
- + port->x_char = 0;
- +
- + return;
- + }
- + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- + it8712_stop_tx(port, 0);
- + return;
- + }
- +
- + count = port->fifosize >> 1;
- + do {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
- + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- + port->icount.tx++;
- + if (uart_circ_empty(xmit))
- + break;
- + } while (--count > 0);
- +
- + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- + uart_write_wakeup(port);
- +
- + if (uart_circ_empty(xmit))
- + it8712_stop_tx(port, 0);
- +}
- +
- +static void it8712_start_tx(struct uart_port *port, unsigned int tty_start)
- +{
- + unsigned int reg;
- +
- + //printk("it8712 start tx : \n");
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_THRI);
- + UART_PUT_IER(port, reg);
- + it8712_tx_chars(port);
- +}
- +
- +static void it8712_modem_status(struct uart_port *port)
- +{
- + unsigned int status;
- +
- +// printk("it8712 modem status : \n");
- +
- + status = UART_GET_MSR(port);
- +
- + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
- + UART_MSR_TERI | UART_MSR_DDCD)))
- + return;
- +
- + if (status & UART_MSR_DDCD)
- + uart_handle_dcd_change(port, status & UART_MSR_DCD);
- +
- + if (status & UART_MSR_DDSR)
- + port->icount.dsr++;
- +
- + if (status & UART_MSR_DCTS)
- + uart_handle_cts_change(port, status & UART_MSR_CTS);
- +
- + wake_up_interruptible(&port->info->delta_msr_wait);
- +
- +}
- +
- +static irqreturn_t it8712_int(int irq, void *dev_id, struct pt_regs *regs)
- +{
- + struct uart_port *port = dev_id;
- + unsigned int status, pass_counter = 0, data;
- +
- +
- + data = LPC_SERIAL_IRQ_STATUS;
- + if((data&0x10)==0x10)
- + {
- + status = UART_GET_INT_STATUS(port);
- + do {
- +// printk("it8712_int: status %x \n", status);
- + switch(status)
- + {
- + case UART_IIR_RDI:
- + case UART_IIR_RLSI:
- + case UART_IIR_RCTO:
- + it8712_rx_chars(port, regs);
- + break;
- + case UART_IIR_THRI:
- + it8712_tx_chars(port);
- + break;
- + case UART_IIR_MSI:
- + it8712_modem_status(port);
- + break;
- + default:
- + break;
- + }
- + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
- + break;
- +
- + status = UART_GET_INT_STATUS(port);
- + } while (status);
- + }
- +
- + status = 0;
- + status |= (IRQ_LPC_MASK);
- + *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = status;
- +
- + //cnt=0;
- + //do{
- + // data = LPC_SERIAL_IRQ_STATUS;
- + LPC_SERIAL_IRQ_STATUS = data;
- + // cnt++;
- + //}while(data);
- + //if(cnt>2)
- + // printf("it8712_uart_Isr clear LPC_SERIAL_IRQ_STATUS %x \n", cnt);
- + return IRQ_HANDLED;
- +}
- +
- +static u_int it8712_tx_empty(struct uart_port *port)
- +{
- +// printk("it8712 tx empty : \n");
- +
- + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
- +}
- +
- +static u_int it8712_get_mctrl(struct uart_port *port)
- +{
- + unsigned int result = 0;
- + unsigned int status;
- +
- +// printk("it8712 get mctrl : \n");
- +
- + status = UART_GET_MSR(port);
- + if (status & UART_MSR_DCD)
- + result |= TIOCM_CAR;
- + if (status & UART_MSR_DSR)
- + result |= TIOCM_DSR;
- + if (status & UART_MSR_CTS)
- + result |= TIOCM_CTS;
- + if (status & UART_MSR_RI)
- + result |= TIOCM_RI;
- +
- + return result;
- +}
- +
- +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
- +{
- +}
- +
- +static void it8712_break_ctl(struct uart_port *port, int break_state)
- +{
- + unsigned int lcr;
- +
- +// printk("it8712 break ctl : \n");
- +
- + lcr = UART_GET_LCR(port);
- + if (break_state == -1)
- + lcr |= UART_LCR_SBC;
- + else
- + lcr &= ~UART_LCR_SBC;
- + UART_PUT_LCR(port, lcr);
- +}
- +
- +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
- +{
- + u_int quot;
- +
- + /* Special case: B0 rate */
- + if (!baud)
- + baud = 9600;
- +
- + quot = (port->uartclk/(16 * baud)) ;
- +
- + return quot;
- +}
- +static void it8712_set_termios(struct uart_port *port, struct termios *termios,
- + struct termios *old)
- +{
- + unsigned int uart_mc, old_ier, baud, quot;
- + unsigned long flags;
- +
- + termios->c_cflag |= CREAD;
- + termios->c_cflag |= CLOCAL;
- +#ifdef DEBUG
- + printk("it8712_set_cflag(0x%x) called\n", cflag);
- +#endif
- + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- + quot = uart_get_divisor(port, baud);
- +
- + /* byte size and parity */
- + switch (termios->c_cflag & CSIZE) {
- + case CS5:
- + uart_mc = UART_LCR_WLEN5;
- + break;
- + case CS6:
- + uart_mc = UART_LCR_WLEN6;
- + break;
- + case CS7:
- + uart_mc = UART_LCR_WLEN7;
- + break;
- + default: // CS8
- + uart_mc = UART_LCR_WLEN8;
- + break;
- + }
- +
- + if (termios->c_cflag & CSTOPB)
- + uart_mc|= UART_LCR_STOP;
- + if (termios->c_cflag & PARENB) {
- + uart_mc |= UART_LCR_EVEN;
- + if (!(termios->c_cflag & PARODD))
- + uart_mc |= UART_LCR_ODD;
- + }
- +
- + spin_lock_irqsave(&port->lock, flags);
- + /*
- + * Update the per-port timeout
- + */
- + uart_update_timeout(port, termios->c_cflag, baud);
- + port->read_status_mask = UART_LSR_OE;
- + if (termios->c_iflag & INPCK)
- + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (termios->c_iflag & (BRKINT | PARMRK))
- + port->read_status_mask |= UART_LSR_BI;
- +
- + /*
- + * Characters to ignore
- + */
- + port->ignore_status_mask = 0;
- + if (termios->c_iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (termios->c_iflag & IGNBRK) {
- + port->ignore_status_mask |= UART_LSR_BI;
- + /*
- + * If we're ignoring parity and break indicators,
- + * ignore overruns to (for real raw support).
- + */
- + if (termios->c_iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_OE;
- + }
- +
- + old_ier = UART_GET_IER(port);
- +
- + if(UART_ENABLE_MS(port, termios->c_cflag))
- + old_ier |= UART_IER_MSI;
- +
- + /* Set baud rate */
- + quot = quot / 13;
- + UART_PUT_LCR(port, UART_LCR_DLAB);
- + UART_PUT_DIV_LO(port, (quot & 0xff));
- + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
- +
- + UART_PUT_LCR(port, uart_mc);
- +// UART_PUT_LCR(port, 0x07); // ???? it is wired
- + UART_PUT_MCR(port, 0x08);
- + UART_PUT_FCR(port, 0x01);
- + UART_PUT_IER(port, 0x07);
- +
- + spin_unlock_irqrestore(&port->lock, flags);
- +}
- +
- +static int it8712_startup(struct uart_port *port)
- +{
- + int retval, i;
- + unsigned int regs;
- +
- + //printk("it8712 startup : \n");
- +
- + /*
- + * Use iobase to store a pointer to info. We need this to start a
- + * transmission as the tranmittr interrupt is only generated on
- + * the transition to the idle state
- + */
- +
- + // regs = 0;
- + // regs |= (IRQ_LPC_MASK);
- + // *((volatile unsigned int *)IRQ_CLEAR(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- +
- + /*
- + * Allocate the IRQ
- + */
- + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", port);
- + if (retval)
- + return retval;
- +
- + //printk("Init LPC int...........\n");
- + /* setup interrupt controller */
- + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs &= ~(IRQ_LPC_MASK);
- + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs &= ~(IRQ_LPC_MASK);
- + *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_LPC_MASK);
- +
- + LPC_SERIAL_IRQ_POLARITY = 0x10; //0x10; //0x02;
- + LPC_SERIAL_IRQ_TRITYPE = 0x10; //0x10;//
- + LPC_SERIAL_IRQ_ENABLE = 0x10;
- +
- + LPC_BUS_CTRL = 0xc0;
- + LPC_SERIAL_IRQ_CTRL = 0xc0;
- + for(i=0;i<1000;i++) ;
- + LPC_SERIAL_IRQ_CTRL = 0x80;
- + /*
- + * Finally, enable interrupts. Use the TII interrupt to minimise
- + * the number of interrupts generated. If higher performance is
- + * needed, consider using the TI interrupt with a suitable FIFO
- + * threshold
- + */
- + //UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
- + UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI|UART_IER_RLSI));//middle
- +
- + return 0;
- +}
- +
- +static void it8712_shutdown(struct uart_port *port)
- +{
- + //printk("it8712 shutdown : \n");
- +
- + /*
- + * disable all interrupts, disable the port
- + */
- + UART_PUT_IER(port, 0x0);
- +
- + /* disable break condition and fifos */
- +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
- +
- + /*
- + * Free the interrupt
- + */
- + free_irq(port->irq, port);
- +}
- +
- +static const char *it8712_type(struct uart_port *port)
- +{
- + return port->type == PORT_IT8712 ? "IT8712" : NULL;
- +}
- +
- +/*
- + * Release the memory region(s) being used by 'port'
- + */
- +static void it8712_release_port(struct uart_port *port)
- +{
- +// printk("it8712 release port : \n");
- +
- + release_mem_region(port->mapbase, UART_PORT_SIZE);
- +}
- +
- +/*
- + * Request the memory region(s) being used by 'port'
- + */
- +static int it8712_request_port(struct uart_port *port)
- +{
- + return request_mem_region(port->mapbase, UART_PORT_SIZE,
- + "serial_it8712") != NULL ? 0 : -EBUSY;
- +}
- +
- +/*
- + * Configure/autoconfigure the port.
- + */
- +static void it8712_config_port(struct uart_port *port, int flags)
- +{
- +
- + if (flags & UART_CONFIG_TYPE) {
- + if (it8712_request_port(port) == 0)
- + port->type = PORT_IT8712;
- + }
- +}
- +
- +/*
- + * verify the new serial_struct (for TIOCSSERIAL).
- + */
- +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
- +{
- + int ret = 0;
- +
- + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
- + ret = -EINVAL;
- + if (ser->irq < 0 || ser->irq >= NR_IRQS)
- + ret = -EINVAL;
- + if (ser->baud_base < 9600)
- + ret = -EINVAL;
- + return ret;
- +}
- +
- +static struct uart_ops it8712_pops = {
- + .tx_empty = it8712_tx_empty,
- + .set_mctrl = it8712_set_mctrl_null,
- + .get_mctrl = it8712_get_mctrl,
- + .stop_tx = it8712_stop_tx,
- + .start_tx = it8712_start_tx,
- + .stop_rx = it8712_stop_rx,
- + .enable_ms = it8712_enable_ms,
- + .break_ctl = it8712_break_ctl,
- + .startup = it8712_startup,
- + .shutdown = it8712_shutdown,
- + .set_termios = it8712_set_termios,
- + .type = it8712_type,
- + .release_port = it8712_release_port,
- + .request_port = it8712_request_port,
- + .config_port = it8712_config_port,
- + .verify_port = it8712_verify_port,
- +};
- +
- +#ifdef CONFIG_ARCH_SL2312
- +
- +static struct uart_port it8712_ports[UART_NR] = {
- + {
- + membase: (void *)0,
- + mapbase: 0,
- + iotype: SERIAL_IO_MEM,
- + irq: 0,
- + uartclk: UART_CLK/2,
- + fifosize: 16,
- + ops: &it8712_pops,
- + flags: ASYNC_BOOT_AUTOCONF,
- + }
- +};
- +
- +#endif
- +
- +#ifdef CONFIG_SERIAL_IT8712_CONSOLE
- +#ifdef used_and_not_const_char_pointer
- +static int it8712_console_read(struct uart_port *port, char *s, u_int count)
- +{
- + unsigned int status;
- + int c;
- +#ifdef DEBUG
- + printk("it8712_console_read() called\n");
- +#endif
- +
- + c = 0;
- + while (c < count) {
- + status = UART_GET_LSR(port);
- + if (UART_RX_DATA(status)) {
- + *s++ = UART_GET_CHAR(port);
- + c++;
- + } else {
- + // nothing more to get, return
- + return c;
- + }
- + }
- + // return the count
- + return c;
- +}
- +#endif
- +static void it8712_console_write(struct console *co, const char *s, unsigned count)
- +{
- +#ifdef CONFIG_ARCH_SL2312
- + struct uart_port *port = it8712_ports + co->index;
- + unsigned int status, old_ies;
- + int i;
- +
- + /*
- + * First save the CR then disable the interrupts
- + */
- + old_ies = UART_GET_IER(port);
- + //if(old_ies!=7)
- + //{
- + //
- + // printk("old_ies = %x\n",old_ies);
- + // old_ies = 7;
- + //}
- + UART_PUT_IER(port,0x0);
- +
- + /*
- + * Now, do each character
- + */
- + for (i = 0; i < count; i++) {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, s[i]);
- + if (s[i] == '\n') {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, '\r');
- + }
- + }
- +
- + /*
- + * Finally, wait for transmitter to become empty
- + * and restore the IES
- + */
- + do {
- + status = UART_GET_LSR(port);
- + } while (!(status&UART_LSR_THRE));
- + UART_PUT_IER(port, old_ies);
- +#endif
- +}
- +
- +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
- +{
- + //printk("it8712 console get options : \n");
- +
- + u_int uart_mc, quot;
- + uart_mc= UART_GET_MCR(port);
- +
- + *parity = 'n';
- + if (uart_mc & UART_LCR_PARITY) {
- + if (uart_mc & UART_LCR_EVEN)
- + *parity = 'e';
- + else
- + *parity = 'o';
- + }
- +
- + switch (uart_mc & UART_LCR_MSK){
- +
- + case UART_LCR_WLEN5:
- + *bits = 5;
- + break;
- + case UART_LCR_WLEN6:
- + *bits = 6;
- + break;
- + case UART_LCR_WLEN7:
- + *bits = 7;
- + break;
- + case UART_LCR_WLEN8:
- + *bits = 8;
- + break;
- + }
- + UART_PUT_MCR(port,UART_LCR_DLAB);
- + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
- + UART_PUT_MCR(port,uart_mc);
- + *baud = (port->uartclk / (16 *quot));
- +}
- +
- +static int __init it8712_console_setup(struct console *co, char *options)
- +{
- + struct uart_port *port;
- + int baud = 38400;
- + int bits = 8;
- + int parity = 'n';
- + int flow= 'n';
- + int base;//, irq;
- + int i ;
- +
- + printk("it8712 console setup : \n");
- +
- + LPCSetConfig(0, 0x02, 0x01);
- + LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
- + LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
- + base = IT8712_IO_BASE;
- + base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
- + it8712_ports[0].mapbase = base;
- + it8712_ports[0].membase = (void *)IO_ADDRESS(base);
- + it8712_ports[0].irq = IRQ_LPC_OFFSET;
- + // irq = LPCGetConfig(LDN_SERIAL1, 0x70);
- + //it8712_ports[0].irq += irq;
- +
- + //printk("it8712 irq is %x \n", it8712_ports[0].irq);
- +
- + // setup LPC Host 'quiet mode'
- + //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
- + //for(i=0;i<1000;i++) ; // delay
- + //*((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
- + LPC_BUS_CTRL = 0xc0;
- + LPC_SERIAL_IRQ_CTRL = 0xc0;
- + for(i=0;i<1000;i++) ;
- + LPC_SERIAL_IRQ_CTRL = 0x80;
- +
- +#ifdef CONFIG_ARCH_SL2312
- + /*
- + * Check whether an invalid uart number has been specified, and
- + * if so, search for the first available port that does have
- + * console support.
- + */
- + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
- +#else
- + return -ENODEV;
- +#endif
- +
- + if (options)
- + uart_parse_options(options, &baud, &parity, &bits, &flow);
- + else
- + it8712_console_get_options(port, &baud, &parity, &bits);
- +
- + return uart_set_options(port, co, baud, parity, bits, flow);
- +}
- +
- +extern struct uart_driver it8712_reg;
- +static struct console it8712_console = {
- + .name = SERIAL_IT8712_NAME,
- + .write = it8712_console_write,
- + .device = uart_console_device,
- + .setup = it8712_console_setup,
- + .flags = CON_PRINTBUFFER,
- + .index = 0,
- + .data = &it8712_reg,
- +};
- +
- +static int __init it8712_console_init(void)
- +{
- + register_console(&it8712_console);
- + return 0;
- +}
- +
- +console_initcall(it8712_console_init);
- +
- +#define IT8712_CONSOLE &it8712_console
- +#else
- +#define IT8712_CONSOLE NULL
- +#endif
- +
- +static struct uart_driver it8712_reg = {
- + .owner = NULL,
- + .driver_name = SERIAL_IT8712_NAME,
- + .dev_name = SERIAL_IT8712_NAME,
- + .major = SERIAL_IT8712_MAJOR,
- + .minor = SERIAL_IT8712_MINOR,
- + .nr = UART_NR,
- + .cons = IT8712_CONSOLE,
- +};
- +
- +static int __init it8712_init(void)
- +{
- + int result;
- + //printk("serial_it8712: it871212_init \n");
- +
- +
- + result = uart_register_driver(&it8712_reg);
- + if(result)
- + return result;
- + result = uart_add_one_port(&it8712_reg, &it8712_ports[0]);
- +
- + return result;
- +
- +}
- +
- +
- +__initcall(it8712_init);
- --- /dev/null
- +++ b/drivers/serial/it8712.h
- @@ -0,0 +1,135 @@
- +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */
- +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */
- +#define UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */
- +#define UART_TRG 0 /* (LCR=BF) FCTR bit 7 selects Rx or Tx
- + * In: Fifo count
- + * Out: Fifo custom trigger levels
- + * XR16C85x only */
- +
- +#define UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */
- +#define UART_IER 1 /* Out: Interrupt Enable Register */
- +#define UART_FCTR 1 /* (LCR=BF) Feature Control Register
- + * XR16C85x only */
- +
- +#define UART_IIR 2 /* In: Interrupt ID Register */
- +#define UART_FCR 2 /* Out: FIFO Control Register */
- +#define UART_EFR 2 /* I/O: Extended Features Register */
- + /* (DLAB=1, 16C660 only) */
- +
- +#define UART_LCR 3 /* Out: Line Control Register */
- +#define UART_MCR 4 /* Out: Modem Control Register */
- +#define UART_LSR 5 /* In: Line Status Register */
- +#define UART_MSR 6 /* In: Modem Status Register */
- +#define UART_SCR 7 /* I/O: Scratch Register */
- +#define UART_EMSR 7 /* (LCR=BF) Extended Mode Select Register
- + * FCTR bit 6 selects SCR or EMSR
- + * XR16c85x only */
- +
- +/*
- + * These are the definitions for the FIFO Control Register
- + * (16650 only)
- + */
- +#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
- +#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
- +#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */
- +#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */
- +#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */
- +#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */
- +#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
- +#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
- +#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
- +/* 16650 redefinitions */
- +#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
- +#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
- +#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
- +#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
- +#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
- +#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
- +#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
- +#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
- +/* TI 16750 definitions */
- +#define UART_FCR7_64BYTE 0x20 /* Go into 64 byte mode */
- +
- +/*
- + * These are the definitions for the Line Control Register
- + *
- + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting
- + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits.
- + */
- +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
- +#define UART_LCR_SBC 0x40 /* Set break control */
- +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */
- +#define UART_LCR_EPAR 0x10 /* Even parity select */
- +#define UART_LCR_PARITY 0x08 /* Parity Enable */
- +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */
- +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */
- +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */
- +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */
- +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */
- +#define UART_LCR_EVEN 0x18 /* Even parity */
- +#define UART_LCR_ODD 0x08 /* Odd parity */
- +#define UART_LCR_MSK 0x03
- +/*
- + * These are the definitions for the Line Status Register
- + */
- +#define UART_LSR_DE 0x80 /* FIFO Data Error */
- +#define UART_LSR_TEMT 0x40 /* Transmitter empty */
- +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
- +#define UART_LSR_BI 0x10 /* Break interrupt indicator */
- +#define UART_LSR_FE 0x08 /* Frame error indicator */
- +#define UART_LSR_PE 0x04 /* Parity error indicator */
- +#define UART_LSR_OE 0x02 /* Overrun error indicator */
- +#define UART_LSR_DR 0x01 /* Receiver data ready */
- +
- +/*
- + * These are the definitions for the Interrupt Identification Register
- + */
- +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
- +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
- +
- +#define UART_IIR_MSI 0x00 /* Modem status interrupt */
- +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
- +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
- +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
- +#define UART_IIR_RCTO 0x0c /* Receiver character timeout interrupt */
- +/*
- + * These are the definitions for the Interrupt Enable Register
- + */
- +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
- +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
- +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
- +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
- +/*
- + * Sleep mode for ST16650 and TI16750.
- + * Note that for 16650, EFR-bit 4 must be selected as well.
- + */
- +#define UART_IERX_SLEEP 0x10 /* Enable sleep mode */
- +
- +/*
- + * These are the definitions for the Modem Control Register
- + */
- +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
- +#define UART_MCR_OUT2 0x08 /* Out2 complement */
- +#define UART_MCR_OUT1 0x04 /* Out1 complement */
- +#define UART_MCR_RTS 0x02 /* RTS complement */
- +#define UART_MCR_DTR 0x01 /* DTR complement */
- +
- +/*
- + * These are the definitions for the Modem Status Register
- + */
- +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
- +#define UART_MSR_RI 0x40 /* Ring Indicator */
- +#define UART_MSR_DSR 0x20 /* Data Set Ready */
- +#define UART_MSR_CTS 0x10 /* Clear to Send */
- +#define UART_MSR_DDCD 0x08 /* Delta DCD */
- +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
- +#define UART_MSR_DDSR 0x02 /* Delta DSR */
- +#define UART_MSR_DCTS 0x01 /* Delta CTS */
- +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
- +
- +#define UART_PARITY_NONE 0x00
- +#define UART_PARITY_ODD 0x01
- +#define UART_PARITY_EVEN 0x02
- +
- +
- +
- --- /dev/null
- +++ b/drivers/serial/serial_it8712.c
- @@ -0,0 +1,876 @@
- +/*
- + * linux/drivers/char/serial_uart00.c
- + *
- + * Driver for UART00 serial ports
- + *
- + * Based on drivers/char/serial_amba.c, by ARM Limited &
- + * Deep Blue Solutions Ltd.
- + * Copyright 2001 Altera Corporation
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- + *
- + * $Id: serial_it8712.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
- + *
- + */
- +#include <linux/module.h>
- +
- +#include <linux/errno.h>
- +#include <linux/signal.h>
- +#include <linux/sched.h>
- +#include <linux/interrupt.h>
- +#include <linux/tty.h>
- +#include <linux/tty_flip.h>
- +#include <linux/major.h>
- +#include <linux/string.h>
- +#include <linux/fcntl.h>
- +#include <linux/ptrace.h>
- +#include <linux/ioport.h>
- +#include <linux/mm.h>
- +#include <linux/slab.h>
- +#include <linux/init.h>
- +#include <linux/circ_buf.h>
- +#include <linux/serial.h>
- +#include <linux/console.h>
- +#include <linux/sysrq.h>
- +
- +#include <asm/system.h>
- +#include <asm/io.h>
- +#include <asm/irq.h>
- +#include <asm/uaccess.h>
- +#include <asm/bitops.h>
- +#include <asm/sizes.h>
- +
- +#if defined(CONFIG_SERIAL_IT8712_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- +#define SUPPORT_SYSRQ
- +#endif
- +
- +#include <linux/serial_core.h>
- +#include <asm/arch/sl2312.h>
- +#include <asm/arch/int_ctrl.h>
- +#include <asm/arch/it8712.h>
- +#include "serial_it8712.h"
- +
- +//#define DEBUG 1
- +#define UART_NR 1
- +
- +#define SERIAL_IT8712_NAME "ttySI"
- +#define SERIAL_IT8712_MAJOR 204
- +#define SERIAL_IT8712_MINOR 41 /* Temporary - will change in future */
- +#define SERIAL_IT8712_NR UART_NR
- +#define UART_PORT_SIZE 0x50
- +
- +#define CALLOUT_IT8712_NAME "cuaslI"
- +#define CALLOUT_IT8712_MAJOR 205
- +#define CALLOUT_IT8712_MINOR 41 /* Temporary - will change in future */
- +#define CALLOUT_IT8712_NR UART_NR
- +#define LPC_HOST_CONTINUE_MODE 0x00000040
- +
- +#define IT8712_NO_PORTS UART_NR
- +
- +static struct tty_driver normal, callout;
- +static struct tty_struct *it8712_table[UART_NR];
- +static struct termios *it8712_termios[UART_NR], *it8712_termios_locked[UART_NR];
- +static struct console it8712_console;
- +
- +#define IT8712_ISR_PASS_LIMIT 256
- +
- +/*
- + * Access macros for the SL2312 UARTs
- + */
- +#define UART_GET_INT_STATUS(p) (inb(((p)->membase+UART_IIR)) & 0x0F) // interrupt identification
- +#define UART_PUT_IER(p, c) outb(c,((p)->membase+UART_IER)) // interrupt enable
- +#define UART_GET_IER(p) inb(((p)->membase+UART_IER))
- +#define UART_PUT_CHAR(p, c) outb(c,((p)->membase+UART_TX)) // transmitter holding
- +#define UART_GET_CHAR(p) inb(((p)->membase+UART_RX)) // receive buffer
- +#define UART_GET_LSR(p) inb(((p)->membase+UART_LSR)) // line status
- +#define UART_GET_MSR(p) inb(((p)->membase+UART_MSR)) // modem status
- +#define UART_GET_MCR(p) inb(((p)->membase+UART_MCR)) // modem control
- +#define UART_PUT_MCR(p, c) outb(c,((p)->membase+UART_MCR))
- +#define UART_GET_LCR(p) inb(((p)->membase+UART_LCR)) // mode control
- +#define UART_PUT_LCR(p, c) outb(c,((p)->membase+UART_LCR))
- +#define UART_PUT_FCR(p, c) outb(c,((p)->membase+UART_FCR)) // fifo control
- +#define UART_GET_DIV_HI(p) inb(((p)->membase+UART_DLM))
- +#define UART_PUT_DIV_HI(p, c) outb(c,((p)->membase+UART_DLM))
- +#define UART_GET_DIV_LO(p) inb(((p)->membase+UART_DLL))
- +#define UART_PUT_DIV_LO(p, c) outb(c,((p)->membase+UART_DLL))
- +#define UART_PUT_MDR(p, c) outb(c,UART_MDR((p)->membase))
- +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
- +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
- +
- +static void it8712_stop_tx(struct uart_port *port, u_int from_tty)
- +{
- + unsigned int reg;
- +
- +// printk("it8712 stop tx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_THRI);
- + UART_PUT_IER(port, reg);
- +}
- +
- +static void it8712_stop_rx(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("it8712 stop rx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_RDI);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void it8712_enable_ms(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("it8712 enable ms : \n");
- +
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_MSI);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void
- +it8712_rx_chars(struct uart_info *info, struct pt_regs *regs)
- +{
- + struct tty_struct *tty = info->tty;
- + unsigned int status, mask, ch, flg, ignored = 0;
- + struct uart_port *port = info->port;
- +
- + // printk("it8712_rx_chars : \n");
- + status = UART_GET_LSR(port);
- + while (UART_RX_DATA(status)) {
- +
- + /*
- + * We need to read rds before reading the
- + * character from the fifo
- + */
- + ch = UART_GET_CHAR(port);
- + port->icount.rx++;
- +
- + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + goto ignore_char;
- +
- + flg = TTY_NORMAL;
- +
- + /*
- + * Note that the error handling code is
- + * out of the main execution path
- + */
- +
- + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
- + goto handle_error;
- + if (uart_handle_sysrq_char(info, ch, regs))
- + goto ignore_char;
- +
- + error_return:
- + *tty->flip.flag_buf_ptr++ = flg;
- + *tty->flip.char_buf_ptr++ = ch;
- + tty->flip.count++;
- + ignore_char:
- + status = UART_GET_LSR(port);
- + } // end of while
- +out:
- + tty_flip_buffer_push(tty);
- + return;
- +
- +handle_error:
- + if (status & UART_LSR_BI) {
- + status &= ~(UART_LSR_FE);
- + port->icount.brk++;
- +
- +#ifdef SUPPORT_SYSRQ
- + if (uart_handle_break(info, &it8712_console))
- + goto ignore_char;
- +#endif
- + } else if (status & UART_LSR_PE)
- + port->icount.parity++;
- + else if (status & UART_LSR_FE)
- + port->icount.frame++;
- +
- + if (status & UART_LSR_OE)
- + port->icount.overrun++;
- +
- + if (status & port->ignore_status_mask) {
- + if (++ignored > 100)
- + goto out;
- + goto ignore_char;
- + }
- +
- + mask = status & port->read_status_mask;
- +
- + if (mask & UART_LSR_BI)
- + flg = TTY_BREAK;
- + else if (mask & UART_LSR_PE)
- + flg = TTY_PARITY;
- + else if (mask & UART_LSR_FE)
- + flg = TTY_FRAME;
- +
- + if (status & UART_LSR_OE) {
- + /*
- + * CHECK: does overrun affect the current character?
- + * ASSUMPTION: it does not.
- + */
- + *tty->flip.flag_buf_ptr++ = flg;
- + *tty->flip.char_buf_ptr++ = ch;
- + tty->flip.count++;
- + if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + goto ignore_char;
- + ch = 0;
- + flg = TTY_OVERRUN;
- + }
- +#ifdef SUPPORT_SYSRQ
- + info->sysrq = 0;
- +#endif
- + goto error_return;
- +}
- +
- +static void it8712_tx_chars(struct uart_info *info)
- +{
- + int count;
- + struct uart_port *port=info->port;
- +
- + if (port->x_char) {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, port->x_char);
- + port->icount.tx++;
- + port->x_char = 0;
- +
- + return;
- + }
- + if (info->xmit.head == info->xmit.tail
- + || info->tty->stopped
- + || info->tty->hw_stopped) {
- + it8712_stop_tx(info->port, 0);
- + return;
- + }
- +
- + count = port->fifosize >> 1;
- + do {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, info->xmit.buf[info->xmit.tail]);
- + info->xmit.tail = (info->xmit.tail + 1) & (UART_XMIT_SIZE - 1);
- + port->icount.tx++;
- + if (info->xmit.head == info->xmit.tail)
- + break;
- + } while (--count > 0);
- +
- + if (CIRC_CNT(info->xmit.head,
- + info->xmit.tail,
- + UART_XMIT_SIZE) < WAKEUP_CHARS)
- + uart_event(info, EVT_WRITE_WAKEUP);
- +
- + if (info->xmit.head == info->xmit.tail)
- + it8712_stop_tx(info->port, 0);
- +}
- +
- +static void it8712_start_tx(struct uart_port *port, u_int nonempty, u_int from_tty)
- +{
- + unsigned int reg;
- + struct uart_info *info=(struct uart_info*)(port->iobase);
- +
- +// printk("it8712 start tx : \n");
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_THRI);
- + UART_PUT_IER(port, reg);
- + it8712_tx_chars(info);
- +}
- +
- +static void it8712_modem_status(struct uart_info *info)
- +{
- + unsigned int status;
- + struct uart_icount *icount = &info->port->icount;
- +
- +// printk("it8712 modem status : \n");
- +
- + status = UART_GET_MSR(info->port);
- +
- + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
- + UART_MSR_TERI | UART_MSR_DDCD)))
- + return;
- +
- + if (status & UART_MSR_DCD) {
- + icount->dcd++;
- +#ifdef CONFIG_HARD_PPS
- + if ((info->flags & ASYNC_HARDPPS_CD) &&
- + (status & UART_MSR_DCD_MSK))
- + hardpps();
- +#endif
- + if (info->flags & ASYNC_CHECK_CD) {
- + if (status & UART_MSR_DCD)
- + wake_up_interruptible(&info->open_wait);
- + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- + (info->flags & ASYNC_CALLOUT_NOHUP))) {
- + if (info->tty)
- + tty_hangup(info->tty);
- + }
- + }
- + }
- +
- + if (status & UART_MSR_DDSR)
- + icount->dsr++;
- +
- + if (status & UART_MSR_DCTS) {
- + icount->cts++;
- +
- + if (info->flags & ASYNC_CTS_FLOW) {
- + status &= UART_MSR_CTS;
- +
- + if (info->tty->hw_stopped) {
- + if (status) {
- + info->tty->hw_stopped = 0;
- + info->ops->start_tx(info->port, 1, 0);
- + uart_event(info, EVT_WRITE_WAKEUP);
- + }
- + } else {
- + if (!status) {
- + info->tty->hw_stopped = 1;
- + info->ops->stop_tx(info->port, 0);
- + }
- + }
- + }
- + }
- + wake_up_interruptible(&info->delta_msr_wait);
- +
- +}
- +
- +static void it8712_int(int irq, void *dev_id, struct pt_regs *regs)
- +{
- + struct uart_info *info = dev_id;
- + unsigned int status, pass_counter = 0;
- +
- + status = UART_GET_INT_STATUS(info->port);
- + do {
- +// printk("it8712_int: status %x \n", status);
- + switch(status)
- + {
- + case UART_IIR_RDI:
- + case UART_IIR_RLSI:
- + case UART_IIR_RCTO:
- + it8712_rx_chars(info, regs);
- + break;
- + case UART_IIR_THRI:
- + it8712_tx_chars(info);
- + break;
- + case UART_IIR_MSI:
- + it8712_modem_status(info);
- + break;
- + default:
- + break;
- + }
- + if (pass_counter++ > IT8712_ISR_PASS_LIMIT)
- + break;
- +
- + status = UART_GET_INT_STATUS(info->port);
- + } while (status);
- +}
- +
- +static u_int it8712_tx_empty(struct uart_port *port)
- +{
- +// printk("it8712 tx empty : \n");
- +
- + return ((UART_GET_LSR(port) & UART_LSR_THRE)? TIOCSER_TEMT : 0);
- +}
- +
- +static u_int it8712_get_mctrl(struct uart_port *port)
- +{
- + unsigned int result = 0;
- + unsigned int status;
- +
- +// printk("it8712 get mctrl : \n");
- +
- + status = UART_GET_MSR(port);
- + if (status & UART_MSR_DCD)
- + result |= TIOCM_CAR;
- + if (status & UART_MSR_DSR)
- + result |= TIOCM_DSR;
- + if (status & UART_MSR_CTS)
- + result |= TIOCM_CTS;
- + if (status & UART_MSR_RI)
- + result |= TIOCM_RI;
- +
- + return result;
- +}
- +
- +static void it8712_set_mctrl_null(struct uart_port *port, u_int mctrl)
- +{
- +}
- +
- +static void it8712_break_ctl(struct uart_port *port, int break_state)
- +{
- + unsigned int lcr;
- +
- +// printk("it8712 break ctl : \n");
- +
- + lcr = UART_GET_LCR(port);
- + if (break_state == -1)
- + lcr |= UART_LCR_SBC;
- + else
- + lcr &= ~UART_LCR_SBC;
- + UART_PUT_LCR(port, lcr);
- +}
- +
- +static inline u_int uart_calculate_quot(struct uart_info *info, u_int baud)
- +{
- + u_int quot;
- +
- + /* Special case: B0 rate */
- + if (!baud)
- + baud = 9600;
- +
- + quot = (info->port->uartclk/(16 * baud)) ;
- +
- + return quot;
- +}
- +static void it8712_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot)
- +{
- + u_int uart_mc=0, old_ier;
- + unsigned long flags;
- +
- +#ifdef DEBUG
- + printk("it8712_set_cflag(0x%x) called\n", cflag);
- +#endif
- +
- +
- + /* byte size and parity */
- + switch (cflag & CSIZE) {
- + case CS5: uart_mc = UART_LCR_WLEN5; break;
- + case CS6: uart_mc = UART_LCR_WLEN6; break;
- + case CS7: uart_mc = UART_LCR_WLEN7; break;
- + default: uart_mc = UART_LCR_WLEN8; break; // CS8
- + }
- + if (cflag & CSTOPB)
- + uart_mc|= UART_LCR_STOP;
- + if (cflag & PARENB) {
- + uart_mc |= UART_LCR_EVEN;
- + if (!(cflag & PARODD))
- + uart_mc |= UART_LCR_ODD;
- + }
- +
- + port->read_status_mask = UART_LSR_OE;
- + if (iflag & INPCK)
- + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (iflag & (BRKINT | PARMRK))
- + port->read_status_mask |= UART_LSR_BI;
- +
- + /*
- + * Characters to ignore
- + */
- + port->ignore_status_mask = 0;
- + if (iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (iflag & IGNBRK) {
- + port->ignore_status_mask |= UART_LSR_BI;
- + /*
- + * If we're ignoring parity and break indicators,
- + * ignore overruns to (for real raw support).
- + */
- + if (iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_OE;
- + }
- +
- + /* first, disable everything */
- + save_flags(flags); cli();
- + old_ier = UART_GET_IER(port);
- +
- + if ((port->flags & ASYNC_HARDPPS_CD) ||
- + (cflag & CRTSCTS) || !(cflag & CLOCAL))
- + old_ier |= UART_IER_MSI;
- +
- + /* Set baud rate */
- + quot = quot / 13;
- + UART_PUT_LCR(port, UART_LCR_DLAB);
- + UART_PUT_DIV_LO(port, (quot & 0xff));
- + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
- +
- + UART_PUT_LCR(port, uart_mc);
- +// UART_PUT_LCR(port, 0x07); // ???? it is wired
- + UART_PUT_MCR(port, 0x08);
- + UART_PUT_FCR(port, 0x01);
- + UART_PUT_IER(port, 0x05);
- +
- + restore_flags(flags);
- +}
- +
- +static int it8712_startup(struct uart_port *port, struct uart_info *info)
- +{
- + int retval;
- + unsigned int regs;
- +
- +// printk("it8712 startup : \n");
- +
- + /*
- + * Use iobase to store a pointer to info. We need this to start a
- + * transmission as the tranmittr interrupt is only generated on
- + * the transition to the idle state
- + */
- +
- + port->iobase=(u_int)info;
- +
- + /*
- + * Allocate the IRQ
- + */
- + retval = request_irq(port->irq, it8712_int, SA_INTERRUPT, "it8712", info);
- + if (retval)
- + return retval;
- +
- + /* setup interrupt controller */
- + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs |= (IRQ_SERIRQ0_MASK);
- + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + regs = *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs &= ~(IRQ_SERIRQ0_MASK);
- + *((volatile unsigned int *)IRQ_LEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_SERIRQ0_MASK);
- +
- + /*
- + * Finally, enable interrupts. Use the TII interrupt to minimise
- + * the number of interrupts generated. If higher performance is
- + * needed, consider using the TI interrupt with a suitable FIFO
- + * threshold
- + */
- + UART_PUT_IER(port, (UART_IER_RDI|UART_IER_THRI));
- +
- + return 0;
- +}
- +
- +static void it8712_shutdown(struct uart_port *port, struct uart_info *info)
- +{
- +// printk("it8712 shutdown : \n");
- +
- + /*
- + * disable all interrupts, disable the port
- + */
- + UART_PUT_IER(port, 0x0);
- +
- + /* disable break condition and fifos */
- +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
- +
- + /*
- + * Free the interrupt
- + */
- + free_irq(port->irq, info);
- +}
- +
- +static const char *it8712_type(struct uart_port *port)
- +{
- + return port->type == PORT_IT8712 ? "IT8712" : NULL;
- +}
- +
- +/*
- + * Release the memory region(s) being used by 'port'
- + */
- +static void it8712_release_port(struct uart_port *port)
- +{
- +// printk("it8712 release port : \n");
- +
- + release_mem_region(port->mapbase, UART_PORT_SIZE);
- +}
- +
- +/*
- + * Request the memory region(s) being used by 'port'
- + */
- +static int it8712_request_port(struct uart_port *port)
- +{
- + return request_mem_region(port->mapbase, UART_PORT_SIZE,
- + "serial_it8712") != NULL ? 0 : -EBUSY;
- +}
- +
- +/*
- + * Configure/autoconfigure the port.
- + */
- +static void it8712_config_port(struct uart_port *port, int flags)
- +{
- +
- + if (flags & UART_CONFIG_TYPE) {
- + if (it8712_request_port(port) == 0)
- + port->type = PORT_IT8712;
- + }
- +}
- +
- +/*
- + * verify the new serial_struct (for TIOCSSERIAL).
- + */
- +static int it8712_verify_port(struct uart_port *port, struct serial_struct *ser)
- +{
- + int ret = 0;
- +
- + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
- + ret = -EINVAL;
- + if (ser->irq < 0 || ser->irq >= NR_IRQS)
- + ret = -EINVAL;
- + if (ser->baud_base < 9600)
- + ret = -EINVAL;
- + return ret;
- +}
- +
- +static struct uart_ops it8712_pops = {
- + tx_empty: it8712_tx_empty,
- + set_mctrl: it8712_set_mctrl_null,
- + get_mctrl: it8712_get_mctrl,
- + stop_tx: it8712_stop_tx,
- + start_tx: it8712_start_tx,
- + stop_rx: it8712_stop_rx,
- + enable_ms: it8712_enable_ms,
- + break_ctl: it8712_break_ctl,
- + startup: it8712_startup,
- + shutdown: it8712_shutdown,
- + change_speed: it8712_change_speed,
- + type: it8712_type,
- + release_port: it8712_release_port,
- + request_port: it8712_request_port,
- + config_port: it8712_config_port,
- + verify_port: it8712_verify_port,
- +};
- +
- +#ifdef CONFIG_ARCH_SL2312
- +
- +static struct uart_port it8712_ports[UART_NR] = {
- + {
- + membase: (void *)0,
- + mapbase: 0,
- + iotype: SERIAL_IO_MEM,
- + irq: 0,
- + uartclk: UART_CLK/2,
- + fifosize: 16,
- + ops: &it8712_pops,
- + flags: ASYNC_BOOT_AUTOCONF,
- + }
- +};
- +
- +#endif
- +
- +#ifdef CONFIG_SERIAL_IT8712_CONSOLE
- +#ifdef used_and_not_const_char_pointer
- +static int it8712_console_read(struct uart_port *port, char *s, u_int count)
- +{
- + unsigned int status;
- + int c;
- +#ifdef DEBUG
- + printk("it8712_console_read() called\n");
- +#endif
- +
- + c = 0;
- + while (c < count) {
- + status = UART_GET_LSR(port);
- + if (UART_RX_DATA(status)) {
- + *s++ = UART_GET_CHAR(port);
- + c++;
- + } else {
- + // nothing more to get, return
- + return c;
- + }
- + }
- + // return the count
- + return c;
- +}
- +#endif
- +static void it8712_console_write(struct console *co, const char *s, unsigned count)
- +{
- +#ifdef CONFIG_ARCH_SL2312
- + struct uart_port *port = it8712_ports + co->index;
- + unsigned int status, old_ies;
- + int i;
- +
- + /*
- + * First save the CR then disable the interrupts
- + */
- + old_ies = UART_GET_IER(port);
- + UART_PUT_IER(port,0x0);
- +
- + /*
- + * Now, do each character
- + */
- + for (i = 0; i < count; i++) {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, s[i]);
- + if (s[i] == '\n') {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, '\r');
- + }
- + }
- +
- + /*
- + * Finally, wait for transmitter to become empty
- + * and restore the IES
- + */
- + do {
- + status = UART_GET_LSR(port);
- + } while (!(status&UART_LSR_THRE));
- + UART_PUT_IER(port, old_ies);
- +#endif
- +}
- +
- +static kdev_t it8712_console_device(struct console *co)
- +{
- + return MKDEV(SERIAL_IT8712_MAJOR, SERIAL_IT8712_MINOR + co->index);
- +}
- +
- +static int it8712_console_wait_key(struct console *co)
- +{
- +#ifdef CONFIG_ARCH_SL2312
- + struct uart_port *port = (it8712_ports + co->index);
- + unsigned int status;
- +
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_RX_DATA(status));
- + return UART_GET_CHAR(port);
- +#else
- + return 0;
- +#endif
- +}
- +
- +static void /*__init*/ it8712_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
- +{
- + printk("it8712 console get options : \n");
- +
- + u_int uart_mc, quot;
- + uart_mc= UART_GET_MCR(port);
- +
- + *parity = 'n';
- + if (uart_mc & UART_LCR_PARITY) {
- + if (uart_mc & UART_LCR_EVEN)
- + *parity = 'e';
- + else
- + *parity = 'o';
- + }
- +
- + switch (uart_mc & UART_LCR_MSK){
- +
- + case UART_LCR_WLEN5:
- + *bits = 5;
- + break;
- + case UART_LCR_WLEN6:
- + *bits = 6;
- + break;
- + case UART_LCR_WLEN7:
- + *bits = 7;
- + break;
- + case UART_LCR_WLEN8:
- + *bits = 8;
- + break;
- + }
- + UART_PUT_MCR(port,UART_LCR_DLAB);
- + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
- + UART_PUT_MCR(port,uart_mc);
- + *baud = (port->uartclk / (16 *quot));
- +}
- +
- +static int __init it8712_console_setup(struct console *co, char *options)
- +{
- + struct uart_port *port;
- + int baud = 38400;
- + int bits = 8;
- + int parity = 'n';
- + int flow= 'n';
- + int base, irq;
- + int i ;
- +
- +// printk("it8712 console setup : \n");
- +
- + LPCSetConfig(0, 0x02, 0x01);
- + LPCSetConfig(LDN_SERIAL1, 0x30, 0x1);
- + LPCSetConfig(LDN_SERIAL1, 0x23, 0x0);
- + base = IT8712_IO_BASE;
- + base += ((LPCGetConfig(LDN_SERIAL1, 0x60) << 8) + LPCGetConfig(LDN_SERIAL1, 0x61));
- + it8712_ports[0].mapbase = base;
- + it8712_ports[0].membase = IO_ADDRESS(base);
- + it8712_ports[0].irq = IRQ_SERIRQ0_OFFSET;
- + irq = LPCGetConfig(LDN_SERIAL1, 0x70);
- + it8712_ports[0].irq += irq;
- +
- + printk("it8712 irq is %x %x \n", it8712_ports[0].irq, irq);
- +
- + // setup LPC Host 'quiet mode'
- + *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) |= LPC_HOST_CONTINUE_MODE ;
- + for(i=0;i<1000;i++) ; // delay
- + *((volatile unsigned int *)IO_ADDRESS((SL2312_LPC_HOST_BASE+0x04))) &= ~(LPC_HOST_CONTINUE_MODE) ;
- +
- +#ifdef CONFIG_ARCH_SL2312
- + /*
- + * Check whether an invalid uart number has been specified, and
- + * if so, search for the first available port that does have
- + * console support.
- + */
- + port = uart_get_console(it8712_ports,IT8712_NO_PORTS,co);
- +#else
- + return -ENODEV;
- +#endif
- +
- + if (options)
- + uart_parse_options(options, &baud, &parity, &bits, &flow);
- + else
- + it8712_console_get_options(port, &baud, &parity, &bits);
- +
- + return uart_set_options(port, co, baud, parity, bits, flow);
- +}
- +
- +static struct console it8712_console = {
- + name: SERIAL_IT8712_NAME,
- + write: it8712_console_write,
- +#ifdef used_and_not_const_char_pointer
- + read: it8712_console_read,
- +#endif
- + device: it8712_console_device,
- +// wait_key: it8712_console_wait_key,
- + setup: it8712_console_setup,
- + flags: (CON_PRINTBUFFER|CON_ENABLED),
- + index: -1,
- +};
- +
- +void __init it8712_console_init(void)
- +{
- + register_console(&it8712_console);
- +}
- +
- +#define IT8712_CONSOLE &it8712_console
- +#else
- +#define IT8712_CONSOLE NULL
- +#endif
- +
- +static struct uart_driver it8712_reg = {
- + owner: NULL,
- + normal_major: SERIAL_IT8712_MAJOR,
- + normal_name: SERIAL_IT8712_NAME,
- + normal_driver: &normal,
- + callout_major: CALLOUT_IT8712_MAJOR,
- + callout_name: CALLOUT_IT8712_NAME,
- + callout_driver: &callout,
- + table: it8712_table,
- + termios: it8712_termios,
- + termios_locked: it8712_termios_locked,
- + minor: SERIAL_IT8712_MINOR,
- + nr: UART_NR,
- +#ifdef CONFIG_ARCH_SL2312
- + port: it8712_ports,
- +#endif
- + state: NULL,
- + cons: IT8712_CONSOLE,
- +};
- +
- +static int __init it8712_init(void)
- +{
- +// printk("serial_it8712: it871212_init \n");
- +
- + return uart_register_driver(&it8712_reg);
- +}
- +
- +
- +__initcall(it8712_init);
- --- /dev/null
- +++ b/drivers/serial/serial_sl2312.c
- @@ -0,0 +1,827 @@
- +/*
- + * linux/drivers/char/serial_uart00.c
- + *
- + * Driver for UART00 serial ports
- + *
- + * Based on drivers/char/serial_amba.c, by ARM Limited &
- + * Deep Blue Solutions Ltd.
- + * Copyright 2001 Altera Corporation
- + *
- + * This program is free software; you can redistribute it and/or modify
- + * it under the terms of the GNU General Public License as published by
- + * the Free Software Foundation; either version 2 of the License, or
- + * (at your option) any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * You should have received a copy of the GNU General Public License
- + * along with this program; if not, write to the Free Software
- + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- + *
- + * $Id: serial_sl2312.c,v 1.1.1.1 2006/04/03 08:41:00 amos_lee Exp $
- + *
- + */
- +#include <linux/module.h>
- +
- +#include <linux/errno.h>
- +#include <linux/signal.h>
- +#include <linux/sched.h>
- +#include <linux/interrupt.h>
- +#include <linux/tty.h>
- +#include <linux/tty_flip.h>
- +#include <linux/major.h>
- +#include <linux/string.h>
- +#include <linux/fcntl.h>
- +#include <linux/ptrace.h>
- +#include <linux/ioport.h>
- +#include <linux/mm.h>
- +#include <linux/slab.h>
- +#include <linux/init.h>
- +#include <linux/circ_buf.h>
- +#include <linux/serial.h>
- +#include <linux/console.h>
- +#include <linux/sysrq.h>
- +#include <linux/serial_core.h>
- +
- +#include <asm/system.h>
- +#include <asm/hardware.h>
- +#include <asm/io.h>
- +#include <asm/irq.h>
- +#include <asm/uaccess.h>
- +#include <asm/bitops.h>
- +#include <asm/sizes.h>
- +#include <linux/spinlock.h>
- +#include <linux/irq.h>
- +
- +
- +#if defined(CONFIG_SERIAL_SL2312_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
- +#define SUPPORT_SYSRQ
- +#endif
- +
- +#include <asm/arch/sl2312.h>
- +#define UART_TYPE (volatile unsigned int*)
- +#include <asm/arch/uart.h>
- +#include <asm/arch/int_ctrl.h>
- +
- +// #define DEBUG 1
- +#define UART_NR 1
- +
- +
- +#define SERIAL_SL2312_NAME "ttyS"
- +#define SERIAL_SL2312_MAJOR 204
- +#define SERIAL_SL2312_MINOR 40 /* Temporary - will change in future */
- +#define SERIAL_SL2312_NR UART_NR
- +#define UART_PORT_SIZE 0x50
- +
- +#define SL2312_NO_PORTS UART_NR
- +#define SL2312_ISR_PASS_LIMIT 256
- +
- +/*
- + * Access macros for the SL2312 UARTs
- + */
- +#define UART_GET_INT_STATUS(p) (inl(UART_IIR((p)->membase)) & 0x0F) // interrupt identification
- +#define UART_PUT_IER(p, c) outl(c,UART_IER((p)->membase)) // interrupt enable
- +#define UART_GET_IER(p) inl(UART_IER((p)->membase))
- +#define UART_PUT_CHAR(p, c) outl(c,UART_THR((p)->membase)) // transmitter holding
- +#define UART_GET_CHAR(p) inl(UART_RBR((p)->membase)) // receive buffer
- +#define UART_GET_LSR(p) inl(UART_LSR((p)->membase)) // line status
- +#define UART_GET_MSR(p) inl(UART_MSR((p)->membase)) // modem status
- +#define UART_GET_MCR(p) inl(UART_MCR((p)->membase)) // modem control
- +#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase))
- +#define UART_GET_LCR(p) inl(UART_LCR((p)->membase)) // mode control
- +#define UART_PUT_LCR(p, c) outl(c,UART_LCR((p)->membase))
- +#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase))
- +#define UART_PUT_DIV_HI(p, c) outl(c,UART_DIV_HI((p)->membase))
- +#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase))
- +#define UART_PUT_DIV_LO(p, c) outl(c,UART_DIV_LO((p)->membase))
- +#define UART_PUT_MDR(p, c) outl(c,UART_MDR((p)->membase))
- +#define UART_RX_DATA(s) ((s) & UART_LSR_DR)
- +#define UART_TX_READY(s) ((s) & UART_LSR_THRE)
- +
- +
- +static void sl2312_stop_tx(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("sl2312 stop tx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_TE);
- + UART_PUT_IER(port, reg);
- +}
- +
- +static void sl2312_stop_rx(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("sl2312 stop rx : \n");
- + reg = UART_GET_IER(port);
- + reg &= ~(UART_IER_DR);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void sl2312_enable_ms(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("sl2312 enable ms : \n");
- +
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_MS);
- + UART_PUT_IER(port, reg);
- +
- +}
- +
- +static void
- +sl2312_rx_chars(struct uart_port *port)
- +{
- + struct tty_struct *tty = port->info->tty;
- + unsigned int status, mask, ch, flg, ignored = 0;
- +
- +
- + // printk("sl2312_rx_chars : \n");
- + status = UART_GET_LSR(port);
- + while (UART_RX_DATA(status)) {
- +
- + /*
- + * We need to read rds before reading the
- + * character from the fifo
- + */
- + ch = UART_GET_CHAR(port);
- + port->icount.rx++;
- +
- + //if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + if (tty && !tty_buffer_request_room(tty, 1))
- + goto ignore_char;
- +
- + flg = TTY_NORMAL;
- +
- + /*
- + * Note that the error handling code is
- + * out of the main execution path
- + */
- +
- + if (status & (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE))
- + goto handle_error;
- + if (uart_handle_sysrq_char(port, ch))
- + goto ignore_char;
- +
- + error_return:
- + //*tty->flip.flag_buf_ptr++ = flg;
- + //*tty->flip.char_buf_ptr++ = ch;
- + //tty->flip.count++;
- + tty_insert_flip_char(tty, ch, flg);
- + ignore_char:
- + status = UART_GET_LSR(port);
- + } // end of while
- +out:
- + tty_flip_buffer_push(tty);
- + return;
- +
- +handle_error:
- + if (status & UART_LSR_BI) {
- + status &= ~(UART_LSR_FE);
- + port->icount.brk++;
- +
- +#ifdef SUPPORT_SYSRQ
- + if (uart_handle_break(port))
- + goto ignore_char;
- +#endif
- + } else if (status & UART_LSR_PE)
- + port->icount.parity++;
- + else if (status & UART_LSR_FE)
- + port->icount.frame++;
- +
- + if (status & UART_LSR_OE)
- + port->icount.overrun++;
- +
- + if (status & port->ignore_status_mask) {
- + if (++ignored > 100)
- + goto out;
- + goto ignore_char;
- + }
- +
- + mask = status & port->read_status_mask;
- +
- + if (mask & UART_LSR_BI)
- + flg = TTY_BREAK;
- + else if (mask & UART_LSR_PE)
- + flg = TTY_PARITY;
- + else if (mask & UART_LSR_FE)
- + flg = TTY_FRAME;
- +
- + if (status & UART_LSR_OE) {
- + /*
- + * CHECK: does overrun affect the current character?
- + * ASSUMPTION: it does not.
- + */
- + //*tty->flip.flag_buf_ptr++ = flg;
- + //*tty->flip.char_buf_ptr++ = ch;
- + //tty->flip.count++;
- +
- + tty_insert_flip_char(tty, 0, TTY_BREAK);
- +
- + // if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- + if (tty_buffer_request_room(tty, 1))
- + goto ignore_char;
- + ch = 0;
- + flg = TTY_OVERRUN;
- + }
- +#ifdef SUPPORT_SYSRQ
- + port->sysrq = 0;
- +#endif
- + goto error_return;
- +}
- +
- +static void sl2312_tx_chars(struct uart_port *port)
- +{
- + struct circ_buf *xmit = &port->info->xmit;
- + int count;
- +
- +
- + if (port->x_char) {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, port->x_char);
- + port->icount.tx++;
- + port->x_char = 0;
- +
- + return;
- + }
- + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- + sl2312_stop_tx(port);
- +
- + return;
- + }
- +
- + count = port->fifosize >> 1;
- + do {
- + while(!(UART_GET_LSR(port)&UART_LSR_THRE));
- + UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
- + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- + port->icount.tx++;
- + if (uart_circ_empty(xmit))
- + break;
- + } while (--count > 0);
- +
- + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- + uart_write_wakeup(port);
- +
- + if (uart_circ_empty(xmit))
- + sl2312_stop_tx(port);
- +
- +}
- +
- +static void sl2312_start_tx(struct uart_port *port)
- +{
- + unsigned int reg;
- +
- +// printk("sl2312 start tx : \n");
- + reg = UART_GET_IER(port);
- + reg |= (UART_IER_TE);
- + UART_PUT_IER(port, reg);
- +
- + sl2312_tx_chars(port);
- +}
- +
- +static void sl2312_modem_status(struct uart_port *port)
- +{
- + unsigned int status;
- +
- +// printk("it8712 modem status : \n");
- +
- + status = UART_GET_MSR(port);
- +
- + if (!(status & (UART_MSR_DCTS | UART_MSR_DDSR |
- + UART_MSR_TERI | UART_MSR_DDCD)))
- + return;
- +
- + if (status & UART_MSR_DDCD)
- + uart_handle_dcd_change(port, status & UART_MSR_DCD);
- +
- + if (status & UART_MSR_DDSR)
- + port->icount.dsr++;
- +
- + if (status & UART_MSR_DCTS)
- + uart_handle_cts_change(port, status & UART_MSR_CTS);
- +
- + wake_up_interruptible(&port->info->delta_msr_wait);
- +
- +}
- +
- +static irqreturn_t sl2312_int(int irq, void *dev_id)
- +{
- + struct uart_port *port = dev_id;
- + unsigned int status, pass_counter = 0;
- +
- + status = UART_GET_INT_STATUS(port);
- + do {
- + switch(status)
- + {
- + case UART_IIR_DR:
- + case UART_IIR_RLS:
- + sl2312_rx_chars(port);
- + break;
- + case UART_IIR_TE:
- + sl2312_tx_chars(port);
- + break;
- + case UART_IIR_MODEM:
- + sl2312_modem_status(port);
- + break;
- + default:
- + break;
- + }
- + if (pass_counter++ > SL2312_ISR_PASS_LIMIT)
- + break;
- +
- + status = UART_GET_INT_STATUS(port);
- + } while (status);
- +
- + return IRQ_HANDLED;
- +}
- +
- +static u_int sl2312_tx_empty(struct uart_port *port)
- +{
- +// printk("sl2312 tx empty : \n");
- +
- + return ((UART_GET_LSR(port) & UART_LSR_TE)? TIOCSER_TEMT : 0);
- +}
- +
- +static u_int sl2312_get_mctrl(struct uart_port *port)
- +{
- + unsigned int result = 0;
- + unsigned int status;
- +
- +// printk("sl2312 get mctrl : \n");
- +
- + status = UART_GET_MSR(port);
- + if (status & UART_MSR_DCD)
- + result |= TIOCM_CAR;
- + if (status & UART_MSR_DSR)
- + result |= TIOCM_DSR;
- + if (status & UART_MSR_CTS)
- + result |= TIOCM_CTS;
- + if (status & UART_MSR_RI)
- + result |= TIOCM_RI;
- +
- + return result;
- +}
- +
- +static void sl2312_set_mctrl_null(struct uart_port *port, u_int mctrl)
- +{
- +}
- +
- +static void sl2312_break_ctl(struct uart_port *port, int break_state)
- +{
- + unsigned int lcr;
- +
- +// printk("sl2312 break ctl : \n");
- +
- + lcr = UART_GET_LCR(port);
- + if (break_state == -1)
- + lcr |= UART_LCR_SETBREAK;
- + else
- + lcr &= ~UART_LCR_SETBREAK;
- + UART_PUT_LCR(port, lcr);
- +}
- +
- +static inline u_int uart_calculate_quot(struct uart_port *port, u_int baud)
- +{
- + u_int quot;
- +
- + /* Special case: B0 rate */
- + if (!baud)
- + baud = 9600;
- +
- + quot = (port->uartclk / (16 * baud)-1) ;
- +
- + return quot;
- +}
- +
- +static void sl2312_set_termios(struct uart_port *port, struct ktermios *termios,
- + struct ktermios *old)
- +{
- + unsigned int uart_mc, old_ier, baud, quot;
- + unsigned long flags;
- +
- + termios->c_cflag |= CREAD;
- +#ifdef DEBUG
- + printk("it8712_set_cflag(0x%x) called\n", cflag);
- +#endif
- + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- + quot = (port->uartclk / (16 * baud)) ;
- + //uart_get_divisor(port, baud);
- +
- + /* byte size and parity */
- + switch (termios->c_cflag & CSIZE) {
- + case CS5:
- + uart_mc = UART_LCR_LEN5;
- + break;
- + case CS6:
- + uart_mc = UART_LCR_LEN6;
- + break;
- + case CS7:
- + uart_mc = UART_LCR_LEN7;
- + break;
- + default: // CS8
- + uart_mc = UART_LCR_LEN8;
- + break;
- + }
- +
- + if (termios->c_cflag & CSTOPB)
- + uart_mc|= UART_LCR_STOP;
- + if (termios->c_cflag & PARENB) {
- + uart_mc |= UART_LCR_EVEN;
- + if (!(termios->c_cflag & PARODD))
- + uart_mc |= UART_LCR_ODD;
- + }
- +
- + spin_lock_irqsave(&port->lock, flags);
- + /*
- + * Update the per-port timeout
- + */
- + uart_update_timeout(port, termios->c_cflag, baud);
- + port->read_status_mask = UART_LSR_OE;
- + if (termios->c_iflag & INPCK)
- + port->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (termios->c_iflag & (BRKINT | PARMRK))
- + port->read_status_mask |= UART_LSR_BI;
- +
- + /*
- + * Characters to ignore
- + */
- + port->ignore_status_mask = 0;
- + if (termios->c_iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_FE | UART_LSR_PE;
- + if (termios->c_iflag & IGNBRK) {
- + port->ignore_status_mask |= UART_LSR_BI;
- + /*
- + * If we're ignoring parity and break indicators,
- + * ignore overruns to (for real raw support).
- + */
- + if (termios->c_iflag & IGNPAR)
- + port->ignore_status_mask |= UART_LSR_OE;
- + }
- +
- + //save_flags(flags); cli();
- + old_ier = UART_GET_IER(port);
- +
- + if(UART_ENABLE_MS(port, termios->c_cflag))
- + old_ier |= UART_IER_MS;
- +
- + /* Set baud rate */
- + UART_PUT_LCR(port, UART_LCR_DLAB);
- + UART_PUT_DIV_LO(port, (quot & 0xff));
- + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8));
- +
- + UART_PUT_LCR(port, uart_mc);
- + UART_PUT_IER(port, old_ier);
- +
- + //restore_flags(flags);
- + spin_unlock_irqrestore(&port->lock, flags);
- +}
- +
- +
- +
- +static int sl2312_startup(struct uart_port *port)
- +{
- + int retval;
- + unsigned int regs;
- +
- +// printk("sl2312 startup : \n");
- +
- + /*
- + * Use iobase to store a pointer to info. We need this to start a
- + * transmission as the tranmittr interrupt is only generated on
- + * the transition to the idle state
- + */
- +
- + /*
- + * Allocate the IRQ
- + */
- + retval = request_irq(port->irq, sl2312_int, IRQF_DISABLED, "sl2312", port);
- + if (retval)
- + return retval;
- +
- + /* setup interrupt controller */
- + regs = *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs &= ~(IRQ_UART_MASK);
- + *((volatile unsigned int *)IRQ_TMODE(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + regs = *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE)));
- + regs &= ~(IRQ_UART_MASK);
- + *((volatile unsigned int *)IRQ_TLEVEL(IO_ADDRESS(SL2312_INTERRUPT_BASE))) = regs;
- + *((volatile unsigned int *)IRQ_MASK(IO_ADDRESS(SL2312_INTERRUPT_BASE))) |= (unsigned int)(IRQ_UART_MASK);
- +
- + /*
- + * Finally, enable interrupts. Use the TII interrupt to minimise
- + * the number of interrupts generated. If higher performance is
- + * needed, consider using the TI interrupt with a suitable FIFO
- + * threshold
- + */
- + UART_PUT_IER(port, (UART_IER_DR|UART_IER_TE));
- +
- + return 0;
- +}
- +
- +static void sl2312_shutdown(struct uart_port *port)
- +{
- +// printk("sl2312 shutdown : \n");
- +
- + /*
- + * disable all interrupts, disable the port
- + */
- + UART_PUT_IER(port, 0x0);
- +
- + /* disable break condition and fifos */
- +// UART_PUT_MCR(port, (UART_GET_MCR(port)&UART_MCR_MASK));
- +
- + /*
- + * Free the interrupt
- + */
- + free_irq(port->irq, port);
- +}
- +
- +static const char *sl2312_type(struct uart_port *port)
- +{
- + return port->type == PORT_SL2312 ? "SL2312" : NULL;
- +}
- +
- +/*
- + * Release the memory region(s) being used by 'port'
- + */
- +static void sl2312_release_port(struct uart_port *port)
- +{
- +// printk("sl2312 release port : \n");
- +
- + release_mem_region(port->mapbase, UART_PORT_SIZE);
- +}
- +
- +/*
- + * Request the memory region(s) being used by 'port'
- + */
- +static int sl2312_request_port(struct uart_port *port)
- +{
- + return request_mem_region(port->mapbase, UART_PORT_SIZE,
- + "serial_sl2312") != NULL ? 0 : -EBUSY;
- +}
- +
- +/*
- + * Configure/autoconfigure the port.
- + */
- +static void sl2312_config_port(struct uart_port *port, int flags)
- +{
- +
- + if (flags & UART_CONFIG_TYPE) {
- + if (sl2312_request_port(port) == 0)
- + port->type = PORT_SL2312;
- + }
- +}
- +
- +/*
- + * verify the new serial_struct (for TIOCSSERIAL).
- + */
- +static int sl2312_verify_port(struct uart_port *port, struct serial_struct *ser)
- +{
- + int ret = 0;
- +
- + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00)
- + ret = -EINVAL;
- + if (ser->irq < 0 || ser->irq >= NR_IRQS)
- + ret = -EINVAL;
- + if (ser->baud_base < 9600)
- + ret = -EINVAL;
- + return ret;
- +}
- +
- +static struct uart_ops sl2312_pops = {
- + .tx_empty =sl2312_tx_empty,
- + .set_mctrl =sl2312_set_mctrl_null,
- + .get_mctrl =sl2312_get_mctrl,
- + .stop_tx =sl2312_stop_tx,
- + .start_tx =sl2312_start_tx,
- + .stop_rx =sl2312_stop_rx,
- + .enable_ms =sl2312_enable_ms,
- + .break_ctl =sl2312_break_ctl,
- + .startup =sl2312_startup,
- + .shutdown =sl2312_shutdown,
- + .set_termios =sl2312_set_termios,
- + .type =sl2312_type,
- + .release_port =sl2312_release_port,
- + .request_port =sl2312_request_port,
- + .config_port =sl2312_config_port,
- + .verify_port =sl2312_verify_port,
- +};
- +
- +#ifdef CONFIG_ARCH_SL2312
- +
- +static struct uart_port sl2312_ports[UART_NR] = {
- + {
- + membase: (void *)IO_ADDRESS(SL2312_UART_BASE),
- + mapbase: SL2312_UART_BASE,
- + iotype: SERIAL_IO_MEM,
- + irq: IRQ_UART,
- + uartclk: UART_CLK,
- + fifosize: 16,
- + ops: &sl2312_pops,
- + flags: ASYNC_BOOT_AUTOCONF,
- + }
- +};
- +
- +#endif
- +
- +#ifdef CONFIG_SERIAL_SL2312_CONSOLE
- +#ifdef used_and_not_const_char_pointer
- +static int sl2312_console_read(struct uart_port *port, char *s, u_int count)
- +{
- + unsigned int status;
- + int c;
- +#ifdef DEBUG
- + printk("sl2312_console_read() called\n");
- +#endif
- +
- + c = 0;
- + while (c < count) {
- + status = UART_GET_LSR(port);
- + if (UART_RX_DATA(status)) {
- + *s++ = UART_GET_CHAR(port);
- + c++;
- + } else {
- + // nothing more to get, return
- + return c;
- + }
- + }
- + // return the count
- + return c;
- +}
- +#endif
- +static void sl2312_console_write(struct console *co, const char *s, unsigned count)
- +{
- +#ifdef CONFIG_ARCH_SL2312
- + struct uart_port *port = sl2312_ports + co->index;
- + unsigned int status, old_ies;
- + int i;
- +
- + /*
- + * First save the CR then disable the interrupts
- + */
- + old_ies = UART_GET_IER(port);
- + UART_PUT_IER(port,0x0);
- +
- + /*
- + * Now, do each character
- + */
- + for (i = 0; i < count; i++) {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, s[i]);
- + if (s[i] == '\n') {
- + do {
- + status = UART_GET_LSR(port);
- + } while (!UART_TX_READY(status));
- + UART_PUT_CHAR(port, '\r');
- + }
- + }
- +
- + /*
- + * Finally, wait for transmitter to become empty
- + * and restore the IES
- + */
- + do {
- + status = UART_GET_LSR(port);
- + } while (!(status&UART_LSR_TE));
- + UART_PUT_IER(port, old_ies);
- +#endif
- +}
- +
- +#if 0
- +static void sl2312_console_device(struct console *co,int *index)
- +{
- +
- + struct uart_driver *p = co->data;
- + *index = co->index;
- + return p->tty_driver;
- +
- +}
- +#endif
- +
- +static void /*__init*/ sl2312_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
- +{
- +// printk("sl2312 console get options : \n");
- +
- + u_int uart_mc, quot;
- + uart_mc= UART_GET_MCR(port);
- +
- + *parity = 'n';
- + if (uart_mc & UART_LCR_PE) {
- + if (uart_mc & UART_LCR_EVEN)
- + *parity = 'e';
- + else
- + *parity = 'o';
- + }
- +
- + switch (uart_mc & UART_LCR_MSK){
- +
- + case UART_LCR_LEN5:
- + *bits = 5;
- + break;
- + case UART_LCR_LEN6:
- + *bits = 6;
- + break;
- + case UART_LCR_LEN7:
- + *bits = 7;
- + break;
- + case UART_LCR_LEN8:
- + *bits = 8;
- + break;
- + }
- + UART_PUT_MCR(port,UART_LCR_DLAB);
- + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8);
- + UART_PUT_MCR(port,uart_mc);
- + *baud = port->uartclk / (16 *quot );
- +}
- +
- +static int __init sl2312_console_setup(struct console *co, char *options)
- +{
- + struct uart_port *port;
- + int baud = 19200;
- + int bits = 8;
- + int parity = 'n';
- + int flow= 'n';
- +
- + printk("sl2312 console setup : \n");
- +
- +#ifdef CONFIG_ARCH_SL2312
- + /*
- + * Check whether an invalid uart number has been specified, and
- + * if so, search for the first available port that does have
- + * console support.
- + */
- + port = uart_get_console(sl2312_ports,SL2312_NO_PORTS,co);
- +#else
- + return -ENODEV;
- +#endif
- +
- + if (options)
- + uart_parse_options(options, &baud, &parity, &bits, &flow);
- + else
- + sl2312_console_get_options(port, &baud, &parity, &bits);
- +
- + return uart_set_options(port, co, baud, parity, bits, flow);
- +}
- +
- +extern struct uart_driver sl2312_reg;
- +static struct console sl2312_console = {
- + .name = SERIAL_SL2312_NAME,
- + .write = sl2312_console_write,
- + .device = uart_console_device,
- +// .device = sl2312_console_device,
- + .setup = sl2312_console_setup,
- +// .flags = (CON_PRINTBUFFER|CON_ENABLED),
- + .flags = CON_PRINTBUFFER,
- + .index = -1,
- + .data = &sl2312_reg,
- +};
- +
- +static int __init sl2312_console_init(void)
- +{
- + register_console(&sl2312_console);
- + return 0;
- +
- +}
- +
- +console_initcall(sl2312_console_init);
- +
- +#define SL2312_CONSOLE &sl2312_console
- +#else
- +#define SL2312_CONSOLE NULL
- +#endif
- +
- +// static
- +struct uart_driver sl2312_reg = {
- + .owner = NULL,
- + .driver_name = SERIAL_SL2312_NAME,
- + .dev_name = SERIAL_SL2312_NAME,
- + .major = SERIAL_SL2312_MAJOR,
- + .minor = SERIAL_SL2312_MINOR,
- + .nr = UART_NR,
- + .cons = SL2312_CONSOLE,
- +};
- +
- +static int __init sl2312_init(void)
- +{
- + int result;
- + //printk("serial_it8712: it871212_init \n");
- +
- + result = uart_register_driver(&sl2312_reg);
- + if(result)
- + return result;
- + result = uart_add_one_port(&sl2312_reg, &sl2312_ports[0]);
- +
- + return result;
- +}
- +
- +
- +__initcall(sl2312_init);
- --- a/include/linux/serial_core.h
- +++ b/include/linux/serial_core.h
- @@ -147,6 +147,10 @@
- #define PORT_SB1250_DUART 77
-
-
- +/* Storlink Soc */
- +#define PORT_SL2312 72
- +#define PORT_IT8712 73
- +
- #ifdef __KERNEL__
-
- #include <linux/compiler.h>
- --- a/drivers/char/Makefile
- +++ b/drivers/char/Makefile
- @@ -70,6 +70,16 @@
- obj-$(CONFIG_APPLICOM) += applicom.o
- obj-$(CONFIG_SONYPI) += sonypi.o
- obj-$(CONFIG_RTC) += rtc.o
- +
- +### for Storlink SoC ###
- +obj-$(CONFIG_SL2312_RTC) += sl2312_rtc.o
- +obj-$(CONFIG_IT8712_GPIO) += it8712_gpio.o
- +obj-$(CONFIG_GEMINI_GPIO) += gemini_gpio.o
- +obj-$(CONFIG_GEMINI_PWC) += gemini_pwr.o
- +obj-$(CONFIG_GEMINI_CIR) += gemini_cir.o
- +obj-$(CONFIG_GEMINI_I2S) += gemini_i2s.o
- +obj-$(CONFIG_SL2312_WATCHDOG) += sl2312_wd.o
- +
- obj-$(CONFIG_HPET) += hpet.o
- obj-$(CONFIG_GEN_RTC) += genrtc.o
- obj-$(CONFIG_EFI_RTC) += efirtc.o
- --- a/drivers/serial/Kconfig
- +++ b/drivers/serial/Kconfig
- @@ -280,6 +280,56 @@
-
- comment "Non-8250 serial port support"
-
- +config SERIAL_SL2312
- + bool "SL2312 serial port (sl2312) support"
- + depends on ARCH_SL2312
- + select SERIAL_CORE
- + select SERIAL_SL2312_CONSOLE
- + help
- + Say Y here if you want to use the hard logic uart on SWORD. This
- + driver also supports soft logic implentations of this uart core.
- +
- +config SERIAL_SL2312_CONSOLE
- + bool "Support for console on SL2312 serial port"
- + depends on SERIAL_SL2312
- + select SERIAL_CORE_CONSOLE
- + help
- + Say Y here if you want to support a serial console on an SWORD
- + hard logic uart or uart00 IP core.
- +
- + Even if you say Y here, the currently visible virtual console
- + (/dev/tty0) will still be used as the system console by default, but
- + you can alter that using a kernel command line option such as
- + "console=ttyS0". (Try "man bootparam" or see the documentation of
- + your boot loader (lilo or loadlin) about how to pass options to the
- + kernel at boot time.)
- +
- +
- +config SERIAL_IT8712
- + bool "Sl2312 serial port(IT8712) support"
- + depends on ARM && ARCH_SL2312 && SL2312_LPC
- + select SERIAL_CORE
- + select SERIAL_IT8712_CONSOLE
- + help
- + Say Y here if you want to use the hard logic uart on Excalibur. This
- + driver also supports soft logic implentations of this uart core.
- +
- +config SERIAL_IT8712_CONSOLE
- + bool "Support for console on Sword serial port(IT8712)"
- + depends on SERIAL_IT8712
- + select SERIAL_CORE_CONSOLE
- + help
- + Say Y here if you want to support a serial console on an Excalibur
- + hard logic uart or uart00 IP core.
- +
- + Even if you say Y here, the currently visible virtual console
- + (/dev/tty0) will still be used as the system console by default, but
- + you can alter that using a kernel command line option such as
- + "console=ttySI0". (Try "man bootparam" or see the documentation of
- + your boot loader (lilo or loadlin) about how to pass options to the
- + kernel at boot time.)
- +
- +
- config SERIAL_AMBA_PL010
- tristate "ARM AMBA PL010 serial port support"
- depends on ARM_AMBA && (BROKEN || !ARCH_VERSATILE)
- --- a/drivers/serial/Makefile
- +++ b/drivers/serial/Makefile
- @@ -62,5 +62,7 @@
- obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
- obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o
- obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
- +obj-$(CONFIG_SERIAL_IT8712) += it8712.o
- +obj-$(CONFIG_SERIAL_SL2312) += serial_sl2312.o
- obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o
- obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o
|