mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs
@ 2014-07-29 16:27 Ricardo Ribalda Delgado
  2014-07-29 16:27 ` [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART Ricardo Ribalda Delgado
  2014-07-31 14:07 ` [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs One Thousand Gnomes
  0 siblings, 2 replies; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-07-29 16:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel
  Cc: Ricardo Ribalda Delgado

This patch allow the users of the 8250 infrastructure to define a
handler for RS485 configration.

If no handler is defined the 8250 driver will work as usual.

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/tty/serial/8250/8250_core.c | 39 +++++++++++++++++++++++++++++++++++++
 include/linux/serial_8250.h         |  3 +++
 2 files changed, 42 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 1d42dba..b28ed1b 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2843,6 +2843,42 @@ serial8250_verify_port(struct uart_port *port, struct serial_struct *ser)
 	return 0;
 }
 
+static int serial8250_ioctl(struct uart_port *port, unsigned int cmd,
+			   unsigned long arg)
+{
+	struct uart_8250_port *up =
+		container_of(port, struct uart_8250_port, port);
+	int ret;
+	struct serial_rs485 rs485_config;
+
+	if (!up->rs485_config)
+		return -ENOIOCTLCMD;
+
+	switch (cmd) {
+	case TIOCSRS485:
+		if (copy_from_user(&rs485_config, (void __user *)arg,
+				   sizeof(rs485_config)))
+			return -EFAULT;
+
+		ret = up->rs485_config(up, &rs485_config);
+		if (ret)
+			return ret;
+
+		memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
+
+		return 0;
+	case TIOCGRS485:
+		if (copy_to_user((void __user *)arg, &up->rs485,
+				 sizeof(up->rs485)))
+			return -EFAULT;
+		return 0;
+	default:
+		break;
+	}
+
+	return -ENOIOCTLCMD;
+}
+
 static const char *
 serial8250_type(struct uart_port *port)
 {
@@ -2872,6 +2908,7 @@ static struct uart_ops serial8250_pops = {
 	.request_port	= serial8250_request_port,
 	.config_port	= serial8250_config_port,
 	.verify_port	= serial8250_verify_port,
+	.ioctl		= serial8250_ioctl,
 #ifdef CONFIG_CONSOLE_POLL
 	.poll_get_char = serial8250_get_poll_char,
 	.poll_put_char = serial8250_put_poll_char,
@@ -3388,6 +3425,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 		uart->port.fifosize	= up->port.fifosize;
 		uart->tx_loadsz		= up->tx_loadsz;
 		uart->capabilities	= up->capabilities;
+		uart->rs485_config	= up->rs485_config;
+		uart->rs485		= up->rs485;
 
 		/* Take tx_loadsz from fifosize if it wasn't set separately */
 		if (uart->port.fifosize && !uart->tx_loadsz)
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index f93649e..c022370 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -70,6 +70,7 @@ struct uart_8250_dma;
 
 struct uart_8250_port {
 	struct uart_port	port;
+	struct serial_rs485     rs485;
 	struct timer_list	timer;		/* "no irq" timer */
 	struct list_head	list;		/* ports on this IRQ */
 	unsigned short		capabilities;	/* port capabilities */
@@ -100,6 +101,8 @@ struct uart_8250_port {
 	/* 8250 specific callbacks */
 	int			(*dl_read)(struct uart_8250_port *);
 	void			(*dl_write)(struct uart_8250_port *, int);
+	int			(*rs485_config)(struct uart_8250_port *,
+						struct serial_rs485 *rs485);
 };
 
 static inline struct uart_8250_port *up_to_u8250p(struct uart_port *up)
-- 
2.0.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-07-29 16:27 [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs Ricardo Ribalda Delgado
@ 2014-07-29 16:27 ` Ricardo Ribalda Delgado
  2014-07-31 14:19   ` One Thousand Gnomes
  2014-07-31 14:07 ` [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs One Thousand Gnomes
  1 sibling, 1 reply; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-07-29 16:27 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel
  Cc: Ricardo Ribalda Delgado

This patch lets you set the RS485 cappabilites of the device through
TIOCSRS485 and TIOCGRS485 as defined on Documentation/serial/serial-rs485.txt

In order to probe the device, the PNP id and the device id is used.

There is only one device per system, therefore a static mutex is used to
avoid race conditions due to the indirect addressing.

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
 drivers/tty/serial/8250/8250_fintek.c | 231 ++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250/Kconfig       |   9 ++
 drivers/tty/serial/8250/Makefile      |   1 +
 3 files changed, 241 insertions(+)
 create mode 100644 drivers/tty/serial/8250/8250_fintek.c

diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
new file mode 100644
index 0000000..97e7349
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -0,0 +1,231 @@
+/*
+ *  Probe for F81216A LPC to 4 UART
+ *
+ *  Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
+ *
+ *  Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+#include  "8250.h"
+
+#define ADDR_PORT 0x4E
+#define DATA_PORT 0x4F
+#define ENTRY_KEY 0x77
+#define CHIP_ID1  0x20
+#define CHIP_ID1_VAL 0x02
+#define CHIP_ID2  0x21
+#define CHIP_ID2_VAL 0x16
+#define VENDOR_ID1 0x23
+#define VENDOR_ID1_VAL 0x19
+#define VENDOR_ID2 0x24
+#define VENDOR_ID2_VAL 0x34
+#define LDN 0x7
+
+#define RS485  0xF0
+#define RTS_INVERT BIT(5)
+#define RS485_URA BIT(4)
+#define RXW4C_IRA BIT(3)
+#define TXW4C_IRA BIT(3)
+
+static DEFINE_MUTEX(fintek_mutex);
+
+static int fintek_8250_get_index(resource_size_t base_addr)
+{
+	resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(base); i++)
+		if (base_addr == base[i])
+			return i;
+
+	return -ENODEV;
+}
+
+static int fintek_8250_check_id(void)
+{
+
+	outb(CHIP_ID1, ADDR_PORT);
+	if (inb(DATA_PORT) != CHIP_ID1_VAL)
+		return -ENODEV;
+
+	outb(CHIP_ID2, ADDR_PORT);
+	if (inb(DATA_PORT) != CHIP_ID2_VAL)
+		return -ENODEV;
+
+	outb(VENDOR_ID1, ADDR_PORT);
+	if (inb(DATA_PORT) != VENDOR_ID1_VAL)
+		return -ENODEV;
+
+	outb(VENDOR_ID2, ADDR_PORT);
+	if (inb(DATA_PORT) != VENDOR_ID2_VAL)
+		return -ENODEV;
+
+	return 0;
+}
+
+int fintek_8250_rs4850_config(struct uart_8250_port *uart,
+			      struct serial_rs485 *rs485)
+{
+	uint8_t config = 0;
+	int index = fintek_8250_get_index(uart->port.iobase);
+
+	if (index < 0)
+		return -EINVAL;
+
+	if (!rs485->flags & SER_RS485_ENABLED)
+		memset(rs485, 0, sizeof(*rs485));
+	else
+		memset(rs485->padding, 0, sizeof(rs485->padding));
+
+	rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+			SER_RS485_RTS_AFTER_SEND;
+
+	if (rs485->delay_rts_before_send) {
+		rs485->delay_rts_before_send = 1;
+		config |= TXW4C_IRA;
+	}
+
+	if (rs485->delay_rts_after_send) {
+		rs485->delay_rts_after_send = 1;
+		config |= RXW4C_IRA;
+	}
+
+	if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
+			(!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
+		rs485->flags &= SER_RS485_ENABLED;
+	else
+		config |= RS485_URA;
+
+	if (rs485->flags & SER_RS485_RTS_ON_SEND)
+		config |= RTS_INVERT;
+
+	mutex_lock(&fintek_mutex);
+	outb(LDN, ADDR_PORT);
+	outb(index, DATA_PORT);
+	outb(RS485, ADDR_PORT);
+	outb(config, DATA_PORT);
+	mutex_unlock(&fintek_mutex);
+
+	return 0;
+}
+
+static int
+fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+	int line;
+	struct uart_8250_port uart;
+	int ret;
+
+	if (!pnp_port_valid(dev, 0))
+		return -ENODEV;
+
+	if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0)
+		return -ENODEV;
+
+	/* Enable configuration registers*/
+	mutex_lock(&fintek_mutex);
+	outb(ENTRY_KEY, ADDR_PORT);
+	outb(ENTRY_KEY, ADDR_PORT);
+
+	/*Check ID*/
+	ret = fintek_8250_check_id();
+	mutex_unlock(&fintek_mutex);
+	if (ret)
+		return ret;
+
+	memset(&uart, 0, sizeof(uart));
+	if (!pnp_irq_valid(dev, 0))
+		return -ENODEV;
+	uart.port.irq = pnp_irq(dev, 0);
+	uart.port.iobase = pnp_port_start(dev, 0);
+	uart.port.iotype = UPIO_PORT;
+	uart.rs485_config = fintek_8250_rs4850_config;
+
+	uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+	if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
+		uart.port.flags |= UPF_SHARE_IRQ;
+	uart.port.uartclk = 1843200;
+	uart.port.dev = &dev->dev;
+
+	line = serial8250_register_8250_port(&uart);
+	if (line < 0)
+		return -ENODEV;
+
+	pnp_set_drvdata(dev, (void *)((long)line + 1));
+	return 0;
+}
+
+static void fintek_8250_remove(struct pnp_dev *dev)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (line)
+		serial8250_unregister_port(line - 1);
+}
+
+#ifdef CONFIG_PM
+static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (!line)
+		return -ENODEV;
+	serial8250_suspend_port(line - 1);
+	return 0;
+}
+
+static int fintek_8250_resume(struct pnp_dev *dev)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (!line)
+		return -ENODEV;
+	serial8250_resume_port(line - 1);
+	return 0;
+}
+#else
+#define fintek_8250_suspend NULL
+#define fintek_8250_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct pnp_device_id fintek_dev_table[] = {
+	/* Qtechnology Panel PC / IO1000 */
+	{ "PNP0501"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
+
+static struct pnp_driver fintek_8250_driver = {
+	.name		= "8250_fintek",
+	.probe		= fintek_8250_probe,
+	.remove		= fintek_8250_remove,
+	.suspend	= fintek_8250_suspend,
+	.resume		= fintek_8250_resume,
+	.id_table	= fintek_dev_table,
+};
+
+int fintek_8250_init(void)
+{
+	return pnp_register_driver(&fintek_8250_driver);
+}
+module_init(fintek_8250_init);
+
+void fintek_8250_exit(void)
+{
+	pnp_unregister_driver(&fintek_8250_driver);
+}
+module_exit(fintek_8250_exit);
+
+MODULE_DESCRIPTION("Fintek F812164 module");
+MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 349ee59..8b5c40a 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -298,3 +298,12 @@ config SERIAL_8250_RT288X
 	  If you have a Ralink RT288x/RT305x SoC based board and want to use the
 	  serial port, say Y to this option. The driver can handle up to 2 serial
 	  ports. If unsure, say N.
+
+config SERIAL_8250_FINTEK
+	tristate "Support for Fintek F81216A LPC to 4 UART"
+	depends on SERIAL_8250 && PNP
+	help
+	  Selecting this option will add support for the Fintek F81216A
+	  LPC to 4 UART. This device has some RS485 functionality not available
+	  through the PNP driver. If unsure, say N.
+
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..e08407d 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
+obj-$(CONFIG_SERIAL_8250_FINTEK)	+= 8250_fintek.o
-- 
2.0.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs
  2014-07-29 16:27 [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs Ricardo Ribalda Delgado
  2014-07-29 16:27 ` [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART Ricardo Ribalda Delgado
@ 2014-07-31 14:07 ` One Thousand Gnomes
  2014-07-31 16:13   ` Ricardo Ribalda Delgado
  1 sibling, 1 reply; 11+ messages in thread
From: One Thousand Gnomes @ 2014-07-31 14:07 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel

> This patch allow the users of the 8250 infrastructure to define a
> handler for RS485 configration.

This feels to me like the right code in the wrong place.
 
> If no handler is defined the 8250 driver will work as usual.

Is there any reasons we can't have uart_ops.rs485_config and the RS485
ioctl logic in the serial_core, or even push rs485_get/put into the tty
ioctl handler and tty ops so it's not duplicated everywhere ?
 
> +	switch (cmd) {
> +	case TIOCSRS485:
> +		if (copy_from_user(&rs485_config, (void __user *)arg,
> +				   sizeof(rs485_config)))
> +			return -EFAULT;
> +
> +		ret = up->rs485_config(up, &rs485_config);
> +		if (ret)
> +			return ret;
> +
> +		memcpy(&up->rs485, &rs485_config, sizeof(rs485_config));
> +
> +		return 0;
> +	case TIOCGRS485:
> +		if (copy_to_user((void __user *)arg, &up->rs485,
> +				 sizeof(up->rs485)))
> +			return -EFAULT;
> +		return 0;

Possibly your mutex needs to cover parallel get an set, but then again
anyone doing that may well deserve what they get 8)

Alan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-07-29 16:27 ` [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART Ricardo Ribalda Delgado
@ 2014-07-31 14:19   ` One Thousand Gnomes
  2014-07-31 16:07     ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 11+ messages in thread
From: One Thousand Gnomes @ 2014-07-31 14:19 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel

> +static int fintek_8250_get_index(resource_size_t base_addr)
> +{
> +	resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(base); i++)
> +		if (base_addr == base[i])
> +			return i;
> +
> +	return -ENODEV;

Less than ideal in some ways because the base may well be remapped by
other hardware or on non x86 devices. No obvious ideas how to fix it
though and PnP kind of implies x86.

> +	mutex_lock(&fintek_mutex);
> +	outb(LDN, ADDR_PORT);
> +	outb(index, DATA_PORT);
> +	outb(RS485, ADDR_PORT);
> +	outb(config, DATA_PORT);
> +	mutex_unlock(&fintek_mutex);

You really need to request that block of addresses because you may not be
the only superIO chip or driver playing with the various mux hack
registers that are used.

On the bright side you can then make the resource layer do your locking
work for you. We have an IORESOURCE_MUXED flag for these little horrors
so you can request the resource with IORESOURCE_MUXED. If the resource is
busy then you will get a failure back, if it is idle you will get the
resource, if it is busy but held by another driver using IORESOURCE_MUXED
then the request will block until they finish with it.

So you do

	request_muxed_region
	if failed then EBUSY
	prod stuff
	release_region


Alan


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-07-31 14:19   ` One Thousand Gnomes
@ 2014-07-31 16:07     ` Ricardo Ribalda Delgado
  2014-07-31 19:22       ` [PATCH 2/2 v2] " Ricardo Ribalda Delgado
  0 siblings, 1 reply; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-07-31 16:07 UTC (permalink / raw)
  To: One Thousand Gnomes
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial, LKML

Hello Alan

> Less than ideal in some ways because the base may well be remapped by
> other hardware or on non x86 devices. No obvious ideas how to fix it
> though and PnP kind of implies x86.

If I extend the driver to consider other hw than x86 and PnP I will
definitely  look into this.

>
> On the bright side you can then make the resource layer do your locking
> work for you. We have an IORESOURCE_MUXED flag for these little horrors
> so you can request the resource with IORESOURCE_MUXED. If the resource is
> busy then you will get a failure back, if it is idle you will get the
> resource, if it is busy but held by another driver using IORESOURCE_MUXED
> then the request will block until they finish with it.

I was not aware of request_mutex, thanks for your help!. I am
preparing v2 with no mutex and requtest_mutex_region.

Thanks!

-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs
  2014-07-31 14:07 ` [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs One Thousand Gnomes
@ 2014-07-31 16:13   ` Ricardo Ribalda Delgado
  0 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-07-31 16:13 UTC (permalink / raw)
  To: One Thousand Gnomes
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial, LKML

Hello Alan

> Is there any reasons we can't have uart_ops.rs485_config and the RS485
> ioctl logic in the serial_core, or even push rs485_get/put into the tty
> ioctl handler and tty ops so it's not duplicated everywhere ?

What about a step by step approach. First we add this code to the
8250_core, and then I remove all the specific driver
TIOCSRS485 handling and manage it through serial_core.c

Right now these are the drivers using it:

drivers/tty/serial/8250/8250_core.c:    case TIOCSRS485:
drivers/tty/serial/atmel_serial.c:      case TIOCSRS485:
drivers/tty/serial/crisv10.c:   case TIOCSRS485:
drivers/tty/serial/max310x.c:   case TIOCSRS485:
drivers/tty/serial/mcf.c:       case TIOCSRS485: {
drivers/tty/serial/omap-serial.c:       case TIOCSRS485:
rivers/tty/serial/sc16is7xx.c: case TIOCSRS485:

Regards!



-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/2 v2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-07-31 16:07     ` Ricardo Ribalda Delgado
@ 2014-07-31 19:22       ` Ricardo Ribalda Delgado
  2014-08-01 12:23         ` One Thousand Gnomes
  0 siblings, 1 reply; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-07-31 19:22 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel
  Cc: Ricardo Ribalda Delgado

This patch lets you set the RS485 cappabilites of the device through
TIOCSRS485 and TIOCGRS485 as defined on Documentation/serial/serial-rs485.txt

In order to probe the device, the PNP id and the device id is used.

Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
---
v2:

-Remove mutex
-Add exit key after every transaction

Changes Suggested by Alan "One Thousand Gnomes":
	- Use request_muxed_region

 drivers/tty/serial/8250/8250_fintek.c | 249 ++++++++++++++++++++++++++++++++++
 drivers/tty/serial/8250/Kconfig       |   9 ++
 drivers/tty/serial/8250/Makefile      |   1 +
 3 files changed, 259 insertions(+)
 create mode 100644 drivers/tty/serial/8250/8250_fintek.c

diff --git a/drivers/tty/serial/8250/8250_fintek.c b/drivers/tty/serial/8250/8250_fintek.c
new file mode 100644
index 0000000..1bb28cb
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_fintek.c
@@ -0,0 +1,249 @@
+/*
+ *  Probe for F81216A LPC to 4 UART
+ *
+ *  Based on drivers/tty/serial/8250_pnp.c, by Russell King, et al
+ *
+ *  Copyright (C) 2014 Ricardo Ribalda, Qtechnology A/S
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/pnp.h>
+#include <linux/kernel.h>
+#include <linux/serial_core.h>
+#include  "8250.h"
+
+#define ADDR_PORT 0x4E
+#define DATA_PORT 0x4F
+#define ENTRY_KEY 0x77
+#define EXIT_KEY 0xAA
+#define CHIP_ID1  0x20
+#define CHIP_ID1_VAL 0x02
+#define CHIP_ID2  0x21
+#define CHIP_ID2_VAL 0x16
+#define VENDOR_ID1 0x23
+#define VENDOR_ID1_VAL 0x19
+#define VENDOR_ID2 0x24
+#define VENDOR_ID2_VAL 0x34
+#define LDN 0x7
+
+#define RS485  0xF0
+#define RTS_INVERT BIT(5)
+#define RS485_URA BIT(4)
+#define RXW4C_IRA BIT(3)
+#define TXW4C_IRA BIT(2)
+
+#define DRIVER_NAME "8250_fintek"
+
+static int fintek_8250_enter_key(void){
+
+	if (!request_muxed_region(ADDR_PORT, 2, DRIVER_NAME))
+		return -EBUSY;
+
+	outb(ENTRY_KEY, ADDR_PORT);
+	outb(ENTRY_KEY, ADDR_PORT);
+	return 0;
+}
+
+static void fintek_8250_exit_key(void){
+
+	outb(EXIT_KEY, ADDR_PORT);
+	release_region(ADDR_PORT, 2);
+}
+
+static int fintek_8250_get_index(resource_size_t base_addr)
+{
+	resource_size_t base[] = {0x3f8, 0x2f8, 0x3e8, 0x2e8};
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(base); i++)
+		if (base_addr == base[i])
+			return i;
+
+	return -ENODEV;
+}
+
+static int fintek_8250_check_id(void)
+{
+
+	outb(CHIP_ID1, ADDR_PORT);
+	if (inb(DATA_PORT) != CHIP_ID1_VAL)
+		return -ENODEV;
+
+	outb(CHIP_ID2, ADDR_PORT);
+	if (inb(DATA_PORT) != CHIP_ID2_VAL)
+		return -ENODEV;
+
+	outb(VENDOR_ID1, ADDR_PORT);
+	if (inb(DATA_PORT) != VENDOR_ID1_VAL)
+		return -ENODEV;
+
+	outb(VENDOR_ID2, ADDR_PORT);
+	if (inb(DATA_PORT) != VENDOR_ID2_VAL)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int fintek_8250_rs4850_config(struct uart_8250_port *uart,
+			      struct serial_rs485 *rs485)
+{
+	uint8_t config = 0;
+	int index = fintek_8250_get_index(uart->port.iobase);
+
+	if (index < 0)
+		return -EINVAL;
+
+	if (rs485->flags & SER_RS485_ENABLED)
+		memset(rs485->padding, 0, sizeof(rs485->padding));
+	else
+		memset(rs485, 0, sizeof(*rs485));
+
+	rs485->flags &= SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND |
+			SER_RS485_RTS_AFTER_SEND;
+
+	if (rs485->delay_rts_before_send) {
+		rs485->delay_rts_before_send = 1;
+		config |= TXW4C_IRA;
+	}
+
+	if (rs485->delay_rts_after_send) {
+		rs485->delay_rts_after_send = 1;
+		config |= RXW4C_IRA;
+	}
+
+	if ((!!(rs485->flags & SER_RS485_RTS_ON_SEND)) ==
+			(!!(rs485->flags & SER_RS485_RTS_AFTER_SEND)))
+		rs485->flags &= SER_RS485_ENABLED;
+	else
+		config |= RS485_URA;
+
+	if (rs485->flags & SER_RS485_RTS_ON_SEND)
+		config |= RTS_INVERT;
+
+	if (fintek_8250_enter_key())
+		return -EBUSY;
+
+	outb(LDN, ADDR_PORT);
+	outb(index, DATA_PORT);
+	outb(RS485, ADDR_PORT);
+	outb(config, DATA_PORT);
+	fintek_8250_exit_key();
+
+	return 0;
+}
+
+static int
+fintek_8250_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
+{
+	int line;
+	struct uart_8250_port uart;
+	int ret;
+
+	if (!pnp_port_valid(dev, 0))
+		return -ENODEV;
+
+	if (fintek_8250_get_index(pnp_port_start(dev, 0)) < 0)
+		return -ENODEV;
+
+	/* Enable configuration registers*/
+	if (fintek_8250_enter_key())
+		return -EBUSY;
+
+	/*Check ID*/
+	ret = fintek_8250_check_id();
+	fintek_8250_exit_key();
+	if (ret)
+		return ret;
+
+	memset(&uart, 0, sizeof(uart));
+	if (!pnp_irq_valid(dev, 0))
+		return -ENODEV;
+	uart.port.irq = pnp_irq(dev, 0);
+	uart.port.iobase = pnp_port_start(dev, 0);
+	uart.port.iotype = UPIO_PORT;
+	uart.rs485_config = fintek_8250_rs4850_config;
+
+	uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+	if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
+		uart.port.flags |= UPF_SHARE_IRQ;
+	uart.port.uartclk = 1843200;
+	uart.port.dev = &dev->dev;
+
+	line = serial8250_register_8250_port(&uart);
+	if (line < 0)
+		return -ENODEV;
+
+	pnp_set_drvdata(dev, (void *)((long)line + 1));
+	return 0;
+}
+
+static void fintek_8250_remove(struct pnp_dev *dev)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (line)
+		serial8250_unregister_port(line - 1);
+}
+
+#ifdef CONFIG_PM
+static int fintek_8250_suspend(struct pnp_dev *dev, pm_message_t state)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (!line)
+		return -ENODEV;
+	serial8250_suspend_port(line - 1);
+	return 0;
+}
+
+static int fintek_8250_resume(struct pnp_dev *dev)
+{
+	long line = (long)pnp_get_drvdata(dev);
+
+	if (!line)
+		return -ENODEV;
+	serial8250_resume_port(line - 1);
+	return 0;
+}
+#else
+#define fintek_8250_suspend NULL
+#define fintek_8250_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct pnp_device_id fintek_dev_table[] = {
+	/* Qtechnology Panel PC / IO1000 */
+	{ "PNP0501"},
+	{}
+};
+
+MODULE_DEVICE_TABLE(pnp, fintek_dev_table);
+
+static struct pnp_driver fintek_8250_driver = {
+	.name		= DRIVER_NAME,
+	.probe		= fintek_8250_probe,
+	.remove		= fintek_8250_remove,
+	.suspend	= fintek_8250_suspend,
+	.resume		= fintek_8250_resume,
+	.id_table	= fintek_dev_table,
+};
+
+static int fintek_8250_init(void)
+{
+	return pnp_register_driver(&fintek_8250_driver);
+}
+module_init(fintek_8250_init);
+
+static void fintek_8250_exit(void)
+{
+	pnp_unregister_driver(&fintek_8250_driver);
+}
+module_exit(fintek_8250_exit);
+
+MODULE_DESCRIPTION("Fintek F812164 module");
+MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 349ee59..8b5c40a 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -298,3 +298,12 @@ config SERIAL_8250_RT288X
 	  If you have a Ralink RT288x/RT305x SoC based board and want to use the
 	  serial port, say Y to this option. The driver can handle up to 2 serial
 	  ports. If unsure, say N.
+
+config SERIAL_8250_FINTEK
+	tristate "Support for Fintek F81216A LPC to 4 UART"
+	depends on SERIAL_8250 && PNP
+	help
+	  Selecting this option will add support for the Fintek F81216A
+	  LPC to 4 UART. This device has some RS485 functionality not available
+	  through the PNP driver. If unsure, say N.
+
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 36d68d0..e08407d 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_FSL)		+= 8250_fsl.o
 obj-$(CONFIG_SERIAL_8250_DW)		+= 8250_dw.o
 obj-$(CONFIG_SERIAL_8250_EM)		+= 8250_em.o
+obj-$(CONFIG_SERIAL_8250_FINTEK)	+= 8250_fintek.o
-- 
2.0.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-07-31 19:22       ` [PATCH 2/2 v2] " Ricardo Ribalda Delgado
@ 2014-08-01 12:23         ` One Thousand Gnomes
  2014-08-01 12:28           ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 11+ messages in thread
From: One Thousand Gnomes @ 2014-08-01 12:23 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial,
	linux-kernel

On Thu, 31 Jul 2014 21:22:26 +0200
Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> wrote:

> This patch lets you set the RS485 cappabilites of the device through
> TIOCSRS485 and TIOCGRS485 as defined on Documentation/serial/serial-rs485.txt
> 
> In order to probe the device, the PNP id and the device id is used.
> 
> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>

This half of things looks good to me.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-08-01 12:23         ` One Thousand Gnomes
@ 2014-08-01 12:28           ` Ricardo Ribalda Delgado
  2014-08-05  9:34             ` One Thousand Gnomes
  0 siblings, 1 reply; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-08-01 12:28 UTC (permalink / raw)
  To: One Thousand Gnomes
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial, LKML

Hello

>> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
>
> This half of things looks good to me.


Thanks!, What about the other half? Would you accept a two step approach?

1st: add support for 8250_core
2nd: handle rs485 ioctl on serial_core and modify all the other
drivers to use that? (to avoid code duplication)

Thanks


-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-08-01 12:28           ` Ricardo Ribalda Delgado
@ 2014-08-05  9:34             ` One Thousand Gnomes
  2014-08-05  9:47               ` Ricardo Ribalda Delgado
  0 siblings, 1 reply; 11+ messages in thread
From: One Thousand Gnomes @ 2014-08-05  9:34 UTC (permalink / raw)
  To: Ricardo Ribalda Delgado
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial, LKML

On Fri, 1 Aug 2014 14:28:11 +0200
Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com> wrote:

> Hello
> 
> >> Signed-off-by: Ricardo Ribalda Delgado <ricardo.ribalda@gmail.com>
> >
> > This half of things looks good to me.
> 
> 
> Thanks!, What about the other half? Would you accept a two step approach?
> 
> 1st: add support for 8250_core
> 2nd: handle rs485 ioctl on serial_core and modify all the other
> drivers to use that? (to avoid code duplication)

We really want to handle it at the tty layer I think not at serial_core.
I have a patch for that and I'm playing with it but it's taking longer
than I hoped.

In the mean time I think your patch #1 is ok except for the trivial
item that I'd prefer the struct serial_rs485 was further down the struct
uart_8250_port. It's packed so that the bits you need most are in the
first cache line or two.

Alan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/2 v2] serial: Add support for Fintek F81216A LPC to 4 UART
  2014-08-05  9:34             ` One Thousand Gnomes
@ 2014-08-05  9:47               ` Ricardo Ribalda Delgado
  0 siblings, 0 replies; 11+ messages in thread
