Skip to content

Commit 45fdffb

Browse files
committed
Merge branch 'at91-4.14-trunk/serial' into linux-4.14-at91
Signed-off-by: Cristian Birsan <cristian.birsan@microchip.com>
2 parents ee1f213 + 15b4743 commit 45fdffb

13 files changed

Lines changed: 281 additions & 14 deletions

File tree

arch/alpha/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@
102102
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
103103
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
104104
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
105+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
106+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
105107

106108
#define TIOCSERCONFIG 0x5453
107109
#define TIOCSERGWILD 0x5454

arch/mips/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@
9393
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
9494
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
9595
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
96+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
97+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
9698

9799
/* I hope the range from 0x5480 on is free ... */
98100
#define TIOCSCTTY 0x5480 /* become controlling tty */

arch/parisc/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@
6262
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
6363
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
6464
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
65+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
66+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
6567

6668
#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
6769
#define FIOCLEX 0x5451

arch/powerpc/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@
102102
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
103103
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
104104
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
105+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
106+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
105107

106108
#define TIOCSERCONFIG 0x5453
107109
#define TIOCSERGWILD 0x5454

arch/sh/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@
9595
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
9696
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
9797
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
98+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
99+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
98100

99101
#define TIOCSERCONFIG _IO('T', 83) /* 0x5453 */
100102
#define TIOCSERGWILD _IOR('T', 84, int) /* 0x5454 */

arch/sparc/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@
2727
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
2828
#define TIOCGRS485 _IOR('T', 0x41, struct serial_rs485)
2929
#define TIOCSRS485 _IOWR('T', 0x42, struct serial_rs485)
30+
#define TIOCGISO7816 _IOR('T', 0x43, struct serial_iso7816)
31+
#define TIOCSISO7816 _IOWR('T', 0x44, struct serial_iso7816)
3032

