linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 0/2] add ISO7816 support
@ 2018-08-07 13:00 Ludovic Desroches
  2018-08-07 13:00 ` [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure Ludovic Desroches
  2018-08-07 13:00 ` [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support Ludovic Desroches
  0 siblings, 2 replies; 9+ messages in thread
From: Ludovic Desroches @ 2018-08-07 13:00 UTC (permalink / raw)
  To: linux-serial, linux-arch, linux-arm-kernel
  Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
	alexandre.belloni, linux-kernel, Ludovic Desroches

Hi,

This patchset adds support for the ISO7816 standard. The USART devices in
Microchip SoCs have an ISO7816 mode. It allows to let the USART managing
the CLK and I/O signals of a smart card.

Changes:
- v3
  - add IOCTLs to parisc arch.
  - rework atmel_config_iso7816 according to the comments by Richard
  - keep max iteration hard coded. Will see later if the user need to set
  this value. It may also concern the normal/inverse mode.
  - improve the checking of the value from the user space.
- v2
  - uart_get_iso7816_config: check there is an iso7816_config function
  - use IOCTL macros to generate the IOCTL number
  - check that reserved field is not used
  - remove debug logs
  - check that the iso7816_config is right before doing any action
  - change the error from nack and max iteration status to a debug message
  - remove patch 3 as it concerns both rs485 and iso7816 to think more
  about the need of adding a lock or not


Nicolas Ferre (2):
  tty/serial_core: add ISO7816 infrastructure
  tty/serial: atmel: add ISO7816 support

 arch/alpha/include/uapi/asm/ioctls.h   |   2 +
 arch/mips/include/uapi/asm/ioctls.h    |   2 +
 arch/parisc/include/uapi/asm/ioctls.h  |   2 +
 arch/powerpc/include/uapi/asm/ioctls.h |   2 +
 arch/sh/include/uapi/asm/ioctls.h      |   2 +
 arch/sparc/include/uapi/asm/ioctls.h   |   2 +
 arch/xtensa/include/uapi/asm/ioctls.h  |   2 +
 drivers/tty/serial/atmel_serial.c      | 211 ++++++++++++++++++++++++++++++---
 drivers/tty/serial/atmel_serial.h      |   6 +-
 drivers/tty/serial/serial_core.c       |  60 ++++++++++
 include/linux/serial_core.h            |   3 +
 include/uapi/asm-generic/ioctls.h      |   2 +
 include/uapi/linux/serial.h            |  17 +++
 13 files changed, 297 insertions(+), 16 deletions(-)

-- 
2.12.2


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

* [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure
  2018-08-07 13:00 [PATCH v3 0/2] add ISO7816 support Ludovic Desroches
@ 2018-08-07 13:00 ` Ludovic Desroches
  2018-08-07 13:32   ` Christoph Hellwig
  2018-08-07 13:00 ` [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support Ludovic Desroches
  1 sibling, 1 reply; 9+ messages in thread
From: Ludovic Desroches @ 2018-08-07 13:00 UTC (permalink / raw)
  To: linux-serial, linux-arch, linux-arm-kernel
  Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
	alexandre.belloni, linux-kernel, Ludovic Desroches

From: Nicolas Ferre <nicolas.ferre@microchip.com>

Add the ISO7816 ioctl and associated accessors and data structure.
Drivers can then use this common implementation to handle ISO7816.

Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
[ludovic.desroches@microchip.com: squash and rebase, removal of gpios, checkpatch fixes]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
 arch/alpha/include/uapi/asm/ioctls.h   |  2 ++
 arch/mips/include/uapi/asm/ioctls.h    |  2 ++
 arch/parisc/include/uapi/asm/ioctls.h  |  2 ++
 arch/powerpc/include/uapi/asm/ioctls.h |  2 ++
 arch/sh/include/uapi/asm/ioctls.h      |  2 ++
 arch/sparc/include/uapi/asm/ioctls.h   |  2 ++
 arch/xtensa/include/uapi/asm/ioctls.h  |  2 ++
 drivers/tty/serial/serial_core.c       | 60 ++++++++++++++++++++++++++++++++++
 include/linux/serial_core.h            |  3 ++
 include/uapi/asm-generic/ioctls.h      |  2 ++
 include/uapi/linux/serial.h            | 17 ++++++++++
 11 files changed, 96 insertions(+)

diff --git a/arch/alpha/include/uapi/asm/ioctls.h b/arch/alpha/include/uapi/asm/ioctls.h
index 3729d92d3fa8..1e9121c9b3c7 100644
--- a/arch/alpha/include/uapi/asm/ioctls.h
+++ b/arch/alpha/include/uapi/asm/ioctls.h
@@ -102,6 +102,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff --git a/arch/mips/include/uapi/asm/ioctls.h b/arch/mips/include/uapi/asm/ioctls.h
index 890245a9f0c4..16aa8a766aec 100644
--- a/arch/mips/include/uapi/asm/ioctls.h
+++ b/arch/mips/include/uapi/asm/ioctls.h
@@ -93,6 +93,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 /* I hope the range from 0x5480 on is free ... */
 #define TIOCSCTTY	0x5480		/* become controlling tty */
diff --git a/arch/parisc/include/uapi/asm/ioctls.h b/arch/parisc/include/uapi/asm/ioctls.h
index aafb1c0ca0af..82d1148c6379 100644
--- a/arch/parisc/include/uapi/asm/ioctls.h
+++ b/arch/parisc/include/uapi/asm/ioctls.h
@@ -62,6 +62,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define FIONCLEX	0x5450  /* these numbers need to be adjusted. */
 #define FIOCLEX		0x5451
diff --git a/arch/powerpc/include/uapi/asm/ioctls.h b/arch/powerpc/include/uapi/asm/ioctls.h
index 41b1a5c15734..2c145da3b774 100644
--- a/arch/powerpc/include/uapi/asm/ioctls.h
+++ b/arch/powerpc/include/uapi/asm/ioctls.h
@@ -102,6 +102,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG	0x5453
 #define TIOCSERGWILD	0x5454
diff --git a/arch/sh/include/uapi/asm/ioctls.h b/arch/sh/include/uapi/asm/ioctls.h
index cc62f6f98103..11866d4f60e1 100644
--- a/arch/sh/include/uapi/asm/ioctls.h
+++ b/arch/sh/include/uapi/asm/ioctls.h
@@ -95,6 +95,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG	_IO('T', 83) /* 0x5453 */
 #define TIOCSERGWILD	_IOR('T', 84,  int) /* 0x5454 */
diff --git a/arch/sparc/include/uapi/asm/ioctls.h b/arch/sparc/include/uapi/asm/ioctls.h
index 2df52711e170..7fd2f5873c9e 100644
--- a/arch/sparc/include/uapi/asm/ioctls.h
+++ b/arch/sparc/include/uapi/asm/ioctls.h
@@ -27,6 +27,8 @@
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGRS485	_IOR('T', 0x41, struct serial_rs485)
 #define TIOCSRS485	_IOWR('T', 0x42, struct serial_rs485)
+#define TIOCGISO7816	_IOR('T', 0x43, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x44, struct serial_iso7816)
 
 /* Note that all the ioctls that are not available in Linux have a
  * double underscore on the front to: a) avoid some programs to
diff --git a/arch/xtensa/include/uapi/asm/ioctls.h b/arch/xtensa/include/uapi/asm/ioctls.h
index ec43609cbfc5..6d4a87296c95 100644
--- a/arch/xtensa/include/uapi/asm/ioctls.h
+++ b/arch/xtensa/include/uapi/asm/ioctls.h
@@ -107,6 +107,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define TIOCSERCONFIG	_IO('T', 83)
 #define TIOCSERGWILD	_IOR('T', 84,  int)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 9c14a453f73c..af8d5b12fba9 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1301,6 +1301,58 @@ static int uart_set_rs485_config(struct uart_port *port,
 	return 0;
 }
 
+static int uart_get_iso7816_config(struct uart_port *port,
+				   struct serial_iso7816 __user *iso7816)
+{
+	unsigned long flags;
+	struct serial_iso7816 aux;
+
+	if (!port->iso7816_config)
+		return -ENOIOCTLCMD;
+
+	spin_lock_irqsave(&port->lock, flags);
+	aux = port->iso7816;
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	if (copy_to_user(iso7816, &aux, sizeof(aux)))
+		return -EFAULT;
+
+	return 0;
+}
+
+static int uart_set_iso7816_config(struct uart_port *port,
+				   struct serial_iso7816 __user *iso7816_user)
+{
+	struct serial_iso7816 iso7816;
+	int i, ret;
+	unsigned long flags;
+
+	if (!port->iso7816_config)
+		return -ENOIOCTLCMD;
+
+	if (copy_from_user(&iso7816, iso7816_user, sizeof(*iso7816_user)))
+		return -EFAULT;
+
+	/*
+	 * There are 5 words reserved for future use. Check that userspace
+	 * doesn't put stuff in there to prevent breakages in the future.
+	 */
+	for (i = 0; i < 5; i++)
+		if (iso7816.reserved[i])
+			return -EINVAL;
+
+	spin_lock_irqsave(&port->lock, flags);
+	ret = port->iso7816_config(port, &iso7816);
+	spin_unlock_irqrestore(&port->lock, flags);
+	if (ret)
+		return ret;
+
+	if (copy_to_user(iso7816_user, &port->iso7816, sizeof(port->iso7816)))
+		return -EFAULT;
+
+	return 0;
+}
+
 /*
  * Called via sys_ioctl.  We can use spin_lock_irq() here.
  */
@@ -1385,6 +1437,14 @@ uart_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
 	case TIOCSRS485:
 		ret = uart_set_rs485_config(uport, uarg);
 		break;
+
+	case TIOCSISO7816:
+		ret = uart_set_iso7816_config(state->uart_port, uarg);
+		break;
+
+	case TIOCGISO7816:
+		ret = uart_get_iso7816_config(state->uart_port, uarg);
+		break;
 	default:
 		if (uport->ops->ioctl)
 			ret = uport->ops->ioctl(uport, cmd, arg);
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 06ea4eeb09ab..d6e7747ffd46 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -137,6 +137,8 @@ struct uart_port {
 	void			(*handle_break)(struct uart_port *);
 	int			(*rs485_config)(struct uart_port *,
 						struct serial_rs485 *rs485);
+	int			(*iso7816_config)(struct uart_port *,
+						  struct serial_iso7816 *iso7816);
 	unsigned int		irq;			/* irq number */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned int		uartclk;		/* base uart clock */
@@ -253,6 +255,7 @@ struct uart_port {
 	struct attribute_group	*attr_group;		/* port specific attributes */
 	const struct attribute_group **tty_groups;	/* all attributes (serial core use only) */
 	struct serial_rs485     rs485;
+	struct serial_iso7816   iso7816;
 	void			*private_data;		/* generic platform data pointer */
 };
 
diff --git a/include/uapi/asm-generic/ioctls.h b/include/uapi/asm-generic/ioctls.h
index 040651735662..cdc9f4ca8c27 100644
--- a/include/uapi/asm-generic/ioctls.h
+++ b/include/uapi/asm-generic/ioctls.h
@@ -79,6 +79,8 @@
 #define TIOCGPTLCK	_IOR('T', 0x39, int) /* Get Pty lock state */
 #define TIOCGEXCL	_IOR('T', 0x40, int) /* Get exclusive mode state */
 #define TIOCGPTPEER	_IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816	_IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816	_IOWR('T', 0x43, struct serial_iso7816)
 
 #define FIONCLEX	0x5450
 #define FIOCLEX		0x5451
diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h
index 3fdd0dee8b41..93eb3c496ff1 100644
--- a/include/uapi/linux/serial.h
+++ b/include/uapi/linux/serial.h
@@ -132,4 +132,21 @@ struct serial_rs485 {
 					   are a royal PITA .. */
 };
 
+/*
+ * Serial interface for controlling ISO7816 settings on chips with suitable
+ * support. Set with TIOCSISO7816 and get with TIOCGISO7816 if supported by
+ * your platform.
+ */
+struct serial_iso7816 {
+	__u32	flags;			/* ISO7816 feature flags */
+#define SER_ISO7816_ENABLED		(1 << 0)
+#define SER_ISO7816_T_PARAM		(0x0f << 4)
+#define SER_ISO7816_T(t)		(((t) & 0x0f) << 4)
+	__u32	tg;
+	__u32	sc_fi;
+	__u32	sc_di;
+	__u32	clk;
+	__u32	reserved[5];
+};
+
 #endif /* _UAPI_LINUX_SERIAL_H */
-- 
2.12.2


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

* [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-08-07 13:00 [PATCH v3 0/2] add ISO7816 support Ludovic Desroches
  2018-08-07 13:00 ` [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure Ludovic Desroches
@ 2018-08-07 13:00 ` Ludovic Desroches
  2018-08-09  8:47   ` Richard Genoud
  1 sibling, 1 reply; 9+ messages in thread
From: Ludovic Desroches @ 2018-08-07 13:00 UTC (permalink / raw)
  To: linux-serial, linux-arch, linux-arm-kernel
  Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
	alexandre.belloni, linux-kernel, Ludovic Desroches

From: Nicolas Ferre <nicolas.ferre@microchip.com>

When mode is set in atmel_config_iso7816() we backup last RS232 mode
for coming back to this mode if requested.
Also allow setup of T=0 and T=1 parameter and basic support in set_termios
function as well.

Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
[ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
 drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
 drivers/tty/serial/atmel_serial.h |   6 +-
 2 files changed, 201 insertions(+), 16 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 8e4428725848..4a7ec44b0ace 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -34,6 +34,7 @@
 #include <linux/suspend.h>
 #include <linux/mm.h>
 
+#include <asm/div64.h>
 #include <asm/io.h>
 #include <asm/ioctls.h>
 
@@ -83,6 +84,11 @@ static void atmel_stop_rx(struct uart_port *port);
 
 #define ATMEL_ISR_PASS_LIMIT	256
 
+struct atmel_uart_pdata {
+	unsigned int	fidi_min;
+	unsigned int	fidi_max;
+};
+
 struct atmel_dma_buffer {
 	unsigned char	*buf;
 	dma_addr_t	dma_addr;
@@ -114,6 +120,7 @@ struct atmel_uart_char {
  */
 struct atmel_uart_port {
 	struct uart_port	uart;		/* uart */
+	const struct atmel_uart_pdata *pdata;	/* SoC specific parameters */
 	struct clk		*clk;		/* uart clock */
 	int			may_wakeup;	/* cached value of device_may_wakeup for times we need to disable it */
 	u32			backup_imr;	/* IMR saved during suspend */
@@ -147,6 +154,8 @@ struct atmel_uart_port {
 	struct circ_buf		rx_ring;
 
 	struct mctrl_gpios	*gpios;
+	u32			backup_mode;	/* MR saved during iso7816 operations */
+	u32			backup_brgr;	/* BRGR saved during iso7816 operations */
 	unsigned int		tx_done_mask;
 	u32			fifo_size;
 	u32			rts_high;
@@ -192,10 +201,34 @@ static struct console atmel_console;
 #endif
 
 #if defined(CONFIG_OF)
+static struct atmel_uart_pdata at91rm9200_pdata = {
+	.fidi_min = 1,
+	.fidi_max = 2047,
+};
+
+static struct atmel_uart_pdata at91sam9260_pdata = {
+	.fidi_min = 1,
+	.fidi_max = 2047,
+};
+
+static struct atmel_uart_pdata sama5d3_pdata = {
+	.fidi_min = 3,
+	.fidi_max = 65535,
+};
+
 static const struct of_device_id atmel_serial_dt_ids[] = {
-	{ .compatible = "atmel,at91rm9200-usart" },
-	{ .compatible = "atmel,at91sam9260-usart" },
-	{ /* sentinel */ }
+	{
+		.compatible = "atmel,at91rm9200-usart",
+		.data = &at91rm9200_pdata,
+	}, {
+		.compatible = "atmel,at91sam9260-usart",
+		.data = &at91sam9260_pdata,
+	}, {
+		.compatible = "atmel,sama5d3-usart",
+		.data = &sama5d3_pdata,
+	}, {
+		/* sentinel */
+	}
 };
 #endif
 
@@ -362,6 +395,127 @@ static int atmel_config_rs485(struct uart_port *port,
 	return 0;
 }
 
+static unsigned int atmel_calc_cd(struct uart_port *port,
+				  struct serial_iso7816 *iso7816conf)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int cd;
+	u64 mck_rate;
+
+	mck_rate = (u64)clk_get_rate(atmel_port->clk);
+	do_div(mck_rate, iso7816conf->clk);
+	cd = mck_rate;
+	return cd;
+}
+
+static unsigned int atmel_calc_fidi(struct uart_port *port,
+				    struct serial_iso7816 *iso7816conf)
+{
+	u64 fidi = 0;
+
+	if (iso7816conf->sc_fi && iso7816conf->sc_di) {
+		fidi = (u64)iso7816conf->sc_fi;
+		do_div(fidi, iso7816conf->sc_di);
+	}
+	return (u32)fidi;
+}
+
+/* Enable or disable the iso7816 support */
+/* Called with interrupts disabled */
+static int atmel_config_iso7816(struct uart_port *port,
+				struct serial_iso7816 *iso7816conf)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	unsigned int mode;
+	unsigned int cd, fidi;
+	int ret = 0;
+
+	/* Disable interrupts */
+	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
+
+	mode = atmel_uart_readl(port, ATMEL_US_MR);
+
+	if (iso7816conf->flags & SER_ISO7816_ENABLED) {
+		mode &= ~ATMEL_US_USMODE;
+
+		if (iso7816conf->tg > 255) {
+			dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
+			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+			ret = -EINVAL;
+			goto err_out;
+		}
+
+		if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+		    == SER_ISO7816_T(0)) {
+			mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
+		} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
+			   == SER_ISO7816_T(1)) {
+			mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
+		} else {
+			dev_err(port->dev, "ISO7816: Type not supported\n");
+			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+			ret = -EINVAL;
+			goto err_out;
+		}
+
+		mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+		/* select mck clock, and output  */
+		mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+		/* set parity for normal/inverse mode + max iterations */
+		mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
+
+		cd = atmel_calc_cd(port, iso7816conf);
+		fidi = atmel_calc_fidi(port, iso7816conf);
+		if (fidi == 0) {
+			dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
+		} else if (fidi < atmel_port->pdata->fidi_min
+			   || fidi > atmel_port->pdata->fidi_max) {
+			dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
+			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+			ret = -EINVAL;
+			goto err_out;
+		}
+
+		if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
+			/* port not yet in iso7816 mode: store configuration */
+			atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
+			atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
+		}
+
+		atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
+		atmel_uart_writel(port, ATMEL_US_BRGR, cd);
+		atmel_uart_writel(port, ATMEL_US_FIDIR, fidi);
+
+		atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
+		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
+	} else {
+		dev_dbg(port->dev, "Setting UART back to RS232\n");
+		/* back to last RS232 settings */
+		mode = atmel_port->backup_mode;
+		memset(iso7816conf, 0, sizeof(struct serial_iso7816));
+		atmel_uart_writel(port, ATMEL_US_TTGR, 0);
+		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
+		atmel_uart_writel(port, ATMEL_US_FIDIR, 0x174);
+
+		if (atmel_use_pdc_tx(port))
+			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
+						   ATMEL_US_TXBUFE;
+		else
+			atmel_port->tx_done_mask = ATMEL_US_TXRDY;
+	}
+
+	port->iso7816 = *iso7816conf;
+
+	atmel_uart_writel(port, ATMEL_US_MR, mode);
+
+err_out:
+	/* Enable interrupts */
+	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
+
+	return ret;
+}
+
 /*
  * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
  */
@@ -481,8 +635,9 @@ static void atmel_stop_tx(struct uart_port *port)
 	/* Disable interrupts */
 	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
 
-	if ((port->rs485.flags & SER_RS485_ENABLED) &&
-	    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+	if (((port->rs485.flags & SER_RS485_ENABLED) &&
+	     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+	    port->iso7816.flags & SER_ISO7816_ENABLED)
 		atmel_start_rx(port);
 }
 
@@ -500,8 +655,9 @@ static void atmel_start_tx(struct uart_port *port)
 		return;
 
 	if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
-		if ((port->rs485.flags & SER_RS485_ENABLED) &&
-		    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
+		if (((port->rs485.flags & SER_RS485_ENABLED) &&
+		     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+		    port->iso7816.flags & SER_ISO7816_ENABLED)
 			atmel_stop_rx(port);
 
 	if (atmel_use_pdc_tx(port))
@@ -799,8 +955,9 @@ static void atmel_complete_tx_dma(void *arg)
 	 */
 	if (!uart_circ_empty(xmit))
 		atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
-	else if ((port->rs485.flags & SER_RS485_ENABLED) &&
-		 !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+	else if (((port->rs485.flags & SER_RS485_ENABLED) &&
+		  !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+		 port->iso7816.flags & SER_ISO7816_ENABLED) {
 		/* DMA done, stop TX, start RX for RS485 */
 		atmel_start_rx(port);
 	}
@@ -1281,6 +1438,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
 			wake_up_interruptible(&port->state->port.delta_msr_wait);
 		}
 	}
+
+	if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
+		dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
 }
 
 /*
@@ -1373,8 +1533,9 @@ static void atmel_tx_pdc(struct uart_port *port)
 		atmel_uart_writel(port, ATMEL_US_IER,
 				  atmel_port->tx_done_mask);
 	} else {
-		if ((port->rs485.flags & SER_RS485_ENABLED) &&
-		    !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
+		if (((port->rs485.flags & SER_RS485_ENABLED) &&
+		     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
+		    port->iso7816.flags & SER_ISO7816_ENABLED) {
 			/* DMA done, stop TX, start RX for RS485 */
 			atmel_start_rx(port);
 		}
@@ -2099,6 +2260,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 		atmel_uart_writel(port, ATMEL_US_TTGR,
 				  port->rs485.delay_rts_after_send);
 		mode |= ATMEL_US_USMODE_RS485;
+	} else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
+		atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
+		/* select mck clock, and output  */
+		mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
+		/* set max iterations */
+		mode |= ATMEL_US_MAX_ITER(3);
+		if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
+				== SER_ISO7816_T(0))
+			mode |= ATMEL_US_USMODE_ISO7816_T0;
+		else
+			mode |= ATMEL_US_USMODE_ISO7816_T1;
 	} else if (termios->c_cflag & CRTSCTS) {
 		/* RS232 with hardware handshake (RTS/CTS) */
 		if (atmel_use_fifo(port) &&
@@ -2175,7 +2347,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 	}
 	quot = cd | fp << ATMEL_US_FP_OFFSET;
 
-	atmel_uart_writel(port, ATMEL_US_BRGR, quot);
+	if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
+		atmel_uart_writel(port, ATMEL_US_BRGR, quot);
 	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
 	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
 	atmel_port->tx_stopped = false;
@@ -2355,6 +2528,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
 	port->mapbase	= pdev->resource[0].start;
 	port->irq	= pdev->resource[1].start;
 	port->rs485_config	= atmel_config_rs485;
+	port->iso7816_config	= atmel_config_iso7816;
 	port->membase	= NULL;
 
 	memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
@@ -2378,8 +2552,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
 		/* only enable clock when USART is in use */
 	}
 
-	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
-	if (port->rs485.flags & SER_RS485_ENABLED)
+	/*
+	 * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
+	 * ENDTX|TXBUFE
+	 */
+	if (port->rs485.flags & SER_RS485_ENABLED ||
+	    port->iso7816.flags & SER_ISO7816_ENABLED)
 		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
 	else if (atmel_use_pdc_tx(port)) {
 		port->fifosize = PDC_BUFFER_SIZE;
@@ -2719,6 +2897,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
 	}
 
 	atmel_port = &atmel_ports[ret];
+	atmel_port->pdata = of_device_get_match_data(&pdev->dev);
+	if (!atmel_port->pdata) {
+		ret = -EINVAL;
+		goto err;
+	}
 	atmel_port->backup_imr = 0;
 	atmel_port->uart.line = ret;
 	atmel_serial_probe_fifos(atmel_port, pdev);
diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h
index ba3a2437cde4..6911177964ad 100644
--- a/drivers/tty/serial/atmel_serial.h
+++ b/drivers/tty/serial/atmel_serial.h
@@ -78,7 +78,8 @@
 #define	ATMEL_US_OVER		BIT(19)	/* Oversampling Mode */
 #define	ATMEL_US_INACK		BIT(20)	/* Inhibit Non Acknowledge */
 #define	ATMEL_US_DSNACK		BIT(21)	/* Disable Successive NACK */
-#define	ATMEL_US_MAX_ITER	GENMASK(26, 24)	/* Max Iterations */
+#define	ATMEL_US_MAX_ITER_MASK	GENMASK(26, 24)	/* Max Iterations */
+#define	ATMEL_US_MAX_ITER(n)	(((n) << 24) & ATMEL_US_MAX_ITER_MASK)
 #define	ATMEL_US_FILTER		BIT(28)	/* Infrared Receive Line Filter */
 
 #define ATMEL_US_IER		0x08	/* Interrupt Enable Register */
@@ -124,7 +125,8 @@
 #define ATMEL_US_TTGR		0x28	/* Transmitter Timeguard Register */
 #define	ATMEL_US_TG		GENMASK(7, 0)	/* Timeguard Value */
 
-#define ATMEL_US_FIDI		0x40	/* FI DI Ratio Register */
+#define ATMEL_US_FIDIR		0x40	/* FI DI Ratio Register */
+#define ATMEL_US_FIDI		GENMASK(15, 0)	/* FIDI ratio */
 #define ATMEL_US_NER		0x44	/* Number of Errors Register */
 #define ATMEL_US_IF		0x4c	/* IrDA Filter Register */
 
-- 
2.12.2


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

* Re: [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure
  2018-08-07 13:00 ` [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure Ludovic Desroches
@ 2018-08-07 13:32   ` Christoph Hellwig
  0 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2018-08-07 13:32 UTC (permalink / raw)
  To: Ludovic Desroches
  Cc: linux-serial, linux-arch, linux-arm-kernel, gregkh, jslaby, arnd,
	richard.genoud, nicolas.ferre, alexandre.belloni, linux-kernel

On Tue, Aug 07, 2018 at 03:00:48PM +0200, Ludovic Desroches wrote:
> From: Nicolas Ferre <nicolas.ferre@microchip.com>
> 
> Add the ISO7816 ioctl and associated accessors and data structure.
> Drivers can then use this common implementation to handle ISO7816.

It would help a lot of you'd explain what ISO7816 is.  Without that
the changelog is rather meaningless.

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

* Re: [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-08-07 13:00 ` [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support Ludovic Desroches
@ 2018-08-09  8:47   ` Richard Genoud
  2018-08-09 11:30     ` Ludovic Desroches
  0 siblings, 1 reply; 9+ messages in thread
From: Richard Genoud @ 2018-08-09  8:47 UTC (permalink / raw)
  To: Ludovic Desroches, linux-serial, linux-arch, linux-arm-kernel
  Cc: gregkh, jslaby, arnd, richard.genoud, nicolas.ferre,
	alexandre.belloni, linux-kernel

Hi !

On 07/08/2018 15:00, Ludovic Desroches wrote:
> From: Nicolas Ferre <nicolas.ferre@microchip.com>
> 
> When mode is set in atmel_config_iso7816() we backup last RS232 mode
> for coming back to this mode if requested.
> Also allow setup of T=0 and T=1 parameter and basic support in set_termios
> function as well.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> [ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
> Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> ---
>  drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
>  drivers/tty/serial/atmel_serial.h |   6 +-
>  2 files changed, 201 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 8e4428725848..4a7ec44b0ace 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -34,6 +34,7 @@
>  #include <linux/suspend.h>
>  #include <linux/mm.h>
>  
> +#include <asm/div64.h>
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
>  
> @@ -83,6 +84,11 @@ static void atmel_stop_rx(struct uart_port *port);
>  
>  #define ATMEL_ISR_PASS_LIMIT	256
>  
> +struct atmel_uart_pdata {
> +	unsigned int	fidi_min;
> +	unsigned int	fidi_max;
> +};
> +
>  struct atmel_dma_buffer {
>  	unsigned char	*buf;
>  	dma_addr_t	dma_addr;
> @@ -114,6 +120,7 @@ struct atmel_uart_char {
>   */
>  struct atmel_uart_port {
>  	struct uart_port	uart;		/* uart */
> +	const struct atmel_uart_pdata *pdata;	/* SoC specific parameters */
>  	struct clk		*clk;		/* uart clock */
>  	int			may_wakeup;	/* cached value of device_may_wakeup for times we need to disable it */
>  	u32			backup_imr;	/* IMR saved during suspend */
> @@ -147,6 +154,8 @@ struct atmel_uart_port {
>  	struct circ_buf		rx_ring;
>  
>  	struct mctrl_gpios	*gpios;
> +	u32			backup_mode;	/* MR saved during iso7816 operations */
> +	u32			backup_brgr;	/* BRGR saved during iso7816 operations */
>  	unsigned int		tx_done_mask;
>  	u32			fifo_size;
>  	u32			rts_high;
> @@ -192,10 +201,34 @@ static struct console atmel_console;
>  #endif
>  
>  #if defined(CONFIG_OF)
> +static struct atmel_uart_pdata at91rm9200_pdata = {
> +	.fidi_min = 1,
> +	.fidi_max = 2047,
> +};
> +
> +static struct atmel_uart_pdata at91sam9260_pdata = {
> +	.fidi_min = 1,
> +	.fidi_max = 2047,
> +};
> +
> +static struct atmel_uart_pdata sama5d3_pdata = {
> +	.fidi_min = 3,
> +	.fidi_max = 65535,
Are you sure this is for sama5d3 ?
From the datasheets I have, 65535 is for sama5d4/sama5d2
And also, you'll have to s/atmel,at91sam9260-usart/atmel,sama5d2-usart/g
in sama5d{2,4}.dtsi

But I wonder if it could be detected via ATMEL_US_VERSION instead ?


> +};
> +
>  static const struct of_device_id atmel_serial_dt_ids[] = {
> -	{ .compatible = "atmel,at91rm9200-usart" },
> -	{ .compatible = "atmel,at91sam9260-usart" },
> -	{ /* sentinel */ }
> +	{
> +		.compatible = "atmel,at91rm9200-usart",
> +		.data = &at91rm9200_pdata,
> +	}, {
> +		.compatible = "atmel,at91sam9260-usart",
> +		.data = &at91sam9260_pdata,
> +	}, {
> +		.compatible = "atmel,sama5d3-usart",
> +		.data = &sama5d3_pdata,
> +	}, {
> +		/* sentinel */
> +	}
>  };
>  #endif
>  
> @@ -362,6 +395,127 @@ static int atmel_config_rs485(struct uart_port *port,
>  	return 0;
>  }
>  
> +static unsigned int atmel_calc_cd(struct uart_port *port,
> +				  struct serial_iso7816 *iso7816conf)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int cd;
> +	u64 mck_rate;
> +
> +	mck_rate = (u64)clk_get_rate(atmel_port->clk);
> +	do_div(mck_rate, iso7816conf->clk);
> +	cd = mck_rate;
> +	return cd;
> +}
> +
> +static unsigned int atmel_calc_fidi(struct uart_port *port,
> +				    struct serial_iso7816 *iso7816conf)
> +{
> +	u64 fidi = 0;
> +
> +	if (iso7816conf->sc_fi && iso7816conf->sc_di) {
> +		fidi = (u64)iso7816conf->sc_fi;
> +		do_div(fidi, iso7816conf->sc_di);
> +	}
> +	return (u32)fidi;
> +}
> +
> +/* Enable or disable the iso7816 support */
> +/* Called with interrupts disabled */
> +static int atmel_config_iso7816(struct uart_port *port,
> +				struct serial_iso7816 *iso7816conf)
> +{
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +	unsigned int mode;
> +	unsigned int cd, fidi;
> +	int ret = 0;
> +
> +	/* Disable interrupts */
> +	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
> +
> +	mode = atmel_uart_readl(port, ATMEL_US_MR);
> +
> +	if (iso7816conf->flags & SER_ISO7816_ENABLED) {
> +		mode &= ~ATMEL_US_USMODE;
> +
> +		if (iso7816conf->tg > 255) {
> +			dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
> +			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
> +			ret = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
> +		    == SER_ISO7816_T(0)) {
> +			mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
> +		} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
> +			   == SER_ISO7816_T(1)) {
> +			mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
> +		} else {
> +			dev_err(port->dev, "ISO7816: Type not supported\n");
> +			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
> +			ret = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
> +
> +		/* select mck clock, and output  */
> +		mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
> +		/* set parity for normal/inverse mode + max iterations */
> +		mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
> +
> +		cd = atmel_calc_cd(port, iso7816conf);
> +		fidi = atmel_calc_fidi(port, iso7816conf);
> +		if (fidi == 0) {
> +			dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
> +		} else if (fidi < atmel_port->pdata->fidi_min
> +			   || fidi > atmel_port->pdata->fidi_max) {
> +			dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
> +			memset(iso7816conf, 0, sizeof(struct serial_iso7816));
> +			ret = -EINVAL;
> +			goto err_out;
> +		}
> +
> +		if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
> +			/* port not yet in iso7816 mode: store configuration */
> +			atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
> +			atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
> +		}
> +
> +		atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
> +		atmel_uart_writel(port, ATMEL_US_BRGR, cd);
> +		atmel_uart_writel(port, ATMEL_US_FIDIR, fidi);
> +
> +		atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
> +		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
> +	} else {
> +		dev_dbg(port->dev, "Setting UART back to RS232\n");
> +		/* back to last RS232 settings */
> +		mode = atmel_port->backup_mode;
> +		memset(iso7816conf, 0, sizeof(struct serial_iso7816));
> +		atmel_uart_writel(port, ATMEL_US_TTGR, 0);
> +		atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
> +		atmel_uart_writel(port, ATMEL_US_FIDIR, 0x174);
> +
> +		if (atmel_use_pdc_tx(port))
> +			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
> +						   ATMEL_US_TXBUFE;
> +		else
> +			atmel_port->tx_done_mask = ATMEL_US_TXRDY;
> +	}
> +
> +	port->iso7816 = *iso7816conf;
> +
> +	atmel_uart_writel(port, ATMEL_US_MR, mode);
> +
> +err_out:
> +	/* Enable interrupts */
> +	atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
> +
> +	return ret;
> +}
> +
>  /*
>   * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
>   */
> @@ -481,8 +635,9 @@ static void atmel_stop_tx(struct uart_port *port)
>  	/* Disable interrupts */
>  	atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
>  
> -	if ((port->rs485.flags & SER_RS485_ENABLED) &&
> -	    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
> +	if (((port->rs485.flags & SER_RS485_ENABLED) &&
> +	     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
> +	    port->iso7816.flags & SER_ISO7816_ENABLED)
>  		atmel_start_rx(port);
>  }
>  
> @@ -500,8 +655,9 @@ static void atmel_start_tx(struct uart_port *port)
>  		return;
>  
>  	if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
> -		if ((port->rs485.flags & SER_RS485_ENABLED) &&
> -		    !(port->rs485.flags & SER_RS485_RX_DURING_TX))
> +		if (((port->rs485.flags & SER_RS485_ENABLED) &&
> +		     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
> +		    port->iso7816.flags & SER_ISO7816_ENABLED)
>  			atmel_stop_rx(port);
>  
>  	if (atmel_use_pdc_tx(port))
> @@ -799,8 +955,9 @@ static void atmel_complete_tx_dma(void *arg)
>  	 */
>  	if (!uart_circ_empty(xmit))
>  		atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
> -	else if ((port->rs485.flags & SER_RS485_ENABLED) &&
> -		 !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
> +	else if (((port->rs485.flags & SER_RS485_ENABLED) &&
> +		  !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
> +		 port->iso7816.flags & SER_ISO7816_ENABLED) {
>  		/* DMA done, stop TX, start RX for RS485 */
>  		atmel_start_rx(port);
>  	}
> @@ -1281,6 +1438,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
>  			wake_up_interruptible(&port->state->port.delta_msr_wait);
>  		}
>  	}
> +
> +	if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
> +		dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
>  }
>  
>  /*
> @@ -1373,8 +1533,9 @@ static void atmel_tx_pdc(struct uart_port *port)
>  		atmel_uart_writel(port, ATMEL_US_IER,
>  				  atmel_port->tx_done_mask);
>  	} else {
> -		if ((port->rs485.flags & SER_RS485_ENABLED) &&
> -		    !(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
> +		if (((port->rs485.flags & SER_RS485_ENABLED) &&
> +		     !(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
> +		    port->iso7816.flags & SER_ISO7816_ENABLED) {
>  			/* DMA done, stop TX, start RX for RS485 */
>  			atmel_start_rx(port);
>  		}
> @@ -2099,6 +2260,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
>  		atmel_uart_writel(port, ATMEL_US_TTGR,
>  				  port->rs485.delay_rts_after_send);
>  		mode |= ATMEL_US_USMODE_RS485;
> +	} else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
> +		atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
> +		/* select mck clock, and output  */
> +		mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
> +		/* set max iterations */
> +		mode |= ATMEL_US_MAX_ITER(3);
> +		if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
> +				== SER_ISO7816_T(0))
> +			mode |= ATMEL_US_USMODE_ISO7816_T0;
> +		else
> +			mode |= ATMEL_US_USMODE_ISO7816_T1;
>  	} else if (termios->c_cflag & CRTSCTS) {
>  		/* RS232 with hardware handshake (RTS/CTS) */
>  		if (atmel_use_fifo(port) &&
> @@ -2175,7 +2347,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
>  	}
>  	quot = cd | fp << ATMEL_US_FP_OFFSET;
>  
> -	atmel_uart_writel(port, ATMEL_US_BRGR, quot);
> +	if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
> +		atmel_uart_writel(port, ATMEL_US_BRGR, quot);
>  	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
>  	atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN);
>  	atmel_port->tx_stopped = false;
> @@ -2355,6 +2528,7 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
>  	port->mapbase	= pdev->resource[0].start;
>  	port->irq	= pdev->resource[1].start;
>  	port->rs485_config	= atmel_config_rs485;
> +	port->iso7816_config	= atmel_config_iso7816;
>  	port->membase	= NULL;
>  
>  	memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
> @@ -2378,8 +2552,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
>  		/* only enable clock when USART is in use */
>  	}
>  
> -	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
> -	if (port->rs485.flags & SER_RS485_ENABLED)
> +	/*
> +	 * Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
> +	 * ENDTX|TXBUFE
> +	 */
> +	if (port->rs485.flags & SER_RS485_ENABLED ||
> +	    port->iso7816.flags & SER_ISO7816_ENABLED)
>  		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
>  	else if (atmel_use_pdc_tx(port)) {
>  		port->fifosize = PDC_BUFFER_SIZE;
> @@ -2719,6 +2897,11 @@ static int atmel_serial_probe(struct platform_device *pdev)
>  	}
>  
>  	atmel_port = &atmel_ports[ret];
> +	atmel_port->pdata = of_device_get_match_data(&pdev->dev);
> +	if (!atmel_port->pdata) {
> +		ret = -EINVAL;
> +		goto err;
> +	}
>  	atmel_port->backup_imr = 0;
>  	atmel_port->uart.line = ret;
>  	atmel_serial_probe_fifos(atmel_port, pdev);
> diff --git a/drivers/tty/serial/atmel_serial.h b/drivers/tty/serial/atmel_serial.h
> index ba3a2437cde4..6911177964ad 100644
> --- a/drivers/tty/serial/atmel_serial.h
> +++ b/drivers/tty/serial/atmel_serial.h
> @@ -78,7 +78,8 @@
>  #define	ATMEL_US_OVER		BIT(19)	/* Oversampling Mode */
>  #define	ATMEL_US_INACK		BIT(20)	/* Inhibit Non Acknowledge */
>  #define	ATMEL_US_DSNACK		BIT(21)	/* Disable Successive NACK */
> -#define	ATMEL_US_MAX_ITER	GENMASK(26, 24)	/* Max Iterations */
> +#define	ATMEL_US_MAX_ITER_MASK	GENMASK(26, 24)	/* Max Iterations */
> +#define	ATMEL_US_MAX_ITER(n)	(((n) << 24) & ATMEL_US_MAX_ITER_MASK)
>  #define	ATMEL_US_FILTER		BIT(28)	/* Infrared Receive Line Filter */
>  
>  #define ATMEL_US_IER		0x08	/* Interrupt Enable Register */
> @@ -124,7 +125,8 @@
>  #define ATMEL_US_TTGR		0x28	/* Transmitter Timeguard Register */
>  #define	ATMEL_US_TG		GENMASK(7, 0)	/* Timeguard Value */
>  
> -#define ATMEL_US_FIDI		0x40	/* FI DI Ratio Register */
> +#define ATMEL_US_FIDIR		0x40	/* FI DI Ratio Register */
> +#define ATMEL_US_FIDI		GENMASK(15, 0)	/* FIDI ratio */
>  #define ATMEL_US_NER		0x44	/* Number of Errors Register */
>  #define ATMEL_US_IF		0x4c	/* IrDA Filter Register */
>  
> 
Thanks !

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

* Re: [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-08-09  8:47   ` Richard Genoud
@ 2018-08-09 11:30     ` Ludovic Desroches
  2018-09-05 12:43       ` Ludovic Desroches
  0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Desroches @ 2018-08-09 11:30 UTC (permalink / raw)
  To: Richard Genoud
  Cc: linux-serial, linux-arch, linux-arm-kernel, alexandre.belloni,
	arnd, gregkh, linux-kernel, jslaby

Hi Richard,

On Thu, Aug 09, 2018 at 10:47:17AM +0200, Richard Genoud wrote:
> Hi !
> 
> On 07/08/2018 15:00, Ludovic Desroches wrote:
> > From: Nicolas Ferre <nicolas.ferre@microchip.com>
> > 
> > When mode is set in atmel_config_iso7816() we backup last RS232 mode
> > for coming back to this mode if requested.
> > Also allow setup of T=0 and T=1 parameter and basic support in set_termios
> > function as well.
> > 
> > Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> > [ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
> > Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> > ---
> >  drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
> >  drivers/tty/serial/atmel_serial.h |   6 +-
> >  2 files changed, 201 insertions(+), 16 deletions(-)
> > 
> > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> > index 8e4428725848..4a7ec44b0ace 100644
> > --- a/drivers/tty/serial/atmel_serial.c
> > +++ b/drivers/tty/serial/atmel_serial.c

[...]

> >  #if defined(CONFIG_OF)
> > +static struct atmel_uart_pdata at91rm9200_pdata = {
> > +	.fidi_min = 1,
> > +	.fidi_max = 2047,
> > +};
> > +
> > +static struct atmel_uart_pdata at91sam9260_pdata = {
> > +	.fidi_min = 1,
> > +	.fidi_max = 2047,
> > +};
> > +
> > +static struct atmel_uart_pdata sama5d3_pdata = {
> > +	.fidi_min = 3,
> > +	.fidi_max = 65535,
> Are you sure this is for sama5d3 ?
> From the datasheets I have, 65535 is for sama5d4/sama5d2

I checked it and I missed it. What a pity... In fact, it's a bit more
tricky since the min value for d3 is 3 and no longer 1.

> And also, you'll have to s/atmel,at91sam9260-usart/atmel,sama5d2-usart/g
> in sama5d{2,4}.dtsi
>

Yes, I planed to send it later but I can add those patches within this
set of patches. 

> But I wonder if it could be detected via ATMEL_US_VERSION instead ?
> 

I have not checked, I tend to prefer the compatible string for this kind
of thing. But as we already use the version number, I can investigate
this solution if it's the one you prefer.


Regards

Ludovic

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

* Re: [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-08-09 11:30     ` Ludovic Desroches
@ 2018-09-05 12:43       ` Ludovic Desroches
  2018-09-05 13:53         ` Richard Genoud
  0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Desroches @ 2018-09-05 12:43 UTC (permalink / raw)
  To: Richard Genoud, linux-serial, linux-arch, linux-arm-kernel,
	alexandre.belloni, arnd, gregkh, linux-kernel, jslaby

Hi Richard,

On Thu, Aug 09, 2018 at 01:30:35PM +0200, Ludovic Desroches wrote:
> Hi Richard,
> 
> On Thu, Aug 09, 2018 at 10:47:17AM +0200, Richard Genoud wrote:
> > Hi !
> > 
> > On 07/08/2018 15:00, Ludovic Desroches wrote:
> > > From: Nicolas Ferre <nicolas.ferre@microchip.com>
> > > 
> > > When mode is set in atmel_config_iso7816() we backup last RS232 mode
> > > for coming back to this mode if requested.
> > > Also allow setup of T=0 and T=1 parameter and basic support in set_termios
> > > function as well.
> > > 
> > > Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> > > [ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
> > > Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> > > ---
> > >  drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
> > >  drivers/tty/serial/atmel_serial.h |   6 +-
> > >  2 files changed, 201 insertions(+), 16 deletions(-)
> > > 
> > > diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> > > index 8e4428725848..4a7ec44b0ace 100644
> > > --- a/drivers/tty/serial/atmel_serial.c
> > > +++ b/drivers/tty/serial/atmel_serial.c
> 
> [...]
> 
> > >  #if defined(CONFIG_OF)
> > > +static struct atmel_uart_pdata at91rm9200_pdata = {
> > > +	.fidi_min = 1,
> > > +	.fidi_max = 2047,
> > > +};
> > > +
> > > +static struct atmel_uart_pdata at91sam9260_pdata = {
> > > +	.fidi_min = 1,
> > > +	.fidi_max = 2047,
> > > +};
> > > +
> > > +static struct atmel_uart_pdata sama5d3_pdata = {
> > > +	.fidi_min = 3,
> > > +	.fidi_max = 65535,
> > Are you sure this is for sama5d3 ?
> > From the datasheets I have, 65535 is for sama5d4/sama5d2
> 
> I checked it and I missed it. What a pity... In fact, it's a bit more
> tricky since the min value for d3 is 3 and no longer 1.
> 
> > And also, you'll have to s/atmel,at91sam9260-usart/atmel,sama5d2-usart/g
> > in sama5d{2,4}.dtsi
> >
> 
> Yes, I planed to send it later but I can add those patches within this
> set of patches. 
> 
> > But I wonder if it could be detected via ATMEL_US_VERSION instead ?
> > 
> 
> I have not checked, I tend to prefer the compatible string for this kind
> of thing. But as we already use the version number, I can investigate
> this solution if it's the one you prefer.
> 

ping about this question still in suspend in order to prepare a new version.

Regards

Ludovic

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

* Re: [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-09-05 12:43       ` Ludovic Desroches
@ 2018-09-05 13:53         ` Richard Genoud
  2018-09-05 14:14           ` Ludovic Desroches
  0 siblings, 1 reply; 9+ messages in thread
From: Richard Genoud @ 2018-09-05 13:53 UTC (permalink / raw)
  To: Ludovic Desroches
  Cc: linux-serial, linux-arch, linux-arm-kernel, alexandre.belloni,
	arnd, gregkh, linux-kernel, jslaby, Nicolas Ferre

[added Nicolas back in the thread, he was removed somehow]

Hi Ludovic !

On 05/09/2018 14:43, Ludovic Desroches wrote:
> Hi Richard,
> 
> On Thu, Aug 09, 2018 at 01:30:35PM +0200, Ludovic Desroches wrote:
>> Hi Richard,
>>
>> On Thu, Aug 09, 2018 at 10:47:17AM +0200, Richard Genoud wrote:
>>> Hi !
>>>
>>> On 07/08/2018 15:00, Ludovic Desroches wrote:
>>>> From: Nicolas Ferre <nicolas.ferre@microchip.com>
>>>>
>>>> When mode is set in atmel_config_iso7816() we backup last RS232 mode
>>>> for coming back to this mode if requested.
>>>> Also allow setup of T=0 and T=1 parameter and basic support in set_termios
>>>> function as well.
>>>>
>>>> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
>>>> [ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
>>>> Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
>>>> ---
>>>>  drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
>>>>  drivers/tty/serial/atmel_serial.h |   6 +-
>>>>  2 files changed, 201 insertions(+), 16 deletions(-)
>>>>
>>>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>>>> index 8e4428725848..4a7ec44b0ace 100644
>>>> --- a/drivers/tty/serial/atmel_serial.c
>>>> +++ b/drivers/tty/serial/atmel_serial.c
>>
>> [...]
>>
>>>>  #if defined(CONFIG_OF)
>>>> +static struct atmel_uart_pdata at91rm9200_pdata = {
>>>> +	.fidi_min = 1,
>>>> +	.fidi_max = 2047,
>>>> +};
>>>> +
>>>> +static struct atmel_uart_pdata at91sam9260_pdata = {
>>>> +	.fidi_min = 1,
>>>> +	.fidi_max = 2047,
>>>> +};
>>>> +
>>>> +static struct atmel_uart_pdata sama5d3_pdata = {
>>>> +	.fidi_min = 3,
>>>> +	.fidi_max = 65535,
>>> Are you sure this is for sama5d3 ?
>>> From the datasheets I have, 65535 is for sama5d4/sama5d2
>>
>> I checked it and I missed it. What a pity... In fact, it's a bit more
>> tricky since the min value for d3 is 3 and no longer 1.
>>
>>> And also, you'll have to s/atmel,at91sam9260-usart/atmel,sama5d2-usart/g
>>> in sama5d{2,4}.dtsi
>>>
>>
>> Yes, I planed to send it later but I can add those patches within this
>> set of patches. 
>>
>>> But I wonder if it could be detected via ATMEL_US_VERSION instead ?
>>>
>>
>> I have not checked, I tend to prefer the compatible string for this kind
>> of thing. But as we already use the version number, I can investigate
>> this solution if it's the one you prefer.
>>
> 
> ping about this question still in suspend in order to prepare a new version.
Well, if we use the compatible string for this, we will have to add :
- atmel,sama5d2-usart
- atmel,sama5d3-usart
- (maybe others ?)
to the already existing :
- atmel,at91sam9260-usart
- atmel,at91rm9200-usart
just for setting different limits on the fidi register.
IMHO, it seems a bit overkill. Moreover, the ATMEL_US_VERSION has
already been read, so...
But if you think adding compatible strings is a better/cleaner solution, just convince me ! :)

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

* Re: [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support
  2018-09-05 13:53         ` Richard Genoud
@ 2018-09-05 14:14           ` Ludovic Desroches
  0 siblings, 0 replies; 9+ messages in thread
From: Ludovic Desroches @ 2018-09-05 14:14 UTC (permalink / raw)
  To: Richard Genoud
  Cc: linux-serial, linux-arch, linux-arm-kernel, alexandre.belloni,
	arnd, gregkh, linux-kernel, jslaby, Nicolas Ferre

On Wed, Sep 05, 2018 at 03:53:02PM +0200, Richard Genoud wrote:
> [added Nicolas back in the thread, he was removed somehow]
> 
> Hi Ludovic !
> 
> On 05/09/2018 14:43, Ludovic Desroches wrote:
> > Hi Richard,
> > 
> > On Thu, Aug 09, 2018 at 01:30:35PM +0200, Ludovic Desroches wrote:
> >> Hi Richard,
> >>
> >> On Thu, Aug 09, 2018 at 10:47:17AM +0200, Richard Genoud wrote:
> >>> Hi !
> >>>
> >>> On 07/08/2018 15:00, Ludovic Desroches wrote:
> >>>> From: Nicolas Ferre <nicolas.ferre@microchip.com>
> >>>>
> >>>> When mode is set in atmel_config_iso7816() we backup last RS232 mode
> >>>> for coming back to this mode if requested.
> >>>> Also allow setup of T=0 and T=1 parameter and basic support in set_termios
> >>>> function as well.
> >>>>
> >>>> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> >>>> [ludovic.desroches@microchip.com: rebase, add check on fidi ratio, checkpatch fixes]
> >>>> Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> >>>> ---
> >>>>  drivers/tty/serial/atmel_serial.c | 211 +++++++++++++++++++++++++++++++++++---
> >>>>  drivers/tty/serial/atmel_serial.h |   6 +-
> >>>>  2 files changed, 201 insertions(+), 16 deletions(-)
> >>>>
> >>>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> >>>> index 8e4428725848..4a7ec44b0ace 100644
> >>>> --- a/drivers/tty/serial/atmel_serial.c
> >>>> +++ b/drivers/tty/serial/atmel_serial.c
> >>
> >> [...]
> >>
> >>>>  #if defined(CONFIG_OF)
> >>>> +static struct atmel_uart_pdata at91rm9200_pdata = {
> >>>> +	.fidi_min = 1,
> >>>> +	.fidi_max = 2047,
> >>>> +};
> >>>> +
> >>>> +static struct atmel_uart_pdata at91sam9260_pdata = {
> >>>> +	.fidi_min = 1,
> >>>> +	.fidi_max = 2047,
> >>>> +};
> >>>> +
> >>>> +static struct atmel_uart_pdata sama5d3_pdata = {
> >>>> +	.fidi_min = 3,
> >>>> +	.fidi_max = 65535,
> >>> Are you sure this is for sama5d3 ?
> >>> From the datasheets I have, 65535 is for sama5d4/sama5d2
> >>
> >> I checked it and I missed it. What a pity... In fact, it's a bit more
> >> tricky since the min value for d3 is 3 and no longer 1.
> >>
> >>> And also, you'll have to s/atmel,at91sam9260-usart/atmel,sama5d2-usart/g
> >>> in sama5d{2,4}.dtsi
> >>>
> >>
> >> Yes, I planed to send it later but I can add those patches within this
> >> set of patches. 
> >>
> >>> But I wonder if it could be detected via ATMEL_US_VERSION instead ?
> >>>
> >>
> >> I have not checked, I tend to prefer the compatible string for this kind
> >> of thing. But as we already use the version number, I can investigate
> >> this solution if it's the one you prefer.
> >>
> > 
> > ping about this question still in suspend in order to prepare a new version.
> Well, if we use the compatible string for this, we will have to add :
> - atmel,sama5d2-usart
> - atmel,sama5d3-usart
> - (maybe others ?)
> to the already existing :
> - atmel,at91sam9260-usart
> - atmel,at91rm9200-usart
> just for setting different limits on the fidi register.
> IMHO, it seems a bit overkill. Moreover, the ATMEL_US_VERSION has
> already been read, so...
> But if you think adding compatible strings is a better/cleaner solution, just convince me ! :)

I won't try to convince you since we already use the ATMEL_US_VERSION.
IMHO we should use the compatible string from the beginning but we
didn't have the necessary DT experience at this time to figure out it
was probably better than relying on the version number which can be not
incrimented by error.

I'll check the values of the ATMEL_US_VERSION and use it if everything
is okay.

Regards

Ludovic

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

end of thread, other threads:[~2018-09-05 14:16 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-08-07 13:00 [PATCH v3 0/2] add ISO7816 support Ludovic Desroches
2018-08-07 13:00 ` [PATCH v3 1/2] tty/serial_core: add ISO7816 infrastructure Ludovic Desroches
2018-08-07 13:32   ` Christoph Hellwig
2018-08-07 13:00 ` [PATCH v3 2/2] tty/serial: atmel: add ISO7816 support Ludovic Desroches
2018-08-09  8:47   ` Richard Genoud
2018-08-09 11:30     ` Ludovic Desroches
2018-09-05 12:43       ` Ludovic Desroches
2018-09-05 13:53         ` Richard Genoud
2018-09-05 14:14           ` Ludovic Desroches

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).