From: Ricardo Ribalda Delgado @ 2014-08-05  9:47 UTC (permalink / raw)
  To: One Thousand Gnomes
  Cc: Greg Kroah-Hartman, Jiri Slaby, Alan Cox, Heikki Krogerus,
	Murali Karicheri, Jingoo Han, Michael Welling, Peter Hurley,
	Joe Schultz, Ingo Molnar, Doug Anderson, linux-serial, LKML

Hello Alan

> We really want to handle it at the tty layer I think not at serial_core.
> I have a patch for that and I'm playing with it but it's taking longer
> than I hoped.
>
> In the mean time I think your patch #1 is ok except for the trivial
> item that I'd prefer the struct serial_rs485 was further down the struct
> uart_8250_port. It's packed so that the bits you need most are in the
> first cache line or two.

I have just resend 1/2 with rs485 moved further down on the structure.
Shall I also resend 2/2 (no changes)?

Regards!



-- 
Ricardo Ribalda

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-08-05  9:47 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-29 16:27 [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs Ricardo Ribalda Delgado
2014-07-29 16:27 ` [PATCH 2/2] serial: Add support for Fintek F81216A LPC to 4 UART Ricardo Ribalda Delgado
2014-07-31 14:19   ` One Thousand Gnomes
2014-07-31 16:07     ` Ricardo Ribalda Delgado
2014-07-31 19:22       ` [PATCH 2/2 v2] " Ricardo Ribalda Delgado
2014-08-01 12:23         ` One Thousand Gnomes
2014-08-01 12:28           ` Ricardo Ribalda Delgado
2014-08-05  9:34             ` One Thousand Gnomes
2014-08-05  9:47               ` Ricardo Ribalda Delgado
2014-07-31 14:07 ` [PATCH 1/2] serial/8250: Add support for RS485 IOCTLs One Thousand Gnomes
2014-07-31 16:13   ` Ricardo Ribalda Delgado

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®