Hi, please do not top post. On Thu, 25 Jun 2015 17:05:00 +0200, Michael Allwright wrote: > Well almost all my issues ;) > > At the moment there is missing support for having more than one > SC16IS7xx device. Because of this there is a name conflict in sysfs: > > [ 3.241912] sysfs: cannot create duplicate filename '/class/tty/ttySC1' > ... > [ 3.312774] [<c01b157c>] (sysfs_warn_dup) from [<c01b188c>] > (sysfs_do_create_link_sd.isra.2+0xa8/0xb4) > [ 3.323974] [<c01b188c>] (sysfs_do_create_link_sd.isra.2) from > [<c03cd5a4>] (device_add+0x200/0x520) > [ 3.333557] [<c03cd5a4>] (device_add) from [<c039d834>] > (tty_register_device_attr+0x1c8/0x240) > [ 3.333557] [<c039d834>] (tty_register_device_attr) from > [<c03b8e84>] (uart_add_one_port+0x1c4/0x48c) > [ 3.352294] [<c03b8e84>] (uart_add_one_port) from [<c03c0d0c>] > (sc16is7xx_i2c_probe+0x334/0x520) > [ 3.353271] [<c03c0d0c>] (sc16is7xx_i2c_probe) from [<c04cc52c>] > (i2c_device_probe+0xf4/0x14c) > ... > > I will see if I can find a solution for this. It must be possible as > the USB serial core has no problem adding ttyUSBX interfaces for each > device plugged in... Any hints as always would be appreciated. I think USB does some magic which is not necessary for a simple driver like sc16is7xx. Can you try the following patch? --------->8--------------- >From 2ba8fbbfdbfc77008639de89e021d777324de749 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski <kubakici@xxxxx> Date: Thu, 25 Jun 2015 18:17:58 +0200 Subject: [PATCH] sc16is7xx: support multiple devices Signed-off-by: Jakub Kicinski <kubakici@xxxxx> --- drivers/tty/serial/sc16is7xx.c | 48 ++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 5ccc698cbbfa..9db22d9f0e0e 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -11,6 +11,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/bitops.h> #include <linux/clk.h> #include <linux/delay.h> @@ -29,6 +31,7 @@ #include <linux/uaccess.h> #define SC16IS7XX_NAME "sc16is7xx" +#define SC16IS7XX_MAX_DEVS 8 /* SC16IS7XX register definitions */ #define SC16IS7XX_RHR_REG (0x00) /* RX FIFO */ @@ -318,7 +321,6 @@ struct sc16is7xx_one { }; struct sc16is7xx_port { - struct uart_driver uart; struct sc16is7xx_devtype *devtype; struct regmap *regmap; struct clk *clk; @@ -332,6 +334,12 @@ struct sc16is7xx_port { struct sc16is7xx_one p[0]; }; +static struct uart_driver sc16is7xx_uart = { + .owner = THIS_MODULE, + .dev_name = "ttySC", + .nr = SC16IS7XX_MAX_DEVS, +}; + #define to_sc16is7xx_port(p,e) ((container_of((p), struct sc16is7xx_port, e))) #define to_sc16is7xx_one(p,e) ((container_of((p), struct sc16is7xx_one, e))) @@ -661,7 +669,7 @@ static void sc16is7xx_ist(struct kthread_work *ws) struct sc16is7xx_port *s = to_sc16is7xx_port(ws, irq_work); int i; - for (i = 0; i < s->uart.nr; ++i) + for (i = 0; i < s->devtype->nr_uart; ++i) sc16is7xx_port_irq(s, i); } @@ -1134,23 +1142,13 @@ static int sc16is7xx_probe(struct device *dev, s->devtype = devtype; dev_set_drvdata(dev, s); - /* Register UART driver */ - s->uart.owner = THIS_MODULE; - s->uart.dev_name = "ttySC"; - s->uart.nr = devtype->nr_uart; - ret = uart_register_driver(&s->uart); - if (ret) { - dev_err(dev, "Registering UART driver failed\n"); - goto out_clk; - } - init_kthread_worker(&s->kworker); init_kthread_work(&s->irq_work, sc16is7xx_ist); s->kworker_task = kthread_run(kthread_worker_fn, &s->kworker, "sc16is7xx"); if (IS_ERR(s->kworker_task)) { ret = PTR_ERR(s->kworker_task); - goto out_uart; + goto out_clk; } sched_setscheduler(s->kworker_task, SCHED_FIFO, &sched_param); @@ -1195,7 +1193,7 @@ static int sc16is7xx_probe(struct device *dev, init_kthread_work(&s->p[i].tx_work, sc16is7xx_tx_proc); init_kthread_work(&s->p[i].reg_work, sc16is7xx_reg_proc); /* Register port */ - uart_add_one_port(&s->uart, &s->p[i].port); + uart_add_one_port(&sc16is7xx_uart, &s->p[i].port); /* Go to suspend mode */ sc16is7xx_power(&s->p[i].port, 0); } @@ -1206,8 +1204,8 @@ static int sc16is7xx_probe(struct device *dev, if (!ret) return 0; - for (i = 0; i < s->uart.nr; i++) - uart_remove_one_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr_uart; i++) + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); #ifdef CONFIG_GPIOLIB if (devtype->nr_gpio) @@ -1217,9 +1215,6 @@ out_thread: #endif kthread_stop(s->kworker_task); -out_uart: - uart_unregister_driver(&s->uart); - out_clk: if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1237,15 +1232,14 @@ static int sc16is7xx_remove(struct device *dev) gpiochip_remove(&s->gpio); #endif - for (i = 0; i < s->uart.nr; i++) { - uart_remove_one_port(&s->uart, &s->p[i].port); + for (i = 0; i < s->devtype->nr_uart; i++) { + uart_remove_one_port(&sc16is7xx_uart, &s->p[i].port); sc16is7xx_power(&s->p[i].port, 0); } flush_kthread_worker(&s->kworker); kthread_stop(s->kworker_task); - uart_unregister_driver(&s->uart); if (!IS_ERR(s->clk)) clk_disable_unprepare(s->clk); @@ -1398,7 +1392,14 @@ MODULE_ALIAS("i2c:sc16is7xx"); static int __init sc16is7xx_init(void) { - int ret = 0; + int ret; + + ret = uart_register_driver(&sc16is7xx_uart); + if (ret) { + pr_err("Registering UART driver failed\n"); + return ret; + } + #ifdef CONFIG_SERIAL_SC16IS7XX_I2C ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); if (ret < 0) { @@ -1427,6 +1428,7 @@ static void __exit sc16is7xx_exit(void) #ifdef CONFIG_SERIAL_SC16IS7XX_SPI spi_unregister_driver(&sc16is7xx_spi_uart_driver); #endif + uart_unregister_driver(&sc16is7xx_uart); } module_exit(sc16is7xx_exit); -- 2.1.0 -- To unsubscribe from this list: send the line "unsubscribe linux-serial" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html