3133
/* Note that all the ioctls that are not available in Linux have a
3234
* double underscore on the front to: a) avoid some programs to

arch/xtensa/include/uapi/asm/ioctls.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
108108
#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
109109
#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
110+
#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
111+
#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
110112

111113
#define TIOCSERCONFIG _IO('T', 83)
112114
#define TIOCSERGWILD _IOR('T', 84, int)

drivers/tty/serial/atmel_serial.c

Lines changed: 183 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <linux/suspend.h>
4949
#include <linux/mm.h>
5050

51+
#include <asm/div64.h>
5152
#include <asm/io.h>
5253
#include <asm/ioctls.h>
5354

@@ -161,6 +162,8 @@ struct atmel_uart_port {
161162
struct circ_buf rx_ring;
162163

163164
struct mctrl_gpios *gpios;
165+
u32 backup_mode; /* MR saved during iso7816 operations */
166+
u32 backup_brgr; /* BRGR saved during iso7816 operations */
164167
unsigned int tx_done_mask;
165168
u32 fifo_size;
166169
u32 rts_high;
@@ -177,6 +180,10 @@ struct atmel_uart_port {
177180
unsigned int pending_status;
178181
spinlock_t lock_suspended;
179182

183+
/* ISO7816 */
184+
unsigned int fidi_min;
185+
unsigned int fidi_max;
186+
180187
#ifdef CONFIG_PM
181188
struct {
182189
u32 cr;
@@ -375,6 +382,127 @@ static int atmel_config_rs485(struct uart_port *port,
375382
return 0;
376383
}
377384

385+
static unsigned int atmel_calc_cd(struct uart_port *port,
386+
struct serial_iso7816 *iso7816conf)
387+
{
388+
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
389+
unsigned int cd;
390+
u64 mck_rate;
391+
392+
mck_rate = (u64)clk_get_rate(atmel_port->clk);
393+
do_div(mck_rate, iso7816conf->clk);
394+
cd = mck_rate;
395+
return cd;
396+
}
397+
398+
static unsigned int atmel_calc_fidi(struct uart_port *port,
399+
struct serial_iso7816 *iso7816conf)
400+
{
401+
u64 fidi = 0;
402+
403+
if (iso7816conf->sc_fi && iso7816conf->sc_di) {
404+
fidi = (u64)iso7816conf->sc_fi;
405+
do_div(fidi, iso7816conf->sc_di);
406+
}
407+
return (u32)fidi;
408+
}
409+
410+
/* Enable or disable the iso7816 support */
411+
/* Called with interrupts disabled */
412+
static int atmel_config_iso7816(struct uart_port *port,
413+
struct serial_iso7816 *iso7816conf)
414+
{
415+
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
416+
unsigned int mode;
417+
unsigned int cd, fidi;
418+
int ret = 0;
419+
420+
/* Disable interrupts */
421+
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
422+
423+
mode = atmel_uart_readl(port, ATMEL_US_MR);
424+
425+
if (iso7816conf->flags & SER_ISO7816_ENABLED) {
426+
mode &= ~ATMEL_US_USMODE;
427+
428+
if (iso7816conf->tg > 255) {
429+
dev_err(port->dev, "ISO7816: Timeguard exceeding 255\n");
430+
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
431+
ret = -EINVAL;
432+
goto err_out;
433+
}
434+
435+
if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
436+
== SER_ISO7816_T(0)) {
437+
mode |= ATMEL_US_USMODE_ISO7816_T0 | ATMEL_US_DSNACK;
438+
} else if ((iso7816conf->flags & SER_ISO7816_T_PARAM)
439+
== SER_ISO7816_T(1)) {
440+
mode |= ATMEL_US_USMODE_ISO7816_T1 | ATMEL_US_INACK;
441+
} else {
442+
dev_err(port->dev, "ISO7816: Type not supported\n");
443+
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
444+
ret = -EINVAL;
445+
goto err_out;
446+
}
447+
448+
mode &= ~(ATMEL_US_USCLKS | ATMEL_US_NBSTOP | ATMEL_US_PAR);
449+
450+
/* select mck clock, and output */
451+
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
452+
/* set parity for normal/inverse mode + max iterations */
453+
mode |= ATMEL_US_PAR_EVEN | ATMEL_US_NBSTOP_1 | ATMEL_US_MAX_ITER(3);
454+
455+
cd = atmel_calc_cd(port, iso7816conf);
456+
fidi = atmel_calc_fidi(port, iso7816conf);
457+
if (fidi == 0) {
458+
dev_warn(port->dev, "ISO7816 fidi = 0, Generator generates no signal\n");
459+
} else if (fidi < atmel_port->fidi_min
460+
|| fidi > atmel_port->fidi_max) {
461+
dev_err(port->dev, "ISO7816 fidi = %u, value not supported\n", fidi);
462+
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
463+
ret = -EINVAL;
464+
goto err_out;
465+
}
466+
467+
if (!(port->iso7816.flags & SER_ISO7816_ENABLED)) {
468+
/* port not yet in iso7816 mode: store configuration */
469+
atmel_port->backup_mode = atmel_uart_readl(port, ATMEL_US_MR);
470+
atmel_port->backup_brgr = atmel_uart_readl(port, ATMEL_US_BRGR);
471+
}
472+
473+
atmel_uart_writel(port, ATMEL_US_TTGR, iso7816conf->tg);
474+
atmel_uart_writel(port, ATMEL_US_BRGR, cd);
475+
atmel_uart_writel(port, ATMEL_US_FIDI, fidi);
476+
477+
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXEN);
478+
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY | ATMEL_US_NACK | ATMEL_US_ITERATION;
479+
} else {
480+
dev_dbg(port->dev, "Setting UART back to RS232\n");
481+
/* back to last RS232 settings */
482+
mode = atmel_port->backup_mode;
483+
memset(iso7816conf, 0, sizeof(struct serial_iso7816));
484+
atmel_uart_writel(port, ATMEL_US_TTGR, 0);
485+
atmel_uart_writel(port, ATMEL_US_BRGR, atmel_port->backup_brgr);
486+
atmel_uart_writel(port, ATMEL_US_FIDI, 0x174);
487+
488+
if (atmel_use_pdc_tx(port))
489+
atmel_port->tx_done_mask = ATMEL_US_ENDTX |
490+
ATMEL_US_TXBUFE;
491+
else
492+
atmel_port->tx_done_mask = ATMEL_US_TXRDY;
493+
}
494+
495+
port->iso7816 = *iso7816conf;
496+
497+
atmel_uart_writel(port, ATMEL_US_MR, mode);
498+
499+
err_out:
500+
/* Enable interrupts */
501+
atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask);
502+
503+
return ret;
504+
}
505+
378506
/*
379507
* Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
380508
*/
@@ -494,9 +622,12 @@ static void atmel_stop_tx(struct uart_port *port)
494622
/* Disable interrupts */
495623
atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask);
496624

