pmac-zilog: add platform driver

Add platform driver support to the pmac-zilog driver, for m68k macs.
Place the powermac-specific code inside #ifdef CONFIG_PPC_PMAC.

Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
This commit is contained in:
Finn Thain
2009-11-17 20:04:44 +11:00
committed by Geert Uytterhoeven
parent 1f7b5fff50
commit ec9cbe0989
5 changed files with 166 additions and 25 deletions

View File

@@ -63,11 +63,17 @@
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/irq.h>
#ifdef CONFIG_PPC_PMAC
#include <asm/prom.h>
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/dbdma.h>
#include <asm/macio.h>
#else
#include <linux/platform_device.h>
#define of_machine_is_compatible(x) (0)
#endif
#if defined (CONFIG_SERIAL_PMACZILOG_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -83,11 +89,9 @@
static char version[] __initdata = "pmac_zilog: 0.6 (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the PowerMac serial ports.");
MODULE_DESCRIPTION("Driver for the Mac and PowerMac serial ports.");
MODULE_LICENSE("GPL");
#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
#ifdef CONFIG_SERIAL_PMACZILOG_TTYS
#define PMACZILOG_MAJOR TTY_MAJOR
#define PMACZILOG_MINOR 64
@@ -341,7 +345,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
uap->curregs[R1] &= ~(EXT_INT_ENAB | TxINT_ENAB | RxINT_MASK);
write_zsreg(uap, R1, uap->curregs[R1]);
zssync(uap);
dev_err(&uap->dev->ofdev.dev, "pmz: rx irq flood !\n");
pmz_error("pmz: rx irq flood !\n");
return tty;
}
@@ -757,6 +761,8 @@ static void pmz_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
#ifdef CONFIG_PPC_PMAC
/*
* Turn power on or off to the SCC and associated stuff
* (port drivers, modem, IR port, etc.)
@@ -792,6 +798,15 @@ static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
return delay;
}
#else
static int pmz_set_scc_power(struct uart_pmac_port *uap, int state)
{
return 0;
}
#endif /* !CONFIG_PPC_PMAC */
/*
* FixZeroBug....Works around a bug in the SCC receving channel.
* Inspired from Darwin code, 15 Sept. 2000 -DanM
@@ -954,9 +969,9 @@ static int pmz_startup(struct uart_port *port)
}
pmz_get_port_A(uap)->flags |= PMACZILOG_FLAG_IS_IRQ_ON;
if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED, "PowerMac Zilog", uap)) {
dev_err(&uap->dev->ofdev.dev,
"Unable to register zs interrupt handler.\n");
if (request_irq(uap->port.irq, pmz_interrupt, IRQF_SHARED,
"SCC", uap)) {
pmz_error("Unable to register zs interrupt handler.\n");
pmz_set_scc_power(uap, 0);
mutex_unlock(&pmz_irq_mutex);
return -ENXIO;
@@ -1196,7 +1211,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
while ((read_zsreg(uap, R0) & Tx_BUF_EMP) == 0
|| (read_zsreg(uap, R1) & ALL_SNT) == 0) {
if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, "transmitter didn't drain\n");
pmz_error("transmitter didn't drain\n");
return;
}
udelay(10);
@@ -1212,7 +1227,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
read_zsdata(uap);
mdelay(10);
if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev, "receiver didn't drain\n");
pmz_error("receiver didn't drain\n");
return;
}
}
@@ -1233,8 +1248,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev,
"irda_setup timed out on get_version byte\n");
pmz_error("irda_setup timed out on get_version byte\n");
goto out;
}
udelay(10);
@@ -1242,8 +1256,7 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
version = read_zsdata(uap);
if (version < 4) {
dev_info(&uap->dev->ofdev.dev, "IrDA: dongle version %d not supported\n",
version);
pmz_info("IrDA: dongle version %d not supported\n", version);
goto out;
}
@@ -1252,18 +1265,16 @@ static void pmz_irda_setup(struct uart_pmac_port *uap, unsigned long *baud)
t = 5000;
while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0) {
if (--t <= 0) {
dev_err(&uap->dev->ofdev.dev,
"irda_setup timed out on speed mode byte\n");
pmz_error("irda_setup timed out on speed mode byte\n");
goto out;
}
udelay(10);
}
t = read_zsdata(uap);
if (t != cmdbyte)
dev_err(&uap->dev->ofdev.dev,
"irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
pmz_error("irda_setup speed mode byte = %x (%x)\n", t, cmdbyte);
dev_info(&uap->dev->ofdev.dev, "IrDA setup for %ld bps, dongle version: %d\n",
pmz_info("IrDA setup for %ld bps, dongle version: %d\n",
*baud, version);
(void)read_zsdata(uap);
@@ -1413,7 +1424,7 @@ static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
write_zsdata(uap, c);
}
#endif
#endif /* CONFIG_CONSOLE_POLL */
static struct uart_ops pmz_pops = {
.tx_empty = pmz_tx_empty,
@@ -1438,6 +1449,8 @@ static struct uart_ops pmz_pops = {
#endif
};
#ifdef CONFIG_PPC_PMAC
/*
* Setup one port structure after probing, HW is down at this point,
* Unlike sunzilog, we don't need to pre-init the spinlock as we don't
@@ -1834,6 +1847,88 @@ next:
return 0;
}
#else
extern struct platform_device scc_a_pdev, scc_b_pdev;
static int __init pmz_init_port(struct uart_pmac_port *uap)
{
struct resource *r_ports;
int irq;
r_ports = platform_get_resource(uap->node, IORESOURCE_MEM, 0);
irq = platform_get_irq(uap->node, 0);
if (!r_ports || !irq)
return -ENODEV;
uap->port.mapbase = r_ports->start;
uap->port.membase = (unsigned char __iomem *) r_ports->start;
uap->port.iotype = UPIO_MEM;
uap->port.irq = irq;
uap->port.uartclk = ZS_CLOCK;
uap->port.fifosize = 1;
uap->port.ops = &pmz_pops;
uap->port.type = PORT_PMAC_ZILOG;
uap->port.flags = 0;
uap->control_reg = uap->port.membase;
uap->data_reg = uap->control_reg + 4;
uap->port_type = 0;
pmz_convert_to_zs(uap, CS8, 0, 9600);
return 0;
}
static int __init pmz_probe(void)
{
int err;
pmz_ports_count = 0;
pmz_ports[0].mate = &pmz_ports[1];
pmz_ports[0].port.line = 0;
pmz_ports[0].flags = PMACZILOG_FLAG_IS_CHANNEL_A;
pmz_ports[0].node = &scc_a_pdev;
err = pmz_init_port(&pmz_ports[0]);
if (err)
return err;
pmz_ports_count++;
pmz_ports[1].mate = &pmz_ports[0];
pmz_ports[1].port.line = 1;
pmz_ports[1].flags = 0;
pmz_ports[1].node = &scc_b_pdev;
err = pmz_init_port(&pmz_ports[1]);
if (err)
return err;
pmz_ports_count++;
return 0;
}
static void pmz_dispose_port(struct uart_pmac_port *uap)
{
memset(uap, 0, sizeof(struct uart_pmac_port));
}
static int __init pmz_attach(struct platform_device *pdev)
{
int i;
for (i = 0; i < pmz_ports_count; i++)
if (pmz_ports[i].node == pdev)
return 0;
return -ENODEV;
}
static int __exit pmz_detach(struct platform_device *pdev)
{
return 0;
}
#endif /* !CONFIG_PPC_PMAC */
#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE
static void pmz_console_write(struct console *con, const char *s, unsigned int count);
@@ -1894,6 +1989,8 @@ err_out:
return rc;
}
#ifdef CONFIG_PPC_PMAC
static struct of_device_id pmz_match[] =
{
{
@@ -1915,6 +2012,18 @@ static struct macio_driver pmz_driver = {
.resume = pmz_resume,
};
#else
static struct platform_driver pmz_driver = {
.remove = __exit_p(pmz_detach),
.driver = {
.name = "scc",
.owner = THIS_MODULE,
},
};
#endif /* !CONFIG_PPC_PMAC */
static int __init init_pmz(void)
{
int rc, i;
@@ -1953,15 +2062,23 @@ static int __init init_pmz(void)
/*
* Then we register the macio driver itself
*/
#ifdef CONFIG_PPC_PMAC
return macio_register_driver(&pmz_driver);
#else
return platform_driver_probe(&pmz_driver, pmz_attach);
#endif
}
static void __exit exit_pmz(void)
{
int i;
#ifdef CONFIG_PPC_PMAC
/* Get rid of macio-driver (detach from macio) */
macio_unregister_driver(&pmz_driver);
#else
platform_driver_unregister(&pmz_driver);
#endif
for (i = 0; i < pmz_ports_count; i++) {
struct uart_pmac_port *uport = &pmz_ports[i];