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