497-
if ((port->rs485.flags & SER_RS485_ENABLED) &&
498-
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
499-
atmel_start_rx(port);
625+
if (((port->rs485.flags & SER_RS485_ENABLED) &&
626+
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
627+
port->iso7816.flags & SER_ISO7816_ENABLED)
628+
if (!atomic_read(&atmel_port->tasklet_shutdown))
629+
atmel_start_rx(port);
630+
500631
}
501632

502633
/*
@@ -513,8 +644,9 @@ static void atmel_start_tx(struct uart_port *port)
513644
return;
514645

515646
if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port))
516-
if ((port->rs485.flags & SER_RS485_ENABLED) &&
517-
!(port->rs485.flags & SER_RS485_RX_DURING_TX))
647+
if (((port->rs485.flags & SER_RS485_ENABLED) &&
648+
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
649+
port->iso7816.flags & SER_ISO7816_ENABLED)
518650
atmel_stop_rx(port);
519651

520652
if (atmel_use_pdc_tx(port))
@@ -812,8 +944,9 @@ static void atmel_complete_tx_dma(void *arg)
812944
*/
813945
if (!uart_circ_empty(xmit))
814946
atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx);
815-
else if ((port->rs485.flags & SER_RS485_ENABLED) &&
816-
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
947+
else if (((port->rs485.flags & SER_RS485_ENABLED) &&
948+
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
949+
port->iso7816.flags & SER_ISO7816_ENABLED) {
817950
/* DMA done, stop TX, start RX for RS485 */
818951
atmel_start_rx(port);
819952
}
@@ -1295,6 +1428,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending,
12951428
wake_up_interruptible(&port->state->port.delta_msr_wait);
12961429
}
12971430
}
1431+
1432+
if (pending & (ATMEL_US_NACK | ATMEL_US_ITERATION))
1433+
dev_dbg(port->dev, "ISO7816 ERROR (0x%08x)\n", pending);
12981434
}
12991435

