Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-02-12 23:46:15 -0800
committerLinus Torvalds <torvalds@home.osdl.org>2004-02-12 23:46:15 -0800
commitb7e711bad04113ab70e92f2a21974df72b64c17a (patch)
tree5d4724ea1bf926698284ec8fbe02f7afbfb157f3
parentf4dd156ebe818aa46bfc8e2b8a32bc5a0162bc92 (diff)
[PATCH] sh: Add H8/300 support to sh-sci
From: Paul Mundt <lethal@linux-sh.org> This adds support for the H8/300 series to the sh-sci driver. Patch from Yoshinori Sato.
-rw-r--r--drivers/char/sh-sci.c67
-rw-r--r--drivers/char/sh-sci.h131
2 files changed, 184 insertions, 14 deletions
diff --git a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
index db09c604c1a6..378e3d53d3b7 100644
--- a/drivers/char/sh-sci.c
+++ b/drivers/char/sh-sci.c
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.c,v 1.15 2003/10/13 07:21:19 lethal Exp $
+/* $Id: sh-sci.c,v 1.16 2004/02/10 17:04:17 lethal Exp $
*
* linux/drivers/char/sh-sci.c
*
@@ -7,6 +7,7 @@
* Copyright (C) 2000 Sugioka Toshinobu
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7760 SCIF. Paul Mundt (Oct 2003).
+ * Modified to support H8/300 Series. Yoshinori Sato (Feb 2004).
*
* TTY code is based on sx.c (Specialix SX driver) by:
*
@@ -337,6 +338,7 @@ static struct real_driver sci_real_driver = {
NULL
};
+#if !defined(__H8300H__) && !defined(__H8300S__)
#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
{
@@ -403,6 +405,32 @@ static void sci_init_pins_scif(struct sci_port* port, unsigned int cflag)
#endif
#endif /* SCIF_ONLY || SCI_AND_SCIF */
+#else /* !defined(__H8300H__) && !defined(__H8300S__) */
+static void sci_init_pins_sci(struct sci_port* port, unsigned int cflag)
+{
+ int ch = (port->base - SMR0) >> 3;
+ /* set DDR regs */
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
+ /* tx mark output*/
+ H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
+}
+
+#if defined(__H8300S__)
+enum {sci_disable,sci_enable};
+
+static void h8300_sci_enable(struct sci_port* port, unsigned int ctrl)
+{
+ volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
+ int ch = (port->base - SMR0) >> 3;
+ unsigned char mask = 1 << (ch+1);
+ if (ctrl == sci_disable)
+ *mstpcrl |= mask;
+ else
+ *mstpcrl &= ~mask;
+}
+#endif
+#endif
static void sci_setsignals(struct sci_port *port, int dtr, int rts)
{
@@ -487,9 +515,11 @@ static void sci_set_termios_cflag(struct sci_port *port, int cflag, int baud)
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
+#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
}
+#endif
smr_val = sci_in(port, SCSMR) & 3;
if ((cflag & CSIZE) == CS7)
@@ -559,11 +589,15 @@ static void sci_transmit_chars(struct sci_port *port)
while (1) {
count = port->gs.xmit_cnt;
+#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
txroom = 16 - (sci_in(port, SCFDR)>>8);
} else {
txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
}
+#else
+ txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+#endif
if (count > txroom)
count = txroom;
@@ -600,10 +634,12 @@ static void sci_transmit_chars(struct sci_port *port)
ctrl &= ~SCI_CTRL_FLAGS_TIE;
port->gs.flags &= ~GS_TX_INTEN;
} else {
+#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
}
+#endif
ctrl |= SCI_CTRL_FLAGS_TIE;
}
sci_out(port, SCSCR, ctrl);
@@ -627,11 +663,15 @@ static inline void sci_receive_chars(struct sci_port *port,
tty = port->gs.tty;
while (1) {
+#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
count = sci_in(port, SCFDR)&0x001f;
} else {
count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
}
+#else
+ count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+#endif
/* Don't copy more bytes than there is room for in the buffer */
if (tty->flip.count + count > TTY_FLIPBUF_SIZE)
@@ -861,6 +901,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
return IRQ_HANDLED;
}
+#if !defined(SCI_ONLY)
static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
{
struct sci_port *port = ptr;
@@ -871,6 +912,7 @@ static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
return IRQ_HANDLED;
}
+#endif
static void do_softint(void *private_)
{
@@ -955,11 +997,15 @@ static int sci_chars_in_buffer(void * ptr)
{
struct sci_port *port = ptr;
+#if !defined(SCI_ONLY)
if (port->type == PORT_SCIF) {
return (sci_in(port, SCFDR) >> 8) + ((sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1);
} else {
return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
}
+#else
+ return (sci_in(port, SCxSR) & SCxSR_TEND(port))? 0: 1;
+#endif
}
static void sci_shutdown_port(void * ptr)
@@ -970,6 +1016,9 @@ static void sci_shutdown_port(void * ptr)
if (port->gs.tty && port->gs.tty->termios->c_cflag & HUPCL)
sci_setsignals(port, 0, 0);
sci_free_irq(port);
+#if defined(__H8300S__)
+ h8300_sci_enable(port,sci_disable);
+#endif
}
/* ********************************************************************** *
@@ -996,6 +1045,10 @@ static int sci_open(struct tty_struct * tty, struct file * filp)
port->event = 0;
INIT_WORK(&port->tqueue, do_softint, port);
+#if defined(__H8300S__)
+ h8300_sci_enable(port,sci_enable);
+#endif
+
/*
* Start up serial port
*/
@@ -1282,12 +1335,17 @@ static int sci_init_drivers(void)
static int sci_request_irq(struct sci_port *port)
{
int i;
+#if !defined(SCI_ONLY)
irqreturn_t (*handlers[4])(int irq, void *p, struct pt_regs *regs) = {
sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
sci_br_interrupt,
};
-
- for (i=0; i<4; i++) {
+#else
+ void (*handlers[3])(int irq, void *ptr, struct pt_regs *regs) = {
+ sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
+ };
+#endif
+ for (i=0; i<(sizeof(handlers)/sizeof(handlers[0])); i++) {
if (!port->irqs[i]) continue;
if (request_irq(port->irqs[i], handlers[i], SA_INTERRUPT,
"sci", port)) {
@@ -1432,6 +1490,9 @@ static int __init serial_console_setup(struct console *co, char *options)
co->cflag = cflag;
sercons_baud = baud;
+#if defined(__H8300S__)
+ h8300_sci_enable(sercons_port,sci_enable);
+#endif
sci_set_termios_cflag(sercons_port, cflag, baud);
sercons_port->old_cflag = cflag;
diff --git a/drivers/char/sh-sci.h b/drivers/char/sh-sci.h
index 8a826e280116..5d07cd1072cd 100644
--- a/drivers/char/sh-sci.h
+++ b/drivers/char/sh-sci.h
@@ -1,4 +1,4 @@
-/* $Id: sh-sci.h,v 1.6 2003/10/13 01:11:11 lethal Exp $
+/* $Id: sh-sci.h,v 1.7 2004/02/10 17:04:17 lethal Exp $
*
* linux/drivers/char/sh-sci.h
*
@@ -7,10 +7,21 @@
* Copyright (C) 2000 Greg Banks
* Modified to support multiple serial ports. Stuart Menefy (May 2000).
* Modified to support SH7760 SCIF. Paul Mundt (Oct 2003).
+ * Modified to support H8/300 Serise Yoshinori Sato (Feb 2004).
*
*/
#include <linux/config.h>
+#if defined(__H8300H__) || defined(__H8300S__)
+#include <asm/gpio.h>
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_H8S2678)
+#include <asm/regs267x.h>
+#endif
+#endif
+
/* Values for sci_port->type */
#define PORT_SCI 0
#define PORT_SCIF 1
@@ -30,6 +41,12 @@
#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
+#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
+#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
+#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
+#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
+#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
+#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCI_NPORTS 1
@@ -87,6 +104,26 @@
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
+# define SCI_NPORTS 3
+# define SCI_INIT { \
+ { {}, PORT_SCI, 0x00ffffb0, H8300H_SCI_IRQS0, sci_init_pins_sci }, \
+ { {}, PORT_SCI, 0x00ffffb8, H8300H_SCI_IRQS1, sci_init_pins_sci }, \
+ { {}, PORT_SCI, 0x00ffffc0, H8300H_SCI_IRQS2, sci_init_pins_sci } \
+}
+# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
+#elif defined(CONFIG_H8S2678)
+# define SCI_NPORTS 3
+# define SCI_INIT { \
+ { {}, PORT_SCI, 0x00ffff78, H8S_SCI_IRQS0, sci_init_pins_sci }, \
+ { {}, PORT_SCI, 0x00ffff80, H8S_SCI_IRQS1, sci_init_pins_sci }, \
+ { {}, PORT_SCI, 0x00ffff88, H8S_SCI_IRQS2, sci_init_pins_sci } \
+}
+# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCI_ONLY
+# define H8300_SCI_DR(ch) *(volatile char *)(P1DR + h8300_sci_pins[ch].port)
#else
# error CPU subtype not defined
#endif
@@ -242,28 +279,46 @@ struct sci_port {
SCI_OUT(scif_size, scif_offset, value); \
}
+#define CPU_SCI_FNS(name, sci_offset, sci_size) \
+ static inline unsigned int sci_##name##_in(struct sci_port* port) \
+ { \
+ SCI_IN(sci_size, sci_offset); \
+ } \
+ static inline void sci_##name##_out(struct sci_port* port, unsigned int value) \
+ { \
+ SCI_OUT(sci_size, sci_offset, value); \
+ }
+
#ifdef CONFIG_CPU_SH3
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
- sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+ h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh3_scif_offset, sh3_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh3_scif_offset, sh3_scif_size)
+#elif defined(__H8300H__) || defined(__H8300S__)
+#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+ h8_sci_offset, h8_sci_size) \
+ CPU_SCI_FNS(name, h8_sci_offset, h8_sci_size)
+#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size)
#else
#define SCIx_FNS(name, sh3_sci_offset, sh3_sci_size, sh4_sci_offset, sh4_sci_size, \
- sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
+ sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size, \
+ h8_sci_offset, h8_sci_size) \
CPU_SCIx_FNS(name, sh4_sci_offset, sh4_sci_size, sh4_scif_offset, sh4_scif_size)
#define SCIF_FNS(name, sh3_scif_offset, sh3_scif_size, sh4_scif_offset, sh4_scif_size) \
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 */
-/* name off sz off sz off sz off sz */
-SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16)
-SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8)
-SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16)
-SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8)
-SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16)
-SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8)
+/* reg SCI/SH3 SCI/SH4 SCIF/SH3 SCIF/SH4 SCI/H8*/
+/* name off sz off sz off sz off sz off sz*/
+SCIx_FNS(SCSMR, 0x00, 8, 0x00, 8, 0x00, 8, 0x00, 16, 0x00, 8)
+SCIx_FNS(SCBRR, 0x02, 8, 0x04, 8, 0x02, 8, 0x04, 8, 0x01, 8)
+SCIx_FNS(SCSCR, 0x04, 8, 0x08, 8, 0x04, 8, 0x08, 16, 0x02, 8)
+SCIx_FNS(SCxTDR, 0x06, 8, 0x0c, 8, 0x06, 8, 0x0C, 8, 0x03, 8)
+SCIx_FNS(SCxSR, 0x08, 8, 0x10, 8, 0x08, 16, 0x10, 16, 0x04, 8)
+SCIx_FNS(SCxRDR, 0x0a, 8, 0x14, 8, 0x0A, 8, 0x14, 8, 0x05, 8)
SCIF_FNS(SCFCR, 0x0c, 8, 0x18, 16)
SCIF_FNS(SCFDR, 0x0e, 16, 0x1C, 16)
SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
@@ -271,6 +326,50 @@ SCIF_FNS(SCLSR, 0, 0, 0x24, 16)
#define sci_in(port, reg) sci_##reg##_in(port)
#define sci_out(port, reg, value) sci_##reg##_out(port, value)
+/* H8/300 series SCI pins assignment */
+#if defined(__H8300H__) || defined(__H8300S__)
+static const struct __attribute__((packed))
+{
+ int port; /* GPIO port no */
+ unsigned short rx,tx; /* GPIO bit no */
+} h8300_sci_pins[] =
+{
+#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
+ { /* SCI0 */
+ .port = H8300_GPIO_P9,
+ .rx = H8300_GPIO_B2,
+ .tx = H8300_GPIO_B0,
+ },
+ { /* SCI1 */
+ .port = H8300_GPIO_P9,
+ .rx = H8300_GPIO_B3,
+ .tx = H8300_GPIO_B1,
+ },
+ { /* SCI2 */
+ .port = H8300_GPIO_PB,
+ .rx = H8300_GPIO_B7,
+ .tx = H8300_GPIO_B6,
+ }
+#elif defined(CONFIG_H8S2678)
+ { /* SCI0 */
+ .port = H8300_GPIO_P3,
+ .rx = H8300_GPIO_B2,
+ .tx = H8300_GPIO_B0,
+ },
+ { /* SCI1 */
+ .port = H8300_GPIO_P3,
+ .rx = H8300_GPIO_B3,
+ .tx = H8300_GPIO_B1,
+ },
+ { /* SCI2 */
+ .port = H8300_GPIO_P5,
+ .rx = H8300_GPIO_B1,
+ .tx = H8300_GPIO_B0,
+ }
+#endif
+};
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
static inline int sci_rxd_in(struct sci_port *port)
{
@@ -321,6 +420,12 @@ static inline int sci_rxd_in(struct sci_port *port)
return ctrl_inw(SCSPTR2)&0x0001 ? 1 : 0; /* SCIF */
}
+#elif defined(__H8300H__) || defined(__H8300S__)
+static inline int sci_rxd_in(struct sci_port *port)
+{
+ int ch = (port->base - SMR0) >> 3;
+ return (H8300_SCI_DR(ch) & h8300_sci_pins[ch].rx) ? 1 : 0;
+}
#endif
/*
@@ -357,7 +462,11 @@ static inline int sci_rxd_in(struct sci_port *port)
#define PCLK (current_cpu_data.module_clock)
+#if !defined(__H8300H__) && !defined(__H8300S__)
#define SCBRR_VALUE(bps) ((PCLK+16*bps)/(32*bps)-1)
+#else
+#define SCBRR_VALUE(bps) (((CONFIG_CPU_CLOCK*1000/32)/bps)-1)
+#endif
#define BPS_2400 SCBRR_VALUE(2400)
#define BPS_4800 SCBRR_VALUE(4800)
#define BPS_9600 SCBRR_VALUE(9600)