* Re: New serial card development
From: Matt Schulte @ 2012-10-15 19:08 UTC (permalink / raw)
To: Theodore Ts'o; +Cc: linux-serial
In-Reply-To: <20121014093704.GA6207@thunk.org>
On Sun, Oct 14, 2012 at 4:37 AM, Theodore Ts'o <tytso@mit.edu> wrote:
>
> On Tue, Oct 09, 2012 at 01:43:10PM -0500, Matt Schulte wrote:
> > Hello, my name is Matt and I have recently developed a PCIe card based
> > on the Exar 17v35x series of PCIe multiport UART chips.
> >
> > We have written Linux drivers for our other products in the past but
> > they have never been what I would call the best practice for Linux
> > development.
> >
> > This time I would like to write a driver that uses the best practices
> > and possibly submit it to the kernel when I'm done.
> >
> > I am a little bit confused about what method would be best for this
> > device. I have been examining the sample driver provided by Exar
> > and it seems that the only things that they have that are really
> > different from the generic 8250 serial driver are the interrupt
> > handler (optimized for their multiple ports), the transmit and
> > receive character functions (modified to use their 256 byte FIFOs)
> > and the function that calculates the baud. Also I have two features
> > specific to my card that I would likely need to use an ioctl for.
>
> Hi Matt,
>
> It's been a while since I've done serial development (probably close
> to a decade ago), but way back when I was responsible for most of the
> code which is now in drivers/tty/serial/8250/serial.c, I had added
> support for the Exar 16C850 UART; since then someone else has added
> support for the Exar XR17D15x UART.
>
> The EXAR 16C850 had a 128 byte FIFO; it sounds like this EXAR variant
> is similar to the 16C850, although it's been further extended.
>
> > If these are the only differences would I be able to create a driver
> > like what is seen in the /drivers/tty/serial/8250 directory (8250_dw.c
> > for example)? Or would I need to do something similar to what I find in
> > the /drviers/tty/serial directory?
>
> We support a very large number of 8250-like UART's already. It
> doesn't make sense create a new driver which is essentially a clone of
> the 8250.c driver. Instead, the 8250.c driver should be extended to
> support this new Exar UART variant. The preferred way to do this is
> to detect the EXAR UART directly, via the method documented in the
> EXAR data sheet, instead of using the PCI id numbers to make this
> determination. This way, we will be able to support that UART on
> other PCI serial cards, and not just yours.
That sounds reasonable but I am not sure what you mean my the "method
documented in the Exar data sheet." I've been through this thing
quite a bit and I don't see anything about how one might detect the
ports without the PCI id numbers. Could you explain what you mean by
this?
>
>
> If you have some features which are explicitly specific to your card,
> and which are not specific to the UART, then that may need to be
> separately triggered via the PCI vendor/device id numbers. What
> feature is it, by the way? If it has to do with controlling the clock
> crystal, there's infrastructure to deal with this already that you may
> be able to leverage.
* This new Exar UART does not use a crystal it uses a clock from the
PCI Express bus. Also it has a fractional divisor that gets them
1/16th (0.0625) resolution on their divisors. The normal DLL and DLM
registers contain the integer part of the divisor and the DLD register
provides the fractional component. The divisor is able to be set to
anything between 1 and (2^16 - 0.0625) in increments of 0.0625.
* These UARTs have 256 byte FIFOs per port per direction. I would
like to utilize these to their fullest potential.
* I need to toggle 16-bit general purpose IO signals to control two
things on my card: Receive Echo Cancel (useful for 2-wire 485) and the
selectable termination resistance on my receiver chips.
* I need to change two UART specific registers to change the sampling
mode (16x, 8x and 4x).
* I need to figure out if the new RS485 elements that have been added
to 8250 can be used on these Exar parts and if not I need something
that can enable RS485 for us.
* I need to be able to enable 9-bit mode, what they call Normal
Multi-drop as well as the Auto Address Detection Mode used in
conjunction with the Multi-drop mode.
* There is an interruptible hardware timer/counter that I might like
to utilize at some point.
With this laundry list of items that I would like to include, do you
still feel like this is something that should be included in the
kernel's 8250.c/8250_pci.c drivers?
Thanks for helping me think this through.
Matt
^ permalink raw reply
* RE: [RESET PATCH 2/2] Documentation: of-serial.txt - update for clocks phandle for clk
From: Karicheri, Muralidharan @ 2012-10-15 15:05 UTC (permalink / raw)
To: Karicheri, Muralidharan, alan@linux.intel.com,
gregkh@linuxfoundation.org, linux-serial@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-keystone@list.ti.com - Linux developers for Keystone family of devices (May contain non-TIers)
Cc: Chemparathy, Cyril
In-Reply-To: <1350313178-3753-3-git-send-email-m-karicheri2@ti.com>
>> -----Original Message-----
>> From: Karicheri, Muralidharan
>> Sent: Monday, October 15, 2012 11:00 AM
>> To: alan@linux.intel.com; gregkh@linuxfoundation.org; linux-serial@vger.kernel.org;
>> linux-kernel@vger.kernel.org; linux-keystone@list.ti.com - Linux developers for Keystone
>> family of devices (May contain non-TIers)
>> Cc: Chemparathy, Cyril; Karicheri, Muralidharan
>> Subject: [RESET PATCH 2/2] Documentation: of-serial.txt - update for clocks phandle for
>> clk
Sorry for the typo, RESET->RESEND.
>>
>> Signed-off-by: Murali Karicheri <m-karicheri2@ti.com>
>>
>> diff --git a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
>> b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
>> index 0847fde..423b7ff 100644
>> --- a/Documentation/devicetree/bindings/tty/serial/of-serial.txt
>> +++ b/Documentation/devicetree/bindings/tty/serial/of-serial.txt
>> @@ -14,7 +14,10 @@ Required properties:
>> - "serial" if the port type is unknown.
>> - reg : offset and length of the register set for the device.
>> - interrupts : should contain uart interrupt.
>> -- clock-frequency : the input clock frequency for the UART.
>> +- clock-frequency : the input clock frequency for the UART
>> + or
>> + clocks phandle to refer to the clk used as per Documentation/devicetree
>> + /bindings/clock/clock-bindings.txt
>>
>> Optional properties:
>> - current-speed : the current active speed of the UART.
>> --
>> 1.7.9.5
^ permalink raw reply
* Re: [PATCH RESEND] serial/amba-pl011: use devm_* managed resources
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-10-15 13:52 UTC (permalink / raw)
To: Linus Walleij
Cc: Anmar Oueja, Greg Kroah-Hartman, Linus Walleij, linux-arm-kernel,
linux-serial
In-Reply-To: <1350300961-7036-1-git-send-email-linus.walleij@stericsson.com>
On 13:36 Mon 15 Oct , Linus Walleij wrote:
> From: Linus Walleij <linus.walleij@linaro.org>
>
> This switches a bunch of allocation and remapping to use the
> devm_* garbage collected methods and cleans up the error
> path and remove() paths consequently.
>
> devm_ioremap() is only in <linux/io.h> so fix up the
> erroneous <asm/*> include as well.
>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Acked-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
Best Regards,
J.
^ permalink raw reply
* [PATCH RESEND] serial/amba-pl011: use devm_* managed resources
From: Linus Walleij @ 2012-10-15 11:36 UTC (permalink / raw)
To: linux-serial, Greg Kroah-Hartman
Cc: linux-arm-kernel, Anmar Oueja, Linus Walleij
From: Linus Walleij <linus.walleij@linaro.org>
This switches a bunch of allocation and remapping to use the
devm_* garbage collected methods and cleans up the error
path and remove() paths consequently.
devm_ioremap() is only in <linux/io.h> so fix up the
erroneous <asm/*> include as well.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
drivers/tty/serial/amba-pl011.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index d7e1ede..7fca402 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -56,8 +56,7 @@
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/sizes.h>
-
-#include <asm/io.h>
+#include <linux/io.h>
#define UART_NR 14
@@ -1973,7 +1972,8 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
goto out;
}
- uap = kzalloc(sizeof(struct uart_amba_port), GFP_KERNEL);
+ uap = devm_kzalloc(&dev->dev, sizeof(struct uart_amba_port),
+ GFP_KERNEL);
if (uap == NULL) {
ret = -ENOMEM;
goto out;
@@ -1981,16 +1981,17 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
i = pl011_probe_dt_alias(i, &dev->dev);
- base = ioremap(dev->res.start, resource_size(&dev->res));
+ base = devm_ioremap(&dev->dev, dev->res.start,
+ resource_size(&dev->res));
if (!base) {
ret = -ENOMEM;
- goto free;
+ goto out;
}
uap->pinctrl = devm_pinctrl_get(&dev->dev);
if (IS_ERR(uap->pinctrl)) {
ret = PTR_ERR(uap->pinctrl);
- goto unmap;
+ goto out;
}
uap->pins_default = pinctrl_lookup_state(uap->pinctrl,
PINCTRL_STATE_DEFAULT);
@@ -2002,10 +2003,10 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
if (IS_ERR(uap->pins_sleep))
dev_dbg(&dev->dev, "could not get sleep pinstate\n");
- uap->clk = clk_get(&dev->dev, NULL);
+ uap->clk = devm_clk_get(&dev->dev, NULL);
if (IS_ERR(uap->clk)) {
ret = PTR_ERR(uap->clk);
- goto unmap;
+ goto out;
}
uap->vendor = vendor;
@@ -2038,11 +2039,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id)
amba_set_drvdata(dev, NULL);
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- clk_put(uap->clk);
- unmap:
- iounmap(base);
- free:
- kfree(uap);
}
out:
return ret;
@@ -2062,9 +2058,6 @@ static int pl011_remove(struct amba_device *dev)
amba_ports[i] = NULL;
pl011_dma_remove(uap);
- iounmap(uap->port.membase);
- clk_put(uap->clk);
- kfree(uap);
return 0;
}
--
1.7.11.3
^ permalink raw reply related
* Re: [PATCH] serial: clps711x: reworked driver version
From: Alan Cox @ 2012-10-15 10:15 UTC (permalink / raw)
To: Alexander Shiyan; +Cc: Greg Kroah-Hartman, linux-serial
In-Reply-To: <20121014110500.f81f5070d536274245aaca5c@mail.ru>
> Yes, this is understandable. This patch is the result of several
> years of work with this driver. I tried to split into separate
> functional parts and send the new version in a new thread. Please
> comment.
Acked-by: Alan Cox <alan@linux.intel.com> for all the tty layer parts
^ permalink raw reply
* [PATCH] tty: serial: 8250_dw: Implement suspend/resume
From: James Hogan @ 2012-10-15 9:25 UTC (permalink / raw)
To: Alan Cox
Cc: Greg Kroah-Hartman, Paul Gortmaker, Axel Lin, linux-serial,
linux-kernel, James Hogan
Implement suspend and resume callbacks for DesignWare 8250 driver.
They're simple wrappers around serial8250_{suspend,resume}_port.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
---
drivers/tty/serial/8250/8250_dw.c | 25 +++++++++++++++++++++++++
1 files changed, 25 insertions(+), 0 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index f574eef..53db7e8 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -161,6 +161,29 @@ static int __devexit dw8250_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
+static int dw8250_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct dw8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_suspend_port(data->line);
+
+ return 0;
+}
+
+static int dw8250_resume(struct platform_device *pdev)
+{
+ struct dw8250_data *data = platform_get_drvdata(pdev);
+
+ serial8250_resume_port(data->line);
+
+ return 0;
+}
+#else
+#define dw8250_suspend NULL
+#define dw8250_resume NULL
+#endif /* CONFIG_PM */
+
static const struct of_device_id dw8250_match[] = {
{ .compatible = "snps,dw-apb-uart" },
{ /* Sentinel */ }
@@ -175,6 +198,8 @@ static struct platform_driver dw8250_platform_driver = {
},
.probe = dw8250_probe,
.remove = __devexit_p(dw8250_remove),
+ .suspend = dw8250_suspend,
+ .resume = dw8250_resume,
};
module_platform_driver(dw8250_platform_driver);
--
1.7.7.6
^ permalink raw reply related
* RE: 8250_early for big-endian
From: Noam Camus @ 2012-10-14 16:18 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-serial@vger.kernel.org
In-Reply-To: <20121014133216.686277e1@pyramind.ukuu.org.uk>
From: Alan Cox [mailto:alan@lxorguk.ukuu.org.uk]
Sent: Sunday, October 14, 2012 2:32 PM
> For 8250_early it may well be the right thing is to support similar serial_in/serial_out methods.
Is it acceptable solution to add attribute __weak (and remove static) from serial_in/serial_out methods?
Noam
^ permalink raw reply
* Re: New serial card development
From: Theodore Ts'o @ 2012-10-14 9:37 UTC (permalink / raw)
To: Matt Schulte; +Cc: linux-serial
In-Reply-To: <5074703E.408@commtech-fastcom.com>
On Tue, Oct 09, 2012 at 01:43:10PM -0500, Matt Schulte wrote:
> Hello, my name is Matt and I have recently developed a PCIe card based
> on the Exar 17v35x series of PCIe multiport UART chips.
>
> We have written Linux drivers for our other products in the past but
> they have never been what I would call the best practice for Linux
> development.
>
> This time I would like to write a driver that uses the best practices
> and possibly submit it to the kernel when I'm done.
>
> I am a little bit confused about what method would be best for this
> device. I have been examining the sample driver provided by Exar
> and it seems that the only things that they have that are really
> different from the generic 8250 serial driver are the interrupt
> handler (optimized for their multiple ports), the transmit and
> receive character functions (modified to use their 256 byte FIFOs)
> and the function that calculates the baud. Also I have two features
> specific to my card that I would likely need to use an ioctl for.
Hi Matt,
It's been a while since I've done serial development (probably close
to a decade ago), but way back when I was responsible for most of the
code which is now in drivers/tty/serial/8250/serial.c, I had added
support for the Exar 16C850 UART; since then someone else has added
support for the Exar XR17D15x UART.
The EXAR 16C850 had a 128 byte FIFO; it sounds like this EXAR variant
is similar to the 16C850, although it's been further extended.
> If these are the only differences would I be able to create a driver
> like what is seen in the /drivers/tty/serial/8250 directory (8250_dw.c
> for example)? Or would I need to do something similar to what I find in
> the /drviers/tty/serial directory?
We support a very large number of 8250-like UART's already. It
doesn't make sense create a new driver which is essentially a clone of
the 8250.c driver. Instead, the 8250.c driver should be extended to
support this new Exar UART variant. The preferred way to do this is
to detect the EXAR UART directly, via the method documented in the
EXAR data sheet, instead of using the PCI id numbers to make this
determination. This way, we will be able to support that UART on
other PCI serial cards, and not just yours.
If you have some features which are explicitly specific to your card,
and which are not specific to the UART, then that may need to be
separately triggered via the PCI vendor/device id numbers. What
feature is it, by the way? If it has to do with controlling the clock
crystal, there's infrastructure to deal with this already that you may
be able to leverage.
Regards,
- Ted
^ permalink raw reply
* Re: 8250_early for big-endian
From: Alan Cox @ 2012-10-14 12:32 UTC (permalink / raw)
To: Noam Camus; +Cc: linux-serial@vger.kernel.org
In-Reply-To: <264C179F799EF24AB26D5319053335E80CC3001073@ezexch.ezchip.com>
On Sun, 14 Oct 2012 12:11:13 +0200
Noam Camus <noamc@ezchip.com> wrote:
> Soon I will email you my patch for regshift addition.
>
> In the meantime I discovered that one of my boards do need 32bit operations.
>
> How to generalize the solution to cover this case as well?
Then I guess if you need 32bit I/O and aligned we do actually need to to
support the shifts and you do end up needing to do MMIO32 and >> 24 for
your serial_in (or as you originally suggested a byte reverse if faster).
For 8250_early it may well be the right thing is to support similar
serial_in/serial_out methods.
Alan
^ permalink raw reply
* RE: 8250_early for big-endian
From: Noam Camus @ 2012-10-14 10:11 UTC (permalink / raw)
To: Alan Cox; +Cc: linux-serial@vger.kernel.org
In-Reply-To: <20121013145212.27f6fcbd@pyramind.ukuu.org.uk>
Soon I will email you my patch for regshift addition.
In the meantime I discovered that one of my boards do need 32bit operations.
How to generalize the solution to cover this case as well?
Noam
-----Original Message-----
From: Alan Cox [mailto:alan@lxorguk.ukuu.org.uk]
Sent: Saturday, October 13, 2012 3:52 PM
To: Noam Camus
Cc: linux-serial@vger.kernel.org
Subject: Re: 8250_early for big-endian
On Sat, 13 Oct 2012 08:43:02 +0200
Noam Camus <noamc@ezchip.com> wrote:
> On Fri, 12 Oct 2012 21:11:06 +0200
> Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
>
> > Do the values have to be read with 32bit operations and do they have
> > to be read on 32bi alignment ?
>
> Yes I do need the 32bit alignment but I do not need 32bit operations.
> So using mmio (instead of mmio32) with regshift equals 2 worked for me.
>
> However 8250_early got no configurable regshift.
> So it needs to be added.
I would favour adding the regshift and I see no problem in doing that.
Alan
^ permalink raw reply
* Re: [PATCH 01/12] serial: clps711x: Add platform_driver interface to clps711x driver
From: Arnd Bergmann @ 2012-10-14 7:54 UTC (permalink / raw)
To: Alexander Shiyan; +Cc: linux-serial, Alan Cox, Greg Kroah-Hartman
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
On Sunday 14 October 2012, Alexander Shiyan wrote:
> +
> +static int __init uart_clps711x_init(void)
> +{
> + return platform_device_register(&clps711x_uart_device);
> +}
> +module_init(uart_clps711x_init);
> +
> +static void __exit uart_clps711x_exit(void)
> +{
> + platform_device_unregister(&clps711x_uart_device);
> +}
> +module_exit(uart_clps711x_exit);
Patch looks good in general, but the above could be simplified to use
module_platform_driver();
Arnd
^ permalink raw reply
* [PATCH 12/12] serial: clps711x: Cleanup driver
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
This patch performs cleanup on clps711x serial driver. This include:
- Change functions naming style.
- Removed unused includes.
- Removed unneeded comments.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 105 ++++++++++++++++++-----------------------
1 files changed, 46 insertions(+), 59 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 90efe05..a0a6db5 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -10,15 +10,6 @@
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
@@ -26,22 +17,18 @@
#endif
#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/spinlock.h>
#include <linux/device.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
+#include <linux/console.h>
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
#include <linux/clk.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
-#include <asm/irq.h>
#define UART_CLPS711X_NAME "uart-clps711x"
#define UART_CLPS711X_NR 2
@@ -65,7 +52,7 @@ struct clps711x_port {
#endif
};
-static void clps711xuart_stop_tx(struct uart_port *port)
+static void uart_clps711x_stop_tx(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
@@ -75,7 +62,7 @@ static void clps711xuart_stop_tx(struct uart_port *port)
}
}
-static void clps711xuart_start_tx(struct uart_port *port)
+static void uart_clps711x_start_tx(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
@@ -85,13 +72,14 @@ static void clps711xuart_start_tx(struct uart_port *port)
}
}
-static void clps711xuart_stop_rx(struct uart_port *port)
+static void uart_clps711x_stop_rx(struct uart_port *port)
{
disable_irq(RX_IRQ(port));
}
-static void clps711xuart_enable_ms(struct uart_port *port)
+static void uart_clps711x_enable_ms(struct uart_port *port)
{
+ /* Do nothing */
}
static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
@@ -156,7 +144,7 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
struct circ_buf *xmit = &port->state->xmit;
if (port->x_char) {
- clps_writel(port->x_char, UARTDR(port));
+ clps_writew(port->x_char, UARTDR(port));
port->icount.tx++;
port->x_char = 0;
return IRQ_HANDLED;
@@ -182,13 +170,12 @@ static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static unsigned int clps711xuart_tx_empty(struct uart_port *port)
+static unsigned int uart_clps711x_tx_empty(struct uart_port *port)
{
- unsigned int status = clps_readl(SYSFLG(port));
- return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT;
+ return (clps_readl(SYSFLG(port) & SYSFLG_UBUSY)) ? 0 : TIOCSER_TEMT;
}
-static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
+static unsigned int uart_clps711x_get_mctrl(struct uart_port *port)
{
unsigned int status, result = 0;
@@ -206,12 +193,12 @@ static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
return result;
}
-static void
-clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl)
+static void uart_clps711x_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
+ /* Do nothing */
}
-static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
+static void uart_clps711x_break_ctl(struct uart_port *port, int break_state)
{
unsigned long flags;
unsigned int ubrlcr;
@@ -228,7 +215,7 @@ static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
-static int clps711xuart_startup(struct uart_port *port)
+static int uart_clps711x_startup(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
int ret;
@@ -256,7 +243,7 @@ static int clps711xuart_startup(struct uart_port *port)
return 0;
}
-static void clps711xuart_shutdown(struct uart_port *port)
+static void uart_clps711x_shutdown(struct uart_port *port)
{
/* Free the interrupts */
devm_free_irq(port->dev, TX_IRQ(port), port);
@@ -266,9 +253,9 @@ static void clps711xuart_shutdown(struct uart_port *port)
clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
}
-static void
-clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static void uart_clps711x_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
{
unsigned int ubrlcr, baud, quot;
unsigned long flags;
@@ -292,7 +279,8 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
case CS7:
ubrlcr = UBRLCR_WRDLEN7;
break;
- default: // CS8
+ case CS8:
+ default:
ubrlcr = UBRLCR_WRDLEN8;
break;
}
@@ -329,45 +317,44 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
spin_unlock_irqrestore(&port->lock, flags);
}
-static const char *clps711xuart_type(struct uart_port *port)
+static const char *uart_clps711x_type(struct uart_port *port)
{
- return port->type == PORT_CLPS711X ? "CLPS711x" : NULL;
+ return (port->type == PORT_CLPS711X) ? "CLPS711X" : NULL;
}
-/*
- * Configure/autoconfigure the port.
- */
-static void clps711xuart_config_port(struct uart_port *port, int flags)
+static void uart_clps711x_config_port(struct uart_port *port, int flags)
{
if (flags & UART_CONFIG_TYPE)
port->type = PORT_CLPS711X;
}
-static void clps711xuart_release_port(struct uart_port *port)
+static void uart_clps711x_release_port(struct uart_port *port)
{
+ /* Do nothing */
}
-static int clps711xuart_request_port(struct uart_port *port)
+static int uart_clps711x_request_port(struct uart_port *port)
{
+ /* Do nothing */
return 0;
}
-static struct uart_ops uart_clps711x_ops = {
- .tx_empty = clps711xuart_tx_empty,
- .set_mctrl = clps711xuart_set_mctrl_null,
- .get_mctrl = clps711xuart_get_mctrl,
- .stop_tx = clps711xuart_stop_tx,
- .start_tx = clps711xuart_start_tx,
- .stop_rx = clps711xuart_stop_rx,
- .enable_ms = clps711xuart_enable_ms,
- .break_ctl = clps711xuart_break_ctl,
- .startup = clps711xuart_startup,
- .shutdown = clps711xuart_shutdown,
- .set_termios = clps711xuart_set_termios,
- .type = clps711xuart_type,
- .config_port = clps711xuart_config_port,
- .release_port = clps711xuart_release_port,
- .request_port = clps711xuart_request_port,
+static const struct uart_ops uart_clps711x_ops = {
+ .tx_empty = uart_clps711x_tx_empty,
+ .set_mctrl = uart_clps711x_set_mctrl,
+ .get_mctrl = uart_clps711x_get_mctrl,
+ .stop_tx = uart_clps711x_stop_tx,
+ .start_tx = uart_clps711x_start_tx,
+ .stop_rx = uart_clps711x_stop_rx,
+ .enable_ms = uart_clps711x_enable_ms,
+ .break_ctl = uart_clps711x_break_ctl,
+ .startup = uart_clps711x_startup,
+ .shutdown = uart_clps711x_shutdown,
+ .set_termios = uart_clps711x_set_termios,
+ .type = uart_clps711x_type,
+ .config_port = uart_clps711x_config_port,
+ .release_port = uart_clps711x_release_port,
+ .request_port = uart_clps711x_request_port,
};
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
--
1.7.8.6
^ permalink raw reply related
* [PATCH 11/12] serial: clps711x: Fix TERMIOS-flags handling
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 36 ++++++++++++------------------------
1 files changed, 12 insertions(+), 24 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index e715087..90efe05 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -273,10 +273,9 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned int ubrlcr, baud, quot;
unsigned long flags;
- /*
- * We don't implement CREAD.
- */
- termios->c_cflag |= CREAD;
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~(BRKINT | IGNBRK);
/* Ask the core to calculate the divisor for us */
baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096,
@@ -297,8 +296,10 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
ubrlcr = UBRLCR_WRDLEN8;
break;
}
+
if (termios->c_cflag & CSTOPB)
ubrlcr |= UBRLCR_XSTOP;
+
if (termios->c_cflag & PARENB) {
ubrlcr |= UBRLCR_PRTEN;
if (!(termios->c_cflag & PARODD))
@@ -310,33 +311,20 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
spin_lock_irqsave(&port->lock, flags);
- /*
- * Update the per-port timeout.
- */
- uart_update_timeout(port, termios->c_cflag, baud);
-
+ /* Set read status mask */
port->read_status_mask = UARTDR_OVERR;
if (termios->c_iflag & INPCK)
port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR;
- /*
- * Characters to ignore
- */
+ /* Set status ignore mask */
port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR;
- if (termios->c_iflag & IGNBRK) {
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns to (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= UARTDR_OVERR;
- }
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= UARTDR_OVERR | UARTDR_PARERR |
+ UARTDR_FRMERR;
- quot -= 1;
+ uart_update_timeout(port, termios->c_cflag, baud);
- clps_writel(ubrlcr | quot, UBRLCR(port));
+ clps_writel(ubrlcr | (quot - 1), UBRLCR(port));
spin_unlock_irqrestore(&port->lock, flags);
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 10/12] serial: clps711x: Disable "break"-state before port startup
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 29 +++++++----------------------
1 files changed, 7 insertions(+), 22 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 7cf3928..e715087 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -231,7 +231,6 @@ static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
static int clps711xuart_startup(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
- unsigned int syscon;
int ret;
s->tx_enabled[port->line] = 1;
@@ -248,37 +247,23 @@ static int clps711xuart_startup(struct uart_port *port)
return ret;
}
- /*
- * enable the port
- */
- syscon = clps_readl(SYSCON(port));
- syscon |= SYSCON_UARTEN;
- clps_writel(syscon, SYSCON(port));
+ /* Disable break */
+ clps_writel(clps_readl(UBRLCR(port)) & ~UBRLCR_BREAK, UBRLCR(port));
+
+ /* Enable the port */
+ clps_writel(clps_readl(SYSCON(port)) | SYSCON_UARTEN, SYSCON(port));
return 0;
}
static void clps711xuart_shutdown(struct uart_port *port)
{
- unsigned int ubrlcr, syscon;
-
/* Free the interrupts */
devm_free_irq(port->dev, TX_IRQ(port), port);
devm_free_irq(port->dev, RX_IRQ(port), port);
- /*
- * disable the port
- */
- syscon = clps_readl(SYSCON(port));
- syscon &= ~SYSCON_UARTEN;
- clps_writel(syscon, SYSCON(port));
-
- /*
- * disable break condition and fifos
- */
- ubrlcr = clps_readl(UBRLCR(port));
- ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK);
- clps_writel(ubrlcr, UBRLCR(port));
+ /* Disable the port */
+ clps_writel(clps_readl(SYSCON(port)) & ~SYSCON_UARTEN, SYSCON(port));
}
static void
--
1.7.8.6
^ permalink raw reply related
* [PATCH 09/12] serial: clps711x: Using resource-managed functions
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 39 +++++++++++++++++----------------------
1 files changed, 17 insertions(+), 22 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 6039ebe..7cf3928 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -94,7 +94,7 @@ static void clps711xuart_enable_ms(struct uart_port *port)
{
}
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = tty_port_tty_get(&port->state->port);
@@ -149,7 +149,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
+static irqreturn_t uart_clps711x_int_tx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct clps711x_port *s = dev_get_drvdata(port->dev);
@@ -232,23 +232,20 @@ static int clps711xuart_startup(struct uart_port *port)
{
struct clps711x_port *s = dev_get_drvdata(port->dev);
unsigned int syscon;
- int retval;
+ int ret;
s->tx_enabled[port->line] = 1;
-
- /*
- * Allocate the IRQs
- */
- retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0,
- "clps711xuart_tx", port);
- if (retval)
- return retval;
-
- retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0,
- "clps711xuart_rx", port);
- if (retval) {
- free_irq(TX_IRQ(port), port);
- return retval;
+ /* Allocate the IRQs */
+ ret = devm_request_irq(port->dev, TX_IRQ(port), uart_clps711x_int_tx,
+ 0, UART_CLPS711X_NAME " TX", port);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(port->dev, RX_IRQ(port), uart_clps711x_int_rx,
+ 0, UART_CLPS711X_NAME " RX", port);
+ if (ret) {
+ devm_free_irq(port->dev, TX_IRQ(port), port);
+ return ret;
}
/*
@@ -265,11 +262,9 @@ static void clps711xuart_shutdown(struct uart_port *port)
{
unsigned int ubrlcr, syscon;
- /*
- * Free the interrupt
- */
- free_irq(TX_IRQ(port), port); /* TX interrupt */
- free_irq(RX_IRQ(port), port); /* RX interrupt */
+ /* Free the interrupts */
+ devm_free_irq(port->dev, TX_IRQ(port), port);
+ devm_free_irq(port->dev, RX_IRQ(port), port);
/*
* disable the port
--
1.7.8.6
^ permalink raw reply related
* [PATCH 08/12] serial: clps711x: Check for valid TTY in RX-interrupt
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 59 ++++++++++++++++++++---------------------
1 files changed, 29 insertions(+), 30 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 73505c1..6039ebe 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -55,8 +55,6 @@
#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
-#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-
struct clps711x_port {
struct uart_driver uart;
struct clk *uart_clk;
@@ -99,54 +97,55 @@ static void clps711xuart_enable_ms(struct uart_port *port)
static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
- struct tty_struct *tty = port->state->port.tty;
+ struct tty_struct *tty = tty_port_tty_get(&port->state->port);
unsigned int status, ch, flg;
- status = clps_readl(SYSFLG(port));
- while (!(status & SYSFLG_URXFE)) {
- ch = clps_readl(UARTDR(port));
+ if (!tty)
+ return IRQ_HANDLED;
- port->icount.rx++;
+ for (;;) {
+ status = clps_readl(SYSFLG(port));
+ if (status & SYSFLG_URXFE)
+ break;
+ ch = clps_readw(UARTDR(port));
+ status = ch & (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR);
+ ch &= 0xff;
+
+ port->icount.rx++;
flg = TTY_NORMAL;
- /*
- * Note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(ch & UART_ANY_ERR)) {
- if (ch & UARTDR_PARERR)
+ if (unlikely(status)) {
+ if (status & UARTDR_PARERR)
port->icount.parity++;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
port->icount.frame++;
- if (ch & UARTDR_OVERR)
+ else if (status & UARTDR_OVERR)
port->icount.overrun++;
- ch &= port->read_status_mask;
+ status &= port->read_status_mask;
- if (ch & UARTDR_PARERR)
+ if (status & UARTDR_PARERR)
flg = TTY_PARITY;
- else if (ch & UARTDR_FRMERR)
+ else if (status & UARTDR_FRMERR)
flg = TTY_FRAME;
-
-#ifdef SUPPORT_SYSRQ
- port->sysrq = 0;
-#endif
+ else if (status & UARTDR_OVERR)
+ flg = TTY_OVERRUN;
}
if (uart_handle_sysrq_char(port, ch))
- goto ignore_char;
+ continue;
- /*
- * CHECK: does overrun affect the current character?
- * ASSUMPTION: it does not.
- */
- uart_insert_char(port, ch, UARTDR_OVERR, ch, flg);
+ if (status & port->ignore_status_mask)
+ continue;
- ignore_char:
- status = clps_readl(SYSFLG(port));
+ uart_insert_char(port, status, UARTDR_OVERR, ch, flg);
}
+
tty_flip_buffer_push(tty);
+
+ tty_kref_put(tty);
+
return IRQ_HANDLED;
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 07/12] serial: clps711x: Fix break control handling
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 7b0e539..73505c1 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -218,12 +218,14 @@ static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
unsigned int ubrlcr;
spin_lock_irqsave(&port->lock, flags);
+
ubrlcr = clps_readl(UBRLCR(port));
- if (break_state == -1)
+ if (break_state)
ubrlcr |= UBRLCR_BREAK;
else
ubrlcr &= ~UBRLCR_BREAK;
clps_writel(ubrlcr, UBRLCR(port));
+
spin_unlock_irqrestore(&port->lock, flags);
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 06/12] serial: clps711x: Return valid modem controls for port that not support it
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 10 ++++------
1 files changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index d374609..7b0e539 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -191,12 +191,9 @@ static unsigned int clps711xuart_tx_empty(struct uart_port *port)
static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
{
- unsigned int port_addr;
- unsigned int result = 0;
- unsigned int status;
+ unsigned int status, result = 0;
- port_addr = SYSFLG(port);
- if (port_addr == SYSFLG1) {
+ if (port->line == 0) {
status = clps_readl(SYSFLG1);
if (status & SYSFLG1_DCD)
result |= TIOCM_CAR;
@@ -204,7 +201,8 @@ static unsigned int clps711xuart_get_mctrl(struct uart_port *port)
result |= TIOCM_DSR;
if (status & SYSFLG1_CTS)
result |= TIOCM_CTS;
- }
+ } else
+ result = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR;
return result;
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 05/12] serial: clps711x: Improved TX FIFO handling
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 15 +++++++--------
1 files changed, 7 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 0884939..d374609 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -155,7 +155,6 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
struct uart_port *port = dev_id;
struct clps711x_port *s = dev_get_drvdata(port->dev);
struct circ_buf *xmit = &port->state->xmit;
- int count;
if (port->x_char) {
clps_writel(port->x_char, UARTDR(port));
@@ -170,14 +169,13 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
return IRQ_HANDLED;
}
- count = port->fifosize >> 1;
- do {
- clps_writel(xmit->buf[xmit->tail], UARTDR(port));
+ while (!uart_circ_empty(xmit)) {
+ clps_writew(xmit->buf[xmit->tail], UARTDR(port));
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
port->icount.tx++;
- if (uart_circ_empty(xmit))
+ if (clps_readl(SYSFLG(port) & SYSFLG_UTXFF))
break;
- } while (--count > 0);
+ }
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
@@ -327,8 +325,9 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
if (!(termios->c_cflag & PARODD))
ubrlcr |= UBRLCR_EVENPRT;
}
- if (port->fifosize > 1)
- ubrlcr |= UBRLCR_FIFOEN;
+
+ /* Enable FIFO */
+ ubrlcr |= UBRLCR_FIFOEN;
spin_lock_irqsave(&port->lock, flags);
--
1.7.8.6
^ permalink raw reply related
* [PATCH 04/12] serial: clps711x: Using CPU clock subsystem for getting base UART speed
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 20 +++++++++++++++-----
1 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 3b17d19..0884939 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -37,6 +37,7 @@
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
+#include <linux/clk.h>
#include <linux/platform_device.h>
#include <mach/hardware.h>
@@ -58,6 +59,7 @@
struct clps711x_port {
struct uart_driver uart;
+ struct clk *uart_clk;
struct uart_port port[UART_CLPS711X_NR];
int tx_enabled[UART_CLPS711X_NR];
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
@@ -299,10 +301,9 @@ clps711xuart_set_termios(struct uart_port *port, struct ktermios *termios,
*/
termios->c_cflag |= CREAD;
- /*
- * Ask the core to calculate the divisor for us.
- */
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ /* Ask the core to calculate the divisor for us */
+ baud = uart_get_baud_rate(port, termios, old, port->uartclk / 4096,
+ port->uartclk / 16);
quot = uart_get_divisor(port, baud);
switch (termios->c_cflag & CSIZE) {
@@ -487,6 +488,13 @@ static int __devinit uart_clps711x_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, s);
+ s->uart_clk = devm_clk_get(&pdev->dev, "uart");
+ if (IS_ERR(s->uart_clk)) {
+ dev_err(&pdev->dev, "Can't get UART clocks\n");
+ ret = PTR_ERR(s->uart_clk);
+ goto err_out;
+ }
+
s->uart.owner = THIS_MODULE;
s->uart.dev_name = "ttyCL";
s->uart.major = UART_CLPS711X_MAJOR;
@@ -505,6 +513,7 @@ static int __devinit uart_clps711x_probe(struct platform_device *pdev)
ret = uart_register_driver(&s->uart);
if (ret) {
dev_err(&pdev->dev, "Registering UART driver failed\n");
+ devm_clk_put(&pdev->dev, s->uart_clk);
goto err_out;
}
@@ -516,7 +525,7 @@ static int __devinit uart_clps711x_probe(struct platform_device *pdev)
s->port[i].type = PORT_CLPS711X;
s->port[i].fifosize = 16;
s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
- s->port[i].uartclk = 3686400;
+ s->port[i].uartclk = clk_get_rate(s->uart_clk);
s->port[i].ops = &uart_clps711x_ops;
WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
}
@@ -537,6 +546,7 @@ static int __devexit uart_clps711x_remove(struct platform_device *pdev)
for (i = 0; i < UART_CLPS711X_NR; i++)
uart_remove_one_port(&s->uart, &s->port[i]);
+ devm_clk_put(&pdev->dev, s->uart_clk);
uart_unregister_driver(&s->uart);
platform_set_drvdata(pdev, NULL);
--
1.7.8.6
^ permalink raw reply related
* [PATCH 03/12] serial: clps711x: Do not use "uart_port->unused" field
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 32 +++++++++++++++++---------------
1 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index de6aa33..3b17d19 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -56,11 +56,10 @@
#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
-#define tx_enabled(port) ((port)->unused[0])
-
struct clps711x_port {
struct uart_driver uart;
struct uart_port port[UART_CLPS711X_NR];
+ int tx_enabled[UART_CLPS711X_NR];
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
struct console console;
#endif
@@ -68,17 +67,21 @@ struct clps711x_port {
static void clps711xuart_stop_tx(struct uart_port *port)
{
- if (tx_enabled(port)) {
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+ if (s->tx_enabled[port->line]) {
disable_irq(TX_IRQ(port));
- tx_enabled(port) = 0;
+ s->tx_enabled[port->line] = 0;
}
}
static void clps711xuart_start_tx(struct uart_port *port)
{
- if (!tx_enabled(port)) {
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
+
+ if (!s->tx_enabled[port->line]) {
enable_irq(TX_IRQ(port));
- tx_enabled(port) = 1;
+ s->tx_enabled[port->line] = 1;
}
}
@@ -148,6 +151,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
struct circ_buf *xmit = &port->state->xmit;
int count;
@@ -158,8 +162,11 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
return IRQ_HANDLED;
}
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- goto disable_tx_irq;
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ disable_irq_nosync(TX_IRQ(port));
+ s->tx_enabled[port->line] = 0;
+ return IRQ_HANDLED;
+ }
count = port->fifosize >> 1;
do {
@@ -173,12 +180,6 @@ static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- if (uart_circ_empty(xmit)) {
- disable_tx_irq:
- disable_irq_nosync(TX_IRQ(port));
- tx_enabled(port) = 0;
- }
-
return IRQ_HANDLED;
}
@@ -230,10 +231,11 @@ static void clps711xuart_break_ctl(struct uart_port *port, int break_state)
static int clps711xuart_startup(struct uart_port *port)
{
+ struct clps711x_port *s = dev_get_drvdata(port->dev);
unsigned int syscon;
int retval;
- tx_enabled(port) = 1;
+ s->tx_enabled[port->line] = 1;
/*
* Allocate the IRQs
--
1.7.8.6
^ permalink raw reply related
* [PATCH 02/12] serial: clps711x: Convert all static variables to dynamic
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
In-Reply-To: <1350198334-18737-1-git-send-email-shc_work@mail.ru>
This patch converts all static variables of clps711x serial driver
to dynamic allocating. In this case we are should remove console_initcall()
and declare console during driver registration. Early kernel messages can
be retrieved by add "earlyprintk" option to the kernel command line.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 211 +++++++++++++++++------------------------
1 files changed, 89 insertions(+), 122 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index 07fef1c..de6aa33 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -43,28 +43,29 @@
#include <asm/irq.h>
#define UART_CLPS711X_NAME "uart-clps711x"
+#define UART_CLPS711X_NR 2
+#define UART_CLPS711X_MAJOR 204
+#define UART_CLPS711X_MINOR 40
-#define UART_NR 2
-
-#define SERIAL_CLPS711X_MAJOR 204
-#define SERIAL_CLPS711X_MINOR 40
-#define SERIAL_CLPS711X_NR UART_NR
-
-/*
- * We use the relevant SYSCON register as a base address for these ports.
- */
-#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1)
-#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1)
-#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1)
-#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1)
-
-#define TX_IRQ(port) ((port)->irq)
-#define RX_IRQ(port) ((port)->irq + 1)
+#define UBRLCR(port) ((port)->line ? UBRLCR2 : UBRLCR1)
+#define UARTDR(port) ((port)->line ? UARTDR2 : UARTDR1)
+#define SYSFLG(port) ((port)->line ? SYSFLG2 : SYSFLG1)
+#define SYSCON(port) ((port)->line ? SYSCON2 : SYSCON1)
+#define TX_IRQ(port) ((port)->line ? IRQ_UTXINT2 : IRQ_UTXINT1)
+#define RX_IRQ(port) ((port)->line ? IRQ_URXINT2 : IRQ_URXINT1)
#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR)
#define tx_enabled(port) ((port)->unused[0])
+struct clps711x_port {
+ struct uart_driver uart;
+ struct uart_port port[UART_CLPS711X_NR];
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+ struct console console;
+#endif
+};
+
static void clps711xuart_stop_tx(struct uart_port *port)
{
if (tx_enabled(port)) {
@@ -382,7 +383,7 @@ static int clps711xuart_request_port(struct uart_port *port)
return 0;
}
-static struct uart_ops clps711x_pops = {
+static struct uart_ops uart_clps711x_ops = {
.tx_empty = clps711xuart_tx_empty,
.set_mctrl = clps711xuart_set_mctrl_null,
.get_mctrl = clps711xuart_get_mctrl,
@@ -400,72 +401,39 @@ static struct uart_ops clps711x_pops = {
.request_port = clps711xuart_request_port,
};
-static struct uart_port clps711x_ports[UART_NR] = {
- {
- .iobase = SYSCON1,
- .irq = IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */
- .uartclk = 3686400,
- .fifosize = 16,
- .ops = &clps711x_pops,
- .line = 0,
- .flags = UPF_BOOT_AUTOCONF,
- },
- {
- .iobase = SYSCON2,
- .irq = IRQ_UTXINT2, /* IRQ_URXINT2 */
- .uartclk = 3686400,
- .fifosize = 16,
- .ops = &clps711x_pops,
- .line = 1,
- .flags = UPF_BOOT_AUTOCONF,
- }
-};
-
#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
-static void clps711xuart_console_putchar(struct uart_port *port, int ch)
+static void uart_clps711x_console_putchar(struct uart_port *port, int ch)
{
while (clps_readl(SYSFLG(port)) & SYSFLG_UTXFF)
barrier();
- clps_writel(ch, UARTDR(port));
+
+ clps_writew(ch, UARTDR(port));
}
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- *
- * Note that this is called with interrupts already disabled
- */
-static void
-clps711xuart_console_write(struct console *co, const char *s,
- unsigned int count)
+static void uart_clps711x_console_write(struct console *co, const char *c,
+ unsigned n)
{
- struct uart_port *port = clps711x_ports + co->index;
- unsigned int status, syscon;
+ struct clps711x_port *s = (struct clps711x_port *)co->data;
+ struct uart_port *port = &s->port[co->index];
+ u32 syscon;
- /*
- * Ensure that the port is enabled.
- */
+ /* Ensure that the port is enabled */
syscon = clps_readl(SYSCON(port));
clps_writel(syscon | SYSCON_UARTEN, SYSCON(port));
- uart_console_write(port, s, count, clps711xuart_console_putchar);
+ uart_console_write(port, c, n, uart_clps711x_console_putchar);
- /*
- * Finally, wait for transmitter to become empty
- * and restore the uart state.
- */
- do {
- status = clps_readl(SYSFLG(port));
- } while (status & SYSFLG_UBUSY);
+ /* Wait for transmitter to become empty */
+ while (clps_readl(SYSFLG(port)) & SYSFLG_UBUSY)
+ barrier();
+ /* Restore the uart state */
clps_writel(syscon, SYSCON(port));
}
-static void __init
-clps711xuart_console_get_options(struct uart_port *port, int *baud,
- int *parity, int *bits)
+static void uart_clps711x_console_get_options(struct uart_port *port,
+ int *baud, int *parity,
+ int *bits)
{
if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) {
unsigned int ubrlcr, quot;
@@ -490,86 +458,85 @@ clps711xuart_console_get_options(struct uart_port *port, int *baud,
}
}
-static int __init clps711xuart_console_setup(struct console *co, char *options)
+static int uart_clps711x_console_setup(struct console *co, char *options)
{
- struct uart_port *port;
- int baud = 38400;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- /*
- * Check whether an invalid uart number has been specified, and
- * if so, search for the first available port that does have
- * console support.
- */
- port = uart_get_console(clps711x_ports, UART_NR, co);
+ int baud = 38400, bits = 8, parity = 'n', flow = 'n';
+ struct clps711x_port *s = (struct clps711x_port *)co->data;
+ struct uart_port *port = &s->port[(co->index > 0) ? co->index : 0];
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
- clps711xuart_console_get_options(port, &baud, &parity, &bits);
+ uart_clps711x_console_get_options(port, &baud, &parity, &bits);
return uart_set_options(port, co, baud, parity, bits, flow);
}
-
-static struct uart_driver clps711x_reg;
-static struct console clps711x_console = {
- .name = "ttyCL",
- .write = clps711xuart_console_write,
- .device = uart_console_device,
- .setup = clps711xuart_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &clps711x_reg,
-};
-
-static int __init clps711xuart_console_init(void)
-{
- register_console(&clps711x_console);
- return 0;
-}
-console_initcall(clps711xuart_console_init);
-
-#define CLPS711X_CONSOLE &clps711x_console
-#else
-#define CLPS711X_CONSOLE NULL
#endif
-static struct uart_driver clps711x_reg = {
- .driver_name = "ttyCL",
- .dev_name = "ttyCL",
- .major = SERIAL_CLPS711X_MAJOR,
- .minor = SERIAL_CLPS711X_MINOR,
- .nr = UART_NR,
-
- .cons = CLPS711X_CONSOLE,
-};
-
static int __devinit uart_clps711x_probe(struct platform_device *pdev)
{
+ struct clps711x_port *s;
int ret, i;
- printk(KERN_INFO "Serial: CLPS711x driver\n");
+ s = devm_kzalloc(&pdev->dev, sizeof(struct clps711x_port), GFP_KERNEL);
+ if (!s) {
+ dev_err(&pdev->dev, "Error allocating port structure\n");
+ return -ENOMEM;
+ }
+ platform_set_drvdata(pdev, s);
- ret = uart_register_driver(&clps711x_reg);
- if (ret)
- return ret;
+ s->uart.owner = THIS_MODULE;
+ s->uart.dev_name = "ttyCL";
+ s->uart.major = UART_CLPS711X_MAJOR;
+ s->uart.minor = UART_CLPS711X_MINOR;
+ s->uart.nr = UART_CLPS711X_NR;
+#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE
+ s->uart.cons = &s->console;
+ s->uart.cons->device = uart_console_device;
+ s->uart.cons->write = uart_clps711x_console_write;
+ s->uart.cons->setup = uart_clps711x_console_setup;
+ s->uart.cons->flags = CON_PRINTBUFFER;
+ s->uart.cons->index = -1;
+ s->uart.cons->data = s;
+ strcpy(s->uart.cons->name, "ttyCL");
+#endif
+ ret = uart_register_driver(&s->uart);
+ if (ret) {
+ dev_err(&pdev->dev, "Registering UART driver failed\n");
+ goto err_out;
+ }
- for (i = 0; i < UART_NR; i++)
- uart_add_one_port(&clps711x_reg, &clps711x_ports[i]);
+ for (i = 0; i < UART_CLPS711X_NR; i++) {
+ s->port[i].line = i;
+ s->port[i].dev = &pdev->dev;
+ s->port[i].irq = TX_IRQ(&s->port[i]);
+ s->port[i].iobase = SYSCON(&s->port[i]);
+ s->port[i].type = PORT_CLPS711X;
+ s->port[i].fifosize = 16;
+ s->port[i].flags = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+ s->port[i].uartclk = 3686400;
+ s->port[i].ops = &uart_clps711x_ops;
+ WARN_ON(uart_add_one_port(&s->uart, &s->port[i]));
+ }
return 0;
+
+err_out:
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
}
static int __devexit uart_clps711x_remove(struct platform_device *pdev)
{
+ struct clps711x_port *s = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < UART_NR; i++)
- uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
+ for (i = 0; i < UART_CLPS711X_NR; i++)
+ uart_remove_one_port(&s->uart, &s->port[i]);
- uart_unregister_driver(&clps711x_reg);
+ uart_unregister_driver(&s->uart);
+ platform_set_drvdata(pdev, NULL);
return 0;
}
--
1.7.8.6
^ permalink raw reply related
* [PATCH 01/12] serial: clps711x: Add platform_driver interface to clps711x driver
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: linux-serial
Cc: Alan Cox, Greg Kroah-Hartman, Arnd Bergmann, Alexander Shiyan
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
drivers/tty/serial/clps711x.c | 39 +++++++++++++++++++++++++++++++++------
1 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c
index d0f719f..07fef1c 100644
--- a/drivers/tty/serial/clps711x.c
+++ b/drivers/tty/serial/clps711x.c
@@ -37,10 +37,13 @@
#include <linux/serial_core.h>
#include <linux/serial.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <asm/irq.h>
+#define UART_CLPS711X_NAME "uart-clps711x"
+
#define UART_NR 2
#define SERIAL_CLPS711X_MAJOR 204
@@ -543,7 +546,7 @@ static struct uart_driver clps711x_reg = {
.cons = CLPS711X_CONSOLE,
};
-static int __init clps711xuart_init(void)
+static int __devinit uart_clps711x_probe(struct platform_device *pdev)
{
int ret, i;
@@ -559,7 +562,7 @@ static int __init clps711xuart_init(void)
return 0;
}
-static void __exit clps711xuart_exit(void)
+static int __devexit uart_clps711x_remove(struct platform_device *pdev)
{
int i;
@@ -567,12 +570,36 @@ static void __exit clps711xuart_exit(void)
uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]);
uart_unregister_driver(&clps711x_reg);
+
+ return 0;
}
-module_init(clps711xuart_init);
-module_exit(clps711xuart_exit);
+static struct platform_driver clps711x_uart_driver = {
+ .driver = {
+ .name = UART_CLPS711X_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = uart_clps711x_probe,
+ .remove = __devexit_p(uart_clps711x_remove),
+};
+module_platform_driver(clps711x_uart_driver);
+
+static struct platform_device clps711x_uart_device = {
+ .name = UART_CLPS711X_NAME,
+};
+
+static int __init uart_clps711x_init(void)
+{
+ return platform_device_register(&clps711x_uart_device);
+}
+module_init(uart_clps711x_init);
+
+static void __exit uart_clps711x_exit(void)
+{
+ platform_device_unregister(&clps711x_uart_device);
+}
+module_exit(uart_clps711x_exit);
MODULE_AUTHOR("Deep Blue Solutions Ltd");
-MODULE_DESCRIPTION("CLPS-711x generic serial driver");
+MODULE_DESCRIPTION("CLPS711X serial driver");
MODULE_LICENSE("GPL");
-MODULE_ALIAS_CHARDEV(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR);
--
1.7.8.6
^ permalink raw reply related
* Re: [PATCH] serial: clps711x: reworked driver version
From: Alexander Shiyan @ 2012-10-14 7:05 UTC (permalink / raw)
To: Greg Kroah-Hartman; +Cc: linux-serial, Alan Cox
In-Reply-To: <20121011192014.GB1801@kroah.com>
On Fri, 12 Oct 2012 04:20:14 +0900
Greg Kroah-Hartman <gregkh@linuxfoundation.org> wrote:
...
> > > > This patch presents reworked version of CLPS711X serial driver.
> > > > The changes from the old version:
> > > > - Driver converted to platform_device.
> > > > - Using CPU clock subsystem for getting base UART speed, since CPU can run
> > > > on different speeds.
> > > > - Remove console_initcall and make console dynamically. Earler messages in
> > > > this case can be retrieved by using "earlyprintk" kernel option.
> > > > - Using resource-managed functions (devm_xx).
> > > > - Make all variables dynamically (reduce BSS).
> > > > - Cleanup code & comments.
> > >
> > > That's a lot of different things, all at once, making it very hard to
> > > review.
> > > Can you please break this up into the individual patches of what you are
> > > doing above, one patch per thing, as is needed for Linux kernel patches?
> > > That way it is much easier to accept and review.
> >
> > It's too hard to do, since each modification depends on the other...
>
> That's why you do one patch after the other, a series of patches, all
> depending on the previous ones.
>
> > Maybe make a patch through renaming, for example clps711x_uart? Or you
> > still insist to split it into separate patches?
>
> Linux kernel development is all about individual patches, each one only
> doing one thing. We've been doing this for 20+ years now, it's not
> anything "new" :)
Yes, this is understandable. This patch is the result of several years of work
with this driver. I tried to split into separate functional parts and send the
new version in a new thread. Please comment.
--
Alexander Shiyan <shc_work@mail.ru>
^ permalink raw reply
* order
From: Royaldoc International Globe @ 2012-10-11 16:23 UTC (permalink / raw)
Royaldoc International Globe,
103, Park son road,
Carlifonia,USA.
63-1-3522 2501
royaldoc@inbox.org.tw
We are interested in purchasing your products and I would like to
make an inquiry. can you inform me of your minimum order quantity? and
also your maximum order quantity, if there is any available sample do
let me know.
Sincerely,
Purchase Manager
Alan Smith
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox