cuart icc clock freq and divider setting support

Change-Id: I9c99c68511d3972513348ee6be5e7bb3b3a5f99e
diff --git a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
index f9856f3..a8f8044 100644
--- a/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
+++ b/sysmoOCTSIM/cuart_driver_asf4_usart_async.c
@@ -289,6 +289,8 @@
 	cuart->u.asf4.usa_pd = usa_pd;
 	cuart->u.asf4.slot_nr = slot_nr;
 
+	/* in us, 20Mhz with default ncn8025 divider 8, F=372, D=1*/
+	cuart->u.asf4.extrawait_after_rx = 1./(20./8/372);
 
 	usart_async_register_callback(usa_pd, USART_ASYNC_RXC_CB, SIM_rx_cb[slot_nr]);
 	usart_async_register_callback(usa_pd, USART_ASYNC_TXC_CB, SIM_tx_cb[slot_nr]);
@@ -338,6 +340,8 @@
 	return io_read(&usa_pd->io, data, len);
 }
 
+#include "ccid_device.h"
+#include "iso7816_3.h"
 static int asf4_usart_ctrl(struct card_uart *cuart, enum card_uart_ctl ctl, int arg)
 {
 	struct ncn8025_settings settings;
@@ -349,7 +353,7 @@
 			sercom->USART.CTRLB.bit.RXEN = 1;
 			sercom->USART.CTRLB.bit.TXEN = 0;
 		} else {
-			delay_us(100);
+			delay_us(cuart->u.asf4.extrawait_after_rx);
 			sercom->USART.CTRLB.bit.RXEN = 0;
 			sercom->USART.CTRLB.bit.TXEN = 1;
 		}
@@ -361,22 +365,47 @@
 		usart_async_flush_rx_buffer(cuart->u.asf4.usa_pd);
 		break;
 	case CUART_CTL_POWER:
-		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
-		settings.cmdvcc = arg ? true : false;
-		settings.led = arg ? true : false;
-		settings.vsel = SIM_VOLT_5V0;
+		/* in us, 20Mhz with default ncn8025 divider 8, F=372, D=1*/
+		cuart->u.asf4.extrawait_after_rx = 1./(20./8/372);
 
 		// set USART baud rate to match the interface (f = 2.5 MHz) and card default settings (Fd = 372, Dd = 1)
 		if(arg)
 			slot_set_isorate(cuart->u.asf4.slot_nr, SIM_CLKDIV_8, ISO7816_3_DEFAULT_FD, ISO7816_3_DEFAULT_DD);
 
+		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
+		settings.cmdvcc = arg ? true : false;
+		settings.led = arg ? true : false;
+		settings.vsel = SIM_VOLT_5V0;
 		ncn8025_set(cuart->u.asf4.slot_nr, &settings);
+
 		break;
 	case CUART_CTL_WTIME:
 		/* no driver-specific handling of this */
 		break;
 	case CUART_CTL_CLOCK:
-		/* FIXME */
+		/* no clock stop support */
+		break;
+	case CUART_CTL_CLOCK_FREQ:
+		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
+
+		/* 2,5/5/10/20 supported by dividers */
+		enum ncn8025_sim_clkdiv clkdiv = SIM_CLKDIV_1;
+		if(arg < 20000000)
+			clkdiv = SIM_CLKDIV_2;
+		if(arg < 10000000)
+			clkdiv = SIM_CLKDIV_4;
+		if(arg < 5000000)
+			clkdiv = SIM_CLKDIV_8;
+		settings.clkdiv = clkdiv;
+		ncn8025_set(cuart->u.asf4.slot_nr, &settings);
+		break;
+	case CUART_CTL_FD:
+		ncn8025_get(cuart->u.asf4.slot_nr, &settings);
+		uint8_t divider = ncn8025_div_val[settings.clkdiv];
+		uint32_t baudrate = (20e6/divider)/arg;
+		cuart->u.asf4.extrawait_after_rx = 1./baudrate * 1000 * 1000;
+		slot_set_baudrate(cuart->u.asf4.slot_nr, baudrate);
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/sysmoOCTSIM/ncn8025.c b/sysmoOCTSIM/ncn8025.c
index 540b166..74d3b39 100644
--- a/sysmoOCTSIM/ncn8025.c
+++ b/sysmoOCTSIM/ncn8025.c
@@ -159,7 +159,7 @@
 	[SIM_VOLT_1V8] = "1.8",
 };
 
-static const unsigned int div_val[] = {
+const unsigned int ncn8025_div_val[] = {
 	[SIM_CLKDIV_1] = 1,
 	[SIM_CLKDIV_2] = 2,
 	[SIM_CLKDIV_4] = 4,
@@ -168,7 +168,7 @@
 
 void ncn8025_dump(const struct ncn8025_settings *set)
 {
-	printf("VOLT=%s, CLKDIV=%u", volt_str[set->vsel], div_val[set->clkdiv]);
+	printf("VOLT=%s, CLKDIV=%u", volt_str[set->vsel], ncn8025_div_val[set->clkdiv]);
 	if (set->rstin)
 		printf(", RST");
 	if (set->cmdvcc)
diff --git a/sysmoOCTSIM/ncn8025.h b/sysmoOCTSIM/ncn8025.h
index 2e774a7..01ddc97 100644
--- a/sysmoOCTSIM/ncn8025.h
+++ b/sysmoOCTSIM/ncn8025.h
@@ -14,6 +14,8 @@
 	SIM_CLKDIV_8 = 0,
 };
 
+extern const unsigned int ncn8025_div_val[];
+
 struct ncn8025_settings {
 	bool rstin;	/* Reset signal (true: asserted low) */
 	bool cmdvcc;	/* Command VCC pin. Activation sequence Enable (true: active low) */