aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/serial/sunzilog.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial/sunzilog.c')
-rw-r--r--drivers/serial/sunzilog.c128
1 files changed, 73 insertions, 55 deletions
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index a1456d9352cb..d34f336d53d8 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -68,9 +68,6 @@ static int num_sunzilog;
68#define NUM_SUNZILOG num_sunzilog 68#define NUM_SUNZILOG num_sunzilog
69#define NUM_CHANNELS (NUM_SUNZILOG * 2) 69#define NUM_CHANNELS (NUM_SUNZILOG * 2)
70 70
71#define KEYBOARD_LINE 0x2
72#define MOUSE_LINE 0x3
73
74#define ZS_CLOCK 4915200 /* Zilog input clock rate. */ 71#define ZS_CLOCK 4915200 /* Zilog input clock rate. */
75#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */ 72#define ZS_CLOCK_DIVISOR 16 /* Divisor this driver uses. */
76 73
@@ -1149,6 +1146,9 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
1149 unsigned long flags; 1146 unsigned long flags;
1150 int baud, brg; 1147 int baud, brg;
1151 1148
1149 if (up->port.type != PORT_SUNZILOG)
1150 return -1;
1151
1152 printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n", 1152 printk(KERN_INFO "Console: ttyS%d (SunZilog zs%d)\n",
1153 (sunzilog_reg.minor - 64) + con->index, con->index); 1153 (sunzilog_reg.minor - 64) + con->index, con->index);
1154 1154
@@ -1225,12 +1225,10 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
1225{ 1225{
1226 int baud, brg; 1226 int baud, brg;
1227 1227
1228 if (channel == KEYBOARD_LINE) { 1228 if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
1229 up->flags |= SUNZILOG_FLAG_CONS_KEYB;
1230 up->cflag = B1200 | CS8 | CLOCAL | CREAD; 1229 up->cflag = B1200 | CS8 | CLOCAL | CREAD;
1231 baud = 1200; 1230 baud = 1200;
1232 } else { 1231 } else {
1233 up->flags |= SUNZILOG_FLAG_CONS_MOUSE;
1234 up->cflag = B4800 | CS8 | CLOCAL | CREAD; 1232 up->cflag = B4800 | CS8 | CLOCAL | CREAD;
1235 baud = 4800; 1233 baud = 4800;
1236 } 1234 }
@@ -1243,14 +1241,14 @@ static void __init sunzilog_init_kbdms(struct uart_sunzilog_port *up, int channe
1243} 1241}
1244 1242
1245#ifdef CONFIG_SERIO 1243#ifdef CONFIG_SERIO
1246static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int channel) 1244static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
1247{ 1245{
1248 struct serio *serio = &up->serio; 1246 struct serio *serio = &up->serio;
1249 1247
1250 serio->port_data = up; 1248 serio->port_data = up;
1251 1249
1252 serio->id.type = SERIO_RS232; 1250 serio->id.type = SERIO_RS232;
1253 if (channel == KEYBOARD_LINE) { 1251 if (up->flags & SUNZILOG_FLAG_CONS_KEYB) {
1254 serio->id.proto = SERIO_SUNKBD; 1252 serio->id.proto = SERIO_SUNKBD;
1255 strlcpy(serio->name, "zskbd", sizeof(serio->name)); 1253 strlcpy(serio->name, "zskbd", sizeof(serio->name));
1256 } else { 1254 } else {
@@ -1259,7 +1257,8 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up, int ch
1259 strlcpy(serio->name, "zsms", sizeof(serio->name)); 1257 strlcpy(serio->name, "zsms", sizeof(serio->name));
1260 } 1258 }
1261 strlcpy(serio->phys, 1259 strlcpy(serio->phys,
1262 (channel == KEYBOARD_LINE ? "zs/serio0" : "zs/serio1"), 1260 ((up->flags & SUNZILOG_FLAG_CONS_KEYB) ?
1261 "zs/serio0" : "zs/serio1"),
1263 sizeof(serio->phys)); 1262 sizeof(serio->phys));
1264 1263
1265 serio->write = sunzilog_serio_write; 1264 serio->write = sunzilog_serio_write;
@@ -1286,8 +1285,8 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
1286 (void) read_zsreg(channel, R0); 1285 (void) read_zsreg(channel, R0);
1287 } 1286 }
1288 1287
1289 if (up->port.line == KEYBOARD_LINE || 1288 if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
1290 up->port.line == MOUSE_LINE) { 1289 SUNZILOG_FLAG_CONS_MOUSE)) {
1291 sunzilog_init_kbdms(up, up->port.line); 1290 sunzilog_init_kbdms(up, up->port.line);
1292 up->curregs[R9] |= (NV | MIE); 1291 up->curregs[R9] |= (NV | MIE);
1293 write_zsreg(channel, R9, up->curregs[R9]); 1292 write_zsreg(channel, R9, up->curregs[R9]);
@@ -1313,37 +1312,26 @@ static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
1313 spin_unlock_irqrestore(&up->port.lock, flags); 1312 spin_unlock_irqrestore(&up->port.lock, flags);
1314 1313
1315#ifdef CONFIG_SERIO 1314#ifdef CONFIG_SERIO
1316 if (up->port.line == KEYBOARD_LINE || up->port.line == MOUSE_LINE) 1315 if (up->flags & (SUNZILOG_FLAG_CONS_KEYB |
1317 sunzilog_register_serio(up, up->port.line); 1316 SUNZILOG_FLAG_CONS_MOUSE))
1317 sunzilog_register_serio(up);
1318#endif 1318#endif
1319} 1319}
1320 1320
1321static int __devinit zs_get_instance(struct device_node *dp)
1322{
1323 int ret;
1324
1325 ret = of_getintprop_default(dp, "slave", -1);
1326 if (ret != -1)
1327 return ret;
1328
1329 if (of_find_property(dp, "keyboard", NULL))
1330 ret = 1;
1331 else
1332 ret = 0;
1333
1334 return ret;
1335}
1336
1337static int zilog_irq = -1; 1321static int zilog_irq = -1;
1338 1322
1339static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *match) 1323static int __devinit zs_probe(struct of_device *op, const struct of_device_id *match)
1340{ 1324{
1341 struct of_device *op = to_of_device(&dev->dev); 1325 static int inst;
1342 struct uart_sunzilog_port *up; 1326 struct uart_sunzilog_port *up;
1343 struct zilog_layout __iomem *rp; 1327 struct zilog_layout __iomem *rp;
1344 int inst = zs_get_instance(dev->node); 1328 int keyboard_mouse;
1345 int err; 1329 int err;
1346 1330
1331 keyboard_mouse = 0;
1332 if (of_find_property(op->node, "keyboard", NULL))
1333 keyboard_mouse = 1;
1334
1347 sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0, 1335 sunzilog_chip_regs[inst] = of_ioremap(&op->resource[0], 0,
1348 sizeof(struct zilog_layout), 1336 sizeof(struct zilog_layout),
1349 "zs"); 1337 "zs");
@@ -1352,16 +1340,8 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
1352 1340
1353 rp = sunzilog_chip_regs[inst]; 1341 rp = sunzilog_chip_regs[inst];
1354 1342
1355 if (zilog_irq == -1) { 1343 if (zilog_irq == -1)
1356 zilog_irq = op->irqs[0]; 1344 zilog_irq = op->irqs[0];
1357 err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
1358 "zs", sunzilog_irq_chain);
1359 if (err) {
1360 of_iounmap(rp, sizeof(struct zilog_layout));
1361
1362 return err;
1363 }
1364 }
1365 1345
1366 up = &sunzilog_port_table[inst * 2]; 1346 up = &sunzilog_port_table[inst * 2];
1367 1347
@@ -1378,7 +1358,7 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
1378 up[0].port.line = (inst * 2) + 0; 1358 up[0].port.line = (inst * 2) + 0;
1379 up[0].port.dev = &op->dev; 1359 up[0].port.dev = &op->dev;
1380 up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A; 1360 up[0].flags |= SUNZILOG_FLAG_IS_CHANNEL_A;
1381 if (inst == 1) 1361 if (keyboard_mouse)
1382 up[0].flags |= SUNZILOG_FLAG_CONS_KEYB; 1362 up[0].flags |= SUNZILOG_FLAG_CONS_KEYB;
1383 sunzilog_init_hw(&up[0]); 1363 sunzilog_init_hw(&up[0]);
1384 1364
@@ -1395,11 +1375,11 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
1395 up[1].port.line = (inst * 2) + 1; 1375 up[1].port.line = (inst * 2) + 1;
1396 up[1].port.dev = &op->dev; 1376 up[1].port.dev = &op->dev;
1397 up[1].flags |= 0; 1377 up[1].flags |= 0;
1398 if (inst == 1) 1378 if (keyboard_mouse)
1399 up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE; 1379 up[1].flags |= SUNZILOG_FLAG_CONS_MOUSE;
1400 sunzilog_init_hw(&up[1]); 1380 sunzilog_init_hw(&up[1]);
1401 1381
1402 if (inst != 1) { 1382 if (!keyboard_mouse) {
1403 err = uart_add_one_port(&sunzilog_reg, &up[0].port); 1383 err = uart_add_one_port(&sunzilog_reg, &up[0].port);
1404 if (err) { 1384 if (err) {
1405 of_iounmap(rp, sizeof(struct zilog_layout)); 1385 of_iounmap(rp, sizeof(struct zilog_layout));
@@ -1411,9 +1391,18 @@ static int __devinit zs_probe(struct of_device *dev, const struct of_device_id *
1411 of_iounmap(rp, sizeof(struct zilog_layout)); 1391 of_iounmap(rp, sizeof(struct zilog_layout));
1412 return err; 1392 return err;
1413 } 1393 }
1394 } else {
1395 printk(KERN_INFO "%s: Keyboard at MMIO %lx (irq = %d) "
1396 "is a zs\n",
1397 op->dev.bus_id, up[0].port.mapbase, op->irqs[0]);
1398 printk(KERN_INFO "%s: Mouse at MMIO %lx (irq = %d) "
1399 "is a zs\n",
1400 op->dev.bus_id, up[1].port.mapbase, op->irqs[0]);
1414 } 1401 }
1415 1402
1416 dev_set_drvdata(&dev->dev, &up[0]); 1403 dev_set_drvdata(&op->dev, &up[0]);
1404
1405 inst++;
1417 1406
1418 return 0; 1407 return 0;
1419} 1408}
@@ -1462,36 +1451,65 @@ static struct of_platform_driver zs_driver = {
1462static int __init sunzilog_init(void) 1451static int __init sunzilog_init(void)
1463{ 1452{
1464 struct device_node *dp; 1453 struct device_node *dp;
1465 int err; 1454 int err, uart_count;
1455 int num_keybms;
1466 1456
1467 NUM_SUNZILOG = 0; 1457 NUM_SUNZILOG = 0;
1468 for_each_node_by_name(dp, "zs") 1458 num_keybms = 0;
1459 for_each_node_by_name(dp, "zs") {
1469 NUM_SUNZILOG++; 1460 NUM_SUNZILOG++;
1461 if (of_find_property(dp, "keyboard", NULL))
1462 num_keybms++;
1463 }
1470 1464
1465 uart_count = 0;
1471 if (NUM_SUNZILOG) { 1466 if (NUM_SUNZILOG) {
1472 int uart_count; 1467 int uart_count;
1473 1468
1474 err = sunzilog_alloc_tables(); 1469 err = sunzilog_alloc_tables();
1475 if (err) 1470 if (err)
1476 return err; 1471 goto out;
1477 1472
1478 /* Subtract 1 for keyboard, 1 for mouse. */ 1473 uart_count = (NUM_SUNZILOG * 2) - (2 * num_keybms);
1479 uart_count = (NUM_SUNZILOG * 2) - 2;
1480 1474
1481 sunzilog_reg.nr = uart_count; 1475 sunzilog_reg.nr = uart_count;
1482 sunzilog_reg.minor = sunserial_current_minor; 1476 sunzilog_reg.minor = sunserial_current_minor;
1483 err = uart_register_driver(&sunzilog_reg); 1477 err = uart_register_driver(&sunzilog_reg);
1484 if (err) { 1478 if (err)
1485 sunzilog_free_tables(); 1479 goto out_free_tables;
1486 return err; 1480
1487 }
1488 sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64; 1481 sunzilog_reg.tty_driver->name_base = sunzilog_reg.minor - 64;
1489 sunzilog_reg.cons = SUNZILOG_CONSOLE(); 1482 sunzilog_reg.cons = SUNZILOG_CONSOLE();
1490 1483
1491 sunserial_current_minor += uart_count; 1484 sunserial_current_minor += uart_count;
1492 } 1485 }
1493 1486
1494 return of_register_driver(&zs_driver, &of_bus_type); 1487 err = of_register_driver(&zs_driver, &of_bus_type);
1488 if (err)
1489 goto out_unregister_uart;
1490
1491 if (zilog_irq != -1) {
1492 err = request_irq(zilog_irq, sunzilog_interrupt, IRQF_SHARED,
1493 "zs", sunzilog_irq_chain);
1494 if (err)
1495 goto out_unregister_driver;
1496 }
1497
1498out:
1499 return err;
1500
1501out_unregister_driver:
1502 of_unregister_driver(&zs_driver);
1503
1504out_unregister_uart:
1505 if (NUM_SUNZILOG) {
1506 uart_unregister_driver(&sunzilog_reg);
1507 sunzilog_reg.cons = NULL;
1508 }
1509
1510out_free_tables:
1511 sunzilog_free_tables();
1512 goto out;
1495} 1513}
1496 1514
1497static void __exit sunzilog_exit(void) 1515static void __exit sunzilog_exit(void)