13001436
/*
@@ -1387,8 +1523,9 @@ static void atmel_tx_pdc(struct uart_port *port)
13871523
atmel_uart_writel(port, ATMEL_US_IER,
13881524
atmel_port->tx_done_mask);
13891525
} else {
1390-
if ((port->rs485.flags & SER_RS485_ENABLED) &&
1391-
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) {
1526+
if (((port->rs485.flags & SER_RS485_ENABLED) &&
1527+
!(port->rs485.flags & SER_RS485_RX_DURING_TX)) ||
1528+
port->iso7816.flags & SER_ISO7816_ENABLED) {
13921529
/* DMA done, stop TX, start RX for RS485 */
13931530
atmel_start_rx(port);
13941531
}
@@ -1763,6 +1900,22 @@ static void atmel_get_ip_name(struct uart_port *port)
17631900
atmel_port->has_frac_baudrate = true;
17641901
atmel_port->has_hw_timer = true;
17651902
atmel_port->rtor = ATMEL_US_RTOR;
1903+
version = atmel_uart_readl(port, ATMEL_US_VERSION);
1904+
switch (version) {
1905+
case 0x814: /* sama5d2 */
1906+
/* fall through */
1907+
case 0x701: /* sama5d4 */
1908+
atmel_port->fidi_min = 3;
1909+
atmel_port->fidi_max = 65535;
1910+
break;
1911+
case 0x502: /* sam9x5, sama5d3 */
1912+
atmel_port->fidi_min = 3;
1913+
atmel_port->fidi_max = 2047;
1914+
break;
1915+
default:
1916+
atmel_port->fidi_min = 1;
1917+
atmel_port->fidi_max = 2047;
1918+
}
17661919
} else if (name == dbgu_uart) {
17671920
dev_dbg(port->dev, "Dbgu or uart without hw timer\n");
17681921
} else {
@@ -2143,6 +2296,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
21432296
atmel_uart_writel(port, ATMEL_US_TTGR,
21442297
port->rs485.delay_rts_after_send);
21452298
mode |= ATMEL_US_USMODE_RS485;
2299+
} else if (port->iso7816.flags & SER_ISO7816_ENABLED) {
2300+
atmel_uart_writel(port, ATMEL_US_TTGR, port->iso7816.tg);
2301+
/* select mck clock, and output */
2302+
mode |= ATMEL_US_USCLKS_MCK | ATMEL_US_CLKO;
2303+
/* set max iterations */
2304+
mode |= ATMEL_US_MAX_ITER(3);
2305+
if ((port->iso7816.flags & SER_ISO7816_T_PARAM)
2306+
== SER_ISO7816_T(0))
2307+
mode |= ATMEL_US_USMODE_ISO7816_T0;
2308+
else
2309+
mode |= ATMEL_US_USMODE_ISO7816_T1;
21462310
} else if (termios->c_cflag & CRTSCTS) {
21472311
/* RS232 with hardware handshake (RTS/CTS) */
21482312
if (atmel_use_fifo(port) &&
@@ -2219,7 +2383,8 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
22192383
}
22202384
quot = cd | fp << ATMEL_US_FP_OFFSET;
22212385

2222-
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
2386+
if (!(port->iso7816.flags & SER_ISO7816_ENABLED))
2387+
atmel_uart_writel(port, ATMEL_US_BRGR, quot);
22232388
atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
22242389
atmel_uart_writel(port, ATMEL_US_CR,
22252390
mdrop | ATMEL_US_TXEN | ATMEL_US_RXEN);
@@ -2401,7 +2566,8 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
24012566
port->mapbase = mpdev->resource[0].start;
24022567
port->irq = mpdev->resource[1].start;
24032568
port->rs485_config = atmel_config_rs485;
2404-
port->membase = NULL;
2569+
port->iso7816_config = atmel_config_iso7816;
2570+
port->membase = NULL;
24052571

24062572
memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring));
24072573

@@ -2424,8 +2590,12 @@ static int atmel_init_port(struct atmel_uart_port *atmel_port,
24242590
/* only enable clock when USART is in use */
24252591
}
24262592

2427-
/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
2428-
if (port->rs485.flags & SER_RS485_ENABLED)
2593+
/*
2594+
* Use TXEMPTY for interrupt when rs485 or ISO7816 else TXRDY or
2595+
* ENDTX|TXBUFE
2596+
*/
2597+
if (port->rs485.flags & SER_RS485_ENABLED ||
2598+
port->iso7816.flags & SER_ISO7816_ENABLED)
24292599
atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
24302600
else if (atmel_use_pdc_tx(port)) {
24312601
port->fifosize = PDC_BUFFER_SIZE;

drivers/tty/serial/atmel_serial.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,8 @@
8282
#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */
8383
#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */
8484
#define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */
85-
#define ATMEL_US_MAX_ITER GENMASK(26, 24) /* Max Iterations */
85+
#define ATMEL_US_MAX_ITER_MASK GENMASK(26, 24) /* Max Iterations */
86+
#define ATMEL_US_MAX_ITER(n) (((n) << 24) & ATMEL_US_MAX_ITER_MASK)
8687
#define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */
8788

8889
#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */

0 commit comments

Comments
 (0)