From 43b829b3c1aa8d4f748a8e68724df476d242365a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Tue, 25 Jun 2013 10:08:49 +0900 Subject: serial: remove unnecessary platform_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure, since commit 0998d0631001288a5974afc0b2a5f568bcdecb4d (device-core: Ensure drvdata = NULL when no driver is bound). Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Jingoo Han Acked-by: Barry Song Acked-by: Tony Prisk Acked-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index c7730415541..98555179fe1 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -997,8 +997,6 @@ static int sccnxp_probe(struct platform_device *pdev) } err_out: - platform_set_drvdata(pdev, NULL); - return ret; } @@ -1016,7 +1014,6 @@ static int sccnxp_remove(struct platform_device *pdev) uart_remove_one_port(&s->uart, &s->port[i]); uart_unregister_driver(&s->uart); - platform_set_drvdata(pdev, NULL); if (!IS_ERR(s->regulator)) return regulator_disable(s->regulator); -- cgit v1.2.3-70-g09d2 From e087ab74f3dd30105041e1c68db209f235b63042 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 31 Jul 2013 14:56:29 +0400 Subject: serial: sccnxp: Disable regulator on error The patch disables the regulator in case of errors, if we have it. In addition, the patch adds support for deferred regulator probe and makes error path are a bit clean. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 98555179fe1..12a5c265f43 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -787,10 +787,9 @@ static int sccnxp_probe(struct platform_device *pdev) struct sccnxp_port *s; void __iomem *membase; - if (!res) { - dev_err(&pdev->dev, "Missing memory resource data\n"); - return -EADDRNOTAVAIL; - } + membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(membase)) + return PTR_ERR(membase); s = devm_kzalloc(&pdev->dev, sizeof(struct sccnxp_port), GFP_KERNEL); if (!s) { @@ -885,10 +884,20 @@ static int sccnxp_probe(struct platform_device *pdev) break; default: dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); - ret = -ENOTSUPP; - goto err_out; + return -ENOTSUPP; } + s->regulator = devm_regulator_get(&pdev->dev, "vcc"); + if (!IS_ERR(s->regulator)) { + ret = regulator_enable(s->regulator); + if (ret) { + dev_err(&pdev->dev, + "Failed to enable regulator: %i\n", ret); + return ret; + } + } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!pdata) { dev_warn(&pdev->dev, "No platform data supplied, using defaults\n"); @@ -919,22 +928,6 @@ static int sccnxp_probe(struct platform_device *pdev) goto err_out; } - s->regulator = devm_regulator_get(&pdev->dev, "VCC"); - if (!IS_ERR(s->regulator)) { - ret = regulator_enable(s->regulator); - if (ret) { - dev_err(&pdev->dev, - "Failed to enable regulator: %i\n", ret); - return ret; - } - } - - membase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(membase)) { - ret = PTR_ERR(membase); - goto err_out; - } - s->uart.owner = THIS_MODULE; s->uart.dev_name = "ttySC"; s->uart.major = SCCNXP_MAJOR; @@ -997,6 +990,9 @@ static int sccnxp_probe(struct platform_device *pdev) } err_out: + if (!IS_ERR(s->regulator)) + return regulator_disable(s->regulator); + return ret; } -- cgit v1.2.3-70-g09d2 From 90efa75f7ab0be5677f0cca155dbf0b39eacdd03 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 31 Jul 2013 14:56:30 +0400 Subject: serial: sccnxp: Using CLK API for getting UART clock This patch removes "frequency" parameter from SCCNXP platform_data and uses CLK API for getting clock. If CLK ommited, default IC frequency will be used instead. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- arch/mips/sni/a20r.c | 1 - drivers/tty/serial/sccnxp.c | 36 ++++++++++++++++++----------- include/linux/platform_data/serial-sccnxp.h | 3 --- 3 files changed, 22 insertions(+), 18 deletions(-) (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/arch/mips/sni/a20r.c b/arch/mips/sni/a20r.c index dd0ab982d77..f9407e17047 100644 --- a/arch/mips/sni/a20r.c +++ b/arch/mips/sni/a20r.c @@ -122,7 +122,6 @@ static struct resource sc26xx_rsrc[] = { static struct sccnxp_pdata sccnxp_data = { .reg_shift = 2, - .frequency = 3686400, .mctrl_cfg[0] = MCTRL_SIG(DTR_OP, LINE_OP7) | MCTRL_SIG(RTS_OP, LINE_OP3) | MCTRL_SIG(DSR_IP, LINE_IP5) | diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 12a5c265f43..81e70477e6f 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -15,6 +15,7 @@ #define SUPPORT_SYSRQ #endif +#include #include #include #include @@ -783,9 +784,10 @@ static int sccnxp_probe(struct platform_device *pdev) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); int chiptype = pdev->id_entry->driver_data; struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); - int i, ret, fifosize, freq_min, freq_max; + int i, ret, fifosize, freq_min, freq_max, uartclk; struct sccnxp_port *s; void __iomem *membase; + struct clk *clk; membase = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(membase)) @@ -898,11 +900,25 @@ static int sccnxp_probe(struct platform_device *pdev) } else if (PTR_ERR(s->regulator) == -EPROBE_DEFER) return -EPROBE_DEFER; - if (!pdata) { - dev_warn(&pdev->dev, - "No platform data supplied, using defaults\n"); - s->pdata.frequency = s->freq_std; + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_out; + } + dev_notice(&pdev->dev, "Using default clock frequency\n"); + uartclk = s->freq_std; } else + uartclk = clk_get_rate(clk); + + /* Check input frequency */ + if ((uartclk < freq_min) || (uartclk > freq_max)) { + dev_err(&pdev->dev, "Frequency out of bounds\n"); + ret = -EINVAL; + goto err_out; + } + + if (pdata) memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); if (s->pdata.poll_time_us) { @@ -920,14 +936,6 @@ static int sccnxp_probe(struct platform_device *pdev) } } - /* Check input frequency */ - if ((s->pdata.frequency < freq_min) || - (s->pdata.frequency > freq_max)) { - dev_err(&pdev->dev, "Frequency out of bounds\n"); - ret = -EINVAL; - goto err_out; - } - s->uart.owner = THIS_MODULE; s->uart.dev_name = "ttySC"; s->uart.major = SCCNXP_MAJOR; @@ -959,7 +967,7 @@ static int sccnxp_probe(struct platform_device *pdev) s->port[i].mapbase = res->start; s->port[i].membase = membase; s->port[i].regshift = s->pdata.reg_shift; - s->port[i].uartclk = s->pdata.frequency; + s->port[i].uartclk = uartclk; s->port[i].ops = &sccnxp_ops; uart_add_one_port(&s->uart, &s->port[i]); /* Set direction to input */ diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h index bdc510d0324..af0c8c3b89a 100644 --- a/include/linux/platform_data/serial-sccnxp.h +++ b/include/linux/platform_data/serial-sccnxp.h @@ -60,7 +60,6 @@ * }; * * static struct sccnxp_pdata sc2892_info = { - * .frequency = 3686400, * .mctrl_cfg[0] = MCTRL_SIG(DIR_OP, LINE_OP0), * .mctrl_cfg[1] = MCTRL_SIG(DIR_OP, LINE_OP1), * }; @@ -78,8 +77,6 @@ /* SCCNXP platform data structure */ struct sccnxp_pdata { - /* Frequency (extrenal clock or crystal) */ - int frequency; /* Shift for A0 line */ const u8 reg_shift; /* Modem control lines configuration */ -- cgit v1.2.3-70-g09d2 From ea4c39beace859139bc184a1aebdccdc12c04a2e Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 31 Jul 2013 14:56:31 +0400 Subject: serial: sccnxp: Using structure for each supported IC instead of switch in probe This patch replaces switch in probe function to constant structure for each supported IC. This makes code a bit smaller and cleaner and helps adding DT support to the driver in the future. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sccnxp.c | 272 ++++++++++++++++++++------------------------ 1 file changed, 124 insertions(+), 148 deletions(-) (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 81e70477e6f..49e9bbfe6ca 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -95,16 +95,17 @@ #define MCTRL_IBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_IP0) #define MCTRL_OBIT(cfg, sig) ((((cfg) >> (sig)) & 0xf) - LINE_OP0) -/* Supported chip types */ -enum { - SCCNXP_TYPE_SC2681 = 2681, - SCCNXP_TYPE_SC2691 = 2691, - SCCNXP_TYPE_SC2692 = 2692, - SCCNXP_TYPE_SC2891 = 2891, - SCCNXP_TYPE_SC2892 = 2892, - SCCNXP_TYPE_SC28202 = 28202, - SCCNXP_TYPE_SC68681 = 68681, - SCCNXP_TYPE_SC68692 = 68692, +#define SCCNXP_HAVE_IO 0x00000001 +#define SCCNXP_HAVE_MR0 0x00000002 + +struct sccnxp_chip { + const char *name; + unsigned int nr; + unsigned long freq_min; + unsigned long freq_std; + unsigned long freq_max; + unsigned int flags; + unsigned int fifosize; }; struct sccnxp_port { @@ -112,16 +113,10 @@ struct sccnxp_port { struct uart_port port[SCCNXP_MAX_UARTS]; bool opened[SCCNXP_MAX_UARTS]; - const char *name; int irq; - u8 imr; - u8 addr_mask; - int freq_std; - int flags; -#define SCCNXP_HAVE_IO 0x00000001 -#define SCCNXP_HAVE_MR0 0x00000002 + struct sccnxp_chip *chip; #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE struct console console; @@ -137,29 +132,94 @@ struct sccnxp_port { struct regulator *regulator; }; -static inline u8 sccnxp_raw_read(void __iomem *base, u8 reg, u8 shift) -{ - return readb(base + (reg << shift)); -} +static const struct sccnxp_chip sc2681 = { + .name = "SC2681", + .nr = 2, + .freq_min = 1000000, + .freq_std = 3686400, + .freq_max = 4000000, + .flags = SCCNXP_HAVE_IO, + .fifosize = 3, +}; -static inline void sccnxp_raw_write(void __iomem *base, u8 reg, u8 shift, u8 v) -{ - writeb(v, base + (reg << shift)); -} +static const struct sccnxp_chip sc2691 = { + .name = "SC2691", + .nr = 1, + .freq_min = 1000000, + .freq_std = 3686400, + .freq_max = 4000000, + .flags = 0, + .fifosize = 3, +}; + +static const struct sccnxp_chip sc2692 = { + .name = "SC2692", + .nr = 2, + .freq_min = 1000000, + .freq_std = 3686400, + .freq_max = 4000000, + .flags = SCCNXP_HAVE_IO, + .fifosize = 3, +}; + +static const struct sccnxp_chip sc2891 = { + .name = "SC2891", + .nr = 1, + .freq_min = 100000, + .freq_std = 3686400, + .freq_max = 8000000, + .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, + .fifosize = 16, +}; + +static const struct sccnxp_chip sc2892 = { + .name = "SC2892", + .nr = 2, + .freq_min = 100000, + .freq_std = 3686400, + .freq_max = 8000000, + .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, + .fifosize = 16, +}; + +static const struct sccnxp_chip sc28202 = { + .name = "SC28202", + .nr = 2, + .freq_min = 1000000, + .freq_std = 14745600, + .freq_max = 50000000, + .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, + .fifosize = 256, +}; + +static const struct sccnxp_chip sc68681 = { + .name = "SC68681", + .nr = 2, + .freq_min = 1000000, + .freq_std = 3686400, + .freq_max = 4000000, + .flags = SCCNXP_HAVE_IO, + .fifosize = 3, +}; + +static const struct sccnxp_chip sc68692 = { + .name = "SC68692", + .nr = 2, + .freq_min = 1000000, + .freq_std = 3686400, + .freq_max = 4000000, + .flags = SCCNXP_HAVE_IO, + .fifosize = 3, +}; static inline u8 sccnxp_read(struct uart_port *port, u8 reg) { - struct sccnxp_port *s = dev_get_drvdata(port->dev); - - return sccnxp_raw_read(port->membase, reg & s->addr_mask, - port->regshift); + return readb(port->membase + (reg << port->regshift)); } static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) { - struct sccnxp_port *s = dev_get_drvdata(port->dev); - - sccnxp_raw_write(port->membase, reg & s->addr_mask, port->regshift, v); + writeb(v, port->membase + (reg << port->regshift)); } static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) @@ -225,13 +285,14 @@ static int sccnxp_set_baud(struct uart_port *port, int baud) { struct sccnxp_port *s = dev_get_drvdata(port->dev); int div_std, tmp_baud, bestbaud = baud, besterr = -1; + struct sccnxp_chip *chip = s->chip; u8 i, acr = 0, csr = 0, mr0 = 0; /* Find best baud from table */ for (i = 0; baud_std[i].baud && besterr; i++) { - if (baud_std[i].mr0 && !(s->flags & SCCNXP_HAVE_MR0)) + if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0)) continue; - div_std = DIV_ROUND_CLOSEST(s->freq_std, baud_std[i].baud); + div_std = DIV_ROUND_CLOSEST(chip->freq_std, baud_std[i].baud); tmp_baud = DIV_ROUND_CLOSEST(port->uartclk, div_std); if (!sccnxp_update_best_err(baud, tmp_baud, &besterr)) { acr = baud_std[i].acr; @@ -241,7 +302,7 @@ static int sccnxp_set_baud(struct uart_port *port, int baud) } } - if (s->flags & SCCNXP_HAVE_MR0) { + if (chip->flags & SCCNXP_HAVE_MR0) { /* Enable FIFO, set half level for TX */ mr0 |= MR0_FIFO | MR0_TXLVL; /* Update MR0 */ @@ -364,7 +425,7 @@ static void sccnxp_handle_tx(struct uart_port *port) sccnxp_disable_irq(port, IMR_TXRDY); /* Set direction to input */ - if (s->flags & SCCNXP_HAVE_IO) + if (s->chip->flags & SCCNXP_HAVE_IO) sccnxp_set_bit(port, DIR_OP, 0); } return; @@ -438,7 +499,7 @@ static void sccnxp_start_tx(struct uart_port *port) spin_lock_irqsave(&s->lock, flags); /* Set direction to output */ - if (s->flags & SCCNXP_HAVE_IO) + if (s->chip->flags & SCCNXP_HAVE_IO) sccnxp_set_bit(port, DIR_OP, 1); sccnxp_enable_irq(port, IMR_TXRDY); @@ -484,7 +545,7 @@ static void sccnxp_set_mctrl(struct uart_port *port, unsigned int mctrl) struct sccnxp_port *s = dev_get_drvdata(port->dev); unsigned long flags; - if (!(s->flags & SCCNXP_HAVE_IO)) + if (!(s->chip->flags & SCCNXP_HAVE_IO)) return; spin_lock_irqsave(&s->lock, flags); @@ -502,7 +563,7 @@ static unsigned int sccnxp_get_mctrl(struct uart_port *port) struct sccnxp_port *s = dev_get_drvdata(port->dev); unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; - if (!(s->flags & SCCNXP_HAVE_IO)) + if (!(s->chip->flags & SCCNXP_HAVE_IO)) return mctrl; spin_lock_irqsave(&s->lock, flags); @@ -618,7 +679,7 @@ static void sccnxp_set_termios(struct uart_port *port, /* Setup baudrate */ baud = uart_get_baud_rate(port, termios, old, 50, - (s->flags & SCCNXP_HAVE_MR0) ? + (s->chip->flags & SCCNXP_HAVE_MR0) ? 230400 : 38400); baud = sccnxp_set_baud(port, baud); @@ -642,7 +703,7 @@ static int sccnxp_startup(struct uart_port *port) spin_lock_irqsave(&s->lock, flags); - if (s->flags & SCCNXP_HAVE_IO) { + if (s->chip->flags & SCCNXP_HAVE_IO) { /* Outputs are controlled manually */ sccnxp_write(port, SCCNXP_OPCR_REG, 0); } @@ -682,7 +743,7 @@ static void sccnxp_shutdown(struct uart_port *port) sccnxp_port_write(port, SCCNXP_CR_REG, CR_RX_DISABLE | CR_TX_DISABLE); /* Leave direction to input */ - if (s->flags & SCCNXP_HAVE_IO) + if (s->chip->flags & SCCNXP_HAVE_IO) sccnxp_set_bit(port, DIR_OP, 0); spin_unlock_irqrestore(&s->lock, flags); @@ -692,7 +753,7 @@ static const char *sccnxp_type(struct uart_port *port) { struct sccnxp_port *s = dev_get_drvdata(port->dev); - return (port->type == PORT_SC26XX) ? s->name : NULL; + return (port->type == PORT_SC26XX) ? s->chip->name : NULL; } static void sccnxp_release_port(struct uart_port *port) @@ -779,12 +840,24 @@ static int sccnxp_console_setup(struct console *co, char *options) } #endif +static const struct platform_device_id sccnxp_id_table[] = { + { .name = "sc2681", .driver_data = (kernel_ulong_t)&sc2681, }, + { .name = "sc2691", .driver_data = (kernel_ulong_t)&sc2691, }, + { .name = "sc2692", .driver_data = (kernel_ulong_t)&sc2692, }, + { .name = "sc2891", .driver_data = (kernel_ulong_t)&sc2891, }, + { .name = "sc2892", .driver_data = (kernel_ulong_t)&sc2892, }, + { .name = "sc28202", .driver_data = (kernel_ulong_t)&sc28202, }, + { .name = "sc68681", .driver_data = (kernel_ulong_t)&sc68681, }, + { .name = "sc68692", .driver_data = (kernel_ulong_t)&sc68692, }, + { } +}; +MODULE_DEVICE_TABLE(platform, sccnxp_id_table); + static int sccnxp_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - int chiptype = pdev->id_entry->driver_data; struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); - int i, ret, fifosize, freq_min, freq_max, uartclk; + int i, ret, uartclk; struct sccnxp_port *s; void __iomem *membase; struct clk *clk; @@ -802,92 +875,7 @@ static int sccnxp_probe(struct platform_device *pdev) spin_lock_init(&s->lock); - /* Individual chip settings */ - switch (chiptype) { - case SCCNXP_TYPE_SC2681: - s->name = "SC2681"; - s->uart.nr = 2; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO; - fifosize = 3; - freq_min = 1000000; - freq_max = 4000000; - break; - case SCCNXP_TYPE_SC2691: - s->name = "SC2691"; - s->uart.nr = 1; - s->freq_std = 3686400; - s->addr_mask = 0x07; - s->flags = 0; - fifosize = 3; - freq_min = 1000000; - freq_max = 4000000; - break; - case SCCNXP_TYPE_SC2692: - s->name = "SC2692"; - s->uart.nr = 2; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO; - fifosize = 3; - freq_min = 1000000; - freq_max = 4000000; - break; - case SCCNXP_TYPE_SC2891: - s->name = "SC2891"; - s->uart.nr = 1; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; - fifosize = 16; - freq_min = 100000; - freq_max = 8000000; - break; - case SCCNXP_TYPE_SC2892: - s->name = "SC2892"; - s->uart.nr = 2; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; - fifosize = 16; - freq_min = 100000; - freq_max = 8000000; - break; - case SCCNXP_TYPE_SC28202: - s->name = "SC28202"; - s->uart.nr = 2; - s->freq_std = 14745600; - s->addr_mask = 0x7f; - s->flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0; - fifosize = 256; - freq_min = 1000000; - freq_max = 50000000; - break; - case SCCNXP_TYPE_SC68681: - s->name = "SC68681"; - s->uart.nr = 2; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO; - fifosize = 3; - freq_min = 1000000; - freq_max = 4000000; - break; - case SCCNXP_TYPE_SC68692: - s->name = "SC68692"; - s->uart.nr = 2; - s->freq_std = 3686400; - s->addr_mask = 0x0f; - s->flags = SCCNXP_HAVE_IO; - fifosize = 3; - freq_min = 1000000; - freq_max = 4000000; - break; - default: - dev_err(&pdev->dev, "Unsupported chip type %i\n", chiptype); - return -ENOTSUPP; - } + s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; s->regulator = devm_regulator_get(&pdev->dev, "vcc"); if (!IS_ERR(s->regulator)) { @@ -907,12 +895,12 @@ static int sccnxp_probe(struct platform_device *pdev) goto err_out; } dev_notice(&pdev->dev, "Using default clock frequency\n"); - uartclk = s->freq_std; + uartclk = s->chip->freq_std; } else uartclk = clk_get_rate(clk); /* Check input frequency */ - if ((uartclk < freq_min) || (uartclk > freq_max)) { + if ((uartclk < s->chip->freq_min) || (uartclk > s->chip->freq_max)) { dev_err(&pdev->dev, "Frequency out of bounds\n"); ret = -EINVAL; goto err_out; @@ -940,6 +928,7 @@ static int sccnxp_probe(struct platform_device *pdev) s->uart.dev_name = "ttySC"; s->uart.major = SCCNXP_MAJOR; s->uart.minor = SCCNXP_MINOR; + s->uart.nr = s->chip->nr; #ifdef CONFIG_SERIAL_SCCNXP_CONSOLE s->uart.cons = &s->console; s->uart.cons->device = uart_console_device; @@ -961,7 +950,7 @@ static int sccnxp_probe(struct platform_device *pdev) s->port[i].dev = &pdev->dev; s->port[i].irq = s->irq; s->port[i].type = PORT_SC26XX; - s->port[i].fifosize = fifosize; + s->port[i].fifosize = s->chip->fifosize; s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE; s->port[i].iotype = UPIO_MEM; s->port[i].mapbase = res->start; @@ -971,7 +960,7 @@ static int sccnxp_probe(struct platform_device *pdev) s->port[i].ops = &sccnxp_ops; uart_add_one_port(&s->uart, &s->port[i]); /* Set direction to input */ - if (s->flags & SCCNXP_HAVE_IO) + if (s->chip->flags & SCCNXP_HAVE_IO) sccnxp_set_bit(&s->port[i], DIR_OP, 0); } @@ -1025,19 +1014,6 @@ static int sccnxp_remove(struct platform_device *pdev) return 0; } -static const struct platform_device_id sccnxp_id_table[] = { - { "sc2681", SCCNXP_TYPE_SC2681 }, - { "sc2691", SCCNXP_TYPE_SC2691 }, - { "sc2692", SCCNXP_TYPE_SC2692 }, - { "sc2891", SCCNXP_TYPE_SC2891 }, - { "sc2892", SCCNXP_TYPE_SC2892 }, - { "sc28202", SCCNXP_TYPE_SC28202 }, - { "sc68681", SCCNXP_TYPE_SC68681 }, - { "sc68692", SCCNXP_TYPE_SC68692 }, - { }, -}; -MODULE_DEVICE_TABLE(platform, sccnxp_id_table); - static struct platform_driver sccnxp_uart_driver = { .driver = { .name = SCCNXP_NAME, -- cgit v1.2.3-70-g09d2 From 85c996907473e4ef824774b97b26499adf66521f Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Wed, 31 Jul 2013 14:55:45 +0400 Subject: serial: sccnxp: Add DT support Add DT support to the SCCNCP serial driver. Signed-off-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- .../bindings/tty/serial/sccnxp-serial.txt | 53 ++++++++++++++++++++++ drivers/tty/serial/sccnxp.c | 46 +++++++++++++++---- include/linux/platform_data/serial-sccnxp.h | 6 +-- 3 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt b/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt new file mode 100644 index 00000000000..d18b1698133 --- /dev/null +++ b/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt @@ -0,0 +1,53 @@ +* NXP (Philips) SCC+++(SCN+++) serial driver + +Required properties: +- compatible: Should be "nxp,". The supported ICs include sc2681, + sc2691, sc2692, sc2891, sc2892, sc28202, sc68681 and sc68692. +- reg: Address and length of the register set for the device. +- interrupts: Should contain the interrupt number. If omitted, + polling mode will be used instead, so "poll-interval" property should + be populated in this case. + +Optional properties: +- clocks: Phandle to input clock. If omitted, default IC frequency will be + used instead. +- poll-interval: Poll interval time in nanoseconds. +- vcc-supply: The regulator supplying the VCC to drive the chip. +- nxp,sccnxp-io-cfg: Array contains values for the emulated modem signals. + The number of values depends on the UART-number in the selected chip. + Each value should be composed according to the following rules: + (LINE1 << SIGNAL1) | ... | (LINEX << SIGNALX), where: + LINE - VALUE: + OP0 - 1 + OP1 - 2 + OP2 - 3 + OP3 - 4 + OP4 - 5 + OP5 - 6 + OP6 - 7 + OP7 - 8 + IP0 - 9 + IP1 - 10 + IP2 - 11 + IP3 - 12 + IP4 - 13 + IP5 - 14 + IP6 - 15 + SIGNAL - VALUE: + DTR - 0 + RTS - 4 + DSR - 8 + CTS - 12 + DCD - 16 + RNG - 20 + DIR - 24 + +Example (Dual UART with direction control on OP0 & OP1): +sc2892@10100000 { + compatible = "nxp,sc2892"; + reg = <0x10100000 0x10>; + poll-interval = <10000>; + clocks = <&sc2892_clk>; + vcc-supply = <&sc2892_reg>; + nxp,sccnxp-io-cfg = <0x01000000 0x02000000>; +}; diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 49e9bbfe6ca..67f73d1a8e7 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -853,10 +855,25 @@ static const struct platform_device_id sccnxp_id_table[] = { }; MODULE_DEVICE_TABLE(platform, sccnxp_id_table); +static const struct of_device_id sccnxp_dt_id_table[] = { + { .compatible = "nxp,sc2681", .data = &sc2681, }, + { .compatible = "nxp,sc2691", .data = &sc2691, }, + { .compatible = "nxp,sc2692", .data = &sc2692, }, + { .compatible = "nxp,sc2891", .data = &sc2891, }, + { .compatible = "nxp,sc2892", .data = &sc2892, }, + { .compatible = "nxp,sc28202", .data = &sc28202, }, + { .compatible = "nxp,sc68681", .data = &sc68681, }, + { .compatible = "nxp,sc68692", .data = &sc68692, }, + { } +}; +MODULE_DEVICE_TABLE(of, sccnxp_dt_id_table); + static int sccnxp_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); + const struct of_device_id *of_id = + of_match_device(sccnxp_dt_id_table, &pdev->dev); int i, ret, uartclk; struct sccnxp_port *s; void __iomem *membase; @@ -875,7 +892,22 @@ static int sccnxp_probe(struct platform_device *pdev) spin_lock_init(&s->lock); - s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; + if (of_id) { + s->chip = (struct sccnxp_chip *)of_id->data; + + of_property_read_u32(pdev->dev.of_node, "poll-interval", + &s->pdata.poll_time_us); + of_property_read_u32(pdev->dev.of_node, "reg-shift", + &s->pdata.reg_shift); + of_property_read_u32_array(pdev->dev.of_node, + "nxp,sccnxp-io-cfg", + s->pdata.mctrl_cfg, s->chip->nr); + } else { + s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; + + if (pdata) + memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); + } s->regulator = devm_regulator_get(&pdev->dev, "vcc"); if (!IS_ERR(s->regulator)) { @@ -906,16 +938,11 @@ static int sccnxp_probe(struct platform_device *pdev) goto err_out; } - if (pdata) - memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); - if (s->pdata.poll_time_us) { dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", s->pdata.poll_time_us); s->poll = 1; - } - - if (!s->poll) { + } else { s->irq = platform_get_irq(pdev, 0); if (s->irq < 0) { dev_err(&pdev->dev, "Missing irq resource data\n"); @@ -1016,8 +1043,9 @@ static int sccnxp_remove(struct platform_device *pdev) static struct platform_driver sccnxp_uart_driver = { .driver = { - .name = SCCNXP_NAME, - .owner = THIS_MODULE, + .name = SCCNXP_NAME, + .owner = THIS_MODULE, + .of_match_table = sccnxp_dt_id_table, }, .probe = sccnxp_probe, .remove = sccnxp_remove, diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h index af0c8c3b89a..98373d6add2 100644 --- a/include/linux/platform_data/serial-sccnxp.h +++ b/include/linux/platform_data/serial-sccnxp.h @@ -78,11 +78,11 @@ /* SCCNXP platform data structure */ struct sccnxp_pdata { /* Shift for A0 line */ - const u8 reg_shift; + u32 reg_shift; /* Modem control lines configuration */ - const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; + u32 mctrl_cfg[SCCNXP_MAX_UARTS]; /* Timer value for polling mode (usecs) */ - const unsigned int poll_time_us; + u32 poll_time_us; }; #endif -- cgit v1.2.3-70-g09d2 From 461a8ecb2d76fb6f3ac1a90eb886697db869d387 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 2 Aug 2013 15:25:19 +0800 Subject: Revert "serial: sccnxp: Add DT support" This reverts commit 85c996907473e4ef824774b97b26499adf66521f. Alexander wishes to remove this patch as it is incorrect. Reported-by: Alexander Shiyan Signed-off-by: Greg Kroah-Hartman --- .../bindings/tty/serial/sccnxp-serial.txt | 53 ---------------------- drivers/tty/serial/sccnxp.c | 46 ++++--------------- include/linux/platform_data/serial-sccnxp.h | 6 +-- 3 files changed, 12 insertions(+), 93 deletions(-) delete mode 100644 Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt (limited to 'drivers/tty/serial/sccnxp.c') diff --git a/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt b/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt deleted file mode 100644 index d18b1698133..00000000000 --- a/Documentation/devicetree/bindings/tty/serial/sccnxp-serial.txt +++ /dev/null @@ -1,53 +0,0 @@ -* NXP (Philips) SCC+++(SCN+++) serial driver - -Required properties: -- compatible: Should be "nxp,". The supported ICs include sc2681, - sc2691, sc2692, sc2891, sc2892, sc28202, sc68681 and sc68692. -- reg: Address and length of the register set for the device. -- interrupts: Should contain the interrupt number. If omitted, - polling mode will be used instead, so "poll-interval" property should - be populated in this case. - -Optional properties: -- clocks: Phandle to input clock. If omitted, default IC frequency will be - used instead. -- poll-interval: Poll interval time in nanoseconds. -- vcc-supply: The regulator supplying the VCC to drive the chip. -- nxp,sccnxp-io-cfg: Array contains values for the emulated modem signals. - The number of values depends on the UART-number in the selected chip. - Each value should be composed according to the following rules: - (LINE1 << SIGNAL1) | ... | (LINEX << SIGNALX), where: - LINE - VALUE: - OP0 - 1 - OP1 - 2 - OP2 - 3 - OP3 - 4 - OP4 - 5 - OP5 - 6 - OP6 - 7 - OP7 - 8 - IP0 - 9 - IP1 - 10 - IP2 - 11 - IP3 - 12 - IP4 - 13 - IP5 - 14 - IP6 - 15 - SIGNAL - VALUE: - DTR - 0 - RTS - 4 - DSR - 8 - CTS - 12 - DCD - 16 - RNG - 20 - DIR - 24 - -Example (Dual UART with direction control on OP0 & OP1): -sc2892@10100000 { - compatible = "nxp,sc2892"; - reg = <0x10100000 0x10>; - poll-interval = <10000>; - clocks = <&sc2892_clk>; - vcc-supply = <&sc2892_reg>; - nxp,sccnxp-io-cfg = <0x01000000 0x02000000>; -}; diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 67f73d1a8e7..49e9bbfe6ca 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -20,8 +20,6 @@ #include #include #include -#include -#include #include #include #include @@ -855,25 +853,10 @@ static const struct platform_device_id sccnxp_id_table[] = { }; MODULE_DEVICE_TABLE(platform, sccnxp_id_table); -static const struct of_device_id sccnxp_dt_id_table[] = { - { .compatible = "nxp,sc2681", .data = &sc2681, }, - { .compatible = "nxp,sc2691", .data = &sc2691, }, - { .compatible = "nxp,sc2692", .data = &sc2692, }, - { .compatible = "nxp,sc2891", .data = &sc2891, }, - { .compatible = "nxp,sc2892", .data = &sc2892, }, - { .compatible = "nxp,sc28202", .data = &sc28202, }, - { .compatible = "nxp,sc68681", .data = &sc68681, }, - { .compatible = "nxp,sc68692", .data = &sc68692, }, - { } -}; -MODULE_DEVICE_TABLE(of, sccnxp_dt_id_table); - static int sccnxp_probe(struct platform_device *pdev) { struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct sccnxp_pdata *pdata = dev_get_platdata(&pdev->dev); - const struct of_device_id *of_id = - of_match_device(sccnxp_dt_id_table, &pdev->dev); int i, ret, uartclk; struct sccnxp_port *s; void __iomem *membase; @@ -892,22 +875,7 @@ static int sccnxp_probe(struct platform_device *pdev) spin_lock_init(&s->lock); - if (of_id) { - s->chip = (struct sccnxp_chip *)of_id->data; - - of_property_read_u32(pdev->dev.of_node, "poll-interval", - &s->pdata.poll_time_us); - of_property_read_u32(pdev->dev.of_node, "reg-shift", - &s->pdata.reg_shift); - of_property_read_u32_array(pdev->dev.of_node, - "nxp,sccnxp-io-cfg", - s->pdata.mctrl_cfg, s->chip->nr); - } else { - s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; - - if (pdata) - memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); - } + s->chip = (struct sccnxp_chip *)pdev->id_entry->driver_data; s->regulator = devm_regulator_get(&pdev->dev, "vcc"); if (!IS_ERR(s->regulator)) { @@ -938,11 +906,16 @@ static int sccnxp_probe(struct platform_device *pdev) goto err_out; } + if (pdata) + memcpy(&s->pdata, pdata, sizeof(struct sccnxp_pdata)); + if (s->pdata.poll_time_us) { dev_info(&pdev->dev, "Using poll mode, resolution %u usecs\n", s->pdata.poll_time_us); s->poll = 1; - } else { + } + + if (!s->poll) { s->irq = platform_get_irq(pdev, 0); if (s->irq < 0) { dev_err(&pdev->dev, "Missing irq resource data\n"); @@ -1043,9 +1016,8 @@ static int sccnxp_remove(struct platform_device *pdev) static struct platform_driver sccnxp_uart_driver = { .driver = { - .name = SCCNXP_NAME, - .owner = THIS_MODULE, - .of_match_table = sccnxp_dt_id_table, + .name = SCCNXP_NAME, + .owner = THIS_MODULE, }, .probe = sccnxp_probe, .remove = sccnxp_remove, diff --git a/include/linux/platform_data/serial-sccnxp.h b/include/linux/platform_data/serial-sccnxp.h index 98373d6add2..af0c8c3b89a 100644 --- a/include/linux/platform_data/serial-sccnxp.h +++ b/include/linux/platform_data/serial-sccnxp.h @@ -78,11 +78,11 @@ /* SCCNXP platform data structure */ struct sccnxp_pdata { /* Shift for A0 line */ - u32 reg_shift; + const u8 reg_shift; /* Modem control lines configuration */ - u32 mctrl_cfg[SCCNXP_MAX_UARTS]; + const u32 mctrl_cfg[SCCNXP_MAX_UARTS]; /* Timer value for polling mode (usecs) */ - u32 poll_time_us; + const unsigned int poll_time_us; }; #endif -- cgit v1.2.3-70-